关于STM8S ADC脚与其它功能复用时的问题

发布者:老桃子最新更新时间:2016-09-19 来源: eefocus关键字:STM8S  ADC脚  功能复用 手机看文章 扫描二维码
随时随地手机看文章
之前写过一篇关于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脚又是复用的,麻烦就此产生了。

31

在STM8MCU的GPIO 的各IO模块里有个施密特触发器,通过寄存器ADC_TDR控制其开和关。默认情况下是打开的,IO脚的信号可以自由通过它进到输入寄存器或其它外设模块。

如果某管脚做AD模拟输入时,建议通过ADC_TDR将相应的施密特触发器关闭,目的是为了降低GPIO的功耗。如下图所示,当施密特触发器被关闭后,不管外部引脚电平如何变化,它的输出恒定为0。

 

32

结合到本案例中的问题,因为他在AD转换函数中初始化AD时关闭了该施密特触发器,该脚又复用为UART-RX,此时RX信号根本进不到UART接收模块中,不能产生UART接收中断也就自然而然了。

后来当它打开施密特触发器后,URAT-RX接收也就正常了。

显然,客户最先认为的TIM4影响UART-RX是个错觉。因为它是每隔一定时间才去做AD转换,同时做些AD初始化配置。如果TIM4关闭了,相应的时间条件不成立也就不去做AD转换,也就不会禁用施密特触发器,进而就不会发生UART-RX失败的情况。

关键字:STM8S  ADC脚  功能复用 引用地址:关于STM8S ADC脚与其它功能复用时的问题

上一篇:USART模块接收中断的问题处理
下一篇:关于ST MCU的UID详细说明

推荐阅读最新更新时间:2024-03-16 15:10

浅谈STM8S_008_WDG独立看门狗和窗口看门狗
Ⅰ写在前面 STM8S看门狗WDG分为两类: IWDG:Independent WatchDog独立看门狗 WWDG:Window WatchDog窗口看门狗 独立看门狗模块可以用于解决处理器因为硬件或软件的故障所发生的错误。它由一个内部的128kHz的LSI阻容振荡器作为时钟源驱动,因此即使是主时钟失效时它仍然照常工作。 窗口看门狗用于监测由于外部干扰或不可预知的逻辑条件所产生的软件错误,这样的软件错误通常会导致应用程序不按照预期的方式运行。 大概意思主要是:IWDG主要防止硬件问题引起的复位,WWDG主要防止软件问题引起的复位. 为方便大家阅读,本文内容已经整理成PDF文件: http://pan.baidu
[单片机]
浅谈STM8S_008_WDG独立看门狗和窗口看门狗
STM8S MAX7219点阵模块驱动芯片程序
以下为.h文件: #ifndef __MAX7219_H #define __MAX7219_H #include stm8s_gpio.h #include stm8s.h #include iostm8s103f3.h #include intrinsics.h #include tim1.h #define uchar unsigned char #define uint unsigned int #define count 8 void Init_MAX7219(void); void MAX7219_Init(void); void Write_Max7219_byte(uchar Data);
[单片机]
<font color='red'>STM8S</font> MAX7219点阵模块驱动芯片程序
【单片机笔记】STM8S系列单片机FLASH操作
1. 修改stm8s_conf.h的注释,让#include stm8s_flash.h 得以编译 2.修改stm8s.h的注射,让使Flash功能能够从RAM中运行 #if !defined (RAM_EXECUTION) #define RAM_EXECUTION (1) // 块写入时,必须打开这里的注射 #endif /* RAM_EXECUTION */ 3.修改完成后,将产生不少警告,消除的方法,暂时还没有找到,但不影响代码的运行。 附上代码: #include fy_flash.h //操作flash前需要取消注释s
[单片机]
STM8S重映射
一、STM8S003 管脚重映射功能 如图所示,我想使用这个对应关系: PC5- TIM2_CH1; PC6- TIM1_CH1; PC7- TIM1_CH2; 这三个管脚默认功能为: PC5- SPI_SCK PC6- SPI_MOSI PC7- SPI_MISO stm8s不像stm32一样可以配置GPIO就可以了;stm8s需要修改OptionBytes才可以实现管脚复用功能的重映射。 OptionBytes里的AFR寄存器负责实现这个功能,官方手册介绍如下: 上边描述了将AFR寄存器的某一位置为1之后的效果;由于我需要使用 PC5- TIM2_CH1;PC6- TIM1_CH1;PC7- TIM1_CH2; 的功
[单片机]
<font color='red'>STM8S</font>重映射
STM32/STM8L/STM8S系列之一、流水灯
一、STM32F103点亮LED 1、电路图: 2、代码: //FUNCTION:LED初始化 //PARA :无 //RETURN :无 void LED_INIT(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB , ENABLE); //使能AFIO和GPIOB端口 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭PB3 PB4的复用功能,使能通用IO功能
[单片机]
STM32/STM8L/<font color='red'>STM8S</font>系列之一、流水灯
stm8s内部时钟配置详解及配置步骤
  STM8S的4种时钟源可用做主时钟:   ● 1-24MHz高速外部晶体振荡器(HSE)   ● 最大24MHz高速外部时钟信号(HSE user-ext)   ● 16MHz高速内部RC振荡器(HSI)   ● 128KHz低速内部RC(LSI)   各个时钟源可单独打开或关闭,从而优化功耗。   系统的启动   为使系统快速启动,复位后时钟控制器自动使用HSI的8分频(HSI/8)做为主时钟。其原因为HSI的稳定时间短,而8分频可保证系统在较差的VDD条件下安全启动。   另外,stm8s还可以切换时钟源,有自动和手动两种方法。   时钟是单片机的灵魂,所有的东西都和时钟有关。相比AVR反人类的熔丝位设置时
[单片机]
<font color='red'>stm8s</font>内部时钟配置详解及配置步骤
STM8S 115200bps 串口中断连续接收出错问题
内部16M晶振误差太大,导致波特率不准,9600bps可以。要想使用115200,就用外部晶振吧。 还有数据寄存器DR中的数据如果没有及时取走(也可能因为波特率不准)导致数据溢出,出现反复中断现像,如在调试时如果暂停时串口上还有数据,再次运行时DR中的数据将一直是某个数据,正常情况下是不会出现的,解决办法就是进中断的时候清OV标志(不能解决根本问题)。
[单片机]
STM8S定时器工作
TIM4是一个8位通用定时器,TIM4工作时,其计数器从0开始向上计数,计数到TIM4_ARR寄存器中设置的值时,计数器从新从0开始计数,同时产生一个计数器溢出事件。 程序实例 void main(void) { InitLED(); InitTIM4(); asm( ris ); TIM4_CR1 |= 0X01; while(1){} } InitTIM4();为 TIM4 初始化函数,起作用是设置 TIM4 的相关寄存器,使 TIM4 每隔一段时间产生一 次溢出中断。其函数内部如下: void InitTIM4(void) {   TIM4_PSCR = 0X07;//分频2M/2^7=15.625K
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved