3322免费域名注册,公司官网优化方案,可以做营销任务的网站,c 网站开发 readonly属性用过一段时间国民技术N32G031系列单片机#xff0c;编程模式几乎类同STM32系列#xff08;另外一个国产32位单片机品牌兆易创新好像也是仿STM32的编程模式#xff0c;看来STM32的确是一款极其优秀的产品#xff09;#xff0c;但是价格实惠#xff0c;功能也很齐全#…用过一段时间国民技术N32G031系列单片机编程模式几乎类同STM32系列另外一个国产32位单片机品牌兆易创新好像也是仿STM32的编程模式看来STM32的确是一款极其优秀的产品但是价格实惠功能也很齐全软件支持包在官网都可以下载所以总体感觉还是可以的只是稳定性还有待验证。
最近在用N32G031做一款电源产品软件时发现了一个情况这种情况以前几乎都是不关注的就是AD转换的时间。我有10个通道要进行AD转换每个通道采样64次我的AD初始化函数和采样函数如下
初始化函数
/**
*name: ADC_Initial
*description: ADC initialization
*params: none
*return: none
*/
void ADC_Initial(void)
{ADC_InitType ADC_InitStructure;ADC_GPIO_Configuration();/* ADC configuration ------------------------------------------------------*/ADC_InitStructure.MultiChEn DISABLE;ADC_InitStructure.ContinueConvEn DISABLE;ADC_InitStructure.ExtTrigSelect ADC_EXT_TRIGCONV_NONE;ADC_InitStructure.DatAlign ADC_DAT_ALIGN_R;ADC_InitStructure.ChsNumber 1;ADC_Init(ADC, ADC_InitStructure);//ADC1 regular channel13 configuration//ADC_ConfigRegularChannel(ADC, ADC_CH_13_PC2, 1, ADC_SAMP_TIME_55CYCLES5);//Enable ADC DMA//ADC_EnableDMA(ADC, ENABLE);//Enable ADCADC_Enable(ADC, ENABLE);// Check ADC Readywhile (ADC_GetFlagStatusNew(ADC, ADC_FLAG_RDY) RESET);while (ADC_GetFlagStatusNew(ADC, ADC_FLAG_PD_RDY));channel IS1;
}
获取每次AD转换值函数这里设置每次采样的时钟周期是56
/**
*name: ADC_GetData
*description: get the converted AD value
*params: ADC_Channel: channel to be converted
*return: AD value we need
*/
uint16_t ADC_GetData(uint8_t ADC_Channel)
{uint16_t data;ADC_ConfigRegularChannel(ADC, ADC_Channel, 1, ADC_SAMP_TIME_56CYCLES5);// Start ADC Software ConversionADC_EnableSoftwareStartConv(ADC, ENABLE); //start software conversionwhile (ADC_GetFlagStatus(ADC, ADC_FLAG_ENDC) 0) //wait for the conversion to be finished{}ADC_ClearFlag(ADC, ADC_FLAG_ENDC); //clear the end conversion flagADC_ClearFlag(ADC, ADC_FLAG_STR);data ADC_GetDat(ADC);return (data);
}
应用程序采样所有通道AD值的函数共10个通道每个通道采样64次
/**
*name: ADC_Sample
*description: sample all the channelsAccording to the ADC sampling clock(1 MHz) and the cycles(56 cycles) one sampling operation needs,here we need to sample 10 channels, and each channel has to be sampled 64 times. If the ADC samplingclock is 1 MHz, the total time it takes to sample all the 10 channels is 64*10*56/1M 0.03584(S)about 36 milli-seconds.
*params: none
*return: none
*/
void ADC_Sample(void)
{uint16_t ad_data 0;if (!sample_flag){if (sample_cnt 0) //the first value should be discarded when switching channel{sample_cnt 1;return;}switch (channel){case IS1:{ad_data ADC_GetData(IS1);is1_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is1_sample_value_filt is1_sample_sum 6; //get the average AD valueis1_sample_sum 0;channel IS2; //next channel}break;}case IS2:{ad_data ADC_GetData(IS2);is2_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is2_sample_value_filt is2_sample_sum 6;is2_sample_sum 0;channel IS3;}break;}case IS3:{ad_data ADC_GetData(IS3);is3_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is3_sample_value_filt is3_sample_sum 6;is3_sample_sum 0;channel IS4;}break;}case IS4:{ad_data ADC_GetData(IS4);is4_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is4_sample_value_filt is4_sample_sum 6;is4_sample_sum 0;channel IS5;}break;}case IS5:{ad_data ADC_GetData(IS5);is5_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is5_sample_value_filt is5_sample_sum 6;is5_sample_sum 0;channel IS6;}break;}case IS6:{ad_data ADC_GetData(IS6);is6_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is6_sample_value_filt is6_sample_sum 6;is6_sample_sum 0;channel IS7;}break;}case IS7:{ad_data ADC_GetData(IS7);is7_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is7_sample_value_filt is7_sample_sum 6;is7_sample_sum 0;channel IS8;}break;}case IS8:{ad_data ADC_GetData(IS8);is8_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;is8_sample_value_filt is8_sample_sum 6;is8_sample_sum 0;channel TEMP;}break;}case TEMP:{ad_data ADC_GetData(TEMP);otp_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;otp_ad_value otp_sample_sum 6;otp_sample_sum 0;channel VOS;}break;}case VOS:{ad_data ADC_GetData(VOS);vos_sample_sum ad_data;if (sample_cnt SAMPLE_COUNT){sample_cnt 0;vdc_ad_value vos_sample_sum 6;vos_sample_sum 0;sample_flag 1;//sampleing finished flagchannel IS1;}break;}default:{channel IS1;sample_cnt 0;is1_sample_sum 0;is2_sample_sum 0;is3_sample_sum 0;is4_sample_sum 0;is5_sample_sum 0;is6_sample_sum 0;is7_sample_sum 0;is8_sample_sum 0;vos_sample_sum 0;otp_sample_sum 0;break;}}}
}
系统时钟及ADC模块的时钟配置函数其中配置AD模块的1 MHz时钟是必须的
/*** brief Configures the different system clocks.*/
static void RCC_Configuration(void)
{// PCLK1 HCLK/4, configure the clock of APB1 and times uses the prescaled APB1RCC_ConfigPclk1(RCC_HCLK_DIV4);// Enable peripheral clocks ------------------------------------------------// Enable TIM1 clocks//RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_TIM1, ENABLE);//Enable DMA clocks//RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);//Enable GPIO clocksRCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOC | RCC_APB2_PERIPH_GPIOF, ENABLE);//Enable ADC clocksRCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC, ENABLE);//RCC_ADCHCLK_DIV16ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV16);//enable ADC1M clock//RCC_EnableHsi(ENABLE);RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8);//enable USART1 clockRCC_EnableAPB2PeriphClk(USARTy_GPIO_CLK, ENABLE);RCC_EnableAPB2PeriphClk(USARTy_CLK, ENABLE);//TIM3 and TIM clock enableRCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);//RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM6, ENABLE);
}
AD检测滤波函数每20毫秒设置相关警告位主要是输入电压是否欠压或者过压
/**
*name: ADC_Status_Check
*description: ADC filter, the input voltage and OTP check
*params: none
*return: none
*/
static void ADC_Status_Check(void)
{if (vdc_ad_value VDC_UV_OFF_AD) //DC under and over voltage filtervdc_uvp_off;if (vdc_ad_value VDC_UV_ON_AD)vdc_uvp_recovered;if (vdc_ad_value VDC_OV_OFF_AD)vdc_ovp_off;if (vdc_ad_value VDC_OV_ON_AD)vdc_ovp_recovered;if (otp_ad_value OTP_OFF_AD) //OTPotp_off;if (otp_ad_value OTP_RECOVER_AD)otp_recovered;if (adc_filter_cnt IO_FILTER_CNT){if (vdc_uvp_off IO_FILTER_VALID_CNT AlarmStatus.alarm.VDC_UVP 0) //VDCAlarmStatus.alarm.VDC_UVP 1;if (vdc_uvp_recovered IO_FILTER_VALID_CNT AlarmStatus.alarm.VDC_UVP 1)AlarmStatus.alarm.VDC_UVP 0;if (vdc_ovp_off IO_FILTER_VALID_CNT AlarmStatus.alarm.VDC_OVP 0)AlarmStatus.alarm.VDC_OVP 1;if (vdc_ovp_recovered IO_FILTER_VALID_CNT AlarmStatus.alarm.VDC_OVP 1)AlarmStatus.alarm.VDC_OVP 0;if (otp_off IO_FILTER_VALID_CNT AlarmStatus.alarm.OTP 0) //OTPAlarmStatus.alarm.OTP 1;if (otp_recovered IO_FILTER_VALID_CNT AlarmStatus.alarm.OTP 1)AlarmStatus.alarm.OTP 0;if (AlarmStatus.alarm.VDC_OVP 0 AlarmStatus.alarm.VDC_UVP 0){AlarmStatus.alarm.VIN_STATUS_ERR 0;}else{AlarmStatus.alarm.VIN_STATUS_ERR 1;}adc_filter_cnt 0;vdc_uvp_off 0;vdc_uvp_recovered 0;vdc_ovp_off 0;vdc_ovp_recovered 0;otp_off 0;otp_recovered 0;}else{adc_filter_cnt;}
}
根据手册说明及咨询芯片厂的相关技术人员ADC模块的采样时钟频率固定是1MHz每次采样的时间软件设置为56个时钟周期这个可以修改另外每次AD转换还额外需要12.5个时钟周期所以完成10个通道采样每个通道采样64次所需要的总时间是(5612.5)*10*64/1000000 0.04384秒差不多就是44毫秒。
我的程序在做AD检测滤波非AD转换对AD转换完成后的平均值再次进行一段时间的滤波处理避免电源输出产生误动作时只有20毫秒并且初始时所有警告标志位都是清零的尤其是输入电压欠压和过压标志所以在电源开机时会有一个20毫秒输出正常打开然后又有一个40毫秒左右的关闭最后又是完全正常的现象。结合这个现象和AD转换10个通道所需的总时间那20毫秒就是AD滤波的时间在此期间由于所有标志位都清零电源输出正常打开20毫秒滤波过后由于此时AD转换还未完成需要40毫秒左右所以输入电压欠压警告位被置位AD检测未完成AD平均值为0结果输出关闭只有等到一轮AD检测完全完成且AD滤波也检测到完整的AD值后警告标志位才会清除之后输出就一直正常了。
如果要解决这个问题可以把AD滤波的时间加长至少要大于AD转换一轮所需要的时间或者如果对AD转换精度要求不高的话可以把采样次数减少或者把每次采样所需要的时钟数设置得小一些。最为直接的做法就是初始将所有警告标志位置1。这样开机时是异常的只有AD检测结果正常后电源才打开输出。
在这里我也只是记录下出现问题后要根据现象找出原因积极思考再找解决办法就是比较容易些的事情了。