Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.
Obě strany předchozí revize Předchozí verze Následující verze | Předchozí verze | ||
2015:microbrewery [2016/01/14 14:17] Lukáš Janík |
2015:microbrewery [2016/01/15 22:03] (aktuální) Lukáš Janík [Timer] |
||
---|---|---|---|
Řádek 101: | Řádek 101: | ||
==== Output control ==== | ==== Output control ==== | ||
+ | Phase outputs will be driven by custom low frequency PWM signal. This PWM is needed to be done by hand, because hadware PWM can not run on low frequencies. In this project, each output (phase) has its own uint8 register (Phase Duty Counter PDC) which is being incremented in intervals given by Timer A CC0 unit (and is repeatedly overflowing).Those registers are representing progress within uint8 Global Duty Cycle register. At each CC0 interrupt, PDCs are compared with global duty cycle register and appropriate output pins are set or reset. | ||
+ | |||
+ | <code c> | ||
+ | // TACC0 | ||
+ | void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) Timer_A_ISR (void) | ||
+ | { | ||
+ | static uint8_t ptr1 = 0; | ||
+ | static uint8_t ptr2 = HEATER_MARGIN; | ||
+ | static uint8_t ptr3 = 2 * HEATER_MARGIN; | ||
+ | |||
+ | // TACCR0 interval : 50Hz | ||
+ | TACCR0 += 2500; | ||
+ | |||
+ | if(ptr1 < g_duty) | ||
+ | P1OUT |= BIT0; | ||
+ | else | ||
+ | P1OUT &= ~BIT0; | ||
+ | |||
+ | if(ptr2 < g_duty) | ||
+ | P1OUT |= BIT2; | ||
+ | else | ||
+ | P1OUT &= ~BIT2; | ||
+ | |||
+ | if(ptr3 < g_duty) { | ||
+ | P1OUT |= BIT3; | ||
+ | }else{ | ||
+ | P1OUT &= ~BIT3; | ||
+ | } | ||
+ | |||
+ | ptr1++; | ||
+ | ptr2++; | ||
+ | ptr3++; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | While PDCs are static variables affected only by periodical increments, those can be preset differently. If so, outputs are ensured not to be switched on or off at the same time all along the program runtime. If loads are powered from single phase, this will significantly reduce peak switching current (same principle as time relays) and thus EMI. The delay between triggering particular outputs is called **Phase Margin** and is obvious from figure below (margin 5ms): | ||
+ | |||
+ | {{ :2015:msbrew_pwm.png?direct&600 |}} | ||
+ | |||
+ | While counter period is 50Hz and counter length is 8b, PWM period is given by: | ||
+ | |||
+ | ''T = counter_period * counter_length = 20E-3 * 255 = 5,1s'' | ||
===== Stir control ===== | ===== Stir control ===== | ||
- | Stir constrol means putting single output pin to logical "1" or "0" by hand or at predefined time intervals. | + | Stirring control will be switched by power switch driven directly from MCU by putting single pin to logical "1" or "0" by hand or at predefined time intervals. Vid. section "programming". |
===== Display interface ===== | ===== Display interface ===== | ||
Řádek 119: | Řádek 161: | ||
void display_print_char(const char character); | void display_print_char(const char character); | ||
void display_print(const char *text); | void display_print(const char *text); | ||
+ | void display_printxy(const char *text, uint8_t x, uint8_t y); | ||
</code> | </code> | ||
+ | |||
+ | ==== Menu ==== | ||
+ | |||
+ | Menu strings are saved in string array. On display redraw, string adressed by global "menu index" variable is shown. First button controls rolling over menu nodes (menu index), remaining two buttons control change of variable of interest (temperature, stir, program flow). | ||
==== RTC ==== | ==== RTC ==== | ||
Řádek 137: | Řádek 184: | ||
</code> | </code> | ||
- | === Programming === | + | ===== Timer ===== |
+ | Single 16b timer clocked at 125kHz and 3 CC units are used as interval timers. | ||
+ | * CC0 (20ms) handles phase outputs (LFPWM). | ||
+ | * CC1 (100ms) handles redraw of the display (1s), calculation of the PID and ADC triggering (3s) and increments brewing program counter. | ||
+ | * CC2 (1,6ms) serves for buttons debounce | ||
====== Conclusion ====== | ====== Conclusion ====== | ||
- | This project uses newlib, the c library for embedded systems. At first, sprintf() from previously mentioned library was used for string handling, however, this function at its own consumed over 5kB of program memory which is totally unacceptable and must be replaced by custom simplified implementation. | + | This project uses newlib, the c library for embedded systems. At first, sprintf() from previously mentioned library was used for string handling, however, this function at its own consumed over 5kB of program memory which is totally unacceptable and must be replaced by custom simplified implementation. For mitigation of program size, specialized custom string functions were implemented. Currently, not all goals are fullfilled because of program memory size. The use of Link Time Optimalization decreases the binary size to 14kB however for some reason LTO optimizes out interrupt service routines even if "used" attribute is attached on them. The video shows current functionality including simple user menu. Desired temperature is set and PID is turned on. Whole project is assembled on breadbord, the temperature sensor is attached to power resistor, whose current is controlled by power transistor on phase 1 output. The temperature fluctuations are caused by current induced from power resistor current, these fluctuations are also causing increase of differential error of PID regulator and will be negligible on final hardware assembly. |
+ | Further work on this project will consist of optimalization of i2c routines (use of interrupts) and float operations. | ||
+ | |||
+ | Full source available at: [[https://github.com/Degress/MSBrew/tree/master/src|https://github.com/Degress/MSBrew/tree/master/src]] | ||
+ | |||
+ | {{youtube>7fSiO2_RyE8?medium}} | ||