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

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

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

, E. f7 M* [( w0 K+ O. B3 `# J
4.1.jpg

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

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

2 t. I% z2 a1 R& N3 W9 E( z
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.
# i* y1 {5 `1 X& K( C% R
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。
! k! D- b. }0 Y* y. P7 d* h! [# f
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:
" d/ I6 W( |! L! M; t* ~9 f5 q
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。
TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。
但只要把  TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。

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

) _* u! \% U( @4 h* M- Z
  1. int main( void )+ j0 \( l5 y6 H) z
  2. {& ~* d0 `+ B. C- N9 z9 j
  3.   CLK_DeInit(); //寄存器复位) M& |& `% n/ _; J$ n% O
  4.   CLK_HSICmd(ENABLE); //内部高速时钟使能 9 q* D6 P  @; x' j# F5 X
  5.   CLK_HSIPrescalerConfig( ); //分频+ N( z0 U! d2 ~$ C3 Q
  6.   GPIO_initialzation();
    & N3 k" {" Y- P- @" @' g
  7.   uart_initialzation();! t) A! I3 h( A3 Q
  8.   PWM1_initialzation();5 A. {+ T$ e) g/ T) z  }; J
  9.   PWM2_initialzation();
    9 h: g; l2 q$ p  h
  10.   TIM4_initialzation();  //TIM4初始化5 p. M  L! O& r3 }; _- f
  11.   enableInterrupts();//* 开启总中断 */ + D6 D: h3 N9 o9 k  N' E, P

  12. ) N5 Y- o( ^9 _. s  i4 ^
  13.   Ts_cnt = 1000;
    0 K4 G1 N3 ]* u% S" c/ p
  14.   Ls_cnt = 500;
    , [) Z7 n& ~) {+ O. m
  15. ( r! Y6 p7 w) n' L. W
  16.   while(1)
    ' |4 s4 r* K; L$ R
  17.   {
      P7 Y' C) Q& k0 H* ~3 |% d
  18.       PLED_flash(499); //LED 闪烁+ A* V/ n0 T7 X( }
  19.       relay_control(); //继电器控制1 U0 X& }  w7 o% d- {* |5 ?9 E
  20.       CCT_calculate();//获取相关AD值: v  W; G" Y% B+ G2 q
  21.       send_information();//输出提示信息. s" o* E( B4 A( s% Y
  22.       if(Flag_rec)
    - h3 }1 V' q. J; \
  23.       {- D& E: S) E. P* Z8 a  Z
  24.       。。。。。。【略】1 O1 Q9 M, C5 ?/ X$ p- O' R+ Q
  25.       }   
    * \8 J. u" Y6 p
  26.   }
    , n$ o+ E' S2 j" d" ~5 y) ]
  27. }
复制代码
5 [. `6 W# u  ?! h: V% U
现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。
+ E' K4 i  K; Z( B3 D9 k1 R
TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。
2 s8 D& C3 `: c5 Z% ^
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。
6 x. C  D" X" D  z# O- j1 }9 R; q
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。
- G% d6 B: K4 ~/ i0 Q
  1. INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
    4 f5 D9 I6 x6 N, R) v
  2. {
    & s" @; S. p9 @
  3.   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
    3 A3 M; s8 W0 Z( M+ x4 z7 I

  4. 4 ^8 A, j$ T: g* G
  5.   ms_cnt++;//LED FLASH
    5 Z3 S3 U# Z) ^  a3 Q: A' F
  6.   Ts_cnt++; //AD sample
    , L4 v' Y- I* Q4 ]5 E+ F
  7.   Ls_cnt++; //relay control
    # q; {: m3 q# L# h% t- |
  8.   uart_cnt++;//send information
    ( Y0 D, v+ m  r( A; h$ a
  9.   a9 T( E# e6 R% F3 M3 u2 g2 a1 W0 g
  10.   PWM2_duty_setting(Ts_cnt);" C$ a! R7 n3 H! V6 R+ w/ T
  11.   pwm1_correct_cnt++;$ ^- l  G3 Z/ N2 i8 z
  12.   if(pwm1_correct_cnt > 100)
    2 Q$ s5 S& G& v! c0 m
  13.   {
    % o6 J# ^+ W' K$ T6 u8 x
  14.     pwm1_correct_cnt = 0;
    ( ^! T2 _( v, ^, [; I
  15.     if(pwm1_cnt > CCT_target); z4 I* ?+ m4 o; Z, e! q5 q3 h
  16.       pwm1_cnt--;
    3 v3 C$ u% @6 f
  17.     else9 I  `% ~/ f" z. }  Q
  18.       pwm1_cnt++;
    . i% S; H! n+ l% w
  19.     PWM1_duty_setting(pwm1_cnt);, {) e' t) U7 k; g
  20.   }  S# n1 E7 n: Y4 V
  21. }* |9 d1 D2 O: j* q

  22. 9 w: D5 y6 \1 Y$ i1 c9 K$ |
  23. INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
    9 s0 ^4 O" }/ d3 K4 y
  24. {
    4 Y3 j7 s- ]7 o% e" c" u
  25.   static uint8_t index = 0;
    # u; I0 ~4 C/ O& M3 i/ m9 B+ I
  26.   UART1_ClearITPendingBit(UART1_IT_RXNE);+ G9 t3 p0 T) E7 \2 w7 r1 c7 o
  27.   recived_data[index] = UART1_ReceiveData8(); //读数据
    4 ~' e, n' n, Y: m( p  g
  28.   if(recived_data[0] == 0x41), h) B7 F- y) ~6 v1 z. E, f
  29.   {
    4 J; f% L+ q- D/ ?4 v
  30.     index++;3 x9 y% n) \3 _" K
  31.     if((index > 7)&&(recived_data[7] == 0x0d))
    ' `8 T; ^1 l; G. H
  32.     {0 S: y% ^! C5 i9 C. B% u
  33.       index = 0;
    / ^  f+ w8 [" \5 r
  34.       Flag_rec = 1;
    2 v4 c4 O# i: O- A: {
  35.     }
    " D3 Q' V/ C- p8 S. i6 ~( g: W
  36.   }
    * K( v- A: ]# ?" H
  37.   else
    ) B9 G" v9 `8 G0 ?0 }
  38.   {
    , q5 L4 Z) D- J& i" i' q. D
  39.     index = 0;
    # e' C  ~, l5 L; y$ T% ~  _
  40.     recived_data[0] = 0;% Y& A! T/ F3 U+ c4 r
  41.   }! r. u2 B' A" r& @; k
  42. }
复制代码

4 H  }& z3 z1 T8 W) Y0 L+ {1 u! R
从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。
  1. ms_cnt++;//LED FLASH. u# w( _' `; d1 M7 _9 Y
  2.   Ts_cnt++; //AD sample
    * F/ I* G) M- s
  3.   Ls_cnt++; //relay control
    1 f: c5 g) ~6 X: P0 h) w
  4.   uart_cnt++;//send information
    8 U3 w  z% u, @  W: L
复制代码

+ S) G+ {8 |/ f4 H( x* L
问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。

8 j$ A5 |& [2 y" M; w  X2 V
  1. PLED_flash(499); //LED闪烁
    # l0 `% g) d* `, F* c
  2. relay_control(); //继电器控制/ O- _- l* L) r
  3. CCT_calculate();//做AD转换
    : ]* E" ?; }3 u5 S- H
  4. send_information();//输出提示信息
复制代码

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

7 ~+ v* a: ~/ `# g2 {8 y
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。

6 l  Y, }# U# U3 j- {
  1. voidCCT_calculate(void)
    * ]2 J# q0 Q& o( p6 E
  2. {
    " [- i& K( |% F( {+ x0 p
  3.    if(Ts_cnt> 1000), c' J0 x" K6 k- {5 Q0 M
  4.    {
    2 O5 }; ]4 O3 Y; |6 Z
  5.      Ts_cnt = 0;& ^6 Y* p+ x: S9 z; q8 _4 K1 R0 p! i
  6.      T_ad = Get_ADCCH_Value(Ts_channel);% U  P, n5 q6 ~+ F! h3 M' L
  7.      T_degree = cal_temp(T_ad)-11;, k& y3 M2 `2 R
  8.     6 ^5 R' D5 B0 _0 j( M/ c) q
  9.      。。。。。。【略】
    , `6 o* o; ^; X3 X
  10.      }% O- s9 h1 q% |+ ^
  11. }
复制代码

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

2 ?" o8 z' H; r' ?2 ~3 W
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。
) n9 j4 G' l8 ~7 d& ~
4.2.jpg

  F8 g! E( c* ]& S9 `  s0 Y% L
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

) d" G* g: F- u3 W4 D5 T# m* d& [
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。
: V, `, g1 B* T  V6 n$ q
4.3.jpg

$ D; X" m# O: h3 \8 d+ Z; N: h2 ]
结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。

/ }1 Z! k* h* b# n+ H  @% Z3 _' V4 q7 \
后来当它打开施密特触发器后,URAT-RX接收也就正常了。
0 J+ D( h+ ?( w4 l" w
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。
4 E# C  L. G( |  c
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。
6 s: A3 F* ^, K2 \: U% J6 W% z
文章出处: 茶话MCU

/ N6 U4 n. N7 M+ l+ Q( ~* W

& ^& i# ^2 N; z! B0 L5 _1 w
收藏 评论0 发布时间:2021-2-25 14:48

举报

0个回答

所属标签

相似分享

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