123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- /**
- ******************************************************************************
- * @file VAPC-meter/lib/adc.c
- * @author "Vladimir N. Shilov" <shilow@ukr.net>
- * @version V1
- * @date 24-March-2016
- * @brief This file contains the ADC functions.
- ******************************************************************************
- * Tim2 регулярно запускат АЦП.
- * АЦП измеряет два заданных канала и пинает DMA
- * DMA забирает данные у ADC и складывает их в ADC_Buffer
- * В прерывании по окончанию транзакции данные из ADC_Buffer
- * раскладываем по FastBuffers.
- */
- /* Includes ------------------------------------------------------------------*/
- #include "adc.h"
- /** @addtogroup ADC
- * @{
- */
- /* Private typedef -----------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- #define VOLTAGE_CHANNEL ADC_Channel_17
- #define CURRENT_CHANNEL ADC_Channel_18
- #define ADC1_DR_ADDRESS ((uint16_t)0x5344)
- #define ADC_BUFFER_ADDRESS ((uint16_t)(&ADC_Buffer))
- #define ADC_REF 3300
- #define ADC_DIV 4095
- #define ADC_ODIV 32768
- #define ADC_VOLT_K 11
- #define ADC_CURR_K 20
- // (Частота МК (16 МHz) / Предделитель таймера (8) * Нужное время в секундах (0.0015625)) - 1
- #define TIM_PERIOD ((uint16_t)3128)
- #define TIM_PRESCALER TIM2_Prescaler_8
- /* Private macro -------------------------------------------------------------*/
- /* Private variables ---------------------------------------------------------*/
- static __IO uint16_t ADC_Buffer[ADC_BUFFER_SIZE];
- static __IO uint16_t VoltageFastBuffer[FAST_BUFFER_SIZE];
- static __IO uint16_t CurrentFastBuffer[FAST_BUFFER_SIZE];
- /* Private constants ---------------------------------------------------------*/
- __near __no_init const unsigned char Factory_VREFINT @ 0x4910;
- /* Private function prototypes -----------------------------------------------*/
- static void ADC_ConfigADC(void);
- static void ADC_ConfigDMA(void);
- static void ADC_ConfigTIM2(void);
- /* Private functions ---------------------------------------------------------*/
- /**
- * @brief Initialize and start ADC
- * @param None
- * @retval None
- */
- void ADC_Config(void)
- {
- /* ADC configuration */
- ADC_ConfigADC();
- /* DMA configuration */
- ADC_ConfigDMA();
- /* TIM2 configuration */
- ADC_ConfigTIM2();
- }
- /**
- * @brief Configure ADC peripheral
- * @param None
- * @retval None
- */
- static void ADC_ConfigADC(void)
- {
- /* Enable ADC1 clock */
- CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
- /* Initialize and configure ADC1 */
- ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
- ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles);
- ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_384Cycles);
- /* Enable ADC1 */
- ADC_Cmd(ADC1, ENABLE);
- /* Enable ADC1 Voltage meter channel */
- ADC_ChannelCmd(ADC1, VOLTAGE_CHANNEL, ENABLE);
- ADC_SchmittTriggerConfig(ADC1, VOLTAGE_CHANNEL, DISABLE);
- /* Enable ADC1 Current meter channel */
- ADC_ChannelCmd(ADC1, CURRENT_CHANNEL, ENABLE);
- ADC_SchmittTriggerConfig(ADC1, CURRENT_CHANNEL, DISABLE);
- #ifdef ADC_MEASURE_REF_VOLT
- /* ADC Voltage Reference */
- ADC_VrefintCmd(ENABLE);
- /* Enable ADC1 Vrefint Channel */
- ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE);
- #endif // ADC_MEASURE_REF_VOLT
- /* Enable ADC1 DMA requests*/
- ADC_DMACmd(ADC1, ENABLE);
- /* Start ADC1 Conversion using TIM1 TRGO*/
- ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger3, ADC_ExtTRGSensitivity_Rising);
- }
- /**
- * @brief Configure DMA peripheral
- * @param None
- * @retval None
- */
- static void ADC_ConfigDMA(void)
- {
- /* Enable DMA1 clock */
- CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);
- /* Connect ADC to DMA channel 0 */
- SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0);
- DMA_Init(DMA1_Channel0, ADC_BUFFER_ADDRESS,
- ADC1_DR_ADDRESS,
- ADC_BUFFER_SIZE,
- DMA_DIR_PeripheralToMemory,
- DMA_Mode_Circular,
- DMA_MemoryIncMode_Inc,
- DMA_Priority_High,
- DMA_MemoryDataSize_HalfWord);
- /* DMA Channel0 enable */
- DMA_Cmd(DMA1_Channel0, ENABLE);
- /* Enable DMA1 channel0 Transfer complete interrupt */
- DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE);
- /* DMA enable */
- DMA_GlobalCmd(ENABLE);
- }
- /**
- * @brief Configure TIM2 peripheral
- * @param None
- * @retval None
- */
- static void ADC_ConfigTIM2(void)
- {
- /* Enable TIM2 clock */
- CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
- /* Initializes the TIM2 Time Base Unit */
- TIM2_TimeBaseInit(TIM_PRESCALER, TIM2_CounterMode_Up, TIM_PERIOD);
- /* Selects the TIM2 Update Request Interrupt source */
- TIM2_UpdateRequestConfig(TIM2_UpdateSource_Regular);
- /* Master Mode selection: Update event */
- TIM2_SelectOutputTrigger(TIM2_TRGOSource_Update);
- /* Enable TIM2 */
- TIM2_Cmd(ENABLE);
- }
- /**
- * @brief DMA1 channel0 and channel1 Interrupt routine.
- * @param None
- * @retval None
- */
- INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler,2)
- {
- static uint8_t idx = 0;
- VoltageFastBuffer[idx] = ADC_Buffer[0];
- CurrentFastBuffer[idx] = ADC_Buffer[1];
- idx ++;
- if(idx >= FAST_BUFFER_SIZE) {
- idx = 0;
- }
- /* Clear IT Pending Bit */
- DMA1_Channel0->CSPR &= (uint8_t)~(uint8_t)(DMA1_IT_TC0 & (uint8_t)0x06);
- }
- /**
- * @brief Return average values from fast buffers
- * @param None
- * @retval Latest_Voltage
- */
- uint16_t * ADC_GetValues(void) {
- static uint16_t avgVal[ADC_BUFFER_SIZE];
- uint32_t volt=0, curr=0;
- uint16_t shunt_volt;
- uint8_t i;
- /* Summarize buffers values */
- for(i=0;i<FAST_BUFFER_SIZE;i++){
- volt += VoltageFastBuffer[i];
- curr += CurrentFastBuffer[i];
- }
- /* Попытка оверсемплинга, чтобы сделать шаг ~1мВ
- делим на 8, умножаем на опорное напряжение, умножаем на входной делитель
- и делим на (12 бит АЦП * 8). */
- #ifdef ADC_USE_V_OVERS
- volt >>= 3;
- volt *= ADC_REF;
- volt *= ADC_VOLT_K;
- volt /= ADC_ODIV;
- #else
- volt += 32;
- volt >>= 6;
- volt *= ADC_REF;
- volt *= ADC_VOLT_K;
- volt /= ADC_DIV;
- #endif // ADC_USE_V_OVERS
- /* получаем среднее по току, затем фильтруем */
- curr += 32;
- curr >>= 6;
- #ifdef ADC_USE_C_FILTR
- uint16_t middle;
- middle = curr + 8;
- middle &= 0xFFF0;
- curr = 0;
- uint8_t cnt = 0;
- uint16_t tmp;
- for(i=1; i<FAST_BUFFER_SIZE; i+=2){
- tmp = CurrentFastBuffer[i];
- tmp += 8;
- tmp &= 0xFFF0;
- if(tmp == middle){
- cnt ++;
- curr += CurrentFastBuffer[i];
- }
- }
- /* Усредняем преобразованный результат
- и переводим код АЦП в милиамперы */
- if(cnt > 0){
- curr /= cnt;
- } else {
- curr = middle;
- }
- #endif // ADC_USE_C_FILTR
- curr *= ADC_REF;
- curr /= ADC_DIV;
- shunt_volt = curr / ADC_CURR_K;
- volt -= shunt_volt;
- avgVal[0] = (uint16_t)volt;
- avgVal[1] = (uint16_t)curr;
- return avgVal;
- }
- /**
- * @}
- */
- /************************ (C) Vladimir N. Shilov *****END OF FILE****/
|