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

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

[复制链接]
STMCU小助手 发布时间:2021-2-25 14:48
一个STM8S ADC脚与其它功能复用时的话题
% x! |/ l, _+ A' V7 Y0 Z$ e
4.1.jpg
- _* G- v; s4 U3 d& ?/ ~; T
一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。

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

3 `) d, s  z- w, ~) p. m3 A) o
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.
4 G0 t' R. I8 n2 s0 Q
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。
# n" q, z) G* Q4 n; P$ p
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:

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

# q! a: \$ z" ]; L
  1. int main( void )  a2 a8 P* Y5 P
  2. {
    1 f3 W7 [% q1 |: T4 c5 @
  3.   CLK_DeInit(); //寄存器复位
    # [/ q6 N' Z1 X/ x5 i8 B* Q
  4.   CLK_HSICmd(ENABLE); //内部高速时钟使能
    8 R5 _1 ?# r/ d
  5.   CLK_HSIPrescalerConfig( ); //分频
    5 I1 R8 ]4 G* _1 y
  6.   GPIO_initialzation();
    6 p- l% i* N$ n+ G3 s5 g
  7.   uart_initialzation();+ s) k4 X$ `' S6 b/ c
  8.   PWM1_initialzation();5 }5 J: ~8 h2 w* }7 B; E5 U' o) G
  9.   PWM2_initialzation();
    / W9 m+ M# w1 k7 K) N
  10.   TIM4_initialzation();  //TIM4初始化/ H' q6 r8 c! b
  11.   enableInterrupts();//* 开启总中断 */ ' H$ c' K' ]$ P) y+ D

  12.   B: G: v# u) ^: R" h
  13.   Ts_cnt = 1000;
    / l2 S- C. ~3 E' O$ i
  14.   Ls_cnt = 500;5 n3 J7 v. c1 m" I

  15. : m4 v' e, e- r+ m1 v
  16.   while(1)2 @! y( q) V: v0 c& Z
  17.   {3 ]7 ?8 c% {2 D; `2 t( Z) K
  18.       PLED_flash(499); //LED 闪烁. t" \" k/ f; j8 l7 H
  19.       relay_control(); //继电器控制) q( b3 W7 e' D3 |; I. I  c
  20.       CCT_calculate();//获取相关AD值
    0 i8 [/ k2 T) P! w
  21.       send_information();//输出提示信息6 \: N1 Y9 K" J9 E5 N2 Q
  22.       if(Flag_rec)! w" O# u$ L) e7 r( A
  23.       {
    , n6 J+ _* t" e. v* a, b
  24.       。。。。。。【略】
    " ^: I( P5 H- b: P" b$ o( f% e
  25.       }    , p! v, A! a/ @  Q2 F$ q7 B% [/ l
  26.   }
    ' p/ [% z7 Q4 f7 A
  27. }
复制代码
3 {2 g8 ~7 [* r
现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。

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

0 Q: P$ G* q% I. o% k5 D4 I
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。

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

% G8 p7 L2 p! m1 U5 D) z6 ]$ u, }
  1. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)% e$ k6 O% x$ w! H2 A9 ]/ n
  2. {
    & c9 O# @& M2 b( X1 K- G/ b$ _
  3.   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);; x0 |. U, @) ~  [- x  E4 X3 u
  4. 4 l, j7 x) k  V' J% m5 H3 D( A
  5.   ms_cnt++;//LED FLASH
    ( p+ i3 J9 F+ p  ^6 ~* l6 Q2 F" i
  6.   Ts_cnt++; //AD sample! E' A1 y2 M, W7 U) O& |# U" f
  7.   Ls_cnt++; //relay control
    7 U' O. E" h* P0 y+ t8 [( t
  8.   uart_cnt++;//send information. [* i8 m" ]6 w+ R
  9. ! @. K+ Z8 w1 E$ m
  10.   PWM2_duty_setting(Ts_cnt);
    . v1 D9 U! I* C; C
  11.   pwm1_correct_cnt++;/ K9 q9 e0 Y( W( S3 L0 R/ \
  12.   if(pwm1_correct_cnt > 100)
    / {; d% I: N$ v" g4 c3 G
  13.   {3 p+ P. s  B( K- W: X4 b
  14.     pwm1_correct_cnt = 0;
    " [) _& i& o# Z; F
  15.     if(pwm1_cnt > CCT_target), Q' p& m, F% U% T
  16.       pwm1_cnt--;7 e) p3 r0 O3 n
  17.     else
    $ ]* w, ]1 S; e( \' j
  18.       pwm1_cnt++;
    + i' h8 M; a, T" V9 {
  19.     PWM1_duty_setting(pwm1_cnt);) Z* E& i( A) i* U
  20.   }
    7 J" W: X6 H8 Y% X
  21. }8 }0 {  L- p: W6 E, v5 M/ @$ j
  22. 4 D( M, {0 R* ~# d! E+ f
  23. INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
    6 v3 f; R3 L- h8 I( C2 U0 y
  24. {% H. @. ^+ }( ^
  25.   static uint8_t index = 0;
    . q, ^0 S6 s) W3 q
  26.   UART1_ClearITPendingBit(UART1_IT_RXNE);
    4 v, Z. k% S3 n/ ]1 ]& \/ j5 j
  27.   recived_data[index] = UART1_ReceiveData8(); //读数据4 S4 v, Q! {- ~. h$ o, y' @
  28.   if(recived_data[0] == 0x41)5 b. ~8 E0 Z) Y- i8 }$ g% W: M5 l
  29.   {
    * \% c6 f( h5 u) I# M1 J0 j6 u
  30.     index++;1 m  R% ^6 J9 N" z: g& c- p  i% @% l& B  g
  31.     if((index > 7)&&(recived_data[7] == 0x0d))
    ) G7 ]3 t: M% ]# U1 r* O
  32.     {- _7 ^4 U: s" b7 T# K3 V
  33.       index = 0;$ Y# u8 p! K4 b
  34.       Flag_rec = 1;: V+ v, r2 [1 |1 {; q% o( g
  35.     }
    1 b, l# ~0 w& m0 Z  F) O
  36.   }9 G8 a  f: N- O' }
  37.   else
    7 g. v$ X- [) n
  38.   {; _7 Q) [8 L& Z
  39.     index = 0;
    9 Q, K4 B' I# e6 x
  40.     recived_data[0] = 0;8 z$ c7 W" l; x% c
  41.   }  J+ I. p  t* o9 E2 X2 Z% D
  42. }
复制代码

2 f/ G5 L4 }2 G: y
从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  1. ms_cnt++;//LED FLASH. e+ j0 @2 t; L; m
  2.   Ts_cnt++; //AD sample
    . b; X, H- d& y' N
  3.   Ls_cnt++; //relay control/ l# {/ }, B8 r  U
  4.   uart_cnt++;//send information$ J4 `$ D( t6 \" F  V
复制代码

: ]% j8 i& j/ n+ M  u* p
问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。
7 D7 e% g: s" [" K
  1. PLED_flash(499); //LED闪烁. S) L7 ^) N9 A, p4 N5 O. u
  2. relay_control(); //继电器控制% @* Q, l# L- a9 c
  3. CCT_calculate();//做AD转换3 X* C& e  ]7 C- P# n
  4. send_information();//输出提示信息
复制代码

1 R0 \5 U9 Q: u. m( M& ~
后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。
4 P% \3 P1 V- b; B, Z5 ~/ L
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。
; @4 Z" {; Q% a( |' T, y8 d
  1. voidCCT_calculate(void)
    5 e# O7 T/ p! ]2 }8 i% p
  2. {
    ( }: R+ Q- @# h* t6 H
  3.    if(Ts_cnt> 1000)" B* X3 d) q5 K$ U0 l  j
  4.    {0 L7 z& R0 s) s7 f3 L- B
  5.      Ts_cnt = 0;2 T& _( ~( V9 z6 s- P
  6.      T_ad = Get_ADCCH_Value(Ts_channel);
    , R- a& w$ H1 f; \& s7 n, w$ r
  7.      T_degree = cal_temp(T_ad)-11;
    " ^7 ?( b/ h' B, ]% w1 ^) [
  8.       Q5 O( u5 B# k3 T# S, S
  9.      。。。。。。【略】5 ]# A" J1 ]! W2 T8 L$ F& l9 G) h
  10.      }
    + [" k- e& G9 r1 ^+ G8 ]0 |
  11. }
复制代码
+ b/ M! o& E. K
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。

4 @+ |/ d9 K! m$ j" D
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。
. P! \' _0 G5 J" u  m0 @
4.2.jpg
8 O$ c- ]! M+ Z2 }7 V
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

( s2 }- W. f. V  W0 I0 P# A  w+ W8 a
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。

% K$ d8 d# E6 X' D
4.3.jpg

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

- w/ S  f4 v% l6 f2 o
后来当它打开施密特触发器后,URAT-RX接收也就正常了。
2 V. \) i8 p6 V
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。
& h4 a3 t4 E  Y( d! l' p
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。
8 Y; \  k/ L- C: V
文章出处: 茶话MCU
# G+ }* S" R, v. V" y

0 _4 z1 J+ T5 @! V- g% Y
收藏 评论0 发布时间:2021-2-25 14:48

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版