Red-green matrix information panel with real time clock
-
More than a year ago I created this panel based on the RG 32x16 matrix from sureelectronics.
I've posted a local article about it, google translation is here https://translate.google.com/translate?sl=ru&tl=en&js=y&prev=_t&hl=ru&ie=UTF-8&u=http%3A%2F%2Fradiokot.ru%2Fcircuit%2Fdigital%2Fhome%2F194%2F&edit-text=Just got time last night to migrate it from Plain C + MySensors 1.2 to Arduino + MySensors 1.4.1
It was a bit trickier. I had to create a configuration of arduino based on atmega128. I used a way described here http://download.chip45.com/chip45-arduino-extension.zip (http://www.chip45.com/products/crumbuino-128_arduino_compatible_atmega128_module_board_usb.php)The C code was adjusted to C++. I keep usign C based libraries for RTC, BMP85 and for the matrix.
Schematic is here http://radiokot.ru/circuit/digital/home/194/01.jpg and here http://radiokot.ru/circuit/digital/home/194/02.jpg
Clock creates 3 child devices on controller side:

Controller is updated with preassure, temperature, light level and RTC battery status
This Lua is used to push Street temperature from vera to the Clock:
local temp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1","CurrentTemperature", 61) temp = temp*10.0 luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {radioId="1;255", variableId="VAR_5", value=temp}, 430)61 is vera ID of wheather plugin current temperature device
430 is Clock node vera device ID
Similar Lua is used to populate Clock with average home temperature:local temp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1","CurrentTemperature", 384) temp = temp*10.0 luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {radioId="1;255", variableId="VAR_4", value=temp}, 430)384 is vera ID of temperature average device
you can also use VAR_1 to show a short text message on the panel
VAR_2 is reserved to populate a numeric ID to third party connected to Serial1. I plan to setup a voice talking device. ID will call ID.wav or ID.mp3 file to playA short video is here
http://www.youtube.com/watch?v=YOuO6zLDz6UMy hardware kept without changes but it was a challenge to download arduino sketch because I use JTAG. The solution was found with Visualmicro and Atmelstudio. I setup an arduino sketch inside VisulMicro and a separate project for debug of the object file inside atmelStudio,. This allows me not only to upload using the JTAG but also to run a hardware debugging
-
full project is here p6008-rg-matrix-clock.zip
sketch is here:
/* ------------------------------------------------------------------------------------- * user configuration *-------------------------------------------------------------------------------------*/ //#define F_CPU 16000000UL #define TIMERS_BMP085_UPDATE_SEC 10 #define TIMERS_BATTERY_UPDATE_MIN 120 #define TIMERS_VERA_PRESSURE_UPDATE_MINUTE 5 #define TIMERS_VERA_TEMPERATURE_UPDATE_MINUTE 2 #define TIMERS_VERA_BATTERY_UPDATE_MINUTE 120 #define TIMERS_VERA_LIGHT_UPDATE_SECONDS 240 #define TIMERS_VERA_CLOCK_UPDATE_HOUR 12 #define TIMERS_VERA_STREET_TEMPERATURE_MINUTE 60 // minutes, time for street temperature recieved from vera to be timed out #define TIMERS_VERA_FAILED_RADIO_MIN 5 #define rus_str_startup "RG Matrix Clock v1.0" #define rus_str_v_komnate "Local" #define rus_str_v_kvartire "Inside" #define rus_str_na_ulitce "Outside" #define rus_str_davlenie "Preassure" /* ------------------------------------------------------------------------------------- * hardware configuration *-------------------------------------------------------------------------------------*/ #define LED_PORT PORTC #define LED_DATA 3 #define LED_WR 2 #define LED_CLK 1 #define LED_CS 0 #define BUZZER_PORT_OUT PORTE #define BUZZER_PORT_DDR DDRE #define BUZZER_PORT_IN PINE #define BUZZER_PORT_PIN (1 << PE2) typedef enum { ADC_LIGHT=3, ADC_BATTERY=2, ADC_VREF=30 } enum_adc; //#define RF24_NOUART //#define RF24_CE_PORT PORTB //#define RF24_CE_DDR DDRB //#define RF24_CE_PIN PB4 //#define RF24_CSN_PORT PORTB //#define RF24_CSN_DDR DDRB //#define RF24_CSN_PIN PB5 //#define MAX_PAYLOAD_SIZE 32 #define RF_CE 12 #define RF_CSN 13 //#define BMP085_EOC_PORT PINC #define BMP085_EOC_PIN (1 << PINC0) /* ------------------------------------------------------------------------------------- * includes *-------------------------------------------------------------------------------------*/ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/wdt.h> //#include <util/delay.h> #include <stdio.h> #include <MySensor.h> #include <SPI.h> #include "i2c.h" #include "bmp085.h" #include "ds3231.h" #include "ht1632c_c.h" #include "axlib.h" #include "incMsg.h" //#include "uart_printf.h" /* ------------------------------------------------------------------------------------- * globals *-------------------------------------------------------------------------------------*/ #define STREET_TEMPERATURE_NONE -2500 // value used to indicate that street temperature was not set or timed outed enum { vera_sens_temp=0, vera_sens_pressure, vera_sens_light }; typedef enum { display_startup=0, display_clock, display_clock_date, display_temperature_pressure, display_failed_radio } enum_display; volatile struct { uint8_t second; uint8_t display_sec; uint8_t display_type_sec; uint8_t measure_bmp085_sec; uint16_t measure_battery_sec; uint8_t vera_preassure_min; uint8_t vera_temperature_min; uint8_t vera_battery_min; uint16_t vera_light_sec; uint32_t vera_clock_sec; uint16_t vera_failed_radio_min; uint8_t vera_street_temperature; uint8_t vera_apartment_temperature; } timers; enum { radio_ok=0, radio_failed }; struct { int16_t temperature; uint32_t pressureMM; uint8_t light; uint16_t h_light_min; uint16_t h_light_max; uint8_t battery; uint16_t vref; volatile int16_t street_temperature; volatile int16_t apartment_temperature; uint8_t radio_status; char buff[20]; enum_display cur_display; bmp085_calibration calibration; struct { uint16_t s_pressureMM; int16_t temperature; uint8_t battery; uint8_t light; } vera_last; } var; MySensor gw(RF_CE, RF_CSN); /* ------------------------------------------------------------------------------------- * function definition *-------------------------------------------------------------------------------------*/ void buzzerInit() { BUZZER_PORT_DDR |= BUZZER_PORT_PIN; } uint8_t buzzerCheck() { return BUZZER_PORT_IN & BUZZER_PORT_PIN; } void buzzerOn() { BUZZER_PORT_OUT |= BUZZER_PORT_PIN; } void buzzerOff() { BUZZER_PORT_OUT &= ~ BUZZER_PORT_PIN; } AXLIB_TIMER_BLINK(buzzer, buzzerCheck(), buzzerOn(), buzzerOff()) void init_mcu(); void display_sec(uint8_t what); uint8_t adc(uint8_t what); // 20 times each second ISR(TIMER1_COMPA_vect) { axlib_timer_blink_buzzer_update(); } // once a second ISR(TIMER3_COMPA_vect) { timers.second++; if(timers.second == 60) { timers.second = 0; // timers with minutes counting if(timers.vera_preassure_min) timers.vera_preassure_min--; if(timers.vera_temperature_min) timers.vera_temperature_min--; if(timers.vera_battery_min) timers.vera_battery_min--; if(timers.vera_failed_radio_min && timers.vera_failed_radio_min != 1) timers.vera_failed_radio_min--; if(timers.vera_street_temperature) { if(!--timers.vera_street_temperature) var.street_temperature = STREET_TEMPERATURE_NONE; } if(timers.vera_apartment_temperature) { if(!--timers.vera_apartment_temperature) var.apartment_temperature = STREET_TEMPERATURE_NONE; } } // timers with seconds counting if(timers.measure_bmp085_sec) timers.measure_bmp085_sec--; if(timers.display_sec) timers.display_sec--; if(timers.display_type_sec) timers.display_type_sec--; if(timers.vera_clock_sec) timers.vera_clock_sec--; if(timers.vera_light_sec) timers.vera_light_sec--; // measurement of RTC battery level if(timers.measure_battery_sec) --timers.measure_battery_sec; } ISR(TIMER2_OVF_vect) { } // adc #define ADC_COUNT_AVG 16 #define ADC_BG 30 #define BATTERY_MIN 250 // V*100, 0% #define BATTERY_MAX 300 // V*100, 100% volatile uint16_t adc_count; volatile uint16_t adc_sum; uint8_t adc(uint8_t what) { adc_count = ADC_COUNT_AVG; adc_sum = 0; ADMUX = (0 << REFS1) | (1 << REFS0) | what; ADCSRA |= (1 << ADSC); return 1; } ISR(ADC_vect) { adc_sum += ADCW; if(!--adc_count) { // finished uint8_t channel = ADMUX & 0x1F; switch(channel) { case ADC_LIGHT: { // should be between 0% and 100% // 0% is most dark if(var.h_light_max < adc_sum) var.h_light_max = adc_sum; if(var.h_light_min > adc_sum) var.h_light_min = adc_sum; uint32_t v = adc_sum - var.h_light_min; v *= 100; v /= (var.h_light_max - var.h_light_min); var.light = 100 - v; break; } case ADC_BATTERY: { uint32_t v = adc_sum; v *= var.vref; v /= 1023; v /= ADC_COUNT_AVG; // translate voltage to % //if(v >= BATTERY_MAX) var.battery = 100; //else if(v <= BATTERY_MIN) var.battery = 0; //else { //v -= BATTERY_MIN; //v *= 100; //v /= (BATTERY_MAX - BATTERY_MIN); //} //var.battery = v; var.battery = axlib_convert_volt2percent_lithium_notrechargeable(v); timers.measure_battery_sec = TIMERS_BATTERY_UPDATE_MIN * 60; break; } case ADC_BG: { uint32_t v = 131; // should be 123 (1.23V) but this one is corrected v *= 1023; v /= adc_sum; v *= 16; var.vref = v; break; } } // find what next to measure if(!timers.measure_battery_sec) channel = ADC_BATTERY; else { switch(channel) { case ADC_LIGHT: channel = ADC_VREF; break; case ADC_VREF: channel = ADC_LIGHT; break; case ADC_BATTERY: channel = ADC_LIGHT; break; } } adc(channel); } else { // next round ADCSRA |= (1 << ADSC); } } /* ------------------------------------------------------------------------------------- * main functions *-------------------------------------------------------------------------------------*/ void setup() { // variables init timers.second = 0; timers.measure_battery_sec = 0; timers.measure_bmp085_sec = 0; timers.vera_preassure_min = 0; timers.vera_clock_sec = 10; timers.vera_light_sec = 0; timers.vera_battery_min = 0; timers.display_sec = 0; timers.vera_failed_radio_min = 0; timers.vera_street_temperature = 0; timers.vera_apartment_temperature = 0; var.vref = 500; var.radio_status = radio_ok; var.street_temperature = STREET_TEMPERATURE_NONE; var.apartment_temperature = STREET_TEMPERATURE_NONE; init_mcu(); buzzerInit(); axlib_timer_blink_buzzer_init(); // init uart printing Serial.begin(115200); Serial1.begin(9600); //uart_debug_init(UART_PRINTF_BAUDRATE(115200, F_CPU)); //uart_debugf_1_P(PSTR("\n------------------------------\nRG Matrix clock started v1.0\n")); gw.debugPrint(PSTR("\n------------------------------\nRG Matrix clock started v1.0\n")); // init bmp085 i2cInit(); bmp085_readCalibration(&var.calibration); gw.debugPrint(PSTR("\n1. BMP085 calibration data:\n")); gw.debugPrint(PSTR("- ac1 = %i\n"), var.calibration.ac1); gw.debugPrint(PSTR("- ac2 = %i\n"), var.calibration.ac2); gw.debugPrint(PSTR("- ac3 = %i\n"), var.calibration.ac3); gw.debugPrint(PSTR("- ac4 = %i\n"), var.calibration.ac4); gw.debugPrint(PSTR("- ac5 = %i\n"), var.calibration.ac5); gw.debugPrint(PSTR("- ac6 = %i\n"), var.calibration.ac6); gw.debugPrint(PSTR("- b1 = %i\n"), var.calibration.b1); gw.debugPrint(PSTR("- b2 = %i\n"), var.calibration.b2); gw.debugPrint(PSTR("- mb = %i\n"), var.calibration.mb); gw.debugPrint(PSTR("- mc = %i\n"), var.calibration.mc); gw.debugPrint(PSTR("- md = %i\n\n"), var.calibration.md); // set 24 hour format of RTC DS3231Set24(1); gw.debugPrint(PSTR("2. DS3231 init done\n")); // init rg matrix //uart_debugf_1_P(PSTR("3. LED init\n")); gw.debugPrint(PSTR("3. LED init\n")); ht1632c_init(&LED_PORT, LED_DATA, LED_WR, LED_CLK, LED_CS, HT1632_COLOR_GEOM_32x16, 1); ht1632c_pwm(15); // vera init //uart_debugf_1_P(PSTR("4. Vera inititalization started\n")); Serial.println("4. Vera initialization started\n"); gw.begin(incomingMessage); gw.sendSketchInfo("RG Matrix clock", "2.0"); gw.present(vera_sens_temp, S_TEMP); gw.present(vera_sens_pressure, S_BARO); gw.present(vera_sens_light, S_LIGHT_LEVEL); //VeraSensor_sendSensorPresentation(vera_sens_temp, S_TEMP); //VeraSensor_sendSensorPresentation(vera_sens_pressure, S_BARO); //VeraSensor_sendSensorPresentation(vera_sens_light, S_LIGHT_LEVEL); //uart_debugf_2_P(PSTR("- radioId = %i\n"), gw.getNodeId()); axlib_timer_blink_buzzer_run(1, 1); //wdt_enable(WDTO_2S); //uart_debugf_1_P(PSTR("5. WDT init done\n\n")); //uart_debugf_1_P(PSTR("------------------------------\nMain loop initiated\n\n")); gw.debugPrint(PSTR("------------------------------\nMain loop initiated\n")); sei(); var.cur_display = display_startup; timers.display_type_sec = 0; adc(ADC_VREF); } void loop() { gw.process(); // request clock synchronization if needed if(!timers.vera_clock_sec) { //uart_debugf_1_P(PSTR("- requested clock sync from vera\n")); gw.debugPrint(PSTR("- requested clock sync from vera\n")); gw.requestTime(receiveTime); timers.vera_clock_sec = 30; if(!timers.vera_failed_radio_min) timers.vera_failed_radio_min = TIMERS_VERA_FAILED_RADIO_MIN; } // it is a time to update measurement on bmp085 if(!timers.measure_bmp085_sec) { int32_t pressure; bmp085_get(&var.calibration, BMP085_OSS_ULTRAHIGHRESOLUTION, &var.temperature, &pressure); var.pressureMM = bmp085_convertPAtoMM(pressure); gw.debugPrint(PSTR("- updated temperature %i.%i, pressure %li.%li mm\n"), var.temperature/10, var.temperature % 10, var.pressureMM/1000, var.pressureMM%1000); // check if update on pressure to vera is needed if(!timers.vera_preassure_min) { // update vera on pressure only that often // use for vera only one digit after dot, rounded uint16_t s_pressureMM = (var.pressureMM + 50) / 100; if(var.vera_last.s_pressureMM != s_pressureMM) { // do an update to vera sprintf_P(var.buff, PSTR("%i.%d"), s_pressureMM / 10, (int)(s_pressureMM % 10)); gw.debugPrint(PSTR("- sending update to Vera pressureMM = %s\n"), var.buff); MyMessage pressureMsg(vera_sens_pressure, V_PRESSURE); MyMessage forecastMsg(vera_sens_pressure, V_FORECAST); gw.send(pressureMsg.set(var.buff)); gw.send(forecastMsg.set("unknown")); //VeraSensor_sendVariableString(vera_sens_pressure, V_PRESSURE, buff); var.vera_last.s_pressureMM = s_pressureMM; timers.vera_preassure_min = TIMERS_VERA_PRESSURE_UPDATE_MINUTE; } } // check if update on temperature to vera is needed if(!timers.vera_temperature_min || abs(var.vera_last.temperature-var.temperature) > 20) { // update vera on temperature only that often if(var.vera_last.temperature != var.temperature) { // do an update to vera sprintf_P(var.buff, PSTR("%i.%i"), var.temperature / 10, var.temperature % 10); gw.debugPrint(PSTR("- sending update to Vera temperature = %s\n"), var.buff); MyMessage tempMsg(vera_sens_temp, V_TEMP); gw.send(tempMsg.set(var.buff)); //VeraSensor_sendVariableString(vera_sens_temp, V_TEMP, buff); var.vera_last.temperature = var.temperature; timers.vera_temperature_min = TIMERS_VERA_TEMPERATURE_UPDATE_MINUTE; } } timers.measure_bmp085_sec = TIMERS_BMP085_UPDATE_SEC; } // update vera on battery if(!timers.vera_battery_min) { if(var.vera_last.battery != var.battery) { gw.debugPrint(PSTR("- sending update to Vera battery = %d%%\n"), var.battery); gw.sendBatteryLevel(var.battery); var.vera_last.battery = var.battery; timers.vera_battery_min = TIMERS_VERA_BATTERY_UPDATE_MINUTE; } } // update vera on light if(!timers.vera_light_sec || abs(var.vera_last.light - var.light) > 10) { if(var.vera_last.light != var.light) { gw.debugPrint(PSTR("- sending update to Vera light = %d%%\n"), var.light); MyMessage msg(vera_sens_light, V_LIGHT_LEVEL); gw.send(msg.set(var.light)); var.vera_last.light = var.light; timers.vera_light_sec = TIMERS_VERA_LIGHT_UPDATE_SECONDS; } } if(timers.vera_failed_radio_min == 1) { timers.vera_failed_radio_min = TIMERS_VERA_FAILED_RADIO_MIN; var.cur_display = display_failed_radio; var.radio_status = radio_failed; } if(!timers.display_sec) { display_sec(var.cur_display); timers.display_sec = 1; } if(!timers.display_type_sec) { switch(var.cur_display) { case display_startup: case display_failed_radio: case display_temperature_pressure: var.cur_display = display_clock; timers.display_type_sec = 10; //ht1632c_clear(); break; case display_clock: var.cur_display = display_clock_date; timers.display_type_sec = 6; //ht1632c_clear(); break; case display_clock_date: var.cur_display = display_temperature_pressure; timers.display_type_sec = 6; //ht1632c_clear(); break; } } wdt_reset(); } /* ------------------------------------------------------------------------------------- * internal function *-------------------------------------------------------------------------------------*/ // This is called when a new time value was received void receiveTime(unsigned long time) { uint8_t hour, minute, second; uint8_t month, day; uint16_t year; axlib_time_convert(time, &hour, &minute, &second); axlib_date_convert(time, &day, &month, &year); gw.debugPrint(PSTR("- new time recieved %02d:%02d.%02d\n"), hour, minute, second); gw.debugPrint(PSTR("- new date recieved %02d.%02d.%04d\n"), day, month, year); DS3231SetFullTime24(hour, minute, second); DS3231SetFullDate(year, month, day, 1); timers.vera_clock_sec = TIMERS_VERA_CLOCK_UPDATE_HOUR * 3600UL; } void setStreetTemp(int t) { // getting street temperature var.street_temperature = t; gw.debugPrint(PSTR("- street temperature received %d\n"), var.street_temperature); // stupid validity check if(var.street_temperature > -600 && var.street_temperature < 1000) timers.vera_street_temperature = TIMERS_VERA_STREET_TEMPERATURE_MINUTE; else var.street_temperature = STREET_TEMPERATURE_NONE; } void setRoomTemp(int t) { // getting apartment temperature var.apartment_temperature = t; gw.debugPrint(PSTR("- apartment temperature received %d\n"), var.apartment_temperature); // stupid validity check if(var.apartment_temperature > -600 && var.apartment_temperature < 1000) timers.vera_apartment_temperature = TIMERS_VERA_STREET_TEMPERATURE_MINUTE; else var.apartment_temperature = STREET_TEMPERATURE_NONE; } void setTextToShow(char* str) { // text message received ht1632c_setfont(FONT_8x13BK); ht1632c_animate_hscrolltext(1, str, HT1632_COLOR_GREEN, 20, 1, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 8); } void setSoundID(int id) { Serial1.println(id); } void clearRadioStatus() { timers.vera_failed_radio_min = 0; var.radio_status = radio_ok; ht1632c_animate_rect_fillfrominside(10, 5, HT1632_COLOR_RED, 5); ht1632c_animate_rect_fillfrominside(17, 10, HT1632_COLOR_GREEN, 5); ht1632c_animate_rect_fillfrominside(15, 7, HT1632_COLOR_BLACK, 5); for(uint8_t i=0; i<3; i++) { ht1632c_setfont(FONT_5x7W); ht1632c_rect(8, 2, 23, 13, HT1632_COLOR_ORANGE); ht1632c_putstr(10, 4, "IN", HT1632_COLOR_RED, 0, HT1632_COLOR_BLACK); ht1632c_sendframe(); wdt_reset(); _delay_ms(100); ht1632c_clear(); ht1632c_sendframe(); wdt_reset(); _delay_ms(100); wdt_reset(); } } void display_temperature(int16_t temperature, uint8_t color, uint8_t bg_color) { uint8_t neg = (temperature<0)?1:0; if(neg) temperature = -temperature; uint8_t dig1 = temperature / 100; uint8_t dig2 = (temperature / 10) % 10; uint8_t dig3 = temperature % 10; uint8_t x = (dig1)?0:7; if(!dig3) x += 4; ht1632c_setfont(FONT_8x13BK); if(neg) { temperature = - temperature; ht1632c_rect(x, 7, x+2, 8, color); x += (dig1)?3:4; } else { x += 1; } ht1632c_setfont(FONT_8x13BK); if(dig1) { // ГЙЖТБ ДЕУСФЛПЧ, ОПМШ РТПРХУЛБЕН ht1632c_putchar(x, 2, dig1 + '0', color, 0, bg_color); x += 8; } // ГЙЖТБ ЕДЙОЙГ, ОПМШ РПЛБЪЩЧБЕН ht1632c_putchar(x, 2, dig2 + '0', color, 0, bg_color); x += 8; if(dig3) { // ДЕУСФЙЮОБС ФПЮЛБ: ПФПВТБЦБЕН ЕУМЙ ЪОБЮБЪБС ГЙЖТБ РПУМЕ ФПЮЛЙ ht1632c_rect(x, 11, x+1, 12, color); x += 3; ht1632c_putchar(x, 2, dig3 + '0', color, 0, bg_color); x += 8; } // ЪОБЛ ЗТБДХУПЧ ht1632c_line(x-1, 0, x-1, 2, color); ht1632c_line(x+1, 0, x+1, 2, color); ht1632c_line(x-1, 0, x+1, 0, color); ht1632c_line(x-1, 2, x+1, 2, color); x += 3; if(x < 31-8) { ht1632c_putchar(x, 2, 'C', color, 0, bg_color); } ht1632c_sendframe(); /* if(var.street_temperature > 0 || (var.street_temperature > -99)) { // display with dot if we have space sprintf_P(buff, PSTR("%d.%d`"), var.street_temperature/10, abs(var.street_temperature)%10); ht1632c_setfont(FONT_6x13); ht1632c_putstr(1, 1, buff, HT1632_COLOR_RED, 0, HT1632_COLOR_BLACK); } else { // duisplay without dot if space is limited sprintf_P(buff, PSTR("%d`"), var.street_temperature/10); ht1632c_setfont(FONT_8x13BK); ht1632c_putstr(4, 2, buff, HT1632_COLOR_RED, 0, HT1632_COLOR_BLACK); } ht1632c_sendframe(); */ } void display_pressure(uint16_t pressure, uint8_t color, uint8_t bg_color) { uint8_t dig1 = pressure / 100; uint8_t dig2 = (pressure / 10 ) % 10; uint8_t dig3 = pressure % 10; ht1632c_setfont(FONT_8x13BK); ht1632c_putchar(0, 2, dig1+'0', color, 0, bg_color); ht1632c_putchar(8, 2, dig2+'0', color, 0, bg_color); ht1632c_putchar(16, 2, dig3+'0', color, 0, bg_color); ht1632c_setfont(FONT_4x6); ht1632c_putchar(24, 8, 'm', color, 0, bg_color); ht1632c_putchar(28, 8, 'm', color, 0, bg_color); ht1632c_sendframe(); } void display_clockf(int8_t x, int8_t y, uint8_t color, uint8_t bg_color) { uint8_t a, b, c; ht1632c_setfont(FONT_6x13B); DS3231GetFullTime24(&a, &b, &c); x += ht1632c_putchar(x, y, '0'+a/10, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); x += ht1632c_putchar(x, y, '0'+a%10, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); if(c%2) { ht1632c_rect(x, y+3, x+1, y+3+2, HT1632_COLOR_ORANGE); ht1632c_rect(x, y+7, x+1, y+7+2, HT1632_COLOR_ORANGE); } x += 6; x += ht1632c_putchar(x-3, y, '0'+b/10, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); ht1632c_putchar(x-3, y, '0'+b%10, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); ht1632c_sendframe(); } void display_sec(uint8_t what) { char buff[64]; ht1632c_clear(); switch(what) { case display_clock: display_clockf(1, 1, HT1632_COLOR_ORANGE, HT1632_COLOR_BLACK); break; case display_clock_date: { uint8_t a, b, c, d; ht1632c_setfont(FONT_5x7W); DS3231GetFullTime24(&a, &b, &c); sprintf(buff, "%02d%c%02d", a, (c%2)?':':' ', b); ht1632c_putstr(1, 1, buff, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); DS3231GetFullDate(&a, &b, &c, &d); sprintf(buff, "%02d.%02d", c, b); ht1632c_putstr(1, 9, buff, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); break; } case display_startup: { ht1632c_animate_rect_fillfrominside(15, 7, HT1632_COLOR_GREEN, 10); //_delay_ms(500); ht1632c_animate_rect_fillfrominside(15, 7, HT1632_COLOR_RED, 10); //_delay_ms(500); ht1632c_animate_rect_fillfrominside(15, 7, HT1632_COLOR_ORANGE, 10); //_delay_ms(500); ht1632c_animate_rect_fillfrominside(15, 7, HT1632_COLOR_BLACK, 10); ht1632c_setfont(FONT_8x13BK); ht1632c_animate_hscrolltext(1, rus_str_startup, HT1632_COLOR_ORANGE, 20, 1, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 16); break; } case display_temperature_pressure: // display street temperature if(var.street_temperature != STREET_TEMPERATURE_NONE) { ht1632c_setfont(FONT_8x13BK); sprintf_P(buff, PSTR(rus_str_na_ulitce)); ht1632c_animate_hscrolltext(1, buff, HT1632_COLOR_RED, 5, 1, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 16); /* if(var.street_temperature > 0 || (var.street_temperature > -99)) { // display with dot if we have space sprintf_P(buff, PSTR("%d.%d`"), var.street_temperature/10, abs(var.street_temperature)%10); ht1632c_setfont(FONT_6x13); ht1632c_putstr(1, 1, buff, HT1632_COLOR_RED, 0, HT1632_COLOR_BLACK); } else { // duisplay without dot if space is limited sprintf_P(buff, PSTR("%d`"), var.street_temperature/10); ht1632c_setfont(FONT_8x13BK); ht1632c_putstr(4, 2, buff, HT1632_COLOR_RED, 0, HT1632_COLOR_BLACK); } ht1632c_sendframe();*/ display_temperature(var.street_temperature, HT1632_COLOR_RED, HT1632_COLOR_BLACK); ht1632c_delay_ms(3000); ht1632c_clear(); } // display room temperature { const void* str; int16_t temp; if(var.apartment_temperature != STREET_TEMPERATURE_NONE) { str = PSTR(rus_str_v_kvartire); temp = var.apartment_temperature; } else { str = PSTR(rus_str_v_komnate); temp = var.temperature; } ht1632c_setfont(FONT_8x13BK); sprintf_P(buff, (const char*)str); ht1632c_animate_hscrolltext(1, buff, HT1632_COLOR_ORANGE, 5, 1, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 16); // sprintf_P(buff, PSTR("%d.%d`"), temp/10, temp%10); display_temperature(temp, HT1632_COLOR_ORANGE, HT1632_COLOR_BLACK); ht1632c_delay_ms(3000); ht1632c_clear(); } // ht1632c_setfont(FONT_6x13); //ht1632c_putstr(1, 1, buff, HT1632_COLOR_ORANGE, 0, HT1632_COLOR_BLACK); //ht1632c_sendframe(); // display atmosphere preasure ht1632c_setfont(FONT_8x13BK); sprintf_P(buff, PSTR(rus_str_davlenie)); ht1632c_animate_hscrolltext(1, buff, HT1632_COLOR_GREEN, 5, 1, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 16); // sprintf(buff, "%dmm", (int)((var.pressureMM+500)/1000)); // ht1632c_setfont(FONT_6x13); // ht1632c_putstr(1, 1, buff, HT1632_COLOR_GREEN, 0, HT1632_COLOR_BLACK); // ht1632c_sendframe(); display_pressure(((var.pressureMM+500)/1000), HT1632_COLOR_GREEN, HT1632_COLOR_BLACK); ht1632c_delay_ms(3000); break; case display_failed_radio: ht1632c_setfont(FONT_8x13BK); //axlib_timer_blink_buzzer_run(3, 1); ht1632c_animate_hscrolltext(1, "Тег йбиум й Vera", HT1632_COLOR_RED, 50, 2, HT1632_DIR_LEFT, 0, HT1632_COLOR_BLACK, 16); break; } // radio status //ht1632c_rect(30, 0, 31, 1, (var.radio_status==radio_ok)?HT1632_COLOR_GREEN:HT1632_COLOR_RED); ht1632c_plot(31, 0, (var.radio_status==radio_ok)?HT1632_COLOR_GREEN:HT1632_COLOR_RED); ht1632c_sendframe(); } void init_mcu() { // timer 1 - 20 times per second // CTC mode // TCCR1A = (0 << WGM11) | (0 << WGM10); // CTC mode + /64 // TCCR1B = (0 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (1 << CS10); // OCR1A = 9375; // timer2 // clock source - T2 TCCR2 = (1 << CS22) | (1 << CS21) | (1 << CS20); // timer 3 - once a second // CTC mode TCCR3A = (0 << WGM31) | (0 << WGM30); // /256 prescaler + CTC mode TCCR3B = (0 << WGM33) | (1 << WGM32) | (1 << CS32) | (0 << CS31) | (0 << CS30); OCR3A = F_CPU / 256; TIMSK |= (0 << TOIE2);// | (1 << OCIE1A); ETIMSK = (1 << OCIE3A); // adc ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); }
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login