Tracking pulses w/ interrupts May 2016
There are three pulse counters for measuring power at JeeLabs - one for solar PV production and two for the kitchen stove and the rest, respectively:
These generate 2000 pulses per kWh, that’s one pulse per 0.5 Wh, and are optically isolated. Reading them out is super simple: add a 1 kΩ series resistor and power them from 3.3V .. 5V. The result is a series of clean “1” pulses, each 100 ms long (there’s no contact bounce).
At the maximum rated current of 16A each, which corresponds to 3680 Watt for a nominal 230 Vac feed, we get about 2 pulses per second. With room to detect surges at least 5 times as high.
The main trick is to measure the time between these pulses fairly accurately, as this provides a measure of the actual current consumption. With 1s between pulses, we know the power is 1800 W, and with 10s between pulses, it’ll be 180 W - averaged out over those periods, that is.
It’s easy to measure time in a µC, especially on a millisecond scale. There’s a SysTick counter in the ARM µC, which is set up to run at 1000 Hz, i.e. one tick per millisecond. See this code.
So all we need to do is set up three “external interrupts” to trigger on the rising edge, and then count and timestamp each event:
0 0 2variable pulses1 \ last millis and pulse count #1 0 0 2variable pulses2 \ last millis and pulse count #2 0 0 2variable pulses3 \ last millis and pulse count #3 : ext3-tick ( -- ) \ interrupt handler for EXTI3 3 bit EXTI-PR ! \ clear interrupt millis pulses1 1 over +! cell+ ! ; : ext4-tick ( -- ) \ interrupt handler for EXTI4 4 bit EXTI-PR ! \ clear interrupt millis pulses2 1 over +! cell+ ! ; : ext5-tick ( -- ) \ interrupt handler for EXTI9_5 5 bit EXTI-PR ! \ clear interrupt millis pulses3 1 over +! cell+ ! ; : count-pulses ( -- ) \ set up and start the external interrupts ['] ext3-tick irq-exti3 ! \ install interrupt handler EXTI 3 ['] ext4-tick irq-exti4 ! \ install interrupt handler EXTI 4 ['] ext5-tick irq-exti5 ! \ install interrupt handler EXTI 5-9 9 bit NVIC-EN0R bis! \ enable EXTI3 interrupt 9 %0010 12 lshift AFIO-EXTICR1 bis! \ select P<C>3 3 bit EXTI-IMR bis! \ enable PC<3> 3 bit EXTI-RTSR bis! \ trigger on PC<3> rising edge 10 bit NVIC-EN0R bis! \ enable EXTI4 interrupt 10 %0010 AFIO-EXTICR2 bis! \ select P<C>4 4 bit EXTI-IMR bis! \ enable PC<4> 4 bit EXTI-RTSR bis! \ trigger on PC<4> rising edge 23 bit NVIC-EN0R bis! \ enable EXTI9_5 interrupt 23 %0010 4 lshift AFIO-EXTICR2 bis! \ select P<C>5 5 bit EXTI-IMR bis! \ enable PC<5> 5 bit EXTI-RTSR bis! \ trigger on PC<5> rising edge ;
This code is only so long because of the repetition. It’s all fairly straightforward, once you go through the reference manual and find all the register settings.
count-pulses has been called, we end up with three variables of 2 words
each, containing automatically-updating pulse counts and the last millisecond
And because this is based on interrupts and running in the background, we still have Mecrisp’s interactive command loop to peek and poke around, and look at these variables:
pulses1 2@ . . 10 8819 ok. pulses2 2@ . . 9 12928 ok. pulses3 2@ . . 29 17537 ok.
Pulse counter #1 has pulsed 10 times since started, the last one being 8819 milliseconds since the last µC reset. It’s all working like a charm and it doesn’t involve any code or attention to keep this running, all we need to do is pick up these values when we want to report them. Onwards!