add status LEDs and timer to measure DDM100TC meter pulse
This commit is contained in:
parent
405c243f5c
commit
be0b5c8b06
96
main.c
96
main.c
@ -57,6 +57,26 @@ volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ti
|
||||
|
||||
#define QUERY_PERIOD 10 /**< period in seconds to query meter measurements */
|
||||
|
||||
/** @defgroup main_leds LED to indicate status
|
||||
* @{
|
||||
*/
|
||||
#define LED_HEARTBEAT_PORT A /**< port for heart beat LED (green, on on low) */
|
||||
#define LED_HEARTBEAT_PIN 5 /**< pin for heart beat LED (green, on on low) */
|
||||
#define LED_QUERY_PORT A /**< port for query LED (yellow, on on low) */
|
||||
#define LED_QUERY_PIN 6 /**< pin for query LED (yellow, on on low) */
|
||||
#define LED_SUBMIT_PORT A /**< port for submit LED (blue, on on low) */
|
||||
#define LED_SUBMIT_PIN 7 /**< pin for submit LED (blue, on on low) */
|
||||
/** @} */
|
||||
|
||||
/** @defgroup main_ddm100tc resources to capture pulses from DDM100TC electricity meter
|
||||
* @{
|
||||
*/
|
||||
#define DDM100TC_TIMER 4 /**< timer to measure time between pulses **/
|
||||
#define DDM100TC_PORT B /**< timer ipnut capture port (TIM4_CH1=PB6) **/
|
||||
#define DDM100TC_CAPTURE TIM4_CH1 /**< time input capture used to detect pulse **/
|
||||
volatile uint32_t ddm100tc_interval = 0; /**< last time interval between pulses **/
|
||||
volatile uint32_t ddm100tc_pulses = 0; /**< total number of pulses captured **/
|
||||
/** @} */
|
||||
|
||||
int _write(int file, char *ptr, int len)
|
||||
{
|
||||
@ -243,7 +263,20 @@ void main(void)
|
||||
setbuf(stderr, NULL); // set standard error buffer to NULL to immediately print
|
||||
|
||||
// minimal setup ready
|
||||
printf("welcome to the STM32F1 CuVoodoo example code\n"); // print welcome message
|
||||
printf("welcome to the spark abacus electricity monitoring system\n"); // print welcome message
|
||||
|
||||
// setup LEDs
|
||||
printf("setup status LEDs: ");
|
||||
rcc_periph_clock_enable(RCC_GPIO(LED_HEARTBEAT_PORT)); // enable clock for LED
|
||||
gpio_set_mode(GPIO(LED_HEARTBEAT_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(LED_HEARTBEAT_PIN)); // set LED pin to 'output push-pull'
|
||||
gpio_set(GPIO(LED_HEARTBEAT_PORT), GPIO(LED_HEARTBEAT_PIN)); // switch off LED per default
|
||||
rcc_periph_clock_enable(RCC_GPIO(LED_QUERY_PORT)); // enable clock for LED
|
||||
gpio_set_mode(GPIO(LED_QUERY_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(LED_QUERY_PIN)); // set LED pin to 'output push-pull'
|
||||
gpio_set(GPIO(LED_QUERY_PORT), GPIO(LED_QUERY_PIN)); // switch off LED per default
|
||||
rcc_periph_clock_enable(RCC_GPIO(LED_SUBMIT_PORT)); // enable clock for LED
|
||||
gpio_set_mode(GPIO(LED_SUBMIT_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(LED_SUBMIT_PIN)); // set LED pin to 'output push-pull'
|
||||
gpio_set(GPIO(LED_SUBMIT_PORT), GPIO(LED_SUBMIT_PIN)); // switch off LED per default
|
||||
printf("OK\n");
|
||||
|
||||
// setup RTC
|
||||
printf("setup internal RTC: ");
|
||||
@ -255,6 +288,33 @@ void main(void)
|
||||
uint32_t ticks_time = rtc_get_counter_val(); // get time from internal RTC (since first start/power up)
|
||||
printf("uptime: %02lu:%02lu:%02lu\n", ticks_time/(60*60), (ticks_time%(60*60))/60, (ticks_time%60)); // display time
|
||||
|
||||
// setup DDM100TC electricity meter
|
||||
rcc_periph_clock_enable(RCC_GPIO(DDM100TC_PORT)); // enable clock for GPIO block
|
||||
gpio_set_mode(GPIO_BANK_(DDM100TC_CAPTURE), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_(DDM100TC_CAPTURE)); // setup GPIO pin as input
|
||||
gpio_clear(GPIO_BANK_(DDM100TC_CAPTURE), GPIO_(DDM100TC_CAPTURE)); // pull down since the meter will set VCC when pulsing
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable pin alternate function (timer capture)
|
||||
rcc_periph_clock_enable(RCC_TIM(DDM100TC_TIMER)); // enable clock for timer block
|
||||
timer_reset(TIM(DDM100TC_TIMER)); // reset timer state
|
||||
timer_set_mode(TIM(DDM100TC_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
|
||||
timer_set_prescaler(TIM(DDM100TC_TIMER), 0xffff); // set the prescaler to the maximum ( 1/(72E6/(2**16))=0.91ms which is a good enough resolution for this purpose)
|
||||
timer_set_ti1_ch1(TIM(DDM100TC_TIMER)); // connect TIMx_CH1 to TI1 (this depends on the input capture pin you selected)
|
||||
timer_ic_set_input(TIM(DDM100TC_TIMER), TIM_IC1, TIM_IC_IN_TI1); // configure IC1 to use TI1
|
||||
timer_ic_set_filter(TIM(DDM100TC_TIMER), TIM_IC1, TIM_IC_CK_INT_N_8); // use 8 sample to filter input (remove noise)
|
||||
timer_ic_set_filter(TIM(DDM100TC_TIMER), TIM_IC1, TIM_IC_DTF_DIV_32_N_8);
|
||||
timer_ic_set_polarity(TIM(DDM100TC_TIMER), TIM_IC1, TIM_IC_RISING); // capture on rising edge
|
||||
timer_ic_set_prescaler(TIM(DDM100TC_TIMER), TIM_IC1, TIM_IC_PSC_OFF); // don't use any prescaler since we want to capture every pulse
|
||||
timer_slave_set_trigger(TIM(DDM100TC_TIMER), TIM_SMCR_TS_TI1FP1); // set filtered TI1 as trigger
|
||||
timer_slave_set_mode(TIM(DDM100TC_TIMER), TIM_SMCR_SMS_RM); // reinitialise counter on rising edge of trigger
|
||||
timer_clear_flag(TIM(DDM100TC_TIMER), TIM_SR_UIF); // clear update (UEv) flag
|
||||
timer_update_on_overflow(TIM(DDM100TC_TIMER)); // only use counter overflow as UEV source
|
||||
timer_enable_irq(TIM(DDM100TC_TIMER), TIM_DIER_UIE); // enable update event interrupt
|
||||
timer_clear_flag(TIM(DDM100TC_TIMER), TIM_SR_CC1IF); // clear input compare flag
|
||||
timer_enable_irq(TIM(DDM100TC_TIMER), TIM_DIER_CC1IE); // enable capture interrupt
|
||||
nvic_enable_irq(NVIC_TIM_IRQ(DDM100TC_TIMER)); // catch interrupt in service routine
|
||||
timer_ic_enable(TIM(DDM100TC_TIMER), TIM_IC1); // enable capture
|
||||
timer_set_counter(TIM(DDM100TC_TIMER), 0); // reset timer counter
|
||||
timer_enable_counter(TIM(DDM100TC_TIMER)); // enable timer
|
||||
|
||||
// setup PZEM electricity meter
|
||||
printf("setup PZEM-004 electricity meter: ");
|
||||
sensor_pzem_setup(); // setup PZEM electricity meter
|
||||
@ -291,6 +351,7 @@ void main(void)
|
||||
button_flag = false; // reset button flag
|
||||
char c = '\0'; // to store received character
|
||||
bool char_flag = false; // a new character has been received
|
||||
led_on(); // indicate setup is complete
|
||||
|
||||
// variables for PZEM-004T meter measurements
|
||||
struct sensor_pzem_measurement_t pzem_measurements[2][SENSOR_PZEM_MAX]; // PZEM-004T measurements (2 meters, all measurements)
|
||||
@ -304,17 +365,8 @@ void main(void)
|
||||
|
||||
while (true) { // infinite loop
|
||||
iwdg_reset(); // kick the dog
|
||||
/*
|
||||
while (usart_received) { // data received over UART
|
||||
action = true; // action has been performed
|
||||
led_toggle(); // toggle LED
|
||||
c = usart_getchar(); // store receive character
|
||||
char_flag = true; // notify character has been received
|
||||
}
|
||||
*/
|
||||
while (cdcacm_received) { // data received over USB
|
||||
action = true; // action has been performed
|
||||
led_toggle(); // toggle LED
|
||||
c = cdcacm_getchar(); // store receive character
|
||||
char_flag = true; // notify character has been received
|
||||
}
|
||||
@ -464,7 +516,7 @@ void main(void)
|
||||
}
|
||||
while (rtc_internal_tick_flag) { // the internal RTC ticked
|
||||
rtc_internal_tick_flag = false; // reset flag
|
||||
//led_toggle(); // toggle LED (good to indicate if main function is stuck). do not toggle onboard the LED on PC13 on the blue pill board since this heavily influences the RTC (by ~13%)
|
||||
gpio_toggle(GPIO(LED_HEARTBEAT_PORT), GPIO(LED_HEARTBEAT_PIN)); // toggle heart beat LED to indicate if main function is stuck (do not toggle onboard the LED on PC13 on the blue pill board since this heavily influences the RTC)
|
||||
ticks_time = rtc_get_counter_val(); // copy time from internal RTC for processing
|
||||
action = true; // action has been performed
|
||||
if ((ticks_time%(60))==0) { // one minute passed
|
||||
@ -472,6 +524,7 @@ void main(void)
|
||||
}
|
||||
if ((ticks_time%(QUERY_PERIOD))==0) { // query period passed
|
||||
printf("query meter measurements (%lu.%02lu:%02lu:%02lu)\n", ticks_time/(60*60*24), (ticks_time/(60*60))%24, (ticks_time%(60*60))/60, (ticks_time%60));
|
||||
gpio_clear(GPIO(LED_QUERY_PORT), GPIO(LED_QUERY_PIN)); // switch on query LED
|
||||
// start getting all PZEM-004T measurements from all meters
|
||||
pzem_meter = 0; // reset PZEM meter number
|
||||
pzem_measurement = 0; // reset PZEM measurement index
|
||||
@ -485,6 +538,8 @@ void main(void)
|
||||
while (pzem_meter>=LENGTH(pzem_measurements) && sdm120_meter>=LENGTH(sdm120_measurements)) { // all measurements received for all meter
|
||||
action = true; // action has been performed
|
||||
printf("saving measurements to database: ");
|
||||
gpio_set(GPIO(LED_QUERY_PORT), GPIO(LED_QUERY_PIN)); // switch off query LED
|
||||
gpio_clear(GPIO(LED_SUBMIT_PORT), GPIO(LED_SUBMIT_PIN)); // switch off submit LED
|
||||
const char* pzem_strings[SENSOR_PZEM_MAX] = {
|
||||
"voltage,meter=PZEM-004T,phase=%u value=%.1f\n",
|
||||
"current,meter=PZEM-004T,phase=%u value=%.2f\n",
|
||||
@ -585,6 +640,7 @@ void main(void)
|
||||
}
|
||||
}
|
||||
http_end(); // end HTTP request (don't care about the result)
|
||||
gpio_set(GPIO(LED_SUBMIT_PORT), GPIO(LED_SUBMIT_PIN)); // switch off submit LED
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
@ -607,3 +663,21 @@ void rtc_isr(void)
|
||||
rtc_clear_flag(RTC_SEC); // clear flag
|
||||
rtc_internal_tick_flag = true; // notify to show new time
|
||||
}
|
||||
|
||||
/** interrupt service routine called for DDM100TC timer */
|
||||
void TIM_ISR(DDM100TC_TIMER)(void)
|
||||
{
|
||||
static uint32_t long_time = 0; // large value of time, compared to the 16 bits counters
|
||||
if (timer_get_flag(TIM(DDM100TC_TIMER), TIM_SR_UIF)) { // overflow update event happened
|
||||
timer_clear_flag(TIM(DDM100TC_TIMER), TIM_SR_UIF); // clear flag
|
||||
long_time += 0x10000; // count timer overflow for large time value
|
||||
} else if (timer_get_flag(TIM(DDM100TC_TIMER), TIM_SR_CC1IF)) { // pulse detected
|
||||
long_time += TIM_CCR1(TIM(DDM100TC_TIMER)); // get time (reading also clears the flag)
|
||||
if (long_time>90) { // pulse is 90ms long, thus a new pulse before this time is probably just noise)
|
||||
ddm100tc_interval = long_time;
|
||||
ddm100tc_pulses++; // increment the number of pulses detected
|
||||
long_time = 0; // reset time (slave mode should also have reset the counter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user