//////////////////////////////////////////////////////////////////////////////// /// @file adc_dma_multichanit.c /// @author AE TEAM /// @brief Multichannel sampling using DMA.The final sampling results /// (ADCVolatge) are viewed through simulation. //////////////////////////////////////////////////////////////////////////////// /// @attention /// /// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE /// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE /// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR /// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH /// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN /// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS. /// ///

© COPYRIGHT MINDMOTION

//////////////////////////////////////////////////////////////////////////////// // Define to prevent recursive inclusion #define _ADC_DMA_MultiChanIT_C_ // Files includes #include "adc_dma_multichanit.h" #include "public.h" #include "math.h" #include "sim_eeprom.h" #include "key.h" #include "pid.h" #include "tim3_pwm_output.h" #include "fpc.h" //#include "delay.h" //////////////////////////////////////////////////////////////////////////////// /// @addtogroup MM32_Hardware_Abstract_Layer /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ADC_DMA_MULTICHANIT /// @{ //////////////////////////////////////////////////////////////////////////////// /// @addtogroup ADC_Exported_Functions /// @{ vu32 adc_value = 0; vu8 ADCflag = 0; vu16 varADCavarage[AVERAGELEN][ADCSCANNUM]; //////////////////////////////////////////////////////////////////////////////// /// @brief Configure sampling GPIO with single conversion mode for ADC1 /// @note Note the corresponding channel selection. /// @param ADC_Channel_x: The sampling channel /// @retval None. //////////////////////////////////////////////////////////////////////////////// void ADCConfig(ADCCHANNEL_TypeDef adc_channel) { if( ADC_Channel_0 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_0); ADCSingleChannelInit(ADC_Channel_0); } else if( ADC_Channel_1 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_1); } else if( ADC_Channel_2 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_2); } else if( ADC_Channel_3 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_3); } else if( ADC_Channel_4 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_4); } else if( ADC_Channel_5 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_5); } else if( ADC_Channel_6 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_6); } else if( ADC_Channel_7 == adc_channel ) { GPIO_PinConfigAnalog(GPIOA, GPIO_Pin_7); } else if( ADC_Channel_8 == adc_channel ) { GPIO_PinConfigAnalog(GPIOB, GPIO_Pin_0); } else if( ADC_Channel_9 == adc_channel ) { GPIO_PinConfigAnalog(GPIOB, GPIO_Pin_1); } else if( ADC_Channel_11 == adc_channel ) { GPIO_PinConfigAnalog(GPIOB, GPIO_Pin_4); } else if( ADC_Channel_12 == adc_channel ) { GPIO_PinConfigAnalog(GPIOB, GPIO_Pin_7); } ADCSingleChannelInit(adc_channel); } //////////////////////////////////////////////////////////////////////////////// /// @brief Configure the ADC1 single conversion mode to correspond to the PIN /// @note It must be careful of the Chip Version. /// @param GPIOn: The sampling GPIOn corresponds to the port /// @param gpio_pin: The sampling gpio_pin corresponds to the pin. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void GPIO_PinConfigAnalog(GPIO_TypeDef* GPIOn, u16 gpio_pin) { GPIO_InitTypeDef GPIO_InitStruct; if(GPIOn == GPIOA) { RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE); } if(GPIOn == GPIOB) { RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE); } if(GPIOn == GPIOC) { RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE); } if(GPIOn == GPIOD) { RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOD, ENABLE); } GPIO_StructInit(&GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = gpio_pin; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOn, &GPIO_InitStruct); } //////////////////////////////////////////////////////////////////////////////// /// @brief Configure ADC1 single conversion mode��external interrupt source /// interrupt priority /// @note Configure parameters according to requirements. /// @param ADC_Channel_x: The sampling channel /// @retval None. //////////////////////////////////////////////////////////////////////////////// void ADCInit(void) { ADC_InitTypeDef ADC_InitStruct; ADC_StructInit(&ADC_InitStruct); //Initialize PA1 to analog input mode //Enable ADC clock RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1, ENABLE); ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; //ADC prescale factor ADC_InitStruct.ADC_PRESCARE = ADC_PCLK2_PRESCARE_8; //Set ADC mode to continuous conversion mode ADC_InitStruct.ADC_Mode = ADC_CR_SCAN;//ADC_Mode_Continue; //AD data right-justified ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_Init(ADC1, &ADC_InitStruct); //Enable ADCDMA ADC_DMACmd(ADC1, ENABLE); //Enable AD conversion ADC_Cmd(ADC1, ENABLE); } //////////////////////////////////////////////////////////////////////////////// /// @brief Configure ADC1 single conversion mode��external interrupt source /// interrupt priority /// @note Configure parameters according to requirements. /// @param ADC_Channel_x: The sampling channel /// @retval None. //////////////////////////////////////////////////////////////////////////////// void ADCSingleChannelInit(ADCCHANNEL_TypeDef ADC_Channel_x) { //Enable the channel ADC_RegularChannelConfig(ADC1, ADC_Channel_x, 0, ADC_Samctl_240_5); } //////////////////////////////////////////////////////////////////////////////// /// @brief DMA and interrupt priority configuration /// @note Configure parameters according to requirements. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void DMAInit(void) { DMA_InitTypeDef DMA_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); DMA_StructInit(&DMA_InitStruct); DMA_InitStruct.DMA_PeripheralBaseAddr = (u32) & (ADC1->DR); DMA_InitStruct.DMA_MemoryBaseAddr = (u32)&ADCValue; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_BufferSize = ADCSCANNUM; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStruct); DMA_Cmd(DMA1_Channel1, ENABLE); //DMA interrupt initialization DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority = 0x02; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); } //////////////////////////////////////////////////////////////////////////////// /// @brief Process values read from DMA,ADC second-order filter, /// when the filter is completed erection filter end marker. /// @note None. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// //u32 lastAD_value[ADCSCANNUM ] = {0,0,0}; //u8 last_count[ADCSCANNUM] = {0,0,0}; u8 onetimes = 0; //修改为中值滤波 void ADCFilter(void) { u16 chan; u16 cntFilter; u32 lADCFilterValue[ADCSCANNUM] = {0,0,0,0}; for(chan = 0; chan < ADCSCANNUM; chan++) { for(cntFilter = 0; cntFilter < AVERAGELEN; cntFilter++) { lADCFilterValue[chan] += varADCavarage[cntFilter][chan]; } ADCFilterValue[chan] = lADCFilterValue[chan] / AVERAGELEN; //printf("\nADCFilterValue[chan]:%d\n",ADCFilterValue[chan]); } } //////////////////////////////////////////////////////////////////////////////// /// @brief Transform the optimized data to get the final result. /// @note None. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// float R_1 = 0; float R_2 = 0 ; float current_temp_1 = 0; u32 current_temp_2 = 0; u16 count = 0; void Get_ADCVolatge(void) { u16 chan; float sub_1 = 0; float sub_2 = 0; float T_1 = 0; float T_2 = 0; WWDG_SetCounter(0x7e); for(chan = 0; chan < ADCSCANNUM; chan++) { ADCVolatge[chan] = ((float)ADCFilterValue[chan] / 4095) * REFVOLATGE; //printf("\nADCVolatge[%d]:%f\n",chan, ADCVolatge[chan]); } //printf("\nV:%f\n", ADCVolatge[2] * 2); sub_1 = (ADCVolatge[1] / 50 )/ 0.01f; //电流 电压/0.003欧姆电阻 // printf("\nADCVolatge[1]:%f\n",ADCVolatge[1]); //printf("\nsub_1:%f\n", sub_1); //2024年5月8日11:13:20 0.3 误差补偿 R_1 = (ADCVolatge[2] * 2) / sub_1 - 0.01 + 0.3;//ADCVolatge[1] / sub_1; g_work.r_value = R_1 * 1000; //printf("\nR_1:%f\n", R_1); //printf("\ng_work.m_set_other_hot.TCR_vlaue:%d\n",g_work.m_set_other_hot.TCR_vlaue); if( g_work.m_work_flag._nor_stand_flag == 0 ) { T_1 = ( R_1 - (float)g_work.m_set_other_hot.normal_R_Value/ 1000.0f) / ( (float)g_work.m_set_other_hot.TCR_vlaue / 1000000.0f *g_work.m_set_other_hot.normal_R_Value/1000.0f ); current_temp_1 = (g_work.m_set_other_hot.normal_T_Value + T_1) ; g_work.temp_1 = current_temp_1 ; // printf("\ng_work.m_set_other_hot.TCR_vlaue:%d\n",g_work.m_set_other_hot.TCR_vlaue); //printf("\ng_work.temp_1:%f\n",g_work.temp_1); } else // 开始低温标定 { if( g_work.work_conditon == STANDY ) // 待机模式 { if ( g_work.m_work_flag._nor_stand_flag == 1 ) { if(g_work.temp_delay > 1500) { if( R_1 > 0.7 && R_1 < 0.9 ) { g_work.m_set_other_hot.normal_R_Value = R_1 * 1000; send_TCR(g_work.m_set_other_hot.normal_R_Value); // 开始标定标定标志 flash_wite(); } else { send_ack(2); // 标定错误; } } } } } if( g_work.m_work_flag._high_stand_flag == 1) //高温标定 { flash_wite(); g_work.m_work_flag._high_stand_flag = 0; } if(g_work.check_info == 1) { send_TCR_value(g_work.m_set_other_hot.TCR_vlaue,g_work.m_set_other_hot.normal_R_Value,g_work.m_set_other_hot.normal_T_Value); g_work.check_info = 0; } pid.curr = g_work.temp_1; if(g_work.work_conditon == STANDY) { //由于误差问题,需要校正电压。 g_work.V_real_Value = (ADCVolatge[2]) * 100 * 2; } else { g_work.V_real_Value = (ADCVolatge[2]) * 100 * 2; } //printf("\ng_work.V_real_Value:%d\n",g_work.V_real_Value); if( g_work.m_time._work_time > 500 ) { g_work.m_time._work_time = 0; // 电池温度 判断 以及预警 if( ADCVolatge[0] < 0.901 ) // 60 22k { if( ADCVolatge[0] < 0.454 ) // 80 10k { if( V_5_V == 0 ) { if( g_work.power == 1 ) { if( g_work.err_fault == NO_WARING ) { g_work.m_time._Sleep_time = 0; g_work.err_fault = BATT_HIG_ERR; } } } } g_work.m_work_flag.chargeflag = NOCHARGE; } else if( ADCVolatge[0] > 1.240f ) // 50 33K { if( g_work.work_conditon == STANDY ) // 待机的情况下充电 { g_work.m_work_flag.chargeflag = CHARGE; } else { g_work.m_work_flag.chargeflag = NOCHARGE; } } if ( ADCVolatge[0] > 3.901f ) // 0 355K` { g_work.m_work_flag.zero_T_flag = 1; } else { g_work.m_work_flag.zero_T_flag = 0; } if( g_work.m_work_flag.chargeflag == CHARGE ) { if( g_work.power == 1 ) { Charge_ON(); } else { Charge_OFF(); } } else { Charge_OFF(); } } } //电量达到100%时 ,白灯长亮. 4.35 //电量为70%-99%之间时,白灯常亮 //电量为30%-69%之间时,蓝灯常亮 //电量为1-29%之间时,红灯闪烁 // 0: 白灯 // 1:蓝灯 // 2:红灯 // 3:红灯闪 void V_Conditon() // 电压判断 { if(g_work._write_v_ok == 1) { //printf("\ng_work.m_conditon.m_conditon.V_conditon:%d\n",g_work.m_conditon.m_conditon.V_conditon); //printf("\ng_work.V_real_Value:%d\n",g_work.V_real_Value); //printf("\nOK!\n"); switch( g_work.m_conditon.m_conditon.V_conditon ) { case 0: if( g_work.V_real_Value <= 410) //99-70% { g_work.m_conditon.m_conditon.V_conditon = 1; Write_condtion(); } break; case 1: if( g_work.V_real_Value <= 375 ) //30-70% { g_work.m_conditon.m_conditon.V_conditon = 2; Write_condtion(); } break; case 2: if( g_work.V_real_Value <= 350 ) // <30% { g_work.m_conditon.m_conditon.V_conditon = 3; Write_condtion(); } break; case 3: // 3.50 break; case 4: break; } if( g_work.power == 0 ) { //printf("123\r\n"); Write_condtion(); } } // } } //////////////////////////////////////////////////////////////////////////////// /// @brief When DMA send data, set ADCflag, PA8, clear the interrupt flag, /// stop the conversion. /// @note If error occurs,Simulation to see if you can enter the interrupt /// function. /// @param None. /// @retval None. //////////////////////////////////////////////////////////////////////////////// void DMA1_Channel1_IRQHandler(void) { //Stop Conversion ADC_SoftwareStartConvCmd(ADC1, DISABLE); //Clear interrupt flag DMA_ClearITPendingBit(DMA1_IT_TC1); ADC_DMACmd(ADC1,DISABLE); //Erected transmission complete flag ADCflag = 1; adc_get(); g_work.get_r_flag = 0; } //void get_adc void adc_get() { static u16 chan, averagenumber = 0; if(ADCflag == 1) { ADCflag = 0; for(chan = 0; chan < ADCSCANNUM; chan++) { varADCavarage[averagenumber][chan] = ADCValue[chan]; // printf("ADC_F chan %d cnt: %d __ %d ",chan,averagenumber,varADCavarage[averagenumber][chan]); // printf("ADC_%d __ %d ",chan,ADCValue[chan]); } //printf("\r\n"); WWDG_SetCounter(0x7e); //DELAY_Ms(2); ADC_SoftwareStartConvCmd(ADC1, ENABLE); ADC_DMACmd(ADC1,ENABLE); averagenumber++; if(averagenumber >= AVERAGELEN) { averagenumber = 0; ADCTrigFilterflag = 1; } } } void ADC_work() { // if(ADCTrigFilterflag) // { // ADCFilter(); // ADCTrigFilterflag = 0; // Get_ADCVolatge_new(); // } // //adc_get(); // //Determine whether the second-order filter is over // if(ADCTrigFilterflag) { // ADCFilter(); // //Clear the filter end flag // ADCTrigFilterflag = 0; // //Convert the filtered value to voltage // Get_ADCVolatge(); // g_work._write_v_ok = 1; // } // // //常温标定 // if(g_work.temp_delay > 5) // { // ADC_SoftwareStartConvCmd(ADC1, ENABLE); // } // // if(g_work.get_r_flag == 1 && g_work.adc_count > 100) // { // ADC_SoftwareStartConvCmd(ADC1, ENABLE); // ADC_DMACmd(ADC1,ENABLE); // g_work.adc_count = 0; //定时采集 // } // WWDG_SetCounter(0x7e); } /// @} /// @} /// @}