|
一个STM8S ADC脚与其它功能复用时的话题 % s3 \8 p* Z+ w! T- r
4 v3 I5 x4 Q* K$ u7 A 一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。 & j2 T/ v; ~" ^1 G9 O
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。 6 y4 n& M1 T- c O
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0.
' @. q$ o0 ?+ [* I
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。 # ?+ L" w& V' D# `
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下:
% A: G* s$ T3 u8 z
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。 TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。 但只要把 TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。 ; T+ Y" R! { [& e1 D
上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】 下面是他的主循环代码【为了排版和阅读,做了些删减】 0 T5 t/ `; Q8 ^& ~; L4 a
- int main( void )
% Z$ _* s9 u4 B* R6 n$ O8 K3 B - {
9 y' d N8 Y7 a, J2 P - CLK_DeInit(); //寄存器复位" J& M: v2 {7 j8 P a8 w0 P
- CLK_HSICmd(ENABLE); //内部高速时钟使能 6 l! b( p0 _/ d0 k
- CLK_HSIPrescalerConfig( ); //分频
1 {5 A) Z9 K2 w - GPIO_initialzation();
4 H9 v& H8 p3 M8 U - uart_initialzation();
% A2 z1 z% Q! k - PWM1_initialzation();
- C; ?+ t% L5 p$ i - PWM2_initialzation();6 I4 v+ c& G- ]* m
- TIM4_initialzation(); //TIM4初始化) f5 {/ L7 u/ p9 O+ k1 d5 l' n
- enableInterrupts();//* 开启总中断 */
* d$ P6 y& H" L1 d3 s( @4 z - : m, w6 i( u( |, x6 O
- Ts_cnt = 1000;
6 o9 @# Y% n3 A) F- U L2 c. Q - Ls_cnt = 500;
* I3 c$ X% Q; e - 2 K3 e* x5 F# |
- while(1)' E; A, z! |1 X g* o8 s9 f
- {# t3 ?- U# q8 l$ Q6 A! x
- PLED_flash(499); //LED 闪烁
+ B9 o7 g* K) l6 ?4 F( S, [4 w - relay_control(); //继电器控制
8 M& o, U: U+ {. L3 G. N - CCT_calculate();//获取相关AD值
0 p% D. U _: u - send_information();//输出提示信息
s+ m* a8 C2 F, l - if(Flag_rec)
4 F0 j% S* B) s$ U, X - {
* ~4 P) e. x( L; Z6 | - 。。。。。。【略】1 }7 m: G/ X( _! f. P
- }
. N( g, M( W# A. Q& [+ R% P - }4 L1 Q1 T# {4 A: Q
- }
复制代码
# B* R* A* I# C7 v现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。 ) O% v, e+ A( l
TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。 $ n/ G) v" m( w+ Y( N7 R! _
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。
9 e6 }2 G2 _7 M( ?- P: f
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。
: L/ D; L3 c4 k. o8 N7 w
- INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)0 N- ^) _$ `$ p% F. n
- {
! k( @) w$ p' v - TIM4_ClearITPendingBit(TIM4_IT_UPDATE); a% g1 v3 D/ x5 D: ^
-
z7 L) W! v [5 t% ~0 u! f - ms_cnt++;//LED FLASH
; I1 O' E. ^( I: V8 W - Ts_cnt++; //AD sample0 p1 m0 a( z0 [: f7 C
- Ls_cnt++; //relay control
0 k8 h+ X8 _1 m( V! d - uart_cnt++;//send information0 K/ [( Z3 m" W3 Z
-
* |/ _* B7 U8 ^5 ?' S# A - PWM2_duty_setting(Ts_cnt);: D9 q) C9 A F* I
- pwm1_correct_cnt++;
" x) L: h/ ~3 k) T8 ~2 Z3 L - if(pwm1_correct_cnt > 100)
1 ?7 r. c1 _8 q; \0 {! K - {
$ w3 n3 l, a6 I# W* U2 E - pwm1_correct_cnt = 0;
8 `) a2 ~8 ?. a# @( A' h% g - if(pwm1_cnt > CCT_target)6 N. _9 \+ f" _" c0 L: h1 Y
- pwm1_cnt--;
* J0 k8 Q* l( U ? - else q/ s0 J( n" Z
- pwm1_cnt++; 2 G8 \5 g3 w2 H: S* Z! H5 z
- PWM1_duty_setting(pwm1_cnt);
/ Y* w J- l5 l% |$ N - }
3 w- G2 G9 V" h' v4 X8 i - }
" K8 `" @ }4 q7 {' D% G* P - 4 i4 W; M% G( V9 e
- INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)7 S! e$ `7 |' h' P
- {# Y7 M' A- x* |0 u3 j* B) F6 h: ~0 l
- static uint8_t index = 0;1 r- E- V" F6 X( R
- UART1_ClearITPendingBit(UART1_IT_RXNE);5 D+ q) J( C" J3 H( I
- recived_data[index] = UART1_ReceiveData8(); //读数据
; B1 p6 b) R) J8 g* t& i6 K! Q - if(recived_data[0] == 0x41). o/ x- c( }; b9 t$ z
- {
7 P: I n0 Y# ~; N - index++;
, A" |: K5 _( L( g+ E+ y/ _9 v - if((index > 7)&&(recived_data[7] == 0x0d))
% ?0 R, O3 V# i" P& i& a( { - {
/ h" Q% b9 Y( e6 ^4 ]* V - index = 0;
/ R8 b8 ~- Z+ R( k% j - Flag_rec = 1;" Z1 c& t! O/ m0 i( r3 w2 V# v+ E
- }- G' Q7 q4 W$ H* X
- }
$ Z( }( Z7 T4 K1 w/ _+ H - else
5 z4 v1 Q; D: p - {# ]3 P( y( b/ F
- index = 0;
; R$ b$ p' W: ?$ C- p j - recived_data[0] = 0;
. B. x! l; u/ A$ E n% Y, Q - }
n: w8 D5 a/ |$ Z - }
复制代码
) f4 E7 O9 O- G6 L从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。 - ms_cnt++;//LED FLASH( N* [# Y `0 Y3 c$ J4 K9 e2 W. d
- Ts_cnt++; //AD sample* V! P1 ^$ h3 o( A6 v
- Ls_cnt++; //relay control
* B8 X6 l7 L+ g% s7 m3 r - uart_cnt++;//send information
f5 r" w9 O! g; c1 `
复制代码
; i, @9 [$ s2 h0 C: ]; c5 v 问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。 % ]8 h! \# ^4 x' D; }' M7 z
- PLED_flash(499); //LED闪烁
- N# w9 ^- v* ^/ W - relay_control(); //继电器控制5 l$ L. S, Y. B/ [1 H& v4 B
- CCT_calculate();//做AD转换
' H; t$ X: ~! X. c2 N( t - send_information();//输出提示信息
复制代码
5 ^) i2 v6 [. P# \4 }后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。 9 b, W# q4 r, Z6 w; P
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。
% N5 a, J! Q' D7 q6 N
- voidCCT_calculate(void)
( {2 ^/ f, N1 x0 k) ` - {
6 \6 S% @9 o) p; w% C7 b4 o+ ]7 T x* p - if(Ts_cnt> 1000)
1 K9 Z8 S8 t( s2 a& D9 N( c' O - {2 C* v0 U7 a; r# B
- Ts_cnt = 0;- k* Q# D6 \8 Q" _6 ]" L5 {
- T_ad = Get_ADCCH_Value(Ts_channel);: q1 c+ h& }. C$ p4 E5 s( r
- T_degree = cal_temp(T_ad)-11;
' F2 j7 d; Q' R2 C3 @ d' D - 4 e# n, f1 O* c
- 。。。。。。【略】: x0 w& s: W+ k+ V& r
- }$ {* x U$ `% ]3 U
- }
复制代码 $ v5 O0 Q6 }( Y
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。 * Z/ i. m0 l# Y3 k
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。 . f7 ]* p9 N* U* y
/ U O& B0 X7 ?1 {6 B6 W: X在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。 9 d) D2 J, c. \
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。 : g0 c: d9 H. `% J' H# w
/ q' |- G* u( _
结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。 $ I: ~) ~2 j v8 V4 ]
后来当它打开施密特触发器后,URAT-RX接收也就正常了。 6 g; s" j) Q& G! R3 b( T3 x
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。 / ?: {7 o3 w! T- ]4 x4 G
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。 ( J( N5 z3 N7 k1 o
文章出处: 茶话MCU
2 A5 U' j: p* D8 x3 w5 [4 I* G
# ]( F* d6 z# t* i* p |