本帖最后由 zerg_aoo 于 2016-9-21 15:03 编辑 1、芯片及开发环境:STM8S003和IAR开发环境; 2、主要问题:程序需实现3.5V以下关机功能,若每12秒未收到串口输入的数据(数据是5秒发一次的字符a),否则闪断关机脚,实现RESET。现在的问题是串口没有中断输入时,可正常检测到3.5V并关机,若串口有数据不断输入时,则3.3V才关机,请问何原因?查到较多关于串口中断,定时器,串口过载错误等资料,一个星期了始终没有解决。项目是一个车载跟踪器的项目,马上要出货了,比较着急,求助大家帮忙看看,谢谢了! 3、main.c完整程序如下: #include<iostm8s103f3.h> unsigned int ADCData; unsigned int second_count; unsigned int uart_count; unsigned char powerflag; #define ONOFF_ON() PC_ODR_bit.ODR7 = 0 #define ONOFF_OFF() PC_ODR_bit.ODR7 = 1 #define MX6_POR_B_ON() PC_ODR_bit.ODR5 = 0 #define MX6_POR_B_OFF() PC_ODR_bit.ODR5 = 1 #define Voltage_3V7 0x02EE //3.75v*22k/(22k+12k)=2.43v(%d0750) #define Voltage_3V5 0x02B8 //3.50v*22k/(22k+12k)=2.26v(%d0696) /******************************************************************************* **函数名称:void delay(unsigned int ms) **功能描述:大概延时 **入口参数:unsigned int ms 输入大概延时数值 **输出:无 *******************************************************************************/ void delay(unsigned int ms) { unsigned int x , y; for(x = ms; x > 0; x--) /*通过一定周期循环进行延时*/ for(y = 1000 ; y > 0 ; y--); } /******************************************************************************* **函数名称:ONOFF_Init() **功能描述:初始化ONOFF引脚 **入口参数:无 **输出:无 *******************************************************************************/ void ONOFF_Init() { PC_DDR_bit.DDR7 = 1; //设置端口PC->7的输入输出方向寄存器为输出方向 PC_CR1_bit.C17 = 1; //PC->7为推挽输出 PC_CR2_bit.C27 = 1; //PC->7是输出速度最快为10MHz } /******************************************************************************* **函数名称:MX6_POR_B_Init() **功能描述:初始化MX6_POR_B控制引脚 **入口参数:无 **输出:无 *******************************************************************************/ void MX6_POR_B_Init() { PC_DDR_bit.DDR5 = 1; //设置端口PC->5的输入输出方向寄存器为输出方向 PC_CR1_bit.C15 = 1; //PC->5为推挽输出 PC_CR2_bit.C25 = 1; //PC->5是输出速度最快为10MHz } /******************************************************************************* **函数名称:void TIM1_Init() **功能描述:定时器1参数初始化 **入口参数:无 **输出:无 *******************************************************************************/ void TIM1_Init() { TIM1_CR1_bit.CEN = 0; //stop tim1 //设置定时器的时钟为 = 16000000 / (psc + 1) = 16000000 / 400 = 40000Hz TIM1_PSCRH = 399 / 256; //设置定时器1的预分频数值为 psc = 399 + 1 TIM1_PSCRL = 399 % 256; // TIM1_CR1_bit.CMS = 0; //设置定时器1的边沿对齐模式 TIM1_CR1_bit.DIR = 0; //计数模式为向上计数 UP Count //设置定时器1计数40000次 = 1秒时间产生中断 TIM1_ARRH = 40000 / 256; //高八位 TIM1_ARRL = 40000 % 256; //低八位 TIM1_CNTRH = 0x0000; //清除计数寄存器的高八位 TIM1_CNTRL = 0x0000; //清除计数寄存器的低八位 TIM1_IER_bit.UIE = 1; //使能更新中断 TIM1_CR1_bit. ARPE = 1; //设置允许自动更新 TIM1_CR1_bit. CEN = 1; //使能定时器1开始计数 } /******************************************************************************* **函数名称:void UART1_Init(unsigned int baudrate) **功能描述:初始化USART模块 **入口参数:unsigned int baudrate -> 设置串口波特率 **输出:无 *******************************************************************************/ void UART1_Init(unsigned int baudrate) { unsigned int baud; baud = 16000000 / baudrate; //设定串口相应波特率与串口时钟的分频数 //先写BRR2 , 再写BRR1 UART1_BRR2 = ((unsigned char)((baud & 0xf000) >> 8 )) | ((unsigned char)(baud & 0x000f)); //先写波特比率的高4位与低4位 UART1_BRR1 = ((unsigned char)((baud & 0x0ff0) >> 4)); //后写波特比率的中间8位 UART1_CR1_bit.UART0 = 0; //使能UART0 UART1_CR2_bit.RIEN = 1; //使能中断接收 UART1_CR2_bit.TEN = 1; //使能发送 UART1_CR2_bit.REN = 1; //接收使能 } /******************************************************************************* **函数名称:void Uart_SendData(unsigned char data) **功能描述:向串口发送寄存器写入一个字节数据 **入口参数:unsigned char data **输出:无 *******************************************************************************/ void Uart_SendData(unsigned char data) { while(!(UART1_SR&0X80)); //判断发送数据寄存器是否为空 UART1_DR = data; //向发送寄存器写入数据 } /******************************************************************************* **函数名称:void ADC_Init() **功能描述:初始化ADC **入口参数:无 **输出:无 *******************************************************************************/ void ADC_Init() { PD_DDR_bit.DDR3 = 0; //设置PD->3 为输入 PD_CR1_bit.C13 = 0; //设置为悬空输入 PD_CR2_bit.C23 = 0; //设置中断禁止 ADC_CR1_bit.SPSEL = 3; //fmaster / 18 = 16MHZ / 18 = 888888HZ ADC_CR2_bit.ALIGN = 1; //RIGHT ALIGN ADC_CSR_bit.CH = 4; //SELECT AIN4 ADC_CR1_bit.ADON = 1; //启动ADC } /******************************************************************************* **函数名称:void ADC_Data_Read(unsigned int *AD_Value) **功能描述:读取ADC完成一次模数转换结果 **入口参数:unsigned int *AD_Value *AD_Value ->读取ADC采样数据的指针 **输出:无 *******************************************************************************/ void ADC_Data_Read(unsigned int *AD_Value) { ADC_CR1_bit.ADON = 1; //启动ADC while(ADC_CSR_bit.EOC == 0); //等待转换结束 *AD_Value = ADC_DRH; //先读取高8位 *AD_Value = (unsigned int)((*AD_Value << 8) + ADC_DRL); //高8位与低8位相加,凑成16位数据 } /******************************************************************************* **函数名称:void IWDG_Init() **功能描述:初始化独立看门狗 **入口参数:无 **输出:无 *******************************************************************************/ void IWDG_init(void) { IWDG_KR = 0xCC; //启动IWDG IWDG_KR = 0x55; //解除 PR 及 RLR 的写保护 IWDG_RLR = 0xFF; //看门狗计数器重装载数值 IWDG_PR = 0x06; //分频系数为256,最长超时时间为:1.02S IWDG_KR = 0xAA; //刷新IDDG,避免产生看门狗复位,同时恢复 PR 及 RLR 的写保护状态 } /******************************************************************************* **函数名称:void Power_Manage() **功能描述:MX6电源控制函数 **入口参数:无 **输出:无 *******************************************************************************/ void Power_Manage(void) { ADC_Data_Read(&ADCData); //读取ADC的采样数值 if(ADCData >= Voltage_3V7) //如果电压大于3.7V,则打开MX6电源 { delay(50); //延时去抖动 ADC_Data_Read(&ADCData); //读取ADC的采样数值 if(ADCData >= Voltage_3V7) { MX6_POR_B_ON(); //开启MX6电源 powerflag=1; //置MX6电源标志位为1 } } else if((ADCData > 0)&&(ADCData <= Voltage_3V5)) //如果电压为3.5v以下,关掉MX6电源 { delay(50); //延时去抖动 ADC_Data_Read(&ADCData); //读取ADC的采样数值 if((ADCData > 0)&&(ADCData <= Voltage_3V5)) { MX6_POR_B_OFF(); //关MX6电源 powerflag=0; //置MX6电源标志位为0 } } else {;} delay(50); //延时去抖动 } /* 主函数 */ int main(void) { asm("sim"); //关闭系统总中断 CLK_CKDIVR = 0x00; //CPUDIV = 1 HSIDIV = 1 内部时钟 = 16Mhz UART1_Init(9600); //调用串口初始化函数,并设置波特率为9600 bps TIM1_Init(); //调用定时器1初始化函数 ADC_Init(); //调用ADC初始化函数 ONOFF_Init(); //初始化NOOFF控制引脚 ONOFF_ON(); //默认关闭imx6ul睡眠控制脚 MX6_POR_B_Init(); //初始化MX6_POR_B控制引脚 MX6_POR_B_ON(); //默认开启imx6ul电源 powerflag=1; //清除MX6电源标志位 IWDG_init(); //始化独立看门狗 asm("rim"); //打开系统总中断 while(1) { Power_Manage(); IWDG_KR = 0xAA; //刷新IDDG,避免产生看门狗复位,同时恢复 PR 及 RLR 的写保护状态 } } /******************************************************************************* **函数名称:__interrupt void UART1_RX_RXNE(void) **功能描述:串口接收数据中断服务函数 **入口参数:无 **输出:无 *******************************************************************************/ #pragma vector = 0x14 //设置串口接收中断向量号 = 0X14 __interrupt void UART1_RX_RXNE(void) { unsigned char ch1; UART1_SR_RXNE = 1; //清除中断标志 uart_count++; //中断使 uart_count++++ 做加法,记录产生的中断次数 if(UART1_SR_OR_LHE) //发生过载错误,顺序读UART1_SR,UART1_DR来清UART1_SR_OR_LHE位 { ch1 = UART1_SR; ch1 = UART1_DR; } else { ch1 = UART1_DR; } Uart_SendData(ch1); //把接收到的数据再通过串口发送出去 return; } /******************************************************************************* **函数名称:__interrupt void TIM1_UPDATE_IRQHandler(void) **功能描述:定时器1重载更新中断服务函数 **入口参数:无 **输出:无 *******************************************************************************/ #pragma vector = TIM1_OVR_UIF_vector //设置定时器1重载的中断向量号 = 13 __interrupt void TIM1_UPDATE_IRQHandler(void) { TIM1_SR1_bit.UIF = 0; //清除中断标志 second_count++; //中断使 second_count++ 做加法,记录1秒产生的中断次数 if(second_count >= 12) //记录达到12秒,即12秒(与MX6的kernel启动时间相关) { second_count = 0; //复位记录TIM1中断次数 if((uart_count == 0)&&(powerflag==1)) { MX6_POR_B_OFF(); //关MX6电源 delay(500); MX6_POR_B_ON(); //打开MX6电源 } else { uart_count = 0; //复位记录串口中断次数 //PC_ODR ^= 0x80; //对LED2进行异或取反,使LED2以1秒的周期亮灭 } } } |
纠正下:现在的问题是没有串口中断输入时,可正常检测到3.5V并关机,若串口有数据不断输入时,则3.3V才关机,请问何原因? |