Modbus RTU Clock/remote dispaly. Wired RS-485 connection, remote powered 7-36V.
Industrial format clock. Power up to 36V. Control via RS-485 Modbus RTU protocol.
Hardware
Combine LED board, Pro Mini, DC-DC, RS485 by wires.
Software
Coded in Arduino, want rewrite in Atmel Studio.
#include "ModbusRtu.h"
#include "TM1637.h"
#include "timer-api.h"
#include "EEPROM.h"
//#include <avr/wdt.h>
//1024 0x03FF EEPROM, 32Kb FLASH, 2Kb RAM - atmega328
//512 0x01FF EEPROM, 16Kb FLASH, 1Kb RAM - atmega168
//512 0x01FF EEPROM, 8Kb FLASH, 1Kb RAM - atmega8
#define tm1637_CLK 5
#define tm1637_DIO 6
#define buzzer 9
#define rs485ctr 4
#define button1 2
#define statusled 13
#define msIDdef 45
#define resonans 2200
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long buzzerMillis = 0;
byte msID = msIDdef;
// meteodata
int temp = 32767; //
byte humd = 255; // 0 .. 99
// time config
byte hours = 24; // 0 .. 23
byte minute = 60; // 0 .. 59
byte second = 60; // 0 .. 59
byte year = 100; // 0 .. 99
byte month = 13; // 1 .. 12
byte day = 32; // 1 .. 28/29/30/31
byte bright = 7; //0-7
//byte isRTC = 0;
int countdownMax = 60;
int todisplay = -1;
int countdown = 0;
int cd_buzzer = 0;
int screen = 0;
int tik = 0;
int ledState = LOW;
int light = 0;
int daycorection = 0;
int n1, n2, n3, n4;
uint16_t au16data[16];
uint16_t au16dataS[16];
int8_t state = 0;
const unsigned int interval = 500;
TM1637 tm1637(tm1637_CLK,tm1637_DIO);
Modbus slave(msID,0,rs485ctr);
//http://www.uize.com/examples/seven-segment-display.html
void setup(){
timer_init_ISR_1Hz(TIMER_DEFAULT);
//wdt_enable(WDTO_8S);
msID = EEPROM.read(0x0000);
if (msID<1 or msID>247){
msID = msIDdef;
EEPROM.write(0x0000,msID);
};
slave.setID(msID);
slave.begin(9600);
tm1637.init();
tm1637.set(bright);
daycorection = EEPROM_int_read(0x0001);
pinMode(statusled, OUTPUT);
//digitalWrite(statusled, HIGH);
PORTB &= ~ B00100000;
pinMode(button1, INPUT_PULLUP);
// attachInterrupt(digitalPinToInterrupt(button1), button, FALLING );
pinMode(buzzer, OUTPUT);
screen=5;
beepit(1000);
//humd=69;
//temp = 800;
//hours = 0;
//minute = 0;
//second = 0;
}
void loop(){
currentMillis = millis();
if (cd_buzzer>0){
if (currentMillis - buzzerMillis >= cd_buzzer){
noTone(buzzer);
cd_buzzer=0;
};
};
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (tik==0) screen=1;
if (tik==9) screen=2;
if (tik==14) screen=3;
if (countdown>0){
if (countdown%20==2){
screen=1;
}else{
screen=4;
};
};
if(todisplay>=0){
screen=6;
};
tik++;
if (tik>20) tik=0;
};
io_sh();
state = slave.poll( au16data, 16 );
if (state > 4) {
io_ch();
};
// годинник
if (screen==1){
if (hours==24 & minute==60) {
tm1637.displayByte(0b01000000,0b11000000,0b01000000,0b01000000); // відображення --:--
}else{
n1 = (int) minute % 10;
n2 = (int) ((minute % 100)-n1)/10;
n3 = (int) hours % 10;
n4 = (int) ((hours % 100)-n3)/10;
tm1637.point(1);
tm1637.display(0,n4);
tm1637.display(1,n3);
tm1637.display(2,n2);
tm1637.display(3,n1);
tm1637.point(0);
};
screen=0;
};
// відображення температури
if (screen==2){
if (temp<32767){
int tempd = (int) abs(temp / 100);
n1 = (int) tempd % 10;
n2 = (int) ((tempd % 100)-n1)/10;
n3 = (int) ((tempd % 1000) - n2 - n1) / 100;
if (temp<0){
tm1637.displayByte(0,0x40);
};
if (n3>0){ tm1637.display(0,n3);}else{tm1637.displayByte(0,0x00);};
if (n2>0){ tm1637.display(1,n2);}else{tm1637.displayByte(1,0x00);};
if (n1>0 | temp==0){ tm1637.display(2,n1);}else{tm1637.displayByte(2,0x00);};
tm1637.displayByte(3,0x63);
};
screen=0;
};
// відображення вологості
if (screen==3){
if (humd <100){
n1 = (int) humd % 10;
n2 = (int) ((humd % 100)-n1)/10;
tm1637.display(0,n2);
tm1637.display(1,n1);
tm1637.displayByte(2,0x63);
tm1637.displayByte(3,0x5c);
};
screen=0;
};
// відображення зворотнього секундоміра
if (screen==4){
tm1637.displayByte(0b00000000,0b00000000,0b00000000,0b00000000);
tm1637.displayInt(countdown);
screen=0;
};
// відображення адреси Modbus
if (screen==5){
tm1637.clearDisplay();
tm1637.displayInt(msID);
tm1637.displayByte(0,0x77);
screen=0;
};
// відображення числа з регістру
if (screen==6){
if(todisplay>=0){
//tm1637.clearDisplay();
tm1637.displayIntZero(todisplay);
};
screen=0;
};
// тест екрану
if (screen==9){
tm1637.displayByte(0xff,0xff,0xff,0xff); //8.8.:8.8.
screen=0;
};
}
void io_sh() {
au16data[0]=hours;
au16data[1]=minute;
au16data[2]=second;
au16data[3]=year;
au16data[4]=month;
au16data[5]=day;
au16data[6]=bright; // яскравість LED екрану
au16data[7]=temp; // температура
au16data[8]=humd; // вологість
au16data[9]=msID; // виставлення адреси слейва
au16data[10]=countdown; // запуск таймера з цих секунд
au16data[11]=countdownMax; // число секунд таймера
au16data[12]=todisplay; // відображеня числа на екрані
au16data[13]=cd_buzzer; // включення пищалки на n мілісекунд
au16data[14]=light; // рівень освітленості LDR
au16data[15]=daycorection; // корекція годинника
for (int i=0; i<16;i++){
au16dataS[i]=au16data[i];
};
};
void io_ch() {
for (int i=0; i<6;i++){
if (au16data[i] != au16dataS[i]){
switch (i) {
case 0:hours=au16data[0];break;
case 1:minute=au16data[1];break;
case 2:second=au16data[2];break;
case 3:year=au16data[3];break;
case 4:month=au16data[4];break;
case 5:day=au16data[5];break;
};
screen=1;
};
};
if (au16data[6] != au16dataS[6]){
bright=au16data[6];
tm1637.set(bright);
};
if (au16data[7] != au16dataS[7]){
temp=au16data[7];
screen=2;
};
if (au16data[8] != au16dataS[8]){
humd=au16data[8];
screen=3;
};
if (au16data[9] != au16dataS[9]){
msID = (byte) au16data[9];
slave.setID(msID);
EEPROM.write(0x0000,msID);
screen=5;
};
if (au16data[10] != au16dataS[10]){
countdown=au16dataS[10];
screen=4;
};
if (au16data[11] != au16dataS[11]){
countdownMax = au16data[11];
};
if (au16data[12] != au16dataS[12]){
todisplay = au16data[12];
if (todisplay<0){
screen=1;
}else{
screen=6;
};
};
if (au16data[13] != au16dataS[13]){
beepit(au16data[13]);
};
if (au16data[15] != au16dataS[15]){
daycorection = au16data[15];
EEPROM_int_write(0x0001,daycorection);
};
};
void timer_handle_interrupts(int timer) {
//wdt_reset();
if (hours!=24 & minute!=60) {
second++;
if (second>59) {
second=0;
minute++;
minute_upd();
screen=1;
if (minute>59) {
minute=0;
hours++;
hours_upd();
if (hours>23) {
hours=0;
};
};
};
};
if (countdown>0){
countdown--;
screen=4;
if (countdown==0){
beepit(1000);
};
};
if (ledState == LOW) {
ledState = HIGH;
PORTB &= ~ B00100000;
} else {
ledState = LOW;
PORTB |= B00100000;
};
//digitalWrite(LED_BUILTIN, ledState);
};
void button() {
countdown=countdownMax;
screen=4;
};
void beepit(int timeus) {
tone(buzzer, resonans);
cd_buzzer = timeus;
buzzerMillis = currentMillis;
};
void minute_upd(){
}
void hours_upd(){
if (daycorection<5000){
int hourcor = (int) daycorection % 24;
if (hours == 0){
second = second + (daycorection-hourcor*24);
};
if (hourcor>0){
second = second + hourcor;
if (second>=60){
int minutc = (int) second % 60;
second = second - minutc*60;
minute = minute + minutc;
};
if (second<0){
};
};
};
};
int EEPROM_int_read(int addr) {
byte raw[2];
for(byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr+i);
int &num = (int&)raw;
return num;
}
void EEPROM_int_write(int addr, int num) {
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++) EEPROM.write(addr+i, raw[i]);
}