完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
测试STM32单片机低功耗模式时,遇到一个问题。当单片机从停止模式被唤醒后,LED指示灯闪烁变慢,同时串口通信出现乱码。
程序如下: //将串口接收口做为中断唤醒 void EXIT_UART_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource10); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_Line10; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line10) != RESET) { EXTI_ClearITPendingBit(EXTI_Line10); } } //进入停止模式 任意外部中断唤醒 WKUP不能唤醒 void enter_stop_mode(void) { EXIT_UART_Init(); //RX引脚配置为外部中断 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //开电源管理时钟 PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); //进入停机模式 } 进入停止模式时,首先将串口接收引脚PA10设置为外部中断,然后配置电源时钟,下来进入停止模式。在主程序中通过一个按键控制程序进入停止模式,然后给串口发送任意数据可以唤醒停止模式。 当程序从停机模式被唤醒后,发现LED闪烁频率变慢。 正常情况下LED指示灯波形为: LED高低电平时长为51ms。 当从停机模式唤醒后,LED波形为: 从停机模式被唤醒后,LED高低电平时长变为450ms左右,和正常情况下为1:9的关系。为什么会这样呢?看到STM32中文参考手册里面有这样一句话: 退出停止模式时,HSI 被选为系统时钟。 HSI时钟为8MHz,而开发板的时钟是由外部晶振8MHz倍频到72MHz,刚好相差了9倍。所以从停机模式被唤醒后,LED的翻转速度为正常的1/9。 于是代码修改为从停机模式唤醒后,重新初始化一次时钟。 void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line10) != RESET) { EXTI_ClearITPendingBit(EXTI_Line10); SystemInit(); //重新设置时钟 } } 这样从停止模式恢复后,LED指示灯正常。但是又发现新的问题,串口通信出现了乱码。 主程序中隔3s发送一次数据,用来提示程序运行情况。当从停机模式唤醒后,会出现一次串口乱码情况。会不会是停止模式唤醒是只重新设置了系统时钟,没有重新设置串口引起的。那么在中断中在增加一个串口初始化看看。 void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line10) != RESET) { EXTI_ClearITPendingBit(EXTI_Line10); SystemInit(); //重新设置时钟 uart_init(9600); //重新初始化串口 } } 增加串口初始化后,依然会出现乱码。那是什么原因造成的?会不会是在进入停止模式后,串口的寄存器某个位发生了改变? 在初始化串口前,先复位一次串口试试。 void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line10) != RESET) { EXTI_ClearITPendingBit(EXTI_Line10); SystemInit(); //重新设置时钟 USART_DeInit(USART1); //复位串口 uart_init(9600); //重新初始化串口 } } 先将串口复位后,在初始化串口,未出现乱码情况。 为了验证这个现象,在调试模式看看串口寄存器的值是不是发生了变化,正常情况下串口寄存器值: 还未初始化串口时,串口1寄存器的值 SR寄存器为0xc0,其他寄存器全部为0。 串口初始化结束后,BRR寄存器值变为0x1D4C,CR1寄存器值变为0x202C。 然后全速运行一会程序,进入停止模式,再次唤醒后观察串口1寄存器的值。 当从停止模式唤醒后,SR寄存器值变为了0xFA,DR寄存器的值变成了0x55。 可以看出,串口的状态寄存器和数据寄存器发生了改变。所以在初始化串口之前要重新复位状态寄存器,和数据寄存器。那么在停机模式唤醒时不用复位串口,只需复位串口状态寄存器和数据寄存器就行。于是代码修改如下: void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line10) != RESET) { EXTI_ClearITPendingBit(EXTI_Line10); SystemInit(); //重新设置时钟 USART1->SR = 0x00C0; //复位状态寄存器 USART1->DR = 0x00; //复位数据寄存器 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 } } 中断中唤醒时,先重置系统时钟,然后复位串口状态寄存器和数据寄存器,然后重新初始化串口和GPIOA口时钟。 测试结果如下: 通过串口数据可以看出,串口未出现复位。同时和刚才直接复位串口相比,接收的数据中多了一行 退出停机模式提示。说明刚才直接复位串口的方法,会丢失一组数据。 主程序代码如下: //进入停止模式 任意外部中断唤醒 WKUP不能唤醒 停止模式唤醒后系统 默认为 HSI 需要重新设置时钟 void enter_stop_mode(void) { EXIT_UART_Init(); //RX引脚配置为外部中断 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //开电源管理时钟 PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); //进入停机模式 } int main(void) { u8 i = 0, j = 0; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); //延时函数初始化 LED_Init(); //初始化与LED连接的硬件接口 KEY_Init(); uart_init(9600); LED = 1; delay_ms(500); printf("low power test! rnrn"); while(1) { i = KEY_Scan(1); switch(i) { case 0: break; case 1: printf("进入停机模式rnrn"); enter_stop_mode(); //唤醒后 接着下一行语句执行 printf("退出停机模式rnrn"); //唤醒后执行当前语句 break; case 2: printf("进入待机模式rnrn"); Sys_Enter_Standby(); //唤醒后从程序开始位置执行 printf("退出待机模式rnrn"); //执行不到这块 break; case 3: printf("进入睡眠模式 中断唤醒 rnrn"); sleep_mode_wfi(); //唤醒后接着下一条语句执行 printf("退出睡眠模式 中断唤醒 rnrn"); //唤醒后执行当前语句 break; case 4: printf("进入睡眠模式 事件唤醒 rnrn"); sleep_mode_wfe(); //唤醒后接着下一条语句执行 printf("退出睡眠模式 事件唤醒 rnrn"); //唤醒后执行当前语句 break; } j++; if(j>199) { j = 0; printf("low power test running!rn"); } if(j % 5==0) { LED = !LED; } delay_ms(10); } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1804 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1097 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
736 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1686 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
747浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
580浏览 3评论
602浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-28 10:34 , Processed in 0.379190 second(s), Total 43, Slave 37 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号