前言stm32常见的低功耗模式有三种:睡眠模式、stop模式以及待机模式,stm32l系列还有其他低功耗模式。这里主要讲的是stop模式,stop模式可以通过外部中断或事件唤醒,但是不能通过串口中断唤醒,因为串口中断本身不是外部中断,那么如何才能实现串口唤醒stop模式呢?
因为我这里只是为了做验证,为了快速验证,我也就没有用rt-thread的pm电源管理组件进入stop模式,感兴趣的读者可以用rt-thread的电源管理组件去实现进行stop模式。
一、为什么要串口唤醒stop模式?想象一下,在某些场合,如果你有一个无线通信模块(例如esp8266、sim800c)和stm32通过串口发送at命令来对接服务器实现与服务器的数据交互,那么如果在没有进行数据交互的时候,我们是不是可以让stm32进入stop模式来达到省电的状态,从而让电池续航更长。例如:stm32+esp8266与后台服务器进行数据交互,当不用发送数据完毕,等待下次发送数据或等待后台下发数据给设备的这段时间可以让stm32进入stop模式来达到省电,当后台服务器下发数据给设备的时候,我们可以向让后台发送一个唤醒设备的指令,esp8266接收到后台的这条指令之后通过串口下发给stm32,那么就可以唤醒stm32了,这时候stm32就可以继续接收后台下发的数据。
二、串口唤醒stop模式的思路1、我们知道stop模式只能外部中断或事件唤醒,那么想象一下,在stm32进行stop模式之前,是不是可以先将uart_rx对应的gpio引脚配置为外部中断引脚,而串口接收到字符相当于接收到01010…这样的高低电平,从二可以唤醒串口,当唤醒之后,我们再马上重新初始化串口,把uart_rx对应的gpio引脚配置为接收中断模式?答案当然是可以的。
2、唤醒之后的程序是从哪里开始执行?答案是从进行stop模式之前的那个地方重新开始执行,一会进行验证。
三、串口唤醒stop模式实验光说不练都是假把式,接下来进行实验。
1、 实验平台: 中国移动物联网onenet nb开发板(板载stm32)。
2、stm32f103ret6、12m外部晶振、串口3进行实验。
3、 操作系统: rt-thread。
4、用rt-thread创建两个线程,一个线程用于读取按键是否按下,按下则调用进入stop模式函数进入stop模式,另一个线程读取串口接收到的数据。
1、如何进行stop模式?
实验时用的是标准库,在这里主要实现在进入stop模式前将rx对应的gpio引脚配置为外部中断模式以及进入stop模式,代码如下:
1/************************************************************** 2函数名称:system_enter_stop 3函数功能:系统进入stop模式 4输入参数:无 5返 回 值:无 6备 注:无 7**************************************************************/ 8void system_enter_stop(void) 9{10 uart_exti_init(); /* 进入stop模式前配置rx引脚为外部中断模式 */11 rcc_apb1periphclockcmd(rcc_apb1periph_pwr , enable); /* 开电源管理时钟 */12 //pwr_enterstopmode(pwr_regulator_on, pwr_stopentry_wfi); /* 进入stop模式,外部中断唤醒 */13 pwr_enterstopmode(pwr_regulator_lowpower, pwr_stopentry_wfe); /* 进入stop模式,外部中断或事件唤醒 */14}2、配置rx对应的gpio引脚为外部中断模式
这里采用rt-thread的pin设备进行配置,在配置之前需要先关闭uart中断、复位uart、复位gpio,然后在进行配置为外部中断模式,代码如下:
1/************************************************************** 2函数名称:uart_exti_init 3函数功能:rx引脚配置为外部中断 4输入参数:无 5返 回 值:无 6备 注:无 7**************************************************************/ 8void uart_exti_init(void) 9{10 /* 关闭uart中断、复位uart、复位gpio */11 usart_itconfig(usart3, usart_it_rxne, disable);12 usart_cmd(usart3, disable);13 gpio_deinit(gpiob);14 usart_deinit(usart3);1516 /* 配置rx对应的gpio引脚为外部中断模式 */17 rt_pin_mode(pin_uart3_rx, pin_mode_input_pullup);18 rt_pin_attach_irq(pin_uart3_rx, pin_irq_mode_falling, uart_exti_callback, rt_null);19 rt_pin_irq_enable(pin_uart3_rx, pin_irq_enable);20}3、接收中断回调函数
在上面的配置中,有一个接收回调函数uart_exti_callback,就是在发送中断的时候要执行的事情,在接收回调函数里面,我们主要实现systeminit,重新初始化串口,代码如下:
1/************************************************************** 2函数名称:uart_exti_callback 3函数功能:rx引脚外部中断唤醒回调函数 4输入参数:args:回调函数入口参数 5返 回 值:无 6备 注:无 7**************************************************************/ 8void uart_exti_callback(void *args) 9{10 systeminit();11 uart_reinit(); /* 重新初始化串口 */12 rt_kprintf(wake up\\r\\n);1314}4、进入stop模式的线程
这里,创建一个线程来实现判断是否按键按下,按下则调用system_enter_stop函数进入stop模式,同时为了验证唤醒之后时钟正常以及程序是从进行stop模式之前的那个地方重新开始执行,我们设计led灯500ms亮500ms灭,再一个计数变量,每隔1秒自动加1并打印,代码如下:
1static void sleep_thread_entry(void *parameter) 2{ 3 unsigned char key; 4 unsigned int count=0; 5 6 while(1) 7 { 8 key = key_scan(0); 910 if(key == key4_pres)11 {12 rt_kprintf(system_enter_stop\\r\\n);13 system_enter_stop();14 }15 led1(1);16 rt_thread_mdelay(500);17 led1(0);18 rt_thread_mdelay(500);19 rt_kprintf(count:%d\\r\\n,count);20 count++;21 }22}5、实验操作和现象
1、开机之后,led闪烁,串口打印count每隔1秒加1的值,等待一小会按下按键key4进入stop模式:
finsh抓取的串口打印信息
2、对比进入stop模式前和stop模式之后的电流情况(这里进入stop模式之后电流还是很大是因为我们板子还接了其他耗电的模块,我们这对比电流有没有降下来就可以了),很明显,电流降下来了:
进入stop模式前的电流
进入stop模式后的电流
3、通过串口发送一个字符“a”,唤醒了stm32,这时候串口并不会打印字符“a”,因为唤醒之后要重新初始化串口,第二次发送字符“a”才能显示,这时候,我们观察finsh打印出来的信息,可以看到count是从9开始打印,说明stop唤醒之后会从原来进入stop模式之前的地方重新执行代码:
验证代码的执行情况
唤醒之后第二次发一个字符能正常打印
4、接下来,我们再次按下key4重新然stm32进入sto模式,然后发送一个比较长的字符串来唤醒stm32,例如发“abcdefghijklmnopq1234567890”,这时候,我们发现第一次发送之后,竟然会有字符出来,不是说没有吗?而且这些字符和我们发送的不一样,少了,第二次才正常:
唤醒之后打印字符不正常
四、串口唤醒存在的问题
1、上面我们提到,发送一个字符唤醒就很正常,而发送比较长的字符串唤醒却出现了不然正常的现象,这是为什么呢?想象一下m如果你是发一串很长的数据来唤醒串口,这串数据也是通过0101010等二进制来发送的,当rx引脚被触发中断唤醒mcu之后,唤醒之后串口初始化完成了,剩余的数据也就会接着以010101的高低电平发给stm32的串口,有可能导致有些字符的01丢失了一部分(例如上面出现了k567890),从而可以接下来的字符会打印出来。如果是发一个字符,一个字符的01010101其实也就8位,发送很快的,唤醒之后都已经发送结束了,所以就会直接唤醒,也就不会接收这个字符,只有第二次发送的时候才会接收到这个字符。
首款带有外设触摸控制器(PTC)的功能安全型AVR MCU系列
荣耀进军笔记本市场,再掘“金矿”背后的秘诀探秘
2015 TI 汽车应用处理器 与 ADAS 方案网上展示会
看AI教父对人工智能研究的年轻人,给出的一些忠告
探讨“新基建”时代云计算数据中心面临的各种挑战
为什么要串口唤醒STOP模式?如何才能实现串口唤醒STOP模式呢?
龙芯中科发布基于自主指令系统“龙架构”29款自主工业系列产品
一文读懂振动传感器测量振动的方式
TRO新文:用于数据关联、建图和高级任务的对象级SLAM框架
NVIDIA宣布开放DRIVE Constellation模拟平台
传三星s8只有曲面屏版本 指纹识别或嵌入屏幕
进一步聚焦LED封装器件,发展Mini LED等其他业务
凌阳科技推出高性能的16位变频马达驱动微控制器
使用AD620仪表放大器来实现扩展DSO功能
关于LDO和DCDC的不同点分析
低功耗SPST双边开关
海信推出游戏电视全新细分品类,加速进入“电视=游戏机”时代
中国平煤神马集团与中兴通讯达成战略合作 聚焦煤炭产业数智化升级
智能家居是怎样成为市场爆点的
亿纬锂能的电池发布会