你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
STMCU小助手 发布时间:2021-2-25 14:48
一个STM8S ADC脚与其它功能复用时的话题
% s3 \8 p* Z+ w! T- r
4.1.jpg

4 v3 I5 x4 Q* K$ u7 A
一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。
& j2 T/ v; ~" ^1 G9 O
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。
6 y4 n& M1 T- c  O
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.

' @. q$ o0 ?+ [* I
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。
# ?+ L" w& V' D# `
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:

% A: G* s$ T3 u8 z
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。
TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。
但只要把  TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。
; T+ Y" R! {  [& e1 D
上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】
下面是他的主循环代码【为了排版和阅读,做了些删减】
0 T5 t/ `; Q8 ^& ~; L4 a
  1. int main( void )
    % Z$ _* s9 u4 B* R6 n$ O8 K3 B
  2. {
    9 y' d  N8 Y7 a, J2 P
  3.   CLK_DeInit(); //寄存器复位" J& M: v2 {7 j8 P  a8 w0 P
  4.   CLK_HSICmd(ENABLE); //内部高速时钟使能 6 l! b( p0 _/ d0 k
  5.   CLK_HSIPrescalerConfig( ); //分频
    1 {5 A) Z9 K2 w
  6.   GPIO_initialzation();
    4 H9 v& H8 p3 M8 U
  7.   uart_initialzation();
    % A2 z1 z% Q! k
  8.   PWM1_initialzation();
    - C; ?+ t% L5 p$ i
  9.   PWM2_initialzation();6 I4 v+ c& G- ]* m
  10.   TIM4_initialzation();  //TIM4初始化) f5 {/ L7 u/ p9 O+ k1 d5 l' n
  11.   enableInterrupts();//* 开启总中断 */
    * d$ P6 y& H" L1 d3 s( @4 z
  12. : m, w6 i( u( |, x6 O
  13.   Ts_cnt = 1000;
    6 o9 @# Y% n3 A) F- U  L2 c. Q
  14.   Ls_cnt = 500;
    * I3 c$ X% Q; e
  15. 2 K3 e* x5 F# |
  16.   while(1)' E; A, z! |1 X  g* o8 s9 f
  17.   {# t3 ?- U# q8 l$ Q6 A! x
  18.       PLED_flash(499); //LED 闪烁
    + B9 o7 g* K) l6 ?4 F( S, [4 w
  19.       relay_control(); //继电器控制
    8 M& o, U: U+ {. L3 G. N
  20.       CCT_calculate();//获取相关AD值
    0 p% D. U  _: u
  21.       send_information();//输出提示信息
      s+ m* a8 C2 F, l
  22.       if(Flag_rec)
    4 F0 j% S* B) s$ U, X
  23.       {
    * ~4 P) e. x( L; Z6 |
  24.       。。。。。。【略】1 }7 m: G/ X( _! f. P
  25.       }   
    . N( g, M( W# A. Q& [+ R% P
  26.   }4 L1 Q1 T# {4 A: Q
  27. }
复制代码

# B* R* A* I# C7 v
现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。
) O% v, e+ A( l
TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。
$ n/ G) v" m( w+ Y( N7 R! _
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。

9 e6 }2 G2 _7 M( ?- P: f
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。

: L/ D; L3 c4 k. o8 N7 w
  1. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)0 N- ^) _$ `$ p% F. n
  2. {
    ! k( @) w$ p' v
  3.   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);  a% g1 v3 D/ x5 D: ^

  4.   z7 L) W! v  [5 t% ~0 u! f
  5.   ms_cnt++;//LED FLASH
    ; I1 O' E. ^( I: V8 W
  6.   Ts_cnt++; //AD sample0 p1 m0 a( z0 [: f7 C
  7.   Ls_cnt++; //relay control
    0 k8 h+ X8 _1 m( V! d
  8.   uart_cnt++;//send information0 K/ [( Z3 m" W3 Z

  9. * |/ _* B7 U8 ^5 ?' S# A
  10.   PWM2_duty_setting(Ts_cnt);: D9 q) C9 A  F* I
  11.   pwm1_correct_cnt++;
    " x) L: h/ ~3 k) T8 ~2 Z3 L
  12.   if(pwm1_correct_cnt > 100)
    1 ?7 r. c1 _8 q; \0 {! K
  13.   {
    $ w3 n3 l, a6 I# W* U2 E
  14.     pwm1_correct_cnt = 0;
    8 `) a2 ~8 ?. a# @( A' h% g
  15.     if(pwm1_cnt > CCT_target)6 N. _9 \+ f" _" c0 L: h1 Y
  16.       pwm1_cnt--;
    * J0 k8 Q* l( U  ?
  17.     else  q/ s0 J( n" Z
  18.       pwm1_cnt++; 2 G8 \5 g3 w2 H: S* Z! H5 z
  19.     PWM1_duty_setting(pwm1_cnt);
    / Y* w  J- l5 l% |$ N
  20.   }
    3 w- G2 G9 V" h' v4 X8 i
  21. }
    " K8 `" @  }4 q7 {' D% G* P
  22. 4 i4 W; M% G( V9 e
  23. INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)7 S! e$ `7 |' h' P
  24. {# Y7 M' A- x* |0 u3 j* B) F6 h: ~0 l
  25.   static uint8_t index = 0;1 r- E- V" F6 X( R
  26.   UART1_ClearITPendingBit(UART1_IT_RXNE);5 D+ q) J( C" J3 H( I
  27.   recived_data[index] = UART1_ReceiveData8(); //读数据
    ; B1 p6 b) R) J8 g* t& i6 K! Q
  28.   if(recived_data[0] == 0x41). o/ x- c( }; b9 t$ z
  29.   {
    7 P: I  n0 Y# ~; N
  30.     index++;
    , A" |: K5 _( L( g+ E+ y/ _9 v
  31.     if((index > 7)&&(recived_data[7] == 0x0d))
    % ?0 R, O3 V# i" P& i& a( {
  32.     {
    / h" Q% b9 Y( e6 ^4 ]* V
  33.       index = 0;
    / R8 b8 ~- Z+ R( k% j
  34.       Flag_rec = 1;" Z1 c& t! O/ m0 i( r3 w2 V# v+ E
  35.     }- G' Q7 q4 W$ H* X
  36.   }
    $ Z( }( Z7 T4 K1 w/ _+ H
  37.   else
    5 z4 v1 Q; D: p
  38.   {# ]3 P( y( b/ F
  39.     index = 0;
    ; R$ b$ p' W: ?$ C- p  j
  40.     recived_data[0] = 0;
    . B. x! l; u/ A$ E  n% Y, Q
  41.   }
      n: w8 D5 a/ |$ Z
  42. }
复制代码

) f4 E7 O9 O- G6 L
从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  1. ms_cnt++;//LED FLASH( N* [# Y  `0 Y3 c$ J4 K9 e2 W. d
  2.   Ts_cnt++; //AD sample* V! P1 ^$ h3 o( A6 v
  3.   Ls_cnt++; //relay control
    * B8 X6 l7 L+ g% s7 m3 r
  4.   uart_cnt++;//send information
      f5 r" w9 O! g; c1 `
复制代码

; i, @9 [$ s2 h0 C: ]; c5 v
问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。
% ]8 h! \# ^4 x' D; }' M7 z
  1. PLED_flash(499); //LED闪烁
    - N# w9 ^- v* ^/ W
  2. relay_control(); //继电器控制5 l$ L. S, Y. B/ [1 H& v4 B
  3. CCT_calculate();//做AD转换
    ' H; t$ X: ~! X. c2 N( t
  4. send_information();//输出提示信息
复制代码

5 ^) i2 v6 [. P# \4 }
后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。
9 b, W# q4 r, Z6 w; P
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。

% N5 a, J! Q' D7 q6 N
  1. voidCCT_calculate(void)
    ( {2 ^/ f, N1 x0 k) `
  2. {
    6 \6 S% @9 o) p; w% C7 b4 o+ ]7 T  x* p
  3.    if(Ts_cnt> 1000)
    1 K9 Z8 S8 t( s2 a& D9 N( c' O
  4.    {2 C* v0 U7 a; r# B
  5.      Ts_cnt = 0;- k* Q# D6 \8 Q" _6 ]" L5 {
  6.      T_ad = Get_ADCCH_Value(Ts_channel);: q1 c+ h& }. C$ p4 E5 s( r
  7.      T_degree = cal_temp(T_ad)-11;
    ' F2 j7 d; Q' R2 C3 @  d' D
  8.     4 e# n, f1 O* c
  9.      。。。。。。【略】: x0 w& s: W+ k+ V& r
  10.      }$ {* x  U$ `% ]3 U
  11. }
复制代码
$ v5 O0 Q6 }( Y
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。
* Z/ i. m0 l# Y3 k
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。
. f7 ]* p9 N* U* y
4.2.jpg

/ U  O& B0 X7 ?1 {6 B6 W: X
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。
9 d) D2 J, c. \
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。
: g0 c: d9 H. `% J' H# w
4.3.jpg
/ q' |- G* u( _
结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。
$ I: ~) ~2 j  v8 V4 ]
后来当它打开施密特触发器后,URAT-RX接收也就正常了。
6 g; s" j) Q& G! R3 b( T3 x
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。
/ ?: {7 o3 w! T- ]4 x4 G
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。
( J( N5 z3 N7 k1 o
文章出处: 茶话MCU

2 A5 U' j: p* D8 x3 w5 [4 I* G

# ]( F* d6 z# t* i* p
赞 收藏 评论0 发布时间:2021-2-25 14:48

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版