打印
[应用相关]

一个STM8S ADC脚与其它功能复用时的话题

[复制链接]
647|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一个STM8S ADC脚与其它功能复用时的话题


一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。

大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.

后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分**老少的。

这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:

使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。
TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。
但只要把  TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。

上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】
下面是他的主循环代码【为了排版和阅读,做了些删减】

  • int main( void )
  • {
  •   CLK_DeInit(); //寄存器复位
  •   CLK_HSICmd(ENABLE); //内部高速时钟使能
  •   CLK_HSIPrescalerConfig( ); //分频
  •   GPIO_initialzation();
  •   uart_initialzation();
  •   PWM1_initialzation();
  •   PWM2_initialzation();
  •   TIM4_initialzation();  //TIM4初始化
  •   enableInterrupts();//* 开启总中断 */
  •   Ts_cnt = 1000;
  •   Ls_cnt = 500;
  •   while(1)
  •   {
  •       PLED_flash(499); //LED 闪烁
  •       relay_control(); //继电器控制
  •       CCT_calculate();//获取相关AD值
  •       send_information();//输出提示信息
  •       if(Flag_rec)
  •       {
  •       。。。。。。【略】
  •       }   
  •   }
  • }

[color=rgb(51, 102, 153) !important]复制代码


现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。

TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。

但事实又的确显示出TIM4的中断跟UART-RX接收有关系。

TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。

  • INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
  • {
  •   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
  •   ms_cnt++;//LED FLASH
  •   Ts_cnt++; //AD sample
  •   Ls_cnt++; //relay control
  •   uart_cnt++;//send information
  •   PWM2_duty_setting(Ts_cnt);
  •   pwm1_correct_cnt++;
  •   if(pwm1_correct_cnt > 100)
  •   {
  •     pwm1_correct_cnt = 0;
  •     if(pwm1_cnt > CCT_target)
  •       pwm1_cnt--;
  •     else
  •       pwm1_cnt++;
  •     PWM1_duty_setting(pwm1_cnt);
  •   }
  • }
  • INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
  • {
  •   static uint8_t index = 0;
  •   UART1_ClearITPendingBit(UART1_IT_RXNE);
  •   recived_data[index] = UART1_ReceiveData8(); //读数据
  •   if(recived_data[0] == 0x41)
  •   {
  •     index++;
  •     if((index > 7)&&(recived_data[7] == 0x0d))
  •     {
  •       index = 0;
  •       Flag_rec = 1;
  •     }
  •   }
  •   else
  •   {
  •     index = 0;
  •     recived_data[0] = 0;
  •   }
  • }

[color=rgb(51, 102, 153) !important]复制代码


从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  • ms_cnt++;//LED FLASH
  •   Ts_cnt++; //AD sample
  •   Ls_cnt++; //relay control
  •   uart_cnt++;//send information


[color=rgb(51, 102, 153) !important]复制代码


问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。

  • PLED_flash(499); //LED闪烁
  • relay_control(); //继电器控制
  • CCT_calculate();//做AD转换
  • send_information();//输出提示信息

[color=rgb(51, 102, 153) !important]复制代码


后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。

看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。

  • voidCCT_calculate(void)
  • {
  •    if(Ts_cnt> 1000)
  •    {
  •      Ts_cnt = 0;
  •      T_ad = Get_ADCCH_Value(Ts_channel);
  •      T_degree = cal_temp(T_ad)-11;
  •    
  •      。。。。。。【略】
  •      }
  • }

[color=rgb(51, 102, 153) !important]复制代码


如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。

正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。


在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。


结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。

后来当它打开施密特触发器后,URAT-RX接收也就正常了。

显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。

谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。

使用特权

评论回复
沙发
Bowclad| | 2022-9-11 20:57 | 只看该作者
可以用在别的型号上吗?

使用特权

评论回复
板凳
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
地板
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
5
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
6
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
7
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
8
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
9
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
10
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
11
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
12
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
13
qbwww| | 2022-9-26 12:29 | 只看该作者
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

4056

帖子

1

粉丝