Red-green matrix information panel with real time clock


  • Mod

    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:
    Untitled.jpg

    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 play

    A short video is here
    http://www.youtube.com/watch?v=YOuO6zLDz6U

    My 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


  • Mod

    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);
    }

Log in to reply
 

Suggested Topics

  • 8
  • 29
  • 44
  • 1
  • 90
  • 3

3
Online

11.2k
Users

11.1k
Topics

112.5k
Posts