This is one of those weekend project. It is a timer built using STM8 microcontroller for controlling LED light strip and a water pump. It can be used for other things.
There are two switched outputs: 12V 2A for LED strip switched by a MOSFET and a MC34063 switch mode power supply is used to generate the 2.5V for a small pump. The output voltage can be altered by changing the feedback divider. The buck converter can be disabled by sending a logic '1' via diode D3 to its feedback pin. There is a leakage path (~0.4mA) to the output from GPIO via D3 and R7. The whole block (except C2 and C4) can be removed when not needed.
I am using a 5.1V Zener diode as a shunt regulator for the 5V rail while I was waiting for my 78L05 order. I notice that there are some artifacts on the LCD with the 78L05. I'll guess I can stick with the Zener diode or add a bulk electrolytic or tantalum 10uF capacitor across the 5V rail.
There is a sensor input and two unused solder pads for I2C.
There is a 3-pin connector for the SWIM hardware debugger.
LCD delay vs polling
The datasheet for the character LCD lists the timing for each of the instructions. These are the worse case timing that include timing variations due to component variations, voltage and temperatures. Most of the projects implements a delay loop to meet these timings.The LCD timing can be tighten up by polling the internal Busy Flag to determine when the LCD is ready for the next command. This requires an additional GPIO to control the R/W signal.
The instruction time can be less than the values in the datasheet which have some margins for component variations.
TIM1 is used as a trigger for ADC and timer interrupt every 5ms for a software RTC implementation.
I used a prescaler of 1 and a reload value of 60000 in TIM1_RELOAD.
12MHz/60000 = 200HzWith calibration, the reload value can be used to trim the accuracy to be within +/- 0.72 sec per day.
(24 Hr/day * 3600 sec/Hr )/60000 = 1.44 sec/dayI have implemented a menu for trimming.
The timer reload value could be changed in the IRQ service routine from a software phase accumulator to further increase the resolution to fractional values. The difficult part is to automate the calibration against an external time reference (e.g. GPS).
The ADC alternates between the buttons and sensor inputs. They are managed inside the ADC IRQ and their results stored in global variables. The key input routines are run inside the IRQ.
The ADC value is matched to a look up table for decoding the buttons.
const uint16_t Key_Value[]= { 510+ButtonTolerance, 194, 340, 140, 510, 163, 255, 123 };
- count is used to keep track of the amount of time that the button(s) are pressed.
- code is used to store the code for button. KEY_FLAG bit signalnifies a key make event
- A button is recognized if it reaches KEY_THRESHOLD (passed debouncing)
- If the count reaches KEY_CNT_MAX, then a key make event occurred with a KEY_LONG attribute. The counter is then loaded with the KEY_RELOAD value. The difference of these values controls the key repeat rate.
typedef struct { volatile uint8_t code; volatile uint8_t count; } key_t; enum keys { KEY_MENU=0x04, KEY_DEC=0x02, KEY_INC=0x01, KEY_MASK=0x07, KEY_LONG=0x20, KEY_REPORTED=0x40, KEY_FLAG=0x80 }; #define KEY_REPEAT_RATE 4 #define KEY_THRESHOLD 5 #define KEY_RELOAD 50 #define KEY_CNT_MAX (KEY_RELOAD+TICKS_PER_SEC/2/KEY_REPEAT_RATE)
These data structures are used to control a simple user interface using 3 buttons.
- Value is a pointer to the item which can be an 8/16-bit integer or the text label for a UI_Menu_t structure or a function.
- Modified is a pointer to a flag variable that get set when an item is modified. It is also used as the pointer to a function.
typedef struct { void *Value; uint8_t *Modified; uint8_t X; uint8_t Y; uint8_t Width; uint16_t Min; uint16_t Max; uint8_t Flags; } UI_Item_t; typedef struct { uint8_t *Text; UI_Item_t *Items; uint8_t Size; } UI_Menu_t; enum DataFlags { D_12H, D_U8, D_U8Z, D_U16, D_Menu, D_Function };
This is inside the "Alarm" sub-menu. (See further down for an updated version)
A long press of the Edit/Exit key is used to enter/exit the setting menu. The settings are stored in the STM8's internal EEPROM.
I have selected the items can be selected by using the buttons. An up/down arrow appears on the right hand side of the item. The Prev/Next key can be used to decrease/increase the value by one. When the key is held down, the values auto decrease/increase by 10. The Edit/exit key is used to exit the editing.
The firmware so far consumes a fraction of the available memory - about 2.8kB. (8kB FLASH, 1kB RAM).
I use a bit of hot glue to seal the package. It is a bit of dust and dirt magnet. I hope it doesn't turn yellow like epoxy after exposing to sunlight. I covered the sensor with a bit of plastic from an antistatic bag to reduce the sensitivity.
I paired it up with a 2N3904 to to improve on the gain as the 2N2222 die is not sensitive to light. They are wired as a Darlington pair.
I guess this has to do until I get my CdS photoresistors in the mail. It will be connected directly across the sense input.
This replaces the plug in mechanical timer that runs warm (2W). When running in idle, power consumption at 12V is around 14mA. The wallwart is cool to the touch and below the resolution of the cheap wattmeter I have.
I hooked it up to the LED strip for my urban window garden. The sensor is place above the LED strip and pointing outside the window. The LED strip will be switched off to save power when the ambient light has cross the set threshold. It was still dark outside.
Part 2: https://hw-by-design.blogspot.com/2018/12/stm8-timer-irrigation.html
Files are in github: https://github.com/FPGA-Computer/Timer