/** ****************************************************************************** * @file China AC-meter * @author Vladimir N. Shilov * @version V0.0.1 * @date 2016.11.09 * @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 "stm8s.h" //#include "rtos.h" /* Private defines -----------------------------------------------------------*/ // for 1 msek ticks #define TIM4_PERIOD (uint8_t)124 #define ADC_PORT GPIOD #define ADC_PINS GPIO_PIN_3 #define ADC_CHNL ADC1_CHANNEL_4 #define ADC_SCHT ADC1_SCHMITTTRIG_CHANNEL4 #define ADC_SMPLS 64 // Supply voltage in mili volts #define ADC_VREF 3335 // input OA multiplier -- [(3.6/0.68) + 1) * 1000] #define ADC_MULT 6294 // shunt resistance in mili Ohms #define ADC_SHUNT 50 #define BTN_PORT (GPIOA) #define BTN_PINS (GPIO_PIN_2) /* AAA F B F B GGG E C E C DDD P */ #define LED_ANOD1_PORT GPIOA #define LED_ANOD1_PIN GPIO_PIN_3 #define LED_ANOD2_PORT GPIOD #define LED_ANOD2_PIN GPIO_PIN_6 #define LED_ANOD3_PORT GPIOD #define LED_ANOD3_PIN GPIO_PIN_4 #define LED_SEG1_PORT GPIOA #define LED_SEG1_PINS GPIO_PIN_1 #define LED_SEG_F GPIO_PIN_1 #define LED_SEG2_PORT GPIOB #define LED_SEG2_PINS (GPIO_PIN_5 | GPIO_PIN_4) #define LED_SEG_A GPIO_PIN_5 #define LED_SEG_B GPIO_PIN_4 #define LED_SEG3_PORT GPIOC #define LED_SEG3_PINS (GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_3 | GPIO_PIN_5) #define LED_SEG_G GPIO_PIN_3 #define LED_SEG_C GPIO_PIN_4 #define LED_SEG_P GPIO_PIN_5 #define LED_SEG_D GPIO_PIN_6 #define LED_SEG_E GPIO_PIN_7 #define LED_OUT_OFF {LED_SEG1_PORT->ODR |= LED_SEG1_PINS; LED_SEG2_PORT->ODR |= LED_SEG2_PINS; LED_SEG3_PORT->ODR |= LED_SEG3_PINS;} #define LED_OUT_DP GPIOC->ODR &= (~LED_SEG_P); #define LED_OUT_MM GPIOC->ODR &= LED_SEG_G; #define LED_OUT_0 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0x29; #define LED_OUT_1 GPIOB->ODR &= 0xEF; GPIOC->ODR &= 0xE9; #define LED_OUT_2 GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0x31; #define LED_OUT_3 GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0xA1; #define LED_OUT_4 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xEF; GPIOC->ODR &= 0xE1; #define LED_OUT_5 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xDF; GPIOC->ODR &= 0xA1; #define LED_OUT_6 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xDF; GPIOC->ODR &= 0x21; #define LED_OUT_7 GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0xE9; #define LED_OUT_8 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0x21; #define LED_OUT_9 GPIOA->ODR &= 0xFD; GPIOB->ODR &= 0xCF; GPIOC->ODR &= 0xA1; #define LED_ANODE_OFF {LED_ANOD1_PORT->ODR &= ~LED_ANOD1_PIN; GPIOD->ODR &= ~(LED_ANOD2_PIN | LED_ANOD3_PIN);} #define LED_ANODE_ON1 LED_ANOD1_PORT->ODR |= LED_ANOD1_PIN; #define LED_ANODE_ON2 LED_ANOD2_PORT->ODR |= LED_ANOD2_PIN; #define LED_ANODE_ON3 LED_ANOD3_PORT->ODR |= LED_ANOD3_PIN; #define SUB_SECOND_CNT 5 #define LED_ONE_PERIOD 5 #define ADC_ZERO_EEADDR FLASH_DATA_START_PHYSICAL_ADDRESS /* Private function prototypes -----------------------------------------------*/ static void ADC_CorrectZero(void); static void ADC_Config(void); static void GPIO_Config(void); static void TIM1_Config(void); static void TIM4_Config(void); static void OutputToLed(void); static void PrepareForLed(void); //static void CountCapacity(void); /* Private functions ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ __IO uint16_t ConversionBuffer[ADC_SMPLS]; __IO uint8_t BufferIndex = 0; __IO uint8_t LedCnt = 0; static uint16_t Current = 0; static uint32_t Capacity = 0; static uint8_t LedDigits[3] = {0, 0, 0}; static uint8_t LedPoint = 3; static uint16_t SubSecondBfr = 0; static uint8_t SubSecondCnt = SUB_SECOND_CNT; static uint16_t ADC_ZeroFix = 0; void main(void) { /* Initialization of the clock to 16MHz */ CLK->CKDIVR = 0x00; /* Disable clock of unused perephireal */ /* UART, SPI, I2C */ CLK->PCKENR1 = 0xF0; /* CAN */ CLK->PCKENR2 = 0x0F; /* SWIM clock */ CLK->SWIMCCR = 0x00; /* GPIO configuration ------------------------------------------*/ GPIO_Config(); /* ADC configuration -------------------------------------------*/ ADC_Config(); /* TIM1 configuration -----------------------------------------*/ TIM1_Config(); /* Initialize dispatcher */ //RTOS_Init(); //RTOS_SetTask(OutputToLed, 0, 5); //RTOS_SetTask(PrepareForLed, 210, 200); //RTOS_SetTask(CountCapacity, 1005, 1000); /* TIM4 configuration -----------------------------------------*/ TIM4_Config(); /* enable interrupts */ enableInterrupts(); /** If btn pin == 0 -- auto fix adc zero level else -- read zero value from eeprom Value stored in MSB:LSB */ if((BTN_PORT->IDR & BTN_PINS) == 0){ ADC_CorrectZero(); } else { ADC_ZeroFix = (uint16_t)(FLASH_ReadByte(ADC_ZERO_EEADDR) << 8); ADC_ZeroFix |= FLASH_ReadByte((ADC_ZERO_EEADDR+1)); } /* Infinite loop */ while (1) { if (LedCnt >= LED_ONE_PERIOD) { LedCnt = 0; OutputToLed(); } if (BufferIndex >= ADC_SMPLS) { BufferIndex = 0; /* Oversampling */ uint32_t tbuf = 0; uint8_t i = 0; for(i=0; i ADC_ZeroFix){ tbuf -= ADC_ZeroFix; tbuf >>= 3; // предварительный делитель оверсемплинга tbuf *= ADC_VREF; // Множим на опорное напряжение tbuf = (tbuf + 4096) / 8191; // get ADC input voltage in mV tbuf *= 1000; // компенсация коэф. усиления входного ОУ tbuf *= 1000; // компенсация сопротивления шунта tbuf = (tbuf + (ADC_MULT/2)) / ADC_MULT; // get voltage from shunt /* в Current ток в милиамперах */ Current = (tbuf + (ADC_SHUNT/2)) / ADC_SHUNT; SubSecondBfr += Current; } SubSecondCnt --; if(SubSecondCnt == 0){ Capacity += ( (SubSecondBfr + (SUB_SECOND_CNT/2)) / SUB_SECOND_CNT ); SubSecondBfr = 0; SubSecondCnt = SUB_SECOND_CNT; } PrepareForLed(); } // End of if (BufferIndex >= ADC_SMPLS) //RTOS_DispatchTask(); wfi(); } // End of infinity } // End of main() /** Корректируем напряжение смещения нуля ОУ на входе АЦП */ static void ADC_CorrectZero(void) { /* ждём окончания цикла измерений */ do { } while (BufferIndex < ADC_SMPLS); BufferIndex = 0; /* Получаем 16-ти битное значение от АЦП */ uint8_t i = 0; for(i=0; i>8)); /* LSB */ FLASH_ProgramByte((ADC_ZERO_EEADDR+1), (uint8_t)(ADC_ZeroFix)); /* Lock Data memory */ FLASH_Lock(FLASH_MEMTYPE_DATA); } /** Prepare current value for output ot led */ static void PrepareForLed(void) { uint16_t value; if((BTN_PORT->IDR & BTN_PINS) == 0){ value = Capacity / 3600; } else { value = Current; } if(value > 9999){ /* XX.X Amper */ LedPoint = 1; LedDigits[0] = value / 10000; value = value % 10000; LedDigits[1] = value / 1000; LedDigits[2] = (value % 1000) / 100; } else if(value > 999){ /* X.XX Amper */ LedPoint = 0; LedDigits[0] = value / 1000; value = value % 1000; LedDigits[1] = value / 100; LedDigits[2] = (value % 100) / 10; } else { /* XXX mili Amper */ LedPoint = 3; LedDigits[0] = value / 100; value = value % 100; LedDigits[1] = value / 10; LedDigits[2] = value % 10; } } /** Output current value to next led */ static void OutputToLed(void) { static uint8_t ledn = 0; /* на пине PD2 должен быть меадр с периодом 10 мсек. */ GPIOD->ODR ^= GPIO_PIN_2; /* all off */ //LED_ANODE_OFF LED_ANOD1_PORT->ODR &= ~LED_ANOD1_PIN; LED_ANOD2_PORT->ODR &= ~(LED_ANOD2_PIN | LED_ANOD3_PIN); //LED_OUT_OFF LED_SEG1_PORT->ODR |= LED_SEG1_PINS; LED_SEG2_PORT->ODR |= LED_SEG2_PINS; LED_SEG3_PORT->ODR |= LED_SEG3_PINS; /* out next value */ switch(LedDigits[ledn]){ case 0: LED_OUT_0 break; case 1: LED_OUT_1 break; case 2: LED_OUT_2 break; case 3: LED_OUT_3 break; case 4: LED_OUT_4 break; case 5: LED_OUT_5 break; case 6: LED_OUT_6 break; case 7: LED_OUT_7 break; case 8: LED_OUT_8 break; case 9: LED_OUT_9 break; default: LED_OUT_MM } if(ledn == LedPoint) { LED_OUT_DP } /* Fire on nex led */ switch(ledn){ case 0: LED_ANODE_ON1 ledn = 1; break; case 1: LED_ANODE_ON2 ledn = 2; break; case 2: LED_ANODE_ON3 ledn = 0; break; default: ledn = 0; } } /** * @brief Configure GPIO for LEDs and buttons available on the evaluation board * @param None * @retval None */ static void GPIO_Config(void) { /* Initialize LEDs */ GPIO_Init(LED_ANOD1_PORT, (GPIO_Pin_TypeDef)LED_ANOD1_PIN, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(LED_ANOD2_PORT, (GPIO_Pin_TypeDef)(LED_ANOD2_PIN | LED_ANOD3_PIN), GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(LED_SEG1_PORT, (GPIO_Pin_TypeDef)LED_SEG1_PINS, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(LED_SEG2_PORT, (GPIO_Pin_TypeDef)LED_SEG2_PINS, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(LED_SEG3_PORT, (GPIO_Pin_TypeDef)LED_SEG3_PINS, GPIO_MODE_OUT_PP_LOW_FAST); /* Initialize Button pin */ GPIO_Init(BTN_PORT, (GPIO_Pin_TypeDef)BTN_PINS, GPIO_MODE_IN_PU_NO_IT); /* Init GPIO for ADC */ GPIO_Init(ADC_PORT, (GPIO_Pin_TypeDef)ADC_PINS, GPIO_MODE_IN_FL_NO_IT); /* Test output */ GPIO_Init(GPIOD, (GPIO_Pin_TypeDef)GPIO_PIN_2, GPIO_MODE_OUT_PP_HIGH_FAST); } /** * @brief Configure ADC. * @param None * @retval None */ static void ADC_Config() { /* De-Init ADC peripheral*/ ADC1_DeInit(); /* Init ADC1 peripheral */ ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC_CHNL, ADC1_PRESSEL_FCPU_D8, \ ADC1_EXTTRIG_TIM, ENABLE, ADC1_ALIGN_RIGHT, ADC_SCHT, DISABLE); /* Enable EOC interrupt */ ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE); /*Start Conversion */ //ADC1_StartConversion(); } /** * @brief Configure TIM1. * @param None * @retval None */ static void TIM1_Config(void) { TIM1_DeInit(); /* Time Base configuration */ /* Timer period - 3,125 ms TIM1_Period = 50 TIM1_Prescaler = 1000 TIM1_CounterMode = TIM1_COUNTERMODE_UP TIM1_RepetitionCounter = 0 */ TIM1_TimeBaseInit(999, TIM1_COUNTERMODE_UP, 49, 0); /* Trigrer configuration */ TIM1_SelectOutputTrigger(TIM1_TRGOSOURCE_UPDATE); /* Update Interrupt Enable */ //TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE); /* Enable TIM1 */ TIM1_Cmd(ENABLE); } /** * @brief Configure TIM4. * @param None * @retval None */ static void TIM4_Config(void) { TIM4_DeInit(); /* TIM4 configuration: - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter clock used is 16 MHz / 128 = 125 000 Hz - With 125 000 Hz we can generate time base: max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms min time base is 0.016 ms if TIM4_PERIOD = 1 --> ( 1 + 1) / 125000 = 0.016 ms - In this example we need to generate a time base equal to 1 ms so TIM4_PERIOD = (0.001 * 125000 - 1) = 124 */ /* Time base configuration */ TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD); /* Clear TIM4 update flag */ TIM4_ClearFlag(TIM4_FLAG_UPDATE); /* Enable update interrupt */ TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); /* Enable TIM4 */ TIM4_Cmd(ENABLE); } #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(u8* file, u32 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****/