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.5k 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.
  • A Offline
    A 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
    • A Offline
      A 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

      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
      Reply
      • Reply as topic
      Log in to reply
      • Oldest to Newest
      • Newest to Oldest
      • Most Votes


      12

      Online

      12.0k

      Users

      11.2k

      Topics

      113.4k

      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