之前写过一篇关于STM8S芯片GPIO脚复用AD功用后无法回到GPIO状况的小文,介绍STM8S芯片的ADC运用时相关施密特触发器未当令开关而导致的问题。
大致内容便是某一GPIO口被复用为AD输入脚做相关AD检测。之后,把该脚AD功用禁用掉,再装备切换为带下降沿触发的外部中止触发脚,让其作为芯片休眠唤醒脚。
奇怪的是,那样设置后底子无法唤醒。即便不做休眠,做好切换装备后,直接检查该脚的IDR位的电平,不论外部输入怎么,发现对应IDR位一直提示为0.
后来找到原因是跟那个施密特触发器的装备有关。或许有人觉得该问题是钻牛角尖,其实,也不尽然。究竟运用需求是形形色色的,遇到的问题往往也是五光十色,问题不论巨细折磨起人来也是不分男女老少的。
这儿再次共享个相似论题 ,期望能让见到本文的人有所启示。工程师反应底子状况如下:
运用STM8S芯片开发。由于TIM1/2都用做PWM了,所以用TIM4来做底子守时。TIM4正常中止,UART1串口发送正常,便是串口接纳中止进不去。但只要把 TIM4_initialzation();屏蔽掉,串口立刻正常中止接纳,一旦翻开TIM4,串口就接纳不了,其它功用都正常。
上面是该工程师对症状的底子描绘和初步判别。【当然,调试遇到费事时分的判别不免有误差,误差巨细因人因景不同,有时乃至彻底误判。】
下面是他的主循环代码【为了排版和阅览,做了些删减】。
int main( void )
{
CLK_DeInit(); //寄存器复位
CLK_HSICmd(ENABLE); //内部高速时钟使能
CLK_HSIPrescalerConfig( ); //分频
GPIO_initialzation();
uart_initialzation();
PWM1_initialzation();
PWM2_initialzation();
TIM4_initialzation(); //TIM4初始化
enableInterrupts();//* 敞开总中止 */
Ts_cnt = 1000;
Ls_cnt = 500;
while(1)
{
PLED_flash(499); //LED 闪耀
relay_control(); //继电器操控
CCT_calculate();//获取相关AD值
send_information();//输出提示信息
if(Flag_rec)
{
。。。。。。【略】
}
}
}
现在的状况是当注释掉上面的 TIM4_initialzation();句子后,UART-RX接纳中止就正常。
TIM4仅仅做底子时钟,不触及外面其它硬件,最大或许是二者中止优先级有抵触导致UART-RX的正常接纳。但当把UART-RX中止优先级调高于TIM4的更新中止时问题并无好转。
但现实又确实显示出TIM4的中止跟UART-RX接纳有联系。
TIM4、UART1初始化代码仅仅些各种相关底子装备,不跟其他外设有相关。无妨看看TIM4、UART1中止服务程序里能否找到些蛛丝马迹。
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler,23)
{
TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
ms_cnt++;//LED FLASH
Ts_cnt++; //AD sample
Ls_cnt++; //relay control
uart_cnt++;//send information
PWM2_duty_setting(Ts_cnt);
pwm1_correct_cnt++;
if(pwm1_correct_cnt > 100)
{
pwm1_correct_cnt = 0;
if(pwm1_cnt > CCT_target)
pwm1_cnt–;
else
pwm1_cnt++;
PWM1_duty_setting(pwm1_cnt);
}
}
INTERRUPT_HANDLER(UART1_RX_IRQHandler,18)
{
static uint8_t index = 0;
UART1_ClearITPendingBit(UART1_IT_RXNE);
recived_data[index] = UART1_ReceiveData8(); //读数据
if(recived_data[0] == 0x41)
{
index++;
if((index > 7)&&(recived_data[7] == 0x0d))
{
index = 0;
Flag_rec = 1;
}
}
else
{
index = 0;
recived_data[0] = 0;
}
}
从TIM4的中止服务程序里呈现了好几个全局变量,看看这些全局变量哪些函数会用到。由于TIM4的主要功用便是计数守时,下面几个计时变量肯定是给他人用的。
ms_cnt++;//LED FLASH
Ts_cnt++; //AD sample
Ls_cnt++; //relay control
uart_cnt++;//send information
问题到这儿,持续往下查就需要耐性了。客户代码不杂乱,用到的外设模块也不多,主循环里也就下面几个函数,一个个函数模块进行排查。
PLED_flash(499); //LED闪耀
relay_control(); //继电器操控
CCT_calculate();//做AD转化
send_information();//输出提示信息
后来发现TIM4坚持作业的一起屏蔽CCT_calculate();,UART-RX能正常接纳。看来TIM4并非是影响UART接纳的首恶。不过CCT_calculate()的运转仍是跟TIM4中止有关,有个变量TS_CNT是在TIM4中止里进行累加的。
看看下面CCT_calculate()的代码,里边有个条件判别,即if(Ts_cnt > 1000)的判别。
voidCCT_calculate(void)
{
if(Ts_cnt> 1000)
{
Ts_cnt = 0;
T_ad = Get_ADCCH_Value(Ts_channel);
T_degree = cal_temp(T_ad)-11;
。。。。。
}
}
假如TIM4被屏蔽不作业,TS_CNT就不会得到累加而大于1000然后往下履行Get_ADCCH_Value();函数。该Get_ADCCH_Value();函数对ADC做初始化之后履行AD转化并获取相关AD值。
正是在ADC初始化代码里有对相关ADC通道对应脚的施密特触发器做了禁用装备。并且该ADC通道脚跟UART-RX脚又是复用的,费事就此产生了。
在STM8MCU的GPIO 的各IO模块里有个施密特触发器,经过寄存器ADC_TDR操控其开和关。默许状况下是翻开的,IO脚的信号能够自在经过它进到输入寄存器或其它外设模块。
假如某管脚做AD模仿输入时,主张经过ADC_TDR将相应的施密特触发器封闭,意图是为了下降GPIO的功耗。如下图所示,当施密特触发器被封闭后,不论外部引脚电平怎么改变,它的输出恒定为0。
结合到本事例中的问题,由于他在AD转化函数中初始化AD时封闭了该施密特触发器,该脚又复用为UART-RX,此刻RX信号底子进不到UART接纳模块中,不能产生UART接纳中止也就自然而然了。
后来当它翻开施密特触发器后,URAT-RX接纳也就正常了。
明显,客户最早以为的TIM4影响UART-RX是个幻觉。由于它是每隔一守时刻才去做AD转化,一起做些AD初始化装备。假如TIM4封闭了,相应的时刻条件不成立也就不去做AD转化,也就不会禁用施密特触发器,从而就不会产生UART-RX失利的状况。