So I’ve been tinkering with some code to establish a true PWM signal from the Arduino in order to drive the boiler. Rather than implement a software based “Is it time yet?” approach, I thought I’d take advantage of the 16-bit Timer1 on the Atmega328P (the Pro Mini’s brain). It turns out, you can pre-scale the system clock that drives this timer to as low as about 30Hz, set the number of ticks that must occur before the timer resets, and finally set the number of ticks that must occur before the PWM pin is toggled. All of this requires accessing the system registers on the chip, but ultimately allows me to simply set a value and forget about. Moreover, this value can be updated every single program loop based on a simple PID calculation without glitching out any PWM cycles. All in all, it becomes an efficient and effective use of the underlying PWM hardware to manage a fairly passive process.
Here’s the code that I’m using in setup():
//Define Boiler PWM
DDRB |= 1<<PORTB1; //Sets Pin 9 As Output
TCCR1A = 0; //Clear Timer Counter Control Register A.
TCCR1B = 1<<WGM13; //Set WGM13 - Mode 8 Uses ICR1 as max and OCR1 as width. Mode is symmetrical!
ICR1 = 0x7FFF; //Defines the number of ticks (15 625Hz) per half PWM period (due to PWM symmetry).
OCR1A = 0x4000; //Match Value - Change this from 0x0000 to ICR1 value to adjust PWM.
TCCR1A |= 1<<COM1A1; //OC1A (Pin 9) Clear On Match Up, Set on Match Down.
TCCR1B |= 1<<CS12 | 1<<CS10; //Start Timer With 1024 Prescaler: 16MHz / 1024
All you have to do is change the value of register
OCR1A and it will change the PWM value. Note that this value should never exceed the value stored in
ICR1 otherwise the PWM will never toggle.
ICR1 can be has high as
0xFFFF giving a period of ~8.1s.
This is now easily implemented in a PID control loop. My current algorithm will keep the temperature within 1°C. I’m working to refine it a bit more though :).