- static void adc_gpio_init(void)
- {
- GPIO_InitType GPIO_InitStructure;
-
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC , ENABLE ); //使能 ADC1 通道时钟
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC2 , ENABLE ); //使能 ADC1 通道时钟
- ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV6); //设置 ADC 分频因子 6,64M/6=12,ADC 最大时间不能超过 14M
- //PC1,2,15 作为模拟通道输入引脚
- GPIO_InitStructure.Pin = AD_INPUT2_INDEX | AD_INPUT3_INDEX | AD_INPUT4_INDEX;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
- GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure); //初始化 GPIOC
- RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA , ENABLE ); //使能 ADC1 通道时钟
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC2 , ENABLE ); //使能 ADC1 通道时钟
- ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB,RCC_ADCHCLK_DIV6); //设置 ADC 分频因子 6,64M/6=12,ADC 最大时间不能超过 14M
- //PC1,2,15 作为模拟通道输入引脚
- GPIO_InitStructure.Pin = AD_INPUT5_INDEX;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
- GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure); //初始化 GPIOA
- }
- static void adc_dma_init(void)
- {
- DMA_InitType DMA_InitStructure;
- RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
-
- DMA_DeInit(DMA1_CH8); //将DMA的通道1寄存器重设为缺省值
-
- DMA_InitStructure.PeriphAddr = (u32) & (ADC2->DAT); //DMA外设ADC基地址
- DMA_InitStructure.MemAddr = (u32)& ad_value; //DMA内存基地址
- DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; //内存作为数据传输的目的地
- DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; //DMA通道x没有设置为内存到内存传输
- DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD; //数据宽度为16位
- DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
- DMA_InitStructure.BufSize = ADC_CHANNEL_NUM; //DMA通道的DMA缓存的大小
- DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; //内存地址寄存器递增
- DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;//外设地址寄存器不变
- DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR; //工作在循环缓存模式
- DMA_InitStructure.Priority = DMA_PRIORITY_HIGH; //DMA通道 x拥有高优先级
- DMA_Init(DMA1_CH8, &DMA_InitStructure);
-
- }
- static void adc_init()
- {
- ADC_InitType ADC_InitStructure;
-
- ADC_DeInit(ADC_CHANNEL); //将外设 ADC1 的全部寄存器重设为缺省值
-
- ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; //ADC工作模式:ADC1和ADC2工作在独立模式
- ADC_InitStructure.MultiChEn = ENABLE; //模数转换工作在扫描模式
- ADC_InitStructure.ContinueConvEn = ENABLE; //模数转换工作在连续转换模式
- ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; //外部触发转换关闭
- ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; //ADC数据右对齐
- ADC_InitStructure.ChsNumber = ADC_CHANNEL_NUM; //顺序进行规则转换的ADC通道的数目
- ADC_Init(ADC_CHANNEL, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
-
- //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
- //ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
- ADC_ConfigRegularChannel(ADC_CHANNEL, ADC2_Channel_01_PA4, 1, ADC_SAMP_TIME_55CYCLES5);
- ADC_ConfigRegularChannel(ADC_CHANNEL, ADC2_Channel_07_PC1, 2, ADC_SAMP_TIME_55CYCLES5);
- ADC_ConfigRegularChannel(ADC_CHANNEL, ADC2_Channel_08_PC2, 3, ADC_SAMP_TIME_55CYCLES5);
- ADC_ConfigRegularChannel(ADC_CHANNEL, ADC2_Channel_12_PC5, 4, ADC_SAMP_TIME_55CYCLES5);
-
- ADC_EnableDMA(ADC_CHANNEL, ENABLE); // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
- ADC_Enable(ADC_CHANNEL, ENABLE); //使能指定的ADC1
- //ADC_StartCalibration(ADC_CHANNEL); //复位指定的ADC1的校准寄存器
-
- while(ADC_GetFlagStatusNew(ADC_CHANNEL,ADC_FLAG_RDY) == RESET); //获取ADC1复位校准寄存器的状态,设置状态则等待
- ADC_StartCalibration(ADC_CHANNEL); //开始指定ADC1的校准状态
- while(ADC_GetCalibrationStatus(ADC_CHANNEL)); //获取指定ADC1的校准程序,设置状态则等待
- }
- static void adc_start(void)
- {
- ADC_EnableSoftwareStartConv(ADC_CHANNEL, ENABLE); // start convert
- DMA_EnableChannel(DMA1_CH8, ENABLE);
- }
- void ADCInit(void)
- {
- unsigned char i = 0;
-
- adc_gpio_init();
- adc_dma_init();
- adc_init();
- adc_start();
- }
打印出的AD值如下图

由上图可以看出AD值十分不稳定,最多可相差300多,12位精度AD值的话300就是7.3%,误差很大了
程序上找不到头绪,先拿示波器打了一下AD管脚的波形,如下图

加电容滤波后的波形如下图

可以看到,加电容滤波后的波形好一点,但是也是不稳定.
同时测了一下STM32的AD输入波形,如下图


可以看到STM32就算不加电容波形也是十分平滑
仔细观察受干扰波形的周期发现,10ms的周期和电路上交流电压过零检测的周期一模一样,于是测了一下交流电压过零检测的波形,发现两者同步,于是猜测是过零检测电路的问题,由于过零检测电压幅值可以达到3.8V,而这个AD采样管脚在数据手册上的耐压值并不能达到5V,于是改进了过零检测电路,增加了一个跟随器,问题解决.
滴答延时问题话不多说直接上图

左边是N32,右边是STM32
- void systick_delay_init(void)
- {
- SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //选择AHB8分频作为systick输入时钟,8MHz 这里不能使用AHBCLK/8
- //fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
- fac_us = 8;
- fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
- }
- //延时nus,nus为要延时的us数.
- void delay_us(u32 nus)
- {
- u32 temp;
- SysTick->LOAD=nus*fac_us; //时间加载
- SysTick->VAL=0x00; //清空计数器
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
- do
- {
- temp=SysTick->CTRL;
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
- SysTick->VAL =0X00; //清空计数器
- }
- //延时nms
- //注意nms的范围
- //SysTick->LOAD为24位寄存器,所以,最大延时为:
- //nms<=0xffffff*8*1000/SYSCLK
- //SYSCLK单位为Hz,nms单位为ms
- //对72M条件下,nms<=1864
- void delay_ms(u16 nms)
- {
- u32 temp;
- SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
- SysTick->VAL =0x00; //清空计数器
- SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
- do
- {
- temp=SysTick->CTRL;
- }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
- SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
- SysTick->VAL =0X00; //清空计数器
- }