一个STM8S ADC脚与其它功能复用时的话题
, E. f7 M* [( w0 K+ O. B3 `# J
* 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
- int main( void )+ j0 \( l5 y6 H) z
- {& ~* d0 `+ B. C- N9 z9 j
- CLK_DeInit(); //寄存器复位) M& |& `% n/ _; J$ n% O
- CLK_HSICmd(ENABLE); //内部高速时钟使能 9 q* D6 P @; x' j# F5 X
- CLK_HSIPrescalerConfig( ); //分频+ N( z0 U! d2 ~$ C3 Q
- GPIO_initialzation();
& N3 k" {" Y- P- @" @' g - uart_initialzation();! t) A! I3 h( A3 Q
- PWM1_initialzation();5 A. {+ T$ e) g/ T) z }; J
- PWM2_initialzation();
9 h: g; l2 q$ p h - TIM4_initialzation(); //TIM4初始化5 p. M L! O& r3 }; _- f
- enableInterrupts();//* 开启总中断 */ + D6 D: h3 N9 o9 k N' E, P
-
) N5 Y- o( ^9 _. s i4 ^ - Ts_cnt = 1000;
0 K4 G1 N3 ]* u% S" c/ p - Ls_cnt = 500;
, [) Z7 n& ~) {+ O. m - ( r! Y6 p7 w) n' L. W
- while(1)
' |4 s4 r* K; L$ R - {
P7 Y' C) Q& k0 H* ~3 |% d - PLED_flash(499); //LED 闪烁+ A* V/ n0 T7 X( }
- relay_control(); //继电器控制1 U0 X& } w7 o% d- {* |5 ?9 E
- CCT_calculate();//获取相关AD值: v W; G" Y% B+ G2 q
- send_information();//输出提示信息. s" o* E( B4 A( s% Y
- if(Flag_rec)
- h3 }1 V' q. J; \ - {- D& E: S) E. P* Z8 a Z
- 。。。。。。【略】1 O1 Q9 M, C5 ?/ X$ p- O' R+ Q
- }
* \8 J. u" Y6 p - }
, n$ o+ E' S2 j" d" ~5 y) ] - }
复制代码 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
- INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
4 f5 D9 I6 x6 N, R) v - {
& s" @; S. p9 @ - TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
3 A3 M; s8 W0 Z( M+ x4 z7 I -
4 ^8 A, j$ T: g* G - ms_cnt++;//LED FLASH
5 Z3 S3 U# Z) ^ a3 Q: A' F - Ts_cnt++; //AD sample
, L4 v' Y- I* Q4 ]5 E+ F - Ls_cnt++; //relay control
# q; {: m3 q# L# h% t- | - uart_cnt++;//send information
( Y0 D, v+ m r( A; h$ a - a9 T( E# e6 R% F3 M3 u2 g2 a1 W0 g
- PWM2_duty_setting(Ts_cnt);" C$ a! R7 n3 H! V6 R+ w/ T
- pwm1_correct_cnt++;$ ^- l G3 Z/ N2 i8 z
- if(pwm1_correct_cnt > 100)
2 Q$ s5 S& G& v! c0 m - {
% o6 J# ^+ W' K$ T6 u8 x - pwm1_correct_cnt = 0;
( ^! T2 _( v, ^, [; I - if(pwm1_cnt > CCT_target); z4 I* ?+ m4 o; Z, e! q5 q3 h
- pwm1_cnt--;
3 v3 C$ u% @6 f - else9 I `% ~/ f" z. } Q
- pwm1_cnt++;
. i% S; H! n+ l% w - PWM1_duty_setting(pwm1_cnt);, {) e' t) U7 k; g
- } S# n1 E7 n: Y4 V
- }* |9 d1 D2 O: j* q
-
9 w: D5 y6 \1 Y$ i1 c9 K$ | - INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
9 s0 ^4 O" }/ d3 K4 y - {
4 Y3 j7 s- ]7 o% e" c" u - static uint8_t index = 0;
# u; I0 ~4 C/ O& M3 i/ m9 B+ I - UART1_ClearITPendingBit(UART1_IT_RXNE);+ G9 t3 p0 T) E7 \2 w7 r1 c7 o
- recived_data[index] = UART1_ReceiveData8(); //读数据
4 ~' e, n' n, Y: m( p g - if(recived_data[0] == 0x41), h) B7 F- y) ~6 v1 z. E, f
- {
4 J; f% L+ q- D/ ?4 v - index++;3 x9 y% n) \3 _" K
- if((index > 7)&&(recived_data[7] == 0x0d))
' `8 T; ^1 l; G. H - {0 S: y% ^! C5 i9 C. B% u
- index = 0;
/ ^ f+ w8 [" \5 r - Flag_rec = 1;
2 v4 c4 O# i: O- A: { - }
" D3 Q' V/ C- p8 S. i6 ~( g: W - }
* K( v- A: ]# ?" H - else
) B9 G" v9 `8 G0 ?0 } - {
, q5 L4 Z) D- J& i" i' q. D - index = 0;
# e' C ~, l5 L; y$ T% ~ _ - recived_data[0] = 0;% Y& A! T/ F3 U+ c4 r
- }! r. u2 B' A" r& @; k
- }
复制代码
4 H }& z3 z1 T8 W) Y0 L+ {1 u! R从TIM4的中断服务程序里出现了好几个全局变量,看看这些全局变量哪些函数会用到。因为TIM4的主要功能就是计数定时,下面几个计时变量肯定是给别人用的。 - ms_cnt++;//LED FLASH. u# w( _' `; d1 M7 _9 Y
- Ts_cnt++; //AD sample
* F/ I* G) M- s - Ls_cnt++; //relay control
1 f: c5 g) ~6 X: P0 h) w - 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
- PLED_flash(499); //LED闪烁
# l0 `% g) d* `, F* c - relay_control(); //继电器控制/ O- _- l* L) r
- CCT_calculate();//做AD转换
: ]* E" ?; }3 u5 S- H - 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- {
- voidCCT_calculate(void)
* ]2 J# q0 Q& o( p6 E - {
" [- i& K( |% F( {+ x0 p - if(Ts_cnt> 1000), c' J0 x" K6 k- {5 Q0 M
- {
2 O5 }; ]4 O3 Y; |6 Z - Ts_cnt = 0;& ^6 Y* p+ x: S9 z; q8 _4 K1 R0 p! i
- T_ad = Get_ADCCH_Value(Ts_channel);% U P, n5 q6 ~+ F! h3 M' L
- T_degree = cal_temp(T_ad)-11;, k& y3 M2 `2 R
- 6 ^5 R' D5 B0 _0 j( M/ c) q
- 。。。。。。【略】
, `6 o* o; ^; X3 X - }% O- s9 h1 q% |+ ^
- }
复制代码
. 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& ~
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
$ 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 |