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. Simple Mysensors clock

Simple Mysensors clock

Scheduled Pinned Locked Moved My Project
clock
4 Posts 2 Posters 6.2k Views 2 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

    It was an idea a year ago to test an idea of simple and smart clock
    this clock will need no attention because it will be set and synchronized by MySensors support.

    The previous version a year ago was running my port to Plain C MySensors 1.3 and able to fit into atmega8
    Now it is upgraded to arduino + Mysensors 1.4.1 but for this I had to also upgrade to atmega328p (same as in arduino UNO)
    (google translated article 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%2F176%2F&edit-text=)

    Simple - means simple. MCU itself is driving 7 segment display. I'm not using any external RTC clock but I'm using a special asynchronous mode of atmega328 and external 32768 so called clock crystal.

    DS18B20 and light sensor are on board.

    Display driver contains a software PWM with 0-15 level of the light intensity.
    Intensity is adjusted by light.

    schematics is here http://radiokot.ru/circuit/digital/home/176/01.png

    IMG_2150.JPG
    IMG_2151.JPG
    IMG_2152.JPG

    sense and drive

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

      Sketch is here

      /* p6004_simple_clock.c
      *
      * Created: 07.09.2013 17:39:43
      *  Author: axillent
      
      Simple Mysensors.org clock with time synchronization
      
      */
      
      //---------------------------------------------------------------------------------------------------
      // parameters
      #define TIMERS_CLOCK_SYNC_HOURS		12
      #define TIMERS_TEMPERATURE_SECONDS	30
      #define TIMERS_LIGHT_LEVEL_SECONDS	5
      #define DISPLAY_CLOCK_SECONDS		10
      #define DISPLAY_DATE_SECONDS		2
      #define DISPLAY_TEMPERATURE_SECONDS	2
      #define DISPLAY_LIGHT_SECONDS		0
      #define DISPLAY_MINIMUM_PWM			1
      
      //---------------------------------------------------------------------------------------------------
      // hardware definition
      #include "axlib.h"
      
      #define DISP_7SEG_DIGITS		4
      #define DISP_7SEG_PWMMAX		16
      #define DISP_7SEG_PORT			PORTD
      #define DISP_7SEG_DDR			DDRD
      #define DISP_7SEG_DIG_PORT		PORTC
      #define DISP_7SEG_DIG_DDR		DDRC
      #define DISP_7SEG_DIG_DIG1		PC0
      #define DISP_7SEG_DIG_DIG2		PC1
      #define DISP_7SEG_DIG_DIG3		PC2
      #define DISP_7SEG_DIG_DIG4		PC3
      
      #define SensLight		7				// канал оцифровки освещенности
      AXLIB_define_io_functions(ledRadio, C, 4)
      AXLIB_define_io_functions(ledDot, C, 5)
      
      #define RF_CE	8
      #define RF_CSN	9
      
      // стандартные библиотеки
      #include <avr/io.h>
      #include <avr/wdt.h>
      #include <avr/interrupt.h>
      #include <util/delay.h>
      #include <stdlib.h>
      
      #include <MySensor.h>
      #include <SPI.h>
      
      // configure ds18b20
      #define TEMP_PIN			PINB2
      #define TEMP_IN				PINB
      #define TEMP_OUT			PORTB
      #define TEMP_DDR			DDRB
      #define MAXSENSORS 1
      #include "onewire.h"
      #include "ds18x20.h"
      
      //---------------------------------------------------------------------------------------------------
      // functions definition
      void mcu_init();
      void disp_7seg_update();
      void disp_7seg_init();
      void disp_7seg_show(uint8_t digit, uint8_t value, uint8_t dp);
      void disp_7seg_setpwm(uint8_t v);
      uint8_t disp_7seg_getpwm();
      void disp_7seg_setdots(uint8_t dots);
      
      void displayClock();
      void displayTemp();
      void displayLight();
      void displayDate();
      
      void sync_clock();
      void time_convert(unsigned long time, uint8_t* hour, uint8_t* minute, uint8_t* second);
      
      AXLIB_TIMER_BLINK(radio, ledRadio_getinv(), ledRadio_clr(), ledRadio_set())
      
      //---------------------------------------------------------------------------------------------------
      // the programm itself
      
      enum { display_clock=0, display_temp, display_light, display_date };
      
      MySensor gw(RF_CE, RF_CSN);
      MyMessage msgTemp(0, V_TEMP);
      MyMessage msgLight(1, V_LIGHT_LEVEL);
      
      struct {
      	struct {
      		uint8_t					count;
      		int						temp;
      		int						prev_temp;
      		volatile	uint8_t		timer;
      	} temperature;
      	struct {
      		volatile	uint8_t		seconds;
      		volatile	uint8_t		minutes;
      		volatile	uint8_t		hours;
      		volatile	uint8_t		day;
      		volatile	uint8_t		month;
      		volatile	uint16_t	sync_timer;
      	} clock;
      	struct {
      		volatile	uint8_t		light;
      		volatile	uint16_t	avg;
      		volatile	uint8_t		cnt;	
      		volatile	uint8_t		timer;
      		volatile	uint16_t	max_light;
      		volatile	uint16_t	min_light;
      		uint8_t					prev_light;
      	} light;
      	struct {
      		volatile	uint8_t		what;
      		volatile	uint8_t		timer;
      	} display;
      } var;
      
      uint8_t gSensorIDs[MAXSENSORS][OW_ROMCODE_SIZE]; // содержит 64бит идентификаторы датчиков температуры в произвоьном порядке (определенном при поиске)
      
      // таймер динамической индикации
      ISR(TIMER1_OVF_vect) {
      	disp_7seg_update();
      }
      
      // часовой таймер
      ISR(TIMER2_OVF_vect) {
      	// срабатывает каждую секунду от часового кварца
      	//axnet_rtcsoft_update();
      	var.clock.seconds++;
      	if(var.clock.seconds == 60) {
      		var.clock.seconds = 0;
      		var.clock.minutes++;
      		if(var.clock.minutes == 60) {
      			var.clock.minutes = 0;
      			var.clock.hours++;
      			if(var.clock.hours == 24) {
      				var.clock.hours = 0;
      				var.clock.sync_timer = 0;
      			}
      		}
      	}
      
      	// запускаем измерения уровня освещенности
      	ADCSRA |= (1 << ADSC);
      
      	// мерцание точек
      	if(var.display.what == display_clock) {
      		if(var.clock.seconds % 2) {
      			disp_7seg_setdots(1);
      		} else {
      			disp_7seg_setdots(0);
      		}
      	}
      
      	if(var.clock.sync_timer) var.clock.sync_timer--;
      	if(var.temperature.timer) var.temperature.timer--;
      	if(var.display.timer) var.display.timer--;
      	if(var.light.timer) var.light.timer--;
      
      	axlib_timer_blink_radio_update();
      }
      
      // измерение освещенности завершено
      ISR(ADC_vect) {
      	var.light.avg += ADCW;
      	if(!--var.light.cnt) {
      		uint16_t light = var.light.avg / 32;
      	
      		if(var.light.min_light > light) var.light.min_light = light;
      		if(var.light.max_light < light) var.light.max_light = light;
      	
      		uint32_t v = light - var.light.min_light;
      		v *= 100;
      		v /= (var.light.max_light - var.light.min_light);
      		var.light.light = 100 - v;
      	
      		var.light.avg = 0;
      		var.light.cnt = 32;
      	} else {
      		ADCSRA |= (1 << ADSC);
      	}
      }
      
      void setup()
      {
      	// RTC init  ----------------------------------------------
      	// timer2 prescaler 1/128
      	// timer2 overflow 1Hz (32768 osciilator)
      	// asynhronous timer mode for timer 2 - RTC
      //	TIMSK2 = 0;
      	//_delay_ms(100);
      	ASSR = (1 << AS2);
      	//-----------------------------------------------------------
      	_delay_ms(100);
      	// RTC init  continue ---------------------------------------
      	TCNT2 = 0;
      	OCR2A = 0;
      	OCR2B = 0;
      	TCCR2B = (1 << CS22) | (0 << CS21) | (0 << CS20);
      
      	while(ASSR & ((1 << OCR2AUB) | (1 << OCR2BUB) | (1 << TCR2AUB) | (1 << TCR2BUB)));
      	//_delay_ms(500);
      
      	// interrupts for timer2 overflow
      	//TIFR2 |= (1 << OCF2A) | (1 << OCF2B) | (1 << TOV2);
      	TIMSK2 = (1 << TOIE2);
      	//------------------------------------------------------------------
      	// Startup OneWire
      	var.temperature.count = search_sensors();
      
      	// Startup and initialize MySensors library. Set callback for incoming messages.
      //	gw.begin(incomingMessage);
      	gw.begin();
      
      	// Send the sketch version information to the gateway and Controller
      	gw.sendSketchInfo("Simple Clock", "2.0");
      	gw.present(0, S_TEMP);
      	gw.present(1, S_LIGHT_LEVEL);
      
      	Serial.end();
      	mcu_init();
      	disp_7seg_init();
      
      	ledRadio_set();
      	axlib_timer_blink_radio_init();
      
      	var.display.what = display_clock;
      	var.display.timer = DISPLAY_CLOCK_SECONDS;
      	var.temperature.prev_temp = 9999;
      
      	var.light.light = 255;
      	var.light.min_light = 1023;
      	var.light.max_light = 0;
      	var.light.prev_light = 9999;
      	var.light.timer = 2;
      
      	sei();
      	ADCSRA |= (1 << ADSC);
      }
      
      void loop()
      {
      	gw.process();
      
      	if(!var.clock.sync_timer) {
      		gw.requestTime(receiveTime);
      		axlib_timer_blink_radio_run(3, 1);
      		var.clock.sync_timer =  2;	// next update in seconds
      	}
      	
      	switch(var.display.what) {
      		case display_clock:
      			displayClock();
      			break;
      		case display_date:
      			displayDate();
      			break;
      		case display_temp:
      			displayTemp();
      			break;
      		case display_light:
      			displayLight();
      			break;
      	}
      
      	// -------------------------------------------------------------------------------------------
      	// реагирование на освещенность
      	uint16_t pwm = var.light.light * 15;
      	pwm /= 100;
      	if(pwm < DISPLAY_MINIMUM_PWM) pwm = DISPLAY_MINIMUM_PWM;
      	disp_7seg_setpwm(pwm);
      
      	// -------------------------------------------------------------------------------------------
      	// переключение отображения
      	if(!var.display.timer) {
      		disp_7seg_setdots(0);
      		switch(var.display.what) {
      			case display_clock:
      				if(DISPLAY_DATE_SECONDS) {					// date
      					var.display.what = display_date;
      					var.display.timer = DISPLAY_DATE_SECONDS;
      				} else if(DISPLAY_TEMPERATURE_SECONDS) {			// temperature
      					var.display.what = display_temp;
      					var.display.timer = DISPLAY_TEMPERATURE_SECONDS;
      				} else if(DISPLAY_LIGHT_SECONDS) {			// light
      					var.display.what = display_light;
      					var.display.timer = DISPLAY_LIGHT_SECONDS;
      				} else {
      					var.display.timer = DISPLAY_CLOCK_SECONDS;	// clock
      				}
      				break;
      			case display_date:
      				if(DISPLAY_TEMPERATURE_SECONDS) {					// temperature
      					var.display.what = display_temp;
      					var.display.timer = DISPLAY_TEMPERATURE_SECONDS;
      				} else if(DISPLAY_LIGHT_SECONDS) {			// light
      					var.display.what = display_light;
      					var.display.timer = DISPLAY_LIGHT_SECONDS;
      				} else {
      					var.display.what = display_clock;
      					var.display.timer = DISPLAY_CLOCK_SECONDS;	// clock
      				}
      				break;
      			case display_temp:
      				if(DISPLAY_LIGHT_SECONDS) {					// light
      					var.display.what = display_light;
      					var.display.timer = DISPLAY_LIGHT_SECONDS;
      				} else {
      					var.display.what = display_clock;
      					var.display.timer = DISPLAY_CLOCK_SECONDS;	// clock
      				}
      				break;
      			case display_light:
      				var.display.what = display_clock;
      				var.display.timer = DISPLAY_CLOCK_SECONDS;
      			break;
      		}
      	}
      
      	// -------------------------------------------------------------------------------------------
      	// temperature
      	if(var.temperature.count && !var.temperature.timer) {
      
      		SPCR &= ~(1 << SPE);
      		int temp = 0;
      		if(DS18X20_start_meas( DS18X20_POWER_EXTERN, &gSensorIDs[0][0] ) == DS18X20_OK) {
      			_delay_ms(1000);
      			if(DS18X20_read_decicelsius(&gSensorIDs[0][0], &temp) == DS18X20_OK ) var.temperature.temp = temp;
      		}
      		SPCR |= (1 << SPE);
      	
      		if(var.temperature.temp != var.temperature.prev_temp) {
      			axlib_timer_blink_radio_run(2, 1);
      			gw.send(msgTemp.set(temp/10.0, 1));
      			var.temperature.prev_temp = var.temperature.temp;
      		}
      	
      		var.temperature.timer = TIMERS_TEMPERATURE_SECONDS;
      	}
      
      	// -------------------------------------------------------------------------------------------
      	// light level
      	if(!var.light.timer) {
      		if(var.light.light != var.light.prev_light) {
      			axlib_timer_blink_radio_run(2, 1);
      			gw.send(msgLight.set(var.light.light));
      			var.light.prev_light = var.light.light;
      		}
      		var.light.timer = TIMERS_LIGHT_LEVEL_SECONDS;
      	}
      }
      
      void displayClock() {
      	disp_7seg_show(0, var.clock.hours / 10, 0);
      	disp_7seg_show(1, var.clock.hours % 10, 0);
      	disp_7seg_show(2, var.clock.minutes / 10, 0);
      	disp_7seg_show(3, var.clock.minutes % 10, 0);
      }
      void displayDate() {
      	disp_7seg_show(0, var.clock.day / 10, 0);
      	disp_7seg_show(1, var.clock.day % 10, 1);
      	disp_7seg_show(2, var.clock.month / 10, 0);
      	disp_7seg_show(3, var.clock.month % 10, 0);
      }
      void displayTemp() {
      	disp_7seg_show(0, var.temperature.temp / 100, 0);
      	disp_7seg_show(1, (var.temperature.temp / 10) % 10, 1);
      	disp_7seg_show(2, var.temperature.temp % 10, 0);
      	disp_7seg_show(3, 20, 0);
      }
      void displayLight() {
      	disp_7seg_show(0, var.light.light / 1000, 0);
      	disp_7seg_show(1, (var.light.light / 100) % 10, 0);
      	disp_7seg_show(2, (var.light.light / 10) % 10, 0);
      	disp_7seg_show(3, var.light.light % 10, 0);
      }
      
      void mcu_init() {
      	// specific hardware
      	ledRadio_setoutput();
      	ledDot_setoutput();
      
      	// инициализируем таймер для динамической индикации
      	TCCR1A = (0 << WGM11) | (1 << WGM10);
      	TCCR1B = (0 << WGM13) | (1 << WGM12) | (0 << CS12) | (0 << CS11) | (1 << CS10);
      	TIMSK1 = (1 << TOIE1);
      	//TCCR0 = (1 << CS00);
      	//TIMSK |= (1 << TOIE0);
      
      	// инициализация ADC
      	// AVCC
      	ADMUX = (0 << REFS1) | (1 << REFS0) | SensLight;
      	// interrups ON, prescaler 64 + free running
      	ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
      }
      
      
      //---------------------------------------------------------------------------------------------------
      // 7 segment led handling
      uint8_t buffer_7seg[DISP_7SEG_DIGITS];
      uint8_t buffer_7seg_index;
      uint8_t buffer_7seg_mask;
      
      volatile uint8_t disp_7seg_pwm_cnt = 0;
      volatile uint8_t disp_7seg_pwm_value = 15;
      volatile uint8_t disp_7seg_dots;
      
      static void disp_7seg_setpwm(uint8_t v) { disp_7seg_pwm_value = (v<DISP_7SEG_PWMMAX)?v:DISP_7SEG_PWMMAX-1; }
      uint8_t disp_7seg_getpwm() { return disp_7seg_pwm_value; }
      static void disp_7seg_setdots(uint8_t dots) { disp_7seg_dots = dots; }
      
      // initialise all ports and variables
      void disp_7seg_init() {
      	DISP_7SEG_DDR		 = 0xff;			// все биты порта на вывод
      	DISP_7SEG_DIG_DDR	|= (1 << DISP_7SEG_DIG_DIG1) | (1 << DISP_7SEG_DIG_DIG2) | (1 << DISP_7SEG_DIG_DIG3) | (1 << DISP_7SEG_DIG_DIG4);
      
      	buffer_7seg_index = 0;
      	buffer_7seg_mask = (1 << DISP_7SEG_DIG_DIG1);
      	for(uint8_t i=0; i<DISP_7SEG_DIGITS; i++) { buffer_7seg[i] = 0; }
      }
      
      // should be called often to update dynamically leds
      void disp_7seg_update() {
      	// гасим полностью если pwm=0
      	if(disp_7seg_pwm_cnt == 0 && disp_7seg_pwm_value) {
      		// сначала сбрасываем все цифры в 1 (инверсия, т.е. отключаем)
      		DISP_7SEG_DIG_PORT |= 0b00001111;
      		// выводим новые значения сегментов
      		DISP_7SEG_PORT = buffer_7seg[buffer_7seg_index];
      		// включаем нужную цифру
      		DISP_7SEG_DIG_PORT &= ~ buffer_7seg_mask;
      		// готовимся к показу следующей цифры
      		buffer_7seg_index++;
      		if(buffer_7seg_index == DISP_7SEG_DIGITS) {
      			buffer_7seg_index = 0;
      			buffer_7seg_mask = (1 << DISP_7SEG_DIG_DIG1);
      		} else {
      			buffer_7seg_mask = (buffer_7seg_mask << 1);
      		}
      		// точки
      		if(disp_7seg_dots) { ledDot_clr(); } else { ledDot_set(); }
      	} else if(disp_7seg_pwm_cnt > disp_7seg_pwm_value || !disp_7seg_pwm_value) {
      			DISP_7SEG_DIG_PORT |= 0b00001111;
      			ledDot_set();
      	}
      	disp_7seg_pwm_cnt++;
      	if(disp_7seg_pwm_cnt == DISP_7SEG_PWMMAX) { disp_7seg_pwm_cnt = 0; }
      }
      uint8_t disp_7seg_digits[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,	// digits 0-9
      	0x00,		// blank
      	0x40,		// minus
      	0x77,		// A
      	0x39,		// C
      	0x79,		// E
      	0x71,		// F
      	0x1F,		// G
      	0x76,		// H
      	0x38,		// L
      	0x73,		// P
      	0x63		// градус
      };
      void disp_7seg_show(uint8_t digit, uint8_t value, uint8_t dp) {
      	uint8_t code = 0;
      	if(value < sizeof(disp_7seg_digits)) {
      		// декодируем
      		code = disp_7seg_digits[value];
      	}
      	if(dp) { code |= (1 << 7); }
      	buffer_7seg[(digit<sizeof(buffer_7seg))?digit:0] = code;
      }
      
      
      // 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_timer_blink_radio_run(1, 1);
      	axlib_time_convert(time, &hour, &minute, &second);
      	axlib_date_convert(time, &day, &month, &year);
      
      	cli();
      	var.clock.hours = hour;
      	var.clock.minutes = minute;
      	var.clock.seconds = second;
      	var.clock.day = day;
      	var.clock.month = month;
      	sei();
      
      	var.clock.sync_timer = 60 * 60 * TIMERS_CLOCK_SYNC_HOURS;	// next update in seconds
      }
      
      
      uint8_t search_sensors(void)
      {
      	uint8_t i;
      	uint8_t id[OW_ROMCODE_SIZE];
      	uint8_t diff, nSensors;
      
      	ow_set_bus(&TEMP_IN,&TEMP_OUT,&TEMP_DDR,TEMP_PIN);
      	ow_reset();
      
      	nSensors = 0;
      
      	diff = OW_SEARCH_FIRST;
      	while ( diff != OW_LAST_DEVICE && nSensors < MAXSENSORS ) {
      		DS18X20_find_sensor( &diff, &id[0] );
      
      		for ( i=0; i < OW_ROMCODE_SIZE; i++ )
      		gSensorIDs[nSensors][i] = id[i];
      
      		nSensors++;
      	}
      
      	return nSensors;
      }
      

      sense and drive

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

        some 3D models are here http://www.thingiverse.com/thing:160569

        sense and drive

        RJ_MakeR 1 Reply Last reply
        0
        • axillentA axillent

          some 3D models are here http://www.thingiverse.com/thing:160569

          RJ_MakeR Offline
          RJ_MakeR Offline
          RJ_Make
          Hero Member
          wrote on last edited by
          #4

          @axillent is unstoppable!

          RJ_Make

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


          7

          Online

          11.7k

          Users

          11.2k

          Topics

          113.0k

          Posts


          Copyright 2019 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