ST意法半导体
直播中

陈静

8年用户 1378经验值
私信 关注
[问答]

求助,关于stm8s003 adc中断和通道切换的问题求解

ADC_init(){ADC1_DeInit();ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D2,ADC1_EXTTRIG_tiM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);//初始化adc3ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4, DISABLE);//adc4关闭施密特触发器(逻辑代码会切换adc3到adc4)ADC1_Cmd(ENABLE);}FlagStatus flag_status;void ADC3_read(){ADC1_ITConfig(ADC1_IT_EOCIE, DISABLE);//关闭ADC中断ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM, DISABLE);//关闭tim1触发adcADC1_ClearFlag(ADC1_FLAG_EOC);//清除转换结束标志位(如果不写这一条清除的话,直接执行下面这条获得指定的标志状态有时候会返回SET(不是每次),不知道为什么)flag_status = ADC1_GetFlagStatus(ADC1_FLAG_EOC);//获得指定的标志状态(不写上面那条清除的话有时会返回SET,很奇怪)ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_3, ADC1_ALIGN_RIGHT);//切换通道为3ADC1_StartConversion();//开始转换while(ADC1_GetFlagStatus(ADC1_FLAG_EOC)==RESET);//等待结束ADC1_ClearFlag(ADC1_FLAG_EOC); / /清除转换结束标志位Potentiometer_value = ADC1_GetConversionValue();//获取adc3转换结果}INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)//定时器2(2ms){ADC3_read();/*逻辑控制*/。。。。。。。。。。。。。。。ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_4, ADC1_ALIGN_RIGHT);//切换通道为4ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM, ENABLE);//打开tim1触发adcADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);打开ADC中断}INTERRUPT_HANDLER(ADC1_IRQHandler, 22){ADC1_ClearFlag(ADC1_FLAG_EOC);/ /清除转换结束标志位ADC1_ClearITPendingBit(ADC1_IT_EOC);/ /清除中断标志位ADC4value = ADC1_GetConversionValue();获取adc4转换结果}请教各位师傅是我代码哪里写错了吗?现在是adc3和adc4读取都很正常,就是很奇怪,为什么不写清除有时候会返回SET,我的理解是在那个位置不写清除应该也是RESET才对啊

回帖(3)

李捷

2025-3-15 16:27:45
ADC触发后,需要一段时间采样转换后才能置位EOC


所以是在执行ADC3_read() 前触发才有这个可能的。

这是个概率问题,因此才不会每次都有。
举报

李颜

2025-3-15 16:27:49
注意到在TIM2的中断里打开了 tim1 触发ADC。

如果timer1 触发了ADC, 而接着又执行ADC3_read() 就会发现EOC标志在。
举报

糖栗子

2025-3-21 17:56:05

针对STM8S003的ADC中断和通道切换问题,以下是逐步的解决方案:


问题分析



  1. 通道切换不正确:在切换ADC通道时未正确配置,导致转换结果错误。

  2. 中断配置问题:中断未正确启用或处理,导致无法触发中断服务程序。

  3. 标志位处理不当:转换完成标志未正确清除,导致程序卡死或重复中断。

  4. GPIO配置缺失:未将对应通道的GPIO设置为模拟输入模式。


解决方案


1. 初始化配置



  • 启用全局中断:确保在main()中启用全局中断。

  • GPIO配置:将ADC通道对应的引脚设置为模拟输入模式。
    void GPIO_Init() {
    GPIO_Init(GPIOB, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT); // ADC3 (PB3)
    GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_IN_FL_NO_IT); // ADC4 (PB4)
    }


2. 修改ADC初始化函数



  • 正确启用中断和触发:根据需求选择中断或轮询模式。
    void ADC_init() {
    ADC1_DeInit();
    ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_3, ADC1_PRESSEL_FCPU_D2,
              ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT,
              ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
    ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL4, DISABLE);
    ADC1_Cmd(ENABLE);
    ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE); // 启用中断
    enableInterrupts(); // 启用全局中断
    }


3. 修改ADC读取函数(轮询模式示例)


uint16_t ADC_read(ADC1_Channel_TypeDef channel) {
    ADC1_ITConfig(ADC1_IT_EOCIE, DISABLE); // 关闭中断,使用轮询
    ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM, DISABLE);
    ADC1_ClearFlag(ADC1_FLAG_EOC);

    // 重新配置通道并启动转换
    ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE, channel, ADC1_ALIGN_RIGHT);
    ADC1_StartConversion();
    while (ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET); // 等待转换完成
    uint16_t data = ADC1_GetConversionValue();

    ADC1_ExternalTriggerConfig(ADC1_EXTTRIG_TIM, ENABLE);
    ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE); // 恢复中断
    return data;
}

4. 中断服务程序



  • stm8s_it.c中实现中断处理
    INTERRUPT_HANDLER(ADC1_IRQHandler, 22) {
    if (ADC1_GetITStatus(ADC1_IT_EOC) == SET) {
        uint16_t adc_data = ADC1_GetConversionValue();
        // 处理数据...
        ADC1_ClearITPendingBit(ADC1_IT_EOC); // 清除中断标志
    }
    }


5. 通道切换流程



  • 每次切换通道时调用ADC_read并传入目标通道
    uint16_t adc3_value = ADC_read(ADC1_CHANNEL_3);
    uint16_t adc4_value = ADC_read(ADC1_CHANNEL_4);


关键点说明



  • 通道切换:每次转换前必须调用ADC1_ConversionConfig重新配置通道。

  • 中断与轮询:若使用中断,确保全局中断启用,并在中断中处理数据;若用轮询,需等待标志位。

  • 施密特触发器:根据信号噪声情况决定是否启用,通常禁用可减少功耗。

  • GPIO模式:必须配置为模拟输入,避免引脚电平冲突。


测试建议



  1. 单独测试每个通道的ADC读取,确认硬件连接正确。

  2. 使用示波器检查ADC输入引脚电压是否稳定。

  3. 在中断服务程序中设置断点,确认中断能否正确触发。


通过上述步骤调整,应能解决ADC通道切换和中断处理的问题。

举报

更多回帖

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