Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. Red-green matrix information panel with real time clock

Red-green matrix information panel with real time clock

Scheduled Pinned Locked Moved My Project
2 Posts 1 Posters 4.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • axillentA Offline
    axillentA Offline
    axillent
    Mod
    wrote on last edited by axillent
    #1

    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

    sense and drive

    1 Reply Last reply
    2
    • axillentA Offline
      axillentA Offline
      axillent
      Mod
      wrote on last edited by axillent
      #2

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

      sense and drive

      1 Reply Last reply
      0
      Reply
      • Reply as topic
      Log in to reply
      • Oldest to Newest
      • Newest to Oldest
      • Most Votes


      19

      Online

      11.7k

      Users

      11.2k

      Topics

      113.1k

      Posts


      Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
      • Login

      • Don't have an account? Register

      • Login or register to search.
      • First post
        Last post
      0
      • MySensors
      • OpenHardware.io
      • Categories
      • Recent
      • Tags
      • Popular