|
一个STM8S ADC脚与其它功能复用时的话题
$ g) I5 H& A% ^8 Y! G$ X
& h9 z7 ]0 e3 \, ^6 k( E; H# U 一年多前写过一篇《STM8S芯片GPIO脚复用AD功能后无法回到GPIO状态问题》的小文,介绍STM8S芯片的ADC应用时相关施密特触发器未适时开关而导致的问题。 , B$ u( M, a9 C; o, J$ P! Q
大致内容就是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功能禁用掉,再配置切换为带下降沿触发的外部中断触发脚,让其作为芯片休眠唤醒脚。
$ l. b2 m: ]7 `% X3 t4 m V, B% ~
奇怪的是,那样设置后根本没法唤醒。即使不做休眠,做好切换配置后,直接查看该脚的IDR位的电平,不管外部输入如何,发现对应IDR位始终提示为0. ( [/ x1 b- z! a
后来找到原因是跟那个施密特触发器的配置有关。可能有人觉得该问题是钻牛角尖,其实,也不尽然。毕竟应用需求是五花八门的,遇到的问题往往也是五彩缤纷,问题不论大小折磨起人来也是不分男女老少的。
2 J# U5 `. o }
这里再次分享个类似话题 ,希望能让见到本文的人有所启示。工程师反馈基本情况如下: 9 C8 _: x# J: _* R( V4 ]
使用STM8S芯片开发。因为TIM1/2都用做PWM了,所以用TIM4来做基本定时。 TIM4正常中断,UART1串口发送正常,就是串口接收中断进不去。 但只要把 TIM4_initialzation();屏蔽掉,串口马上正常中断接收,一旦打开TIM4,串口就接收不了,其它功能都正常。
1 V" S% Z+ ~8 y. r- E, H# r; u
上面是该工程师对症状的基本描述和初步判断。【当然,调试遇到麻烦时候的判断难免有偏差,偏差大小因人因景不同,有时甚至完全误判。】 下面是他的主循环代码【为了排版和阅读,做了些删减】
9 {! }/ Z. n0 C& Y8 W" @( t
- int main( void )
' Z9 ` p( J/ @9 [8 Y - {
W/ Y* s E- M' o - CLK_DeInit(); //寄存器复位5 t& i& h1 p: [' @8 `0 |
- CLK_HSICmd(ENABLE); //内部高速时钟使能
, Z M' k4 {9 H% i - CLK_HSIPrescalerConfig( ); //分频8 r) t& v( L9 v
- GPIO_initialzation();
! a) k8 Y* t3 ^- W) G - uart_initialzation();
" S! M* y' O& M - PWM1_initialzation();! Z+ ^1 E8 T, m1 @6 y
- PWM2_initialzation();! z2 M [( n# m4 L3 _0 q
- TIM4_initialzation(); //TIM4初始化# ~5 m( w: A8 l! ~
- enableInterrupts();//* 开启总中断 */
) Z: s8 q7 Q- m0 E2 L0 k -
' M4 y! A0 o* ] |8 o5 S) V - Ts_cnt = 1000;+ y$ [$ g( E! r! a2 r9 j
- Ls_cnt = 500;8 Q9 _4 A( q% X' @7 p* B, w: x
- 1 [/ w6 d; |" ~+ C4 u }1 t' x# {" w
- while(1)* \+ p8 d( D% u$ B
- {# X& q( [+ @/ o) i6 d/ W9 h4 k
- PLED_flash(499); //LED 闪烁
& [1 L7 R; Y- i6 X - relay_control(); //继电器控制
9 ?* V+ C; i! I) d: |: z7 z - CCT_calculate();//获取相关AD值; x' u# Q+ S2 Y: k+ L# o/ K5 N; Y0 o
- send_information();//输出提示信息& ?! k, ~( \) @5 B2 Q
- if(Flag_rec)
% u1 Y U8 N: {, K, w - {: ~. F* E! {' r- G- @( H- |' c! u
- 。。。。。。【略】
j* [1 h" m: @ - } 0 I& C8 j5 o! R! U2 C/ s
- }
) p1 c" e1 N! u - }
复制代码
4 t# x3 z+ R, W2 {: r# I. s3 N现在的情况是当注释掉上面的 TIM4_initialzation();语句后,UART-RX接收中断就正常。
. a4 R, |& K6 W' v" i3 d
TIM4只是做基本时钟,不涉及外面其它硬件,最大可能是二者中断优先级有冲突导致UART-RX的正常接收。但当把UART-RX中断优先级调高于TIM4的更新中断时问题并无好转。 % H" k0 N, i+ e2 x5 Y
但事实又的确显示出TIM4的中断跟UART-RX接收有关系。 7 j8 |; ]/ i. Q A! y, E& E
TIM4、UART1初始化代码只是些各种相关基本配置,不跟别的外设有关联。不妨看看TIM4、UART1中断服务程序里能否找到些蛛丝马迹。 # Y( M6 t# L- q5 b8 K# ~
- INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
4 d- @# R0 w$ J3 |! {% x: }2 I0 S - {
7 c" C& D1 Q! v$ Q& j - TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
! ~' G2 I- a) L% a6 s3 e, g! K+ F - 2 t0 Q6 v0 B1 L
- ms_cnt++;//LED FLASH
+ {" a+ P: V+ q1 o - Ts_cnt++; //AD sample# @, I& G/ ?" F/ C3 a- \
- Ls_cnt++; //relay control
: x; N* w% Y" F' j u* k - uart_cnt++;//send information
' h8 q3 D0 m1 q0 E: n2 n - & {1 d& o- `5 o6 Y1 K' f
- PWM2_duty_setting(Ts_cnt);
. T* p1 N5 p n* M3 C - pwm1_correct_cnt++;
( ^. U, c6 V+ @2 I4 i - if(pwm1_correct_cnt > 100)
9 o8 u/ A8 |/ S$ z - {4 q4 |7 K, y2 o3 h+ f
- pwm1_correct_cnt = 0;# }$ w" g- }; o. j
- if(pwm1_cnt > CCT_target)
! o3 v* P% x: C; j1 b/ Z - pwm1_cnt--;
. z& H" L0 R' }" ~5 z% U - else! g2 ]) Q; `9 v6 n& L/ @
- pwm1_cnt++;
7 m, E" x/ ^3 p1 b6 V1 Y, { - PWM1_duty_setting(pwm1_cnt);: U4 V9 }9 n- _1 P' I
- }' \6 \9 e1 ?+ B- f
- }
% i# K6 c- w: g4 N -
) ]2 S/ a# K3 }& d& D7 | - INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
4 G2 g4 A+ }7 ]3 { - {
) e# S7 u1 D, q% T$ n - static uint8_t index = 0;
7 N8 e% v* x5 U' T, j - UART1_ClearITPendingBit(UART1_IT_RXNE);! b7 M, F8 b' ^ s- K
- recived_data[index] = UART1_ReceiveData8(); //读数据
" @8 I ]/ W+ ?6 [5 W2 o% @ - if(recived_data[0] == 0x41)% g. Y5 K6 s o
- {* w2 y, Q+ j& o7 K
- index++;0 K, H2 Z. H% G7 w
- if((index > 7)&&(recived_data[7] == 0x0d))9 E+ A( S" g7 X/ p }+ |4 U
- {
" u1 L- G: {, G, d0 f9 {. S - index = 0;6 k% V% h% b' S u+ ] ^) G" g
- Flag_rec = 1;" a f( V! S7 a% J' \
- }
4 h. v& t! l3 E. L$ D5 G2 q4 w - }5 r" l9 ?" V% R* L5 E+ o" ^
- else
( F+ k. q2 }, r" v0 w! { - {( H# E# o: _+ _2 ?7 s
- index = 0;
4 _2 _' K3 J, z, ~9 x J0 Y - recived_data[0] = 0;
- O' R0 P" I; U! k" A! ? - }) R" `7 _: i$ E: D! z x
- }
复制代码
! Y# {3 K' ~+ B从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。 - ms_cnt++;//LED FLASH2 q' Y' M4 g% L; D# \8 z' a- ?& p! l/ Y
- Ts_cnt++; //AD sample* i: X5 m3 w: z: B) V7 ?- K1 W) S/ R
- Ls_cnt++; //relay control
8 X" z1 K N t2 G& e S - uart_cnt++;//send information
5 N! s: v2 v V/ g" Q; p
复制代码
, ]+ y q+ V3 Q: T6 ? 问题到这里,继续往下查就需要耐心了。客户代码不复杂,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。 3 H0 T$ i4 V: f1 t7 l
- PLED_flash(499); //LED闪烁
& |+ N2 r3 V' [# D- t+ \+ } - relay_control(); //继电器控制1 C4 N2 @: x2 `0 a8 D2 S5 ]7 n5 y/ W
- CCT_calculate();//做AD转换8 @' q2 I: H7 e& H5 R
- send_information();//输出提示信息
复制代码
! m4 u W/ z) O' T! o后来发现TIM4保持工作的同时屏蔽CCT_calculate();,UART-RX能正常接收。看来TIM4并非是影响UART接收的元凶。不过CCT_calculate()的运行还是跟TIM4中断有关,有个变量TS_CNT是在TIM4中断里进行累加的。
7 {& K% p, \# a
看看下面CCT_calculate()的代码,里面有个条件判断,即if(Ts_cnt > 1000)的判断。
: v9 y. }; v# d7 d. a
- voidCCT_calculate(void); ~/ J) v1 E7 w/ m1 N& F6 A
- {
' _! A# B+ P5 e2 p4 L E - if(Ts_cnt> 1000)
/ @. D2 A. \- E% W: ? W8 u - {
1 N- i v2 R1 R8 P5 c3 k. \ - Ts_cnt = 0;
& y( b0 L4 @; G2 Z! x( J; t - T_ad = Get_ADCCH_Value(Ts_channel);
0 z* T I& V) ?9 \3 l - T_degree = cal_temp(T_ad)-11;
3 J' x9 F' q# \7 y C - ( m# C4 X! c) Y2 Z
- 。。。。。。【略】# L( Q2 o. D: C" K, p
- }
* Q( ~' f7 E, S) A1 @+ r - }
复制代码 8 Y8 l( ]( D, O% K" I$ R
如果TIM4被屏蔽不工作,TS_CNT就不会得到累加而大于1000然后往下执行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后执行AD转换并获取相关AD值。 ( g, q/ P! ~5 f7 o6 F4 z6 B
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用配置。而且该ADC通道脚跟UART-RX脚又是复用的,麻烦就此产生了。
9 V9 H k( l# z8 f# R0 o & O5 A( L. ?* t5 @! H' W
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。
8 Y9 h4 a# D7 K, u- p& V
如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。
) x2 [$ G- C- s' {6 F
% z1 O, P1 H% j6 k( d$ g, }3 f结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。
. h, g q! x: o0 H/ e; o后来当它打开施密特触发器后,URAT-RX接收也就正常了。
* e Q' ~7 f5 o* m' I$ W
显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。
3 \# V' e. E! `) t) t! W7 r
谈到这里,就此打住,目的想让大家通过类似案例分享而有所收获。
6 Q" l5 `3 Z" U# s/ |
文章出处: 茶话MCU
) k+ t# u% ~8 g3 b/ |# y " S; |/ Z; `7 {: `+ E
|