/** ****************************************************************************** * @file VAPC-meter * @author Vladimir N. Shilov * @version V0.0.1 * @date 2015.05.15 * @brief Main program body ****************************************************************************** * @attention * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Shilov V.N. * ---------------------------------------------------------------------------- * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "stm8l15x.h" #include "rtos.h" #include "max7219.h" #include "adc.h" /** @addtogroup STM8L15x_StdPeriph_Template * @{ */ /* Private typedef -----------------------------------------------------------*/ typedef enum _modes_led { dispNoState = 0x00, displayU, displayI, displayP, displayAH, displayWH, displayT } mode_led_t; typedef enum _events { eventNoEvent = 0x00, eventShortPress, eventLongPress } event_t; /* Private define ------------------------------------------------------------*/ #define LED_RED_PORT GPIOB #define LED_RED_PIN GPIO_Pin_7 #define LED_GREEN_PORT GPIOC #define LED_GREEN_PIN GPIO_Pin_4 #define BTNs_PORT GPIOC #define BTN1_PIN GPIO_Pin_0 #define BTN2_PIN GPIO_Pin_1 #define BTN_SCAN_PERIOD 10 // кнопка считается нажатой через BTN_FACTOR * BTN_SCAN_PERIOD ms #define BTN_FACTOR 5 /* #define BTNs_PORT GPIOA #define BTN1_PIN GPIO_Pin_2 #define BTN2_PIN GPIO_Pin_3 */ #define VALUES_BUFFER_SIZE 10 /* Private macro -------------------------------------------------------------*/ #define LED_RED_ON LED_RED_PORT->ODR &= (uint8_t)(~LED_RED_PIN) #define LED_RED_OFF LED_RED_PORT->ODR |= LED_RED_PIN #define LED_GREEN_ON LED_GREEN_PORT->ODR &= (uint8_t)(~LED_GREEN_PIN) #define LED_GREEN_OFF LED_GREEN_PORT->ODR |= LED_GREEN_PIN /* Private constant ----------------------------------------------------------*/ // перевод числа 0-7 в номер индикатора static const max7219_reg_t dig[8] = { RegDigit0, RegDigit1, RegDigit2, RegDigit3, RegDigit4, RegDigit5, RegDigit6, RegDigit7 }; // перевод значения 0x00 - 0x0F в код индикатора static const max7219_sym_t num[16] = { Sym_0, Sym_1, Sym_2, Sym_3, Sym_4, Sym_5, Sym_6, Sym_7, Sym_8, Sym_9, Sym_A, Sym_b, Sym_C, Sym_d, Sym_E, Sym_F }; /* Private variables ---------------------------------------------------------*/ static uint16_t bufVoltage[VALUES_BUFFER_SIZE]; static uint16_t bufCurrent[VALUES_BUFFER_SIZE]; /* averaged values for 1 sek */ static uint16_t Voltage; static uint16_t Current; static uint32_t Power; static uint32_t CapacityAH = 0; static uint32_t CapacityWH = 0; static struct _timer { uint8_t hh; uint8_t mm; uint8_t ss; } Timer; static uint8_t btn1Cnt; static uint8_t btn2Cnt; static mode_led_t displayTopLine, displayBotLine; /* Private function prototypes -----------------------------------------------*/ static void GPIO_Config(void); static void CLK_Config(void); static void showValue(uint32_t val, uint8_t pos); static void showU(uint8_t pos); static void showI(uint8_t pos); static void showP(uint8_t pos); static void showAH(uint8_t pos); static void showWH(uint8_t pos); static void showT(uint8_t pos); static void showLabelU(uint8_t pos); static void showLabelI(uint8_t pos); static void showLabelP(uint8_t pos); static void showLabelAH(uint8_t pos); static void showLabelWH(uint8_t pos); static void showLabelT(uint8_t pos); static void displayMode(mode_led_t * disp, event_t event, uint8_t pos); /* RTOS function prototypes -----------------------------------------------*/ static void getADCValues(void); static void calculateValues(void); static void showTopLineU(void); static void showTopLineI(void); static void showTopLineP(void); static void showTopLineAH(void); static void showTopLineWH(void); static void showTopLineT(void); static void showBotLineU(void); static void showBotLineI(void); static void showBotLineP(void); static void showBotLineAH(void); static void showBotLineWH(void); static void showBotLineT(void); static void btnScan(void); static void btnTest(uint8_t btnPin, uint8_t *pressCount, void (*taskShortPress)(void), void (*taskLongPress)(void)); static void btn1Short(void); static void btn1Long(void); static void btn2Short(void); static void btn2Long(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Main program. * @param None * @retval None */ void main(void) { /* Clock configuration -----------------------------------------*/ CLK_Config(); /* GPIO Configuration -----------------------------------------*/ GPIO_Config(); /* RTOS Configuration */ RTOS_Config(); /* ADC Configuration and start */ ADC_Config(); /* MAX7219 Configuration */ MAX7219_Config(); /* ROTS tasks */ RTOS_SetTask(btnScan, 0, BTN_SCAN_PERIOD); RTOS_SetTask(getADCValues, 100, 100); RTOS_SetTask(calculateValues, 101, 1000); RTOS_SetTask(showTopLineU, 102, 200); RTOS_SetTask(showBotLineI, 103, 200); displayTopLine = displayU; displayBotLine = displayI; /* Infinite loop */ while (1) { RTOS_DispatchTask(); wfi(); } } // End of main() /** * Забираем обработанные данные из быстрого буфера * и складываем в медленный. */ static void getADCValues(void) { static uint8_t bufIdx = 0; uint16_t * avgVal; avgVal = ADC_GetValues(); bufVoltage[bufIdx] = *avgVal; bufCurrent[bufIdx] = *(avgVal + 1); bufIdx ++; if (bufIdx == VALUES_BUFFER_SIZE) { bufIdx = 0; } } /** * Average values from slow buffer. * Calculate Power, Capacitance IH and WH. */ static void calculateValues(void) { uint8_t i; uint16_t c=0; uint32_t v=0; for (i=0; i 4) { Power = ((Voltage * Current) + 500) / 1000; CapacityAH += Current; CapacityWH += Power; Timer.ss ++; if (Timer.ss > 59) { Timer.ss = 0; Timer.mm ++; if (Timer.mm > 59) { Timer.hh ++; } } } } /** * вывод инфы на верхнем индикаторе */ static void showTopLineU(void) { showU(0); } static void showTopLineI(void) { showI(0); } static void showTopLineP(void) { showP(0); } static void showTopLineAH(void) { showAH(0); } static void showTopLineWH(void) { showWH(0); } static void showTopLineT(void) { showT(0); } /** * вывод инфы на нижнем индикаторе */ static void showBotLineU(void) { showU(4); } static void showBotLineI(void) { showI(4); } static void showBotLineP(void) { showP(4); } static void showBotLineAH(void) { showAH(4); } static void showBotLineWH(void) { showWH(4); } static void showBotLineT(void) { showT(4); } /** * Output given value to given indicator * param1: value to show, from '0.000' to '999.9' * param2: starting position -- 0 for top * any other for bottom. */ static void showValue(uint32_t val, uint8_t pos) { uint8_t tmp; if (pos > 0) { pos = 4; } if (val >= 100000) { // 000.0 tmp = (uint8_t)(val / 100000); val %= 100000; MAX7219_WriteData(dig[pos], num[tmp]); tmp = (uint8_t)(val / 10000); val %= 10000; pos ++; MAX7219_WriteData(dig[pos], num[tmp]); tmp = (uint8_t)(val / 1000); val %= 1000; pos ++; MAX7219_WriteData(dig[pos], (num[tmp] | Sym_Dot)); tmp = (uint8_t)(val / 100); pos ++; MAX7219_WriteData(dig[pos], num[tmp]); } else if(val >= 10000){ // 00.00 tmp = (uint8_t)(val / 10000); val %= 10000; MAX7219_WriteData(dig[pos], num[tmp]); tmp = (uint8_t)(val / 1000); val %= 1000; pos ++; MAX7219_WriteData(dig[pos], (num[tmp] | Sym_Dot)); tmp = (uint8_t)(val / 100); val %= 100; pos ++; MAX7219_WriteData(dig[pos], num[tmp]); tmp = (uint8_t)(val / 10); pos ++; MAX7219_WriteData(dig[pos], num[tmp]); } else { // 0.000 tmp = (uint8_t)(val / 1000); val %= 1000; MAX7219_WriteData(dig[pos], (num[tmp] | Sym_Dot)); tmp = (uint8_t)(val / 100); val %= 100; pos ++; MAX7219_WriteData(dig[pos], num[tmp]); tmp = (uint8_t)(val / 10); val %= 10; pos ++; MAX7219_WriteData(dig[pos], num[tmp]); pos ++; tmp = val; MAX7219_WriteData(dig[pos], num[tmp]); } } /** * Output voltage values to given indicator * param: starting position -- 0 for top * any other for bottom. */ static void showU(uint8_t pos) { uint32_t vlt = 0; uint8_t tmp; for (tmp=0; tmp 0) { tmp = Timer.hh / 10; MAX7219_WriteData(dig[pos], num[tmp]); pos ++; tmp = Timer.hh % 10; if (halfsek == 0) { MAX7219_WriteData(dig[pos], num[tmp]); } else { MAX7219_WriteData(dig[pos], (num[tmp] | Sym_Dot)); } pos ++; tmp = Timer.mm / 10; MAX7219_WriteData(dig[pos], num[tmp]); pos ++; tmp = Timer.mm % 10; MAX7219_WriteData(dig[pos], num[tmp]); } else { tmp = Timer.mm / 10; MAX7219_WriteData(dig[pos], num[Timer.mm >> 4]); pos ++; tmp = Timer.mm % 10; MAX7219_WriteData(dig[pos], (num[tmp] | Sym_Dot)); pos ++; tmp = Timer.ss / 10; MAX7219_WriteData(dig[pos], num[tmp]); pos ++; tmp = Timer.ss % 10; MAX7219_WriteData(dig[pos], num[tmp]); } if (halfsek == 0) { halfsek = 1; } else { halfsek = 0; } } /** * @brief Configure GPIO for button available on the VAPC board * @param None * @retval None */ static void GPIO_Config(void) { /* Configure GPIO used to drive LEDs */ GPIO_Init(LED_RED_PORT, LED_RED_PIN, GPIO_Mode_Out_PP_High_Fast); GPIO_Init(LED_GREEN_PORT, LED_GREEN_PIN, GPIO_Mode_Out_PP_High_Fast); /* Configure GPIO used for buttons */ GPIO_Init(BTNs_PORT, BTN1_PIN, GPIO_Mode_In_FL_No_IT); GPIO_Init(BTNs_PORT, BTN2_PIN, GPIO_Mode_In_FL_No_IT); /* Enable general interrupts */ enableInterrupts(); } /** * @brief Configure system clock to run at Maximum clock speed * @param None * @retval None */ static void CLK_Config(void) { CLK_DeInit(); /* Configure the clock source */ CLK_SYSCLKSourceConfig(CLK_SYSCLKSource_HSI); /* Configure the System clock frequency to run at 16Mhz */ CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1); CLK_HSICmd(ENABLE); } /** опрос кнопок */ static void btnScan(void) { btnTest(BTN1_PIN, &btn1Cnt, btn1Short, btn1Long); btnTest(BTN2_PIN, &btn2Cnt, btn2Short, btn2Long); } /** проверка конкретной кнопки */ static void btnTest(uint8_t btnPin, uint8_t *pressCount, void (*taskShortPress)(void), void (*taskLongPress)(void)) { if ((BTNs_PORT->IDR & btnPin) == 0) { if (*pressCount < 255) { *pressCount = *pressCount + 1; } /* if (*pressCount == BTN_FACTOR) { // short } else if(*pressCount == (BTN_FACTOR * 10)) { // long } */ } else { if (*pressCount >= (BTN_FACTOR * 10)) { RTOS_SetTask(taskLongPress, 1, 0); // вызов функции при длительном нажатии } else if (*pressCount >= BTN_FACTOR) { RTOS_SetTask(taskShortPress, 2, 0); // вызов функции при коротком нажатии } *pressCount = 0; } } /** переключение режимов отображения */ static void displayMode(mode_led_t * disp, event_t event, uint8_t pos) { if (pos > 0) { pos = 4; } if (event == eventShortPress) { switch (*disp) { case dispNoState: showLabelU(pos); if (pos == 0) { RTOS_SetTask(showTopLineU, 1000, 250); } else { RTOS_SetTask(showBotLineU, 1000, 250); } *disp = displayU; break; case displayU: if (pos == 0) { RTOS_DeleteTask(showTopLineU); RTOS_SetTask(showTopLineI, 1000, 250); } else { RTOS_DeleteTask(showBotLineU); RTOS_SetTask(showBotLineI, 1000, 250); } showLabelI(pos); *disp = displayI; break; case displayI: if (pos == 0) { RTOS_DeleteTask(showTopLineI); RTOS_SetTask(showTopLineP, 1000, 250); } else { RTOS_DeleteTask(showBotLineI); RTOS_SetTask(showBotLineP, 1000, 250); } showLabelP(pos); *disp = displayP; break; case displayP: if (pos == 0) { RTOS_DeleteTask(showTopLineP); RTOS_SetTask(showTopLineAH, 1000, 250); } else { RTOS_DeleteTask(showBotLineP); RTOS_SetTask(showBotLineAH, 1000, 250); } showLabelAH(pos); *disp = displayAH; break; case displayAH: if (pos == 0) { RTOS_DeleteTask(showTopLineAH); RTOS_SetTask(showTopLineWH, 1000, 250); } else { RTOS_DeleteTask(showBotLineAH); RTOS_SetTask(showBotLineWH, 1000, 250); } showLabelWH(pos); *disp = displayWH; break; case displayWH: if (pos == 0) { RTOS_DeleteTask(showTopLineWH); RTOS_SetTask(showTopLineT, 1000, 500); } else { RTOS_DeleteTask(showBotLineWH); RTOS_SetTask(showBotLineT, 1000, 500); } showLabelT(pos); *disp = displayT; break; case displayT: if (pos == 0) { RTOS_DeleteTask(showTopLineT); RTOS_SetTask(showTopLineU, 1000, 250); } else { RTOS_DeleteTask(showBotLineT); RTOS_SetTask(showBotLineU, 1000, 250); } showLabelU(pos); *disp = displayU; break; } } } /** обработчик короткого нажатия первой кнопки */ static void btn1Short(void) { displayMode(&displayTopLine, eventShortPress, 0); } /** обработчик длинного нажатия первой кнопки */ static void btn1Long(void) { } /** обработчик короткого нажатия второй кнопки */ static void btn2Short(void) { displayMode(&displayBotLine, eventShortPress, 4); } /** обработчик длинного нажатия второй кнопки */ static void btn2Long(void) { Timer.ss = 0; Timer.mm = 0; Timer.hh = 0; CapacityAH = 0; CapacityWH = 0; } /** * show label for selected mode */ static void showLabelU(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_U); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_BLANK); } static void showLabelI(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_1); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_BLANK); } static void showLabelP(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_P); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_BLANK); } static void showLabelAH(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_A); pos ++; MAX7219_WriteData(dig[pos], Sym_H); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); } static void showLabelWH(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_P); pos ++; MAX7219_WriteData(dig[pos], Sym_H); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); } static void showLabelT(uint8_t pos) { MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_t); pos ++; MAX7219_WriteData(dig[pos], Sym_Minus); pos ++; MAX7219_WriteData(dig[pos], Sym_BLANK); } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/