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

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

[复制链接]
STMCU小助手 发布时间:2021-2-25 14:48
一个STM8S ADC脚与其它功能复用时的话题

$ g) I5 H& A% ^8 Y! G$ X
4.1.jpg

& h9 z7 ]0 e3 \, ^6 k( E; H# U
一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。
, B$ u( M, a9 C; o, J$ P! Q
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。

$ l. b2 m: ]7 `% X3 t4 m  V, B% ~
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.
( [/ x1 b- z! a
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。

2 J# U5 `. o  }
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:
9 C8 _: x# J: _* R( V4 ]
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。
TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。
但只要把  TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。

1 V" S% Z+ ~8 y. r- E, H# r; u
上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】
下面是他的主循环代码【为了排版和阅读,做了些删减】

9 {! }/ Z. n0 C& Y8 W" @( t
  1. int main( void )
    ' Z9 `  p( J/ @9 [8 Y
  2. {
      W/ Y* s  E- M' o
  3.   CLK_DeInit(); //寄存器复位5 t& i& h1 p: [' @8 `0 |
  4.   CLK_HSICmd(ENABLE); //内部高速时钟使能
    , Z  M' k4 {9 H% i
  5.   CLK_HSIPrescalerConfig( ); //分频8 r) t& v( L9 v
  6.   GPIO_initialzation();
    ! a) k8 Y* t3 ^- W) G
  7.   uart_initialzation();
    " S! M* y' O& M
  8.   PWM1_initialzation();! Z+ ^1 E8 T, m1 @6 y
  9.   PWM2_initialzation();! z2 M  [( n# m4 L3 _0 q
  10.   TIM4_initialzation();  //TIM4初始化# ~5 m( w: A8 l! ~
  11.   enableInterrupts();//* 开启总中断 */
    ) Z: s8 q7 Q- m0 E2 L0 k

  12. ' M4 y! A0 o* ]  |8 o5 S) V
  13.   Ts_cnt = 1000;+ y$ [$ g( E! r! a2 r9 j
  14.   Ls_cnt = 500;8 Q9 _4 A( q% X' @7 p* B, w: x
  15. 1 [/ w6 d; |" ~+ C4 u  }1 t' x# {" w
  16.   while(1)* \+ p8 d( D% u$ B
  17.   {# X& q( [+ @/ o) i6 d/ W9 h4 k
  18.       PLED_flash(499); //LED 闪烁
    & [1 L7 R; Y- i6 X
  19.       relay_control(); //继电器控制
    9 ?* V+ C; i! I) d: |: z7 z
  20.       CCT_calculate();//获取相关AD值; x' u# Q+ S2 Y: k+ L# o/ K5 N; Y0 o
  21.       send_information();//输出提示信息& ?! k, ~( \) @5 B2 Q
  22.       if(Flag_rec)
    % u1 Y  U8 N: {, K, w
  23.       {: ~. F* E! {' r- G- @( H- |' c! u
  24.       。。。。。。【略】
      j* [1 h" m: @
  25.       }    0 I& C8 j5 o! R! U2 C/ s
  26.   }
    ) p1 c" e1 N! u
  27. }
复制代码

4 t# x3 z+ R, W2 {: r# I. s3 N
现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。

. a4 R, |& K6 W' v" i3 d
TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。
% H" k0 N, i+ e2 x5 Y
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。
7 j8 |; ]/ i. Q  A! y, E& E
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。
# Y( M6 t# L- q5 b8 K# ~
  1. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
    4 d- @# R0 w$ J3 |! {% x: }2 I0 S
  2. {
    7 c" C& D1 Q! v$ Q& j
  3.   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
    ! ~' G2 I- a) L% a6 s3 e, g! K+ F
  4. 2 t0 Q6 v0 B1 L
  5.   ms_cnt++;//LED FLASH
    + {" a+ P: V+ q1 o
  6.   Ts_cnt++; //AD sample# @, I& G/ ?" F/ C3 a- \
  7.   Ls_cnt++; //relay control
    : x; N* w% Y" F' j  u* k
  8.   uart_cnt++;//send information
    ' h8 q3 D0 m1 q0 E: n2 n
  9. & {1 d& o- `5 o6 Y1 K' f
  10.   PWM2_duty_setting(Ts_cnt);
    . T* p1 N5 p  n* M3 C
  11.   pwm1_correct_cnt++;
    ( ^. U, c6 V+ @2 I4 i
  12.   if(pwm1_correct_cnt > 100)
    9 o8 u/ A8 |/ S$ z
  13.   {4 q4 |7 K, y2 o3 h+ f
  14.     pwm1_correct_cnt = 0;# }$ w" g- }; o. j
  15.     if(pwm1_cnt > CCT_target)
    ! o3 v* P% x: C; j1 b/ Z
  16.       pwm1_cnt--;
    . z& H" L0 R' }" ~5 z% U
  17.     else! g2 ]) Q; `9 v6 n& L/ @
  18.       pwm1_cnt++;
    7 m, E" x/ ^3 p1 b6 V1 Y, {
  19.     PWM1_duty_setting(pwm1_cnt);: U4 V9 }9 n- _1 P' I
  20.   }' \6 \9 e1 ?+ B- f
  21. }
    % i# K6 c- w: g4 N

  22. ) ]2 S/ a# K3 }& d& D7 |
  23. INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
    4 G2 g4 A+ }7 ]3 {
  24. {
    ) e# S7 u1 D, q% T$ n
  25.   static uint8_t index = 0;
    7 N8 e% v* x5 U' T, j
  26.   UART1_ClearITPendingBit(UART1_IT_RXNE);! b7 M, F8 b' ^  s- K
  27.   recived_data[index] = UART1_ReceiveData8(); //读数据
    " @8 I  ]/ W+ ?6 [5 W2 o% @
  28.   if(recived_data[0] == 0x41)% g. Y5 K6 s  o
  29.   {* w2 y, Q+ j& o7 K
  30.     index++;0 K, H2 Z. H% G7 w
  31.     if((index > 7)&&(recived_data[7] == 0x0d))9 E+ A( S" g7 X/ p  }+ |4 U
  32.     {
    " u1 L- G: {, G, d0 f9 {. S
  33.       index = 0;6 k% V% h% b' S  u+ ]  ^) G" g
  34.       Flag_rec = 1;" a  f( V! S7 a% J' \
  35.     }
    4 h. v& t! l3 E. L$ D5 G2 q4 w
  36.   }5 r" l9 ?" V% R* L5 E+ o" ^
  37.   else
    ( F+ k. q2 }, r" v0 w! {
  38.   {( H# E# o: _+ _2 ?7 s
  39.     index = 0;
    4 _2 _' K3 J, z, ~9 x  J0 Y
  40.     recived_data[0] = 0;
    - O' R0 P" I; U! k" A! ?
  41.   }) R" `7 _: i$ E: D! z  x
  42. }
复制代码

! Y# {3 K' ~+ B
从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  1. ms_cnt++;//LED FLASH2 q' Y' M4 g% L; D# \8 z' a- ?& p! l/ Y
  2.   Ts_cnt++; //AD sample* i: X5 m3 w: z: B) V7 ?- K1 W) S/ R
  3.   Ls_cnt++; //relay control
    8 X" z1 K  N  t2 G& e  S
  4.   uart_cnt++;//send information
    5 N! s: v2 v  V/ g" Q; p
复制代码

, ]+ y  q+ V3 Q: T6 ?
问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。
3 H0 T$ i4 V: f1 t7 l
  1. PLED_flash(499); //LED闪烁
    & |+ N2 r3 V' [# D- t+ \+ }
  2. relay_control(); //继电器控制1 C4 N2 @: x2 `0 a8 D2 S5 ]7 n5 y/ W
  3. CCT_calculate();//做AD转换8 @' q2 I: H7 e& H5 R
  4. send_information();//输出提示信息
复制代码

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

7 {& K% p, \# a
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。

: v9 y. }; v# d7 d. a
  1. voidCCT_calculate(void); ~/ J) v1 E7 w/ m1 N& F6 A
  2. {
    ' _! A# B+ P5 e2 p4 L  E
  3.    if(Ts_cnt> 1000)
    / @. D2 A. \- E% W: ?  W8 u
  4.    {
    1 N- i  v2 R1 R8 P5 c3 k. \
  5.      Ts_cnt = 0;
    & y( b0 L4 @; G2 Z! x( J; t
  6.      T_ad = Get_ADCCH_Value(Ts_channel);
    0 z* T  I& V) ?9 \3 l
  7.      T_degree = cal_temp(T_ad)-11;
    3 J' x9 F' q# \7 y  C
  8.     ( m# C4 X! c) Y2 Z
  9.      。。。。。。【略】# L( Q2 o. D: C" K, p
  10.      }
    * Q( ~' f7 E, S) A1 @+ r
  11. }
复制代码
8 Y8 l( ]( D, O% K" I$ R
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。
( g, q/ P! ~5 f7 o6 F4 z6 B
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。

9 V9 H  k( l# z8 f# R0 o
4.2.jpg
& O5 A( L. ?* t5 @! H' W
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

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

) x2 [$ G- C- s' {6 F
4.3.jpg

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

. h, g  q! x: o0 H/ e; o
后来当它打开施密特触发器后,URAT-RX接收也就正常了。

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

3 \# V' e. E! `) t) t! W7 r
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。

6 Q" l5 `3 Z" U# s/ |
文章出处: 茶话MCU

) k+ t# u% ~8 g3 b/ |# y
" S; |/ Z; `7 {: `+ E
收藏 评论0 发布时间:2021-2-25 14:48

举报

0个回答

所属标签

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