一个STM8S ADC脚与其它功能复用时的话题 % x! |/ l, _+ A' V7 Y0 Z$ e
- _* 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
- int main( void ) a2 a8 P* Y5 P
- {
1 f3 W7 [% q1 |: T4 c5 @ - CLK_DeInit(); //寄存器复位
# [/ q6 N' Z1 X/ x5 i8 B* Q - CLK_HSICmd(ENABLE); //内部高速时钟使能
8 R5 _1 ?# r/ d - CLK_HSIPrescalerConfig( ); //分频
5 I1 R8 ]4 G* _1 y - GPIO_initialzation();
6 p- l% i* N$ n+ G3 s5 g - uart_initialzation();+ s) k4 X$ `' S6 b/ c
- PWM1_initialzation();5 }5 J: ~8 h2 w* }7 B; E5 U' o) G
- PWM2_initialzation();
/ W9 m+ M# w1 k7 K) N - TIM4_initialzation(); //TIM4初始化/ H' q6 r8 c! b
- enableInterrupts();//* 开启总中断 */ ' H$ c' K' ]$ P) y+ D
-
B: G: v# u) ^: R" h - Ts_cnt = 1000;
/ l2 S- C. ~3 E' O$ i - Ls_cnt = 500;5 n3 J7 v. c1 m" I
-
: m4 v' e, e- r+ m1 v - while(1)2 @! y( q) V: v0 c& Z
- {3 ]7 ?8 c% {2 D; `2 t( Z) K
- PLED_flash(499); //LED 闪烁. t" \" k/ f; j8 l7 H
- relay_control(); //继电器控制) q( b3 W7 e' D3 |; I. I c
- CCT_calculate();//获取相关AD值
0 i8 [/ k2 T) P! w - send_information();//输出提示信息6 \: N1 Y9 K" J9 E5 N2 Q
- if(Flag_rec)! w" O# u$ L) e7 r( A
- {
, n6 J+ _* t" e. v* a, b - 。。。。。。【略】
" ^: I( P5 H- b: P" b$ o( f% e - } , p! v, A! a/ @ Q2 F$ q7 B% [/ l
- }
' p/ [% z7 Q4 f7 A - }
复制代码 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, }
- INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)% e$ k6 O% x$ w! H2 A9 ]/ n
- {
& c9 O# @& M2 b( X1 K- G/ b$ _ - TIM4_ClearITPendingBit(TIM4_IT_UPDATE);; x0 |. U, @) ~ [- x E4 X3 u
- 4 l, j7 x) k V' J% m5 H3 D( A
- ms_cnt++;//LED FLASH
( p+ i3 J9 F+ p ^6 ~* l6 Q2 F" i - Ts_cnt++; //AD sample! E' A1 y2 M, W7 U) O& |# U" f
- Ls_cnt++; //relay control
7 U' O. E" h* P0 y+ t8 [( t - uart_cnt++;//send information. [* i8 m" ]6 w+ R
- ! @. K+ Z8 w1 E$ m
- PWM2_duty_setting(Ts_cnt);
. v1 D9 U! I* C; C - pwm1_correct_cnt++;/ K9 q9 e0 Y( W( S3 L0 R/ \
- if(pwm1_correct_cnt > 100)
/ {; d% I: N$ v" g4 c3 G - {3 p+ P. s B( K- W: X4 b
- pwm1_correct_cnt = 0;
" [) _& i& o# Z; F - if(pwm1_cnt > CCT_target), Q' p& m, F% U% T
- pwm1_cnt--;7 e) p3 r0 O3 n
- else
$ ]* w, ]1 S; e( \' j - pwm1_cnt++;
+ i' h8 M; a, T" V9 { - PWM1_duty_setting(pwm1_cnt);) Z* E& i( A) i* U
- }
7 J" W: X6 H8 Y% X - }8 }0 { L- p: W6 E, v5 M/ @$ j
- 4 D( M, {0 R* ~# d! E+ f
- INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
6 v3 f; R3 L- h8 I( C2 U0 y - {% H. @. ^+ }( ^
- static uint8_t index = 0;
. q, ^0 S6 s) W3 q - UART1_ClearITPendingBit(UART1_IT_RXNE);
4 v, Z. k% S3 n/ ]1 ]& \/ j5 j - recived_data[index] = UART1_ReceiveData8(); //读数据4 S4 v, Q! {- ~. h$ o, y' @
- if(recived_data[0] == 0x41)5 b. ~8 E0 Z) Y- i8 }$ g% W: M5 l
- {
* \% c6 f( h5 u) I# M1 J0 j6 u - index++;1 m R% ^6 J9 N" z: g& c- p i% @% l& B g
- if((index > 7)&&(recived_data[7] == 0x0d))
) G7 ]3 t: M% ]# U1 r* O - {- _7 ^4 U: s" b7 T# K3 V
- index = 0;$ Y# u8 p! K4 b
- Flag_rec = 1;: V+ v, r2 [1 |1 {; q% o( g
- }
1 b, l# ~0 w& m0 Z F) O - }9 G8 a f: N- O' }
- else
7 g. v$ X- [) n - {; _7 Q) [8 L& Z
- index = 0;
9 Q, K4 B' I# e6 x - recived_data[0] = 0;8 z$ c7 W" l; x% c
- } J+ I. p t* o9 E2 X2 Z% D
- }
复制代码
2 f/ G5 L4 }2 G: y从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。 - ms_cnt++;//LED FLASH. e+ j0 @2 t; L; m
- Ts_cnt++; //AD sample
. b; X, H- d& y' N - Ls_cnt++; //relay control/ l# {/ }, B8 r U
- uart_cnt++;//send information$ J4 `$ D( t6 \" F V
复制代码
: ]% j8 i& j/ n+ M u* p 问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。 7 D7 e% g: s" [" K
- PLED_flash(499); //LED闪烁. S) L7 ^) N9 A, p4 N5 O. u
- relay_control(); //继电器控制% @* Q, l# L- a9 c
- CCT_calculate();//做AD转换3 X* C& e ]7 C- P# n
- 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
- voidCCT_calculate(void)
5 e# O7 T/ p! ]2 }8 i% p - {
( }: R+ Q- @# h* t6 H - if(Ts_cnt> 1000)" B* X3 d) q5 K$ U0 l j
- {0 L7 z& R0 s) s7 f3 L- B
- Ts_cnt = 0;2 T& _( ~( V9 z6 s- P
- T_ad = Get_ADCCH_Value(Ts_channel);
, R- a& w$ H1 f; \& s7 n, w$ r - T_degree = cal_temp(T_ad)-11;
" ^7 ?( b/ h' B, ]% w1 ^) [ - Q5 O( u5 B# k3 T# S, S
- 。。。。。。【略】5 ]# A" J1 ]! W2 T8 L$ F& l9 G) h
- }
+ [" k- e& G9 r1 ^+ G8 ]0 | - }
复制代码 + 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 @
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
" }/ 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 |