历史上的今天
返回首页

历史上的今天

今天是:2025年07月08日(星期二)

正在发生

2019年07月08日 | STM32串口唤醒STOP模式的实现

2019-07-08 来源:eefocus

前言

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模式,代码如下:


/**************************************************************

函数名称:system_enter_stop

函数功能:系统进入STOP模式

输入参数:无

返 回 值:无

备    注:无

**************************************************************/

void system_enter_stop(void)

{

        uart_exti_init(); /* 进入STOP模式前配置RX引脚为外部中断模式 */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE); /* 开电源管理时钟 */

//PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); /* 进入STOP模式,外部中断唤醒 */

PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); /* 进入STOP模式,外部中断或事件唤醒 */

}

 


2、配置RX对应的GPIO引脚为外部中断模式


这里采用RT-Thread的PIN设备进行配置,在配置之前需要先关闭UART中断、复位UART、复位GPIO,然后在进行配置为外部中断模式,代码如下:


/**************************************************************

函数名称:uart_exti_init

函数功能:RX引脚配置为外部中断

输入参数:无

返 回 值:无

备    注:无

**************************************************************/

void uart_exti_init(void)

{

        /* 关闭UART中断、复位UART、复位GPIO */

USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);

USART_Cmd(USART3, DISABLE);

GPIO_DeInit(GPIOB);

USART_DeInit(USART3);

 

/* 配置RX对应的GPIO引脚为外部中断模式 */

rt_pin_mode(PIN_UART3_RX, PIN_MODE_INPUT_PULLUP);

rt_pin_attach_irq(PIN_UART3_RX, PIN_IRQ_MODE_FALLING, uart_exti_callback, RT_NULL);

rt_pin_irq_enable(PIN_UART3_RX, PIN_IRQ_ENABLE);

}

 


3、接收中断回调函数


在上面的配置中,有一个接收回调函数uart_exti_callback,就是在发送中断的时候要执行的事情,在接收回调函数里面,我们主要实现SystemInit,重新初始化串口,代码如下:


/**************************************************************

函数名称:uart_exti_callback

函数功能:RX引脚外部中断唤醒回调函数

输入参数:args:回调函数入口参数

返 回 值:无

备    注:无

**************************************************************/

void uart_exti_callback(void *args)

{

SystemInit();

uart_reinit(); /* 重新初始化串口 */

rt_kprintf("wake uprn");

 

}

 


4、进入STOP模式的线程


这里,创建一个线程来实现判断是否按键按下,按下则调用system_enter_stop函数进入STOP模式,同时为了验证唤醒之后时钟正常以及程序是从进行STOP模式之前的那个地方重新开始执行,我们设计LED灯500ms亮500ms灭,再一个计数变量,每隔1秒自动加1并打印,代码如下:


static void sleep_thread_entry(void *parameter)

{

unsigned char key;

unsigned int count=0;

while(1)

{

key = key_scan(0);

 

if(key == KEY4_PRES)

{

rt_kprintf("system_enter_stoprn");

system_enter_stop();

}

LED1(1);

rt_thread_mdelay(500);

LED1(0);

rt_thread_mdelay(500);

rt_kprintf("count:%drn",count);

count++;

}

}

 


5、实验操作和现象


1、开机之后,LED闪烁,串口打印count每隔1秒加1的值,等待一小会按下按键KEY4进入STOP模式:


FinSH抓取的串口打印信息

2、对比进入STOP模式前和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位,发送很快的,唤醒之后都已经发送结束了,所以就会直接唤醒,也就不会接收这个字符,只有第二次发送的时候才会接收到这个字符。


推荐阅读

史海拾趣

三环(CCTC)公司的发展小趣事

近年来,三环(CCTC)公司更加注重产品品质和品牌建设。公司建立了完善的质量管理体系和检测手段,确保产品质量稳定可靠。同时,公司加强了品牌宣传和推广力度,提高了品牌知名度和美誉度。通过不断提升产品品质和加强品牌建设,公司赢得了更多客户的信任和支持,实现了可持续发展。

Compex Corporation公司的发展小趣事

Compex Corporation的创立可以追溯到电子行业的早期阶段。自XXXX年成立以来,公司便致力于研发和生产高质量的单层电容器、电阻以及其他电子元件。初期,公司面临着激烈的市场竞争和技术挑战,但凭借其卓越的技术团队和不懈的努力,逐渐在市场中站稳了脚跟。公司不断推出创新产品,满足了客户对高质量电子元件的需求,逐渐赢得了客户的信任和市场份额。

EDSYN公司的发展小趣事

为了帮助客户更便捷地将设备连接到物联网,Econais与Xively展开了合作。通过这一合作,Econais的WiSmart Wi-Fi用户可以无缝连接到Xively云,为工业、商业和住宅市场带来了创新的医疗保健、智能能源、无线音频控制和监控产品。这种一站式的物联网解决方案大大加快了物联网产品的上市时间,同时也降低了产品的开发成本。

Asia Pacific Microsystems Inc公司的发展小趣事

为了进一步提升市场份额和品牌影响力,APM开始积极拓展国内外市场。公司不仅加强了与现有客户的合作关系,还积极参加各类行业展会和技术交流会,与潜在客户建立联系。同时,APM还加大了对品牌建设的投入,通过广告宣传、媒体报道等方式提升品牌知名度和美誉度。这些举措使得APM在电子行业中的影响力逐渐增强。

AC Interface Inc公司的发展小趣事

ABC Electronics Inc. 起初是一家小型电子元件供应商,专注于为本地市场提供基本的电子零部件。然而,随着技术的快速发展,公司创始人意识到,只有不断创新才能在竞争激烈的市场中立足。于是,ABC Electronics 开始投入大量资源研发具有竞争力的新产品。经过数年的努力,公司成功推出了一款具有高效能、低能耗特点的电源管理芯片,迅速获得了市场的认可。这一创新产品不仅为公司带来了可观的利润,也奠定了其在电子行业的技术领先地位。

Bkc Semiconductors Inc公司的发展小趣事

Bkc深知人才是企业发展的核心动力。因此,公司高度重视研发团队的建设和人才培养。通过引进业内顶尖的技术人才和提供完善的培训机制,Bkc逐渐打造出一支技术实力雄厚的研发团队。这支团队不仅为公司带来了源源不断的技术创新,也为公司的长远发展奠定了坚实的基础。

问答坊 | AI 解惑

我军建国以来到21世纪初的军用电台

我军建国以来到21世纪初的军用电台 50年代,71型报话机 第一代我国生产的无线电台 “英雄儿女”中王成高喊:“向我开炮”用的就是71型报话机。 50年代,我国建国后第一批自行研制生产的短波电台,广泛用于抗美援朝战场 由于当时的报废销毁执行 ...…

查看全部问答>

ARM板子上的网口RTL8019?急

各位大侠 小弟项目中用到ARM(s3c44b0)的网口扩展功能,在主程序中是通过中断形式应用的,最要命的是我不怎么懂那些协议,什么ARP,TCp,我所要建立的连接应该是可靠性连接,但是我看别人的程序,大概是要根据各个包的形式,做一些判断,然后建立 ...…

查看全部问答>

问一个DeviceIoControl的问题

很多ce下流式驱动的xxx_Read和xxx_Write都留空而把相应的代码放在xxx_IOCtrol中,这只是因为习惯问题还是因为ReadFile之类调用会先经过文件系统层然后再转给设备管理层没有DeviceIoControl直接通过设备管理层效率高??…

查看全部问答>

scanf()函数的疑惑

void change(char data *pr,char data *pt); //c主程序声明 void main(void) {        char data *a,*b,x,y;        //定义使用变量         //设定串口的数据传输 ...…

查看全部问答>

请教一个关于VxWorks启动的问题

本人是通过dos加载vxload再加载bootrom然后从网络下载VxWorks启动 但由于重装了系统,从新制作了bootrom,出现了一个怪问题 启动时总是到loading完vxworks后,显示 starting at 0x1008000....然后就停在那了,不知哪位高手指点一下,看哪出了问 ...…

查看全部问答>

网络开发笔记_开发平台

1、BSD TCP/IP协议栈        BSD栈历史上是其他商业栈的起点,大多数专业TCP/IP栈(VxWorks内嵌的TCP/IP 栈)是BSD栈派生的。这是 因为BSD栈在BSD许可协议下提供了这些专业栈的雏形,BSD许用证允许BSD栈以修改或未 ...…

查看全部问答>

LM3S8962学习笔记1——快速了解LM3S8962微处理器

快速了解LM3S8962微处理器 自从脱离了汇编时代,人们学习微控器的方法就发生了重大的改变,以前必须了解微控器内部每个寄存器的地址控制方式和指令等,必须深入挖掘控制器内部的角角落落才能算是了解掌握。 但是C的出现,让我们不必去弄清繁杂的 ...…

查看全部问答>

用PLL产生反向时钟有问题

在Altera的FPGA里用了一个PLL,希望产生一个相位差为180度的时钟,就是和原来的时钟反向,但发现出来的时钟和原时钟相位不是我期望的180度。那位知道该怎么办呢 ?…

查看全部问答>

有关库问题

                                 本人以前用PIC或51芯片的C语言做程序,都是一般自己写。但现在刚接触到ST的资料,见很多人都是用库来做写程序。由 ...…

查看全部问答>

stm8S原理图

请问这个几号与几号口连一起??…

查看全部问答>