ST意法半导体
直播中

laisvl

9年用户 1144经验值
私信 关注
[问答]

stm32f103c8t6 ADC channel 5采样被干扰导致程序卡死重启怎么解决?

   程序里配置了两个ADC进行采样,ADC1:采集输出电流、输出电压的值;ADC2:采集NTC电压、设置旋钮等电压。一共5个采样通道,ADC1:Channel_4、Channel_5;ADC2:Channel_2、Channel_8、Channel_9。    ADC1通过tiM2_CC2事件触发单次采样,用DMA搬运完成后在完成中断里处理数据,ADC2在循环中进行采样取值,在板子上都可以正常运行,但是上到整机使用的时候,会在有输出的时候突然卡死被看门狗重启,卡死的时机不定,但都是在带负载有输出的情况下重启的;输出电流是由TIM1的100kHz PWM控制的。    我在排查过程中,把Channel_5的输出电压采样去掉,再到整机上测试的时候就没有这个现象了。我就把Channel_5采样到的值涉及的程序屏蔽掉,但是Channel_5正常采样,同样运行,还是会重启,再次把Channel_5采样关掉,就没有问题了。我再把ADC1_channel_5换成用ADC2_channel_5,在循环里面采样,还是会出现这个问题。想问一下有大佬遇见过类似的问题吗,这种情况是否是Channel_5被外部干扰了不能正常采样,导致芯片不能正常工作了,有什么解决办法吗?配置如下:void ADC1_DMA_Config(void){    DMA_InitTypeDef DMA_InitStructure;    ADC_InitTypeDef ADC_InitStructure;    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);    /* DMA channel1 configuration */    DMA_DeInit(DMA1_Channel1);    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;             //ADC地址    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue; //内存地址    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;    DMA_InitStructure.DMA_BufferSize = 1;                             //数据长度为5    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //外设地址固定    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //内存地址固定    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                     //循环传输    DMA_InitStructure.DMA_Priority = DMA_Priority_High;    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;    DMA_Init(DMA1_Channel1, &DMA_InitStructure);    DMA_ITConfig (DMA1_Channel1,DMA_IT_TC,ENABLE );    /* Enable DMA channel1 */    DMA_Cmd(DMA1_Channel1, ENABLE);    ADC_DeInit(ADC1);      //复位ADC1,将外设ADC1的所有寄存器重设为缺省值。    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;          //独立ADC模式    ADC_InitStructure.ADC_ScanConvMode = ENABLE ;                   //扫描模式,扫描模式用于多通道采集    /* ADC1 configuration */    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;         //开启连续转换模式,即不停地进行ADC转换    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   //不使用外部触发转换    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //采集数据右对齐    ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //要转换的通道数目5    ADC_Init(ADC1, &ADC_InitStructure);    /*配置ADC时钟,为PCLK2的6分频,即12MHz*/    RCC_ADCCLKConfig(RCC_PCLK2_Div6);    /*配置ADC1的通道6为7.5个采样周期,序列为1 *///  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_28Cycles5);//PA5 VOL_OUT    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_28Cycles5);//PA4 CUR_OUT    ADC_ExternalTrigConvCmd(ADC1, ENABLE);  //设置外部触发使能    /* Enable ADC1 DMA */    ADC_DMACmd(ADC1, ENABLE);    /* Enable ADC1 */    ADC_Cmd(ADC1, ENABLE);    /*复位校准寄存器 */    ADC_ResetCalibration(ADC1);    /*等待校准寄存器复位完成 */    while(ADC_GetResetCalibrationStatus(ADC1));    /* ADC校准 */    ADC_StartCalibration(ADC1);    /* 等待校准完成*/    while(ADC_GetCalibrationStatus(ADC1));}void ADC2_Config(void){    ADC_InitTypeDef ADC_InitStructure;    //复位ADC1,将外设ADC1的所有寄存器重设为缺省值?    RCC_HSICmd(ENABLE);//  while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);    ADC_DeInit(ADC2);    ADC_StructInit(&ADC_InitStructure);    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;          //独立ADC模式    ADC_InitStructure.ADC_ScanConvMode = DISABLE ;                  //扫描模式,扫描模式用于多通道采集    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;         //开启连续转换模式,即不停地进行ADC转换    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发转换    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //采集数据右对齐    ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //要转换的通道数目5    ADC_Init(ADC2, &ADC_InitStructure);    /* Enable ADC1 */    ADC_Cmd(ADC2, ENABLE);    RCC_ADCCLKConfig(RCC_PCLK2_Div6);    /*复位校准寄存器 */    ADC_ResetCalibration(ADC2);    /*等待校准寄存器复位完成 */    while(ADC_GetResetCalibrationStatus(ADC2));    /* ADC校准 */    ADC_StartCalibration(ADC2);    /* 等待校准完成*/    while(ADC_GetCalibrationStatus(ADC2)) {};}void TIM1_PWM_Config(void){    GPIO_InitTypeDef GPIO_InitStructure;    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    TIM_OCInitTypeDef  TIM_OCInitStructure;    //  TIM_BDTRInitTypeDef  TIM_BDTRInitStructure;    /* GPIOB clock enable */    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9 | GPIO_Pin_10;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                            // 复用推挽输出    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOA, &GPIO_InitStructure);    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14 | GPIO_Pin_15;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                            // 复用推挽输出    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOB, &GPIO_InitStructure);    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);    /* 时基结构体初始化 */    TIM_TimeBaseStructure.TIM_Period =1931;                                  //当定时器从0计数到1931,即为1932次,为一个定时周期    TIM_TimeBaseStructure.TIM_Prescaler = 0;                                   //设置预分  频:不预分频,即为72MHz    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;                   //设置时钟分频系数:不分频(这里用不到)    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;  //设置中心对称    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);    /* 输出比较结构体初始化 */    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;    TIM_OCInitStructure.TIM_Pulse =350;    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;    TIM_OC2Init(TIM1, &TIM_OCInitStructure);    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Disable);    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;    TIM_OCInitStructure.TIM_Pulse =1582;    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;    TIM_OC3Init(TIM1, &TIM_OCInitStructure);    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Disable);    TIM_ARRPreloadConfig(TIM1, ENABLE);    TIM_ClearITPendingBit(TIM1, TIM_IT_CC3 | TIM_IT_CC2 );    TIM_ITConfig(TIM1, TIM_IT_CC3 | TIM_IT_CC2, DISABLE);    TIM_CtrlPWMOutputs(TIM1, ENABLE);     //使能外设的主输出}void TIM2_PWM_Config(){    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    TIM_OCInitTypeDef  TIM_OCInitStructure;    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        /* 时基结构体初始化 */    TIM_TimeBaseStructure.TIM_Period =1931;                                  //当定时器从0计数到1931,即为1932次,为一个定时周期    TIM_TimeBaseStructure.TIM_Prescaler = 0;                                   //设置预分  频:不预分频,即为72MHz    TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;                   //设置时钟分频系数:不分频(这里用不到)    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;  //设置中心对称    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    TIM_OCInitStructure.TIM_Pulse =1930 - 54;    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;    TIM_OC2Init(TIM2, &TIM_OCInitStructure);    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_OC2Ref);    TIM_ARRPreloadConfig(TIM2, ENABLE);}循环里的采样用的是下面几个函数:uint16_t Read_ADC_data(uint8_t ch){    uint16_t AD_Value;    ADC_RegularChannelConfig(ADC2, ch, 1, ADC_SampleTime_55Cycles5); //PA5 SET_CUR    ADC_Cmd(ADC2, ENABLE);    ADC_SoftwareStartConvCmd(ADC2, ENABLE);    while(!ADC_GetFlagStatus(ADC2,ADC_FLAG_EOC));    AD_Value = ADC_GetConversionValue(ADC2);    ADC_ClearFlag(ADC2, ADC_FLAG_EOC);    ADC_SoftwareStartConvCmd(ADC2, DISABLE);    ADC_Cmd(ADC2, DISABLE);    return AD_Value;}uint16_t Read_ADC_data(uint8_t ch){    uint16_t AD_Value;    ADC_RegularChannelConfig(ADC2, ch, 1, ADC_SampleTime_55Cycles5); //PA5 SET_CUR    ADC_Cmd(ADC2, ENABLE);    ADC_SoftwareStartConvCmd(ADC2, ENABLE);    while(!ADC_GetFlagStatus(ADC2,ADC_FLAG_EOC));    AD_Value = ADC_GetConversionValue(ADC2);    ADC_ClearFlag(ADC2, ADC_FLAG_EOC);    ADC_SoftwareStartConvCmd(ADC2, DISABLE);    ADC_Cmd(ADC2, DISABLE);    return AD_Value;}

回帖(1)

张莹

2025-3-10 17:46:09

在STM32F103C8T6中使用ADC进行采样时,如果遇到ADC采样被干扰导致程序卡死或重启的问题,可能是由于电源噪声、地线干扰、电磁干扰(EMI)或其他硬件/软件问题引起的。以下是一些可能的解决方案和排查步骤:




1. 硬件层面的排查与优化



  • 电源滤波

    • 确保ADC参考电压(VREF+)和模拟电源(VDDA)干净稳定,建议在VREF+和VDDA引脚附近添加滤波电容(如0.1µF和10µF)。

    • 检查整机的电源设计,确保没有高频噪声耦合到模拟电源。


  • 地线设计

    • 确保模拟地(VSSA)和数字地(VSS)分开布线,并在单点连接。

    • 检查整机的地线设计,避免地线噪声影响ADC采样。


  • 信号隔离

    • 在ADC输入引脚上添加RC低通滤波器(如1kΩ电阻和0.1µF电容),以滤除高频噪声。

    • 如果信号源距离MCU较远,使用屏蔽线或双绞线减少电磁干扰。


  • 电磁干扰(EMI)

    • 检查整机的电磁兼容性(EMC),确保PWM信号(如TIM1的100kHz PWM)不会通过辐射或传导干扰ADC采样。

    • 在PWM信号线上添加磁珠或滤波器,减少高频噪声。





2. 软件层面的优化



  • ADC配置优化

    • 确保ADC的采样时间(Sample Time)足够长,以正确采样信号。对于高频噪声环境,可以增加采样时间(如设置为239.5 cycles)。

    • 如果使用DMA传输,确保DMA缓冲区大小和配置正确,避免缓冲区溢出或数据丢失。


  • 中断处理优化

    • 检查ADC完成中断的处理代码,确保没有死锁或长时间阻塞的情况。

    • 如果中断处理时间较长,可以考虑在中断中设置标志位,在主循环中处理数据。


  • 看门狗配置

    • 如果使用独立看门狗(IWDG),确保看门狗的喂狗间隔合理,避免因ADC采样或数据处理时间过长导致看门狗复位。


  • PWM与ADC同步

    • 如果ADC采样与PWM信号相关,确保ADC采样时机与PWM信号同步,避免在PWM切换时采样。

    • 可以使用TIM2的触发信号(如TIM2_CC2)来同步ADC采样,避免干扰。





3. 调试与测试



  • 模拟故障环境

    • 在实验室中模拟整机的负载条件,观察ADC采样是否受到干扰。

    • 使用示波器检查ADC输入信号和参考电压,观察是否有噪声或异常。


  • 逐步排查

    • 暂时禁用ADC2的采样,只运行ADC1,观察是否仍然出现卡死问题。

    • 如果问题消失,可能是ADC2的采样或数据处理导致的问题。


  • 日志记录

    • 在程序中添加调试日志,记录ADC采样值和程序状态,帮助定位卡死的具体原因。





4. 其他可能的解决方案



  • 使用软件滤波

    • 对ADC采样值进行软件滤波(如均值滤波、中值滤波或卡尔曼滤波),减少噪声影响。


  • 降低PWM频率

    • 如果PWM频率较高(如100kHz),尝试降低频率,观察是否减少干扰。


  • 更换ADC通道

    • 如果怀疑特定ADC通道(如Channel_5)受到干扰,可以尝试更换到其他通道进行测试。





5. 总结


该问题可能是由于硬件干扰(如电源噪声、地线干扰或EMI)或软件配置不当(如ADC采样时间、中断处理或看门狗配置)引起的。建议从硬件和软件两方面逐步排查,并结合调试工具(如示波器、逻辑分析仪)定位问题根源。如果问题仍然无法解决,可以考虑重新设计硬件电路或优化软件逻辑。


希望这些建议能帮助你解决问题!

举报

更多回帖

发帖
×
20
完善资料,
赚取积分