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

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

[复制链接]
STMCU小助手 发布时间:2021-2-25 14:48
一个STM8S ADC脚与其它功能复用时的话题
, J2 K% z4 s- Z3 f8 W- i2 R2 [
4.1.jpg
2 I" V9 f) q0 B
一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。

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

! ~# I5 T) ~- q5 _9 H; f% u% h9 `/ h
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.
& Z0 U1 L! P' d5 k2 A2 A
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。
4 c0 D7 ]  X7 C( a7 C, ^
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:

9 B6 x8 O7 _! t; J7 Y
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。
TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。
但只要把  TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。
6 o1 v  q. M7 c
上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】
下面是他的主循环代码【为了排版和阅读,做了些删减】

0 |; A# f: ^: S7 j! ~2 Z
  1. int main( void )
      d0 u  C5 f) {
  2. {0 M% b7 w" G( {" p0 X& X* K, Y
  3.   CLK_DeInit(); //寄存器复位& U0 o' I9 \2 [' ]9 K4 T5 L
  4.   CLK_HSICmd(ENABLE); //内部高速时钟使能 9 i0 e2 w  ]& D9 _6 \8 l" D
  5.   CLK_HSIPrescalerConfig( ); //分频
    8 Y/ d2 }4 k6 }$ L* G) B
  6.   GPIO_initialzation();" t. r! O1 E( z# A1 ]
  7.   uart_initialzation();
    , ?/ _( c# c, \1 p
  8.   PWM1_initialzation();
    5 t" r( C4 W( Q( A$ J4 f3 W
  9.   PWM2_initialzation();
    + f0 b; n4 _/ l) a
  10.   TIM4_initialzation();  //TIM4初始化
    & E2 R$ f9 p0 k6 i4 J
  11.   enableInterrupts();//* 开启总中断 */
    0 l2 o/ r4 l5 h1 T

  12.   d0 l' J& Y6 y: M; U% _
  13.   Ts_cnt = 1000;
    % Z2 S  ]9 A: S  ?3 R9 N9 v
  14.   Ls_cnt = 500;* I7 ]1 ]2 U. ^2 v

  15. 7 F) d) b3 n! a1 e' O
  16.   while(1)
    ; B, ]! }+ m5 |$ n! E% r7 \+ {
  17.   {( S  m9 p& A+ f5 ?5 \8 D- Y
  18.       PLED_flash(499); //LED 闪烁
    7 A' r7 ^5 [' d) \1 r: B
  19.       relay_control(); //继电器控制
    : u, i* d2 m6 k! f- S; S
  20.       CCT_calculate();//获取相关AD值2 I* n7 _- y' D6 ]* u) a
  21.       send_information();//输出提示信息0 {, O- Q- O; V3 w- X9 W% [
  22.       if(Flag_rec)
    . X# L  j" e/ z" Q& j  E
  23.       {9 a, g6 u" t  Z# g4 N) `
  24.       。。。。。。【略】4 s5 p6 Y* u) `/ Q% D2 h
  25.       }    : ~: |6 o5 h( K! Z$ ^; g
  26.   }! y( y9 P9 q) |+ ]. J- K
  27. }
复制代码
$ q/ ^* b2 b. M+ D7 f5 J$ G( B/ ?
现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。

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

, H0 N% {1 ?# D
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。

5 ]1 ~& {9 I/ M- L. t
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。
* e5 A9 F- r2 ~4 _8 @% D: U
  1. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
    ' x+ b- ?' r" o: q2 L
  2. {
    9 \9 q* a+ |5 M$ Z6 N9 \* R
  3.   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
    # x* l6 L9 S2 c! c
  4. ) y& \6 A+ K" a+ O
  5.   ms_cnt++;//LED FLASH
    1 z; k# d' O2 y7 A* Q/ ]
  6.   Ts_cnt++; //AD sample
    $ @0 ^! S- l5 K5 X9 e1 |
  7.   Ls_cnt++; //relay control
    / U$ p1 c. I% c0 {; \0 _
  8.   uart_cnt++;//send information& h9 `, }2 n- O

  9. 4 Y- j8 c3 j" G6 _# H
  10.   PWM2_duty_setting(Ts_cnt);
    * M' w# k- J7 X  _
  11.   pwm1_correct_cnt++;
    ! ]3 `4 E* c9 d' E/ q
  12.   if(pwm1_correct_cnt > 100)
    $ W( p, {0 F# i. L6 L8 p# j" Z# x
  13.   {
    - r$ I9 P, ]9 T  h
  14.     pwm1_correct_cnt = 0;; G$ ]  p1 D' X6 y# R# y
  15.     if(pwm1_cnt > CCT_target)
    ( f# {8 {7 U) e( e8 j  [
  16.       pwm1_cnt--;, D2 l9 i% c: Y
  17.     else
    9 U2 }1 H7 h/ m; f6 V
  18.       pwm1_cnt++; " q' R; d4 |& y# _# G
  19.     PWM1_duty_setting(pwm1_cnt);
    0 Y* h" t& Q: E, x* G* z5 J
  20.   }4 w0 M9 O$ |# E' l
  21. }/ j5 A0 I) X6 b8 B7 N9 M
  22. : Q% ]4 `- T1 D7 ~5 }* J7 q
  23. INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
    6 L  ]: i$ @+ B* a9 ^' ^" F4 ]
  24. {
    ! L7 P- V0 W( e" G$ n0 k
  25.   static uint8_t index = 0;) D2 J" _# r7 E: Q. }1 ?3 N# a
  26.   UART1_ClearITPendingBit(UART1_IT_RXNE);* D# A6 [3 t1 q' ?/ ~6 _1 h9 d
  27.   recived_data[index] = UART1_ReceiveData8(); //读数据
    4 w, u  T" z3 u% u0 B4 R1 u
  28.   if(recived_data[0] == 0x41)
    : _. F% ]; f6 q. Q- E* L$ a9 X3 E
  29.   {
    : ?% y! H3 [' q: [, x
  30.     index++;/ d% [0 f# s- K9 a( p) m. e
  31.     if((index > 7)&&(recived_data[7] == 0x0d))
    / @  L8 q0 o# Y5 O# a/ d- C8 J3 r
  32.     {8 J- g$ v" y0 y- P1 ]5 {* V3 X: J
  33.       index = 0;" f) ^1 u: ]% H% h+ o' H# v9 R7 e
  34.       Flag_rec = 1;: m- ~6 u6 c- C) Y5 s  ~/ ?, u
  35.     }
    8 i7 {6 Q8 `) c1 F2 P6 {% \9 H
  36.   }! J7 G$ p; U  A6 |5 S2 i
  37.   else
    2 C: ^2 p& W- K& Z/ ^5 F
  38.   {: t# e1 L8 y  O  f1 o% P, I: d* |
  39.     index = 0;
    ; L1 m- {' U& T; g9 q6 A8 u- w
  40.     recived_data[0] = 0;
      m- L1 `* c/ H) c# R. t
  41.   }
    7 r$ Y" ]6 y7 K, \8 O) [" ^& H! J
  42. }
复制代码
. s8 I  q* ]$ d  Y
从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  1. ms_cnt++;//LED FLASH
    $ Z6 J% @: j: ^6 i1 l( J3 B7 }
  2.   Ts_cnt++; //AD sample( G. i/ j( X6 j4 }9 F, j
  3.   Ls_cnt++; //relay control) ?; I2 g; p# b1 v0 u5 V
  4.   uart_cnt++;//send information
    $ M0 y8 x! K! u# [' J
复制代码

, J- r5 p- Q4 n' R
问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。
+ j5 S. X) m: l8 m$ K" }* S4 E
  1. PLED_flash(499); //LED闪烁3 F7 _# G/ [  o& C" @! O
  2. relay_control(); //继电器控制0 I  m$ D% G$ m& u' Q
  3. CCT_calculate();//做AD转换
    ' @5 F1 A6 q' X( O
  4. send_information();//输出提示信息
复制代码
, y" R& A# {* u6 Z
后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。

# y" M4 N: P, x( v) x
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。
: U$ N5 }' t! H# K2 u3 H" I
  1. voidCCT_calculate(void)
    + l4 ~( s5 |1 w) H/ K' _
  2. {& @5 G7 l4 v, N7 f) {
  3.    if(Ts_cnt> 1000)
    + W" N" F& _; b" _- `% \4 B
  4.    {7 \6 J1 D" }2 S/ r
  5.      Ts_cnt = 0;8 x) a8 B6 a2 f+ G, a( E
  6.      T_ad = Get_ADCCH_Value(Ts_channel);
    1 B: H3 e! X2 H" {6 x. F
  7.      T_degree = cal_temp(T_ad)-11;
    + f" t0 [, |2 K' j! H
  8.    
    * k+ C- z6 [" g; B3 K) g
  9.      。。。。。。【略】; r/ P/ E, Y* a" t- X, r
  10.      }4 U* V. K9 i6 s1 Y; P% n3 Q( T  D
  11. }
复制代码
3 g6 a( y- q# C4 U5 O  Q0 K: R; L5 d
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。

  l, Z4 }9 [5 c3 R/ q) l, {
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。
9 ~" v* P6 z6 p8 \6 R  b# r
4.2.jpg
- s( H8 B1 Y2 n6 p
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

1 I/ v  V& V6 G6 Z2 R( x7 D' v2 z
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。
  R% r2 ^; }$ v
4.3.jpg

3 r$ k% }1 N. z
结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。
6 z3 |- n& v% V
后来当它打开施密特触发器后,URAT-RX接收也就正常了。
2 s/ Q0 D, F/ I9 o% J( @' a0 s
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。

, w; M; g: t9 `. W
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。

2 X$ F8 ]: P# r
文章出处: 茶话MCU
4 |  \  ]( r: X/ z0 x3 }. b5 R

! k+ N! }% w# ]: W+ e8 u
收藏 评论0 发布时间:2021-2-25 14:48

举报

0个回答

所属标签

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