前言
STM32常見的低功耗模式有三種:睡眠模式、STOP模式以及待機(jī)模式,STM32L系列還有其他低功耗模式。這里主要講的是STOP模式,STOP模式可以通過外部中斷或事件喚醒,但是不能通過串口中斷喚醒,因?yàn)榇谥袛啾旧聿皇峭獠恐袛啵敲慈绾尾拍軐?shí)現(xiàn)串口喚醒STOP模式呢?
因?yàn)槲疫@里只是為了做驗(yàn)證,為了快速驗(yàn)證,我也就沒有用RT-Thread的PM電源管理組件進(jìn)入STOP模式,感興趣的讀者可以用RT-Thread的電源管理組件去實(shí)現(xiàn)進(jìn)行STOP模式。
一、為什么要串口喚醒STOP模式?
想象一下,在某些場合,如果你有一個無線通信模塊(例如ESP8266、SIM800C)和STM32通過串口發(fā)送AT命令來對接服務(wù)器實(shí)現(xiàn)與服務(wù)器的數(shù)據(jù)交互,那么如果在沒有進(jìn)行數(shù)據(jù)交互的時候,我們是不是可以讓STM32進(jìn)入STOP模式來達(dá)到省電的狀態(tài),從而讓電池續(xù)航更長。例如:STM32+ESP8266與后臺服務(wù)器進(jìn)行數(shù)據(jù)交互,當(dāng)不用發(fā)送數(shù)據(jù)完畢,等待下次發(fā)送數(shù)據(jù)或等待后臺下發(fā)數(shù)據(jù)給設(shè)備的這段時間可以讓STM32進(jìn)入STOP模式來達(dá)到省電,當(dāng)后臺服務(wù)器下發(fā)數(shù)據(jù)給設(shè)備的時候,我們可以向讓后臺發(fā)送一個喚醒設(shè)備的指令,ESP8266接收到后臺的這條指令之后通過串口下發(fā)給STM32,那么就可以喚醒STM32了,這時候STM32就可以繼續(xù)接收后臺下發(fā)的數(shù)據(jù)。
二、串口喚醒STOP模式的思路
1、我們知道STOP模式只能外部中斷或事件喚醒,那么想象一下,在STM32進(jìn)行STOP模式之前,是不是可以先將UART_RX對應(yīng)的GPIO引腳配置為外部中斷引腳,而串口接收到字符相當(dāng)于接收到01010…這樣的高低電平,從二可以喚醒串口,當(dāng)喚醒之后,我們再馬上重新初始化串口,把UART_RX對應(yīng)的GPIO引腳配置為接收中斷模式?答案當(dāng)然是可以的。
2、喚醒之后的程序是從哪里開始執(zhí)行?答案是從進(jìn)行STOP模式之前的那個地方重新開始執(zhí)行,一會進(jìn)行驗(yàn)證。
三、串口喚醒STOP模式實(shí)驗(yàn)
光說不練都是假把式,接下來進(jìn)行實(shí)驗(yàn)。
1、 實(shí)驗(yàn)平臺: 中國移動物聯(lián)網(wǎng)OneNET NB開發(fā)板(板載STM32)。
2、STM32F103RET6、12M外部晶振、串口3進(jìn)行實(shí)驗(yàn)。
3、 操作系統(tǒng): RT-Thread。
4、用RT-Thread創(chuàng)建兩個線程,一個線程用于讀取按鍵是否按下,按下則調(diào)用進(jìn)入STOP模式函數(shù)進(jìn)入STOP模式,另一個線程讀取串口接收到的數(shù)據(jù)。
1、如何進(jìn)行STOP模式?
實(shí)驗(yàn)時用的是標(biāo)準(zhǔn)庫,在這里主要實(shí)現(xiàn)在進(jìn)入STOP模式前將RX對應(yīng)的GPIO引腳配置為外部中斷模式以及進(jìn)入STOP模式,代碼如下:
1/**************************************************************
2函數(shù)名稱:system_enter_stop
3函數(shù)功能:系統(tǒng)進(jìn)入STOP模式
4輸入參數(shù):無
5返 回 值:無
6備 注:無
7**************************************************************/
8void system_enter_stop(void)
9{
10 uart_exti_init(); /* 進(jìn)入STOP模式前配置RX引腳為外部中斷模式 */
11 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE); /* 開電源管理時鐘 */
12 //PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI); /* 進(jìn)入STOP模式,外部中斷喚醒 */
13 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); /* 進(jìn)入STOP模式,外部中斷或事件喚醒 */
14}
2、配置RX對應(yīng)的GPIO引腳為外部中斷模式
這里采用RT-Thread的PIN設(shè)備進(jìn)行配置,在配置之前需要先關(guān)閉UART中斷、復(fù)位UART、復(fù)位GPIO,然后在進(jìn)行配置為外部中斷模式,代碼如下:
1/**************************************************************
2函數(shù)名稱:uart_exti_init
3函數(shù)功能:RX引腳配置為外部中斷
4輸入?yún)?shù):無
5返 回 值:無
6備 注:無
7**************************************************************/
8void uart_exti_init(void)
9{
10 /* 關(guān)閉UART中斷、復(fù)位UART、復(fù)位GPIO */
11 USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
12 USART_Cmd(USART3, DISABLE);
13 GPIO_DeInit(GPIOB);
14 USART_DeInit(USART3);
15
16 /* 配置RX對應(yīng)的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、接收中斷回調(diào)函數(shù)
在上面的配置中,有一個接收回調(diào)函數(shù)uart_exti_callback
,就是在發(fā)送中斷的時候要執(zhí)行的事情,在接收回調(diào)函數(shù)里面,我們主要實(shí)現(xiàn)SystemInit,重新初始化串口,代碼如下:
1/**************************************************************
2函數(shù)名稱:uart_exti_callback
3函數(shù)功能:RX引腳外部中斷喚醒回調(diào)函數(shù)
4輸入?yún)?shù):args:回調(diào)函數(shù)入口參數(shù)
5返 回 值:無
6備 注:無
7**************************************************************/
8void uart_exti_callback(void *args)
9{
10 SystemInit();
11 uart_reinit(); /* 重新初始化串口 */
12 rt_kprintf("wake up\\r\\n");
13
14}
4、進(jìn)入STOP模式的線程
這里,創(chuàng)建一個線程來實(shí)現(xiàn)判斷是否按鍵按下,按下則調(diào)用system_enter_stop
函數(shù)進(jìn)入STOP模式,同時為了驗(yàn)證喚醒之后時鐘正常以及程序是從進(jìn)行STOP模式之前的那個地方重新開始執(zhí)行,我們設(shè)計(jì)LED燈500ms亮500ms滅,再一個計(jì)數(shù)變量,每隔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);
9
10 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、實(shí)驗(yàn)操作和現(xiàn)象
1、開機(jī)之后,LED閃爍,串口打印count每隔1秒加1的值,等待一小會按下按鍵KEY4進(jìn)入STOP模式:
FinSH抓取的串口打印信息
2、對比進(jìn)入STOP模式前和STOP模式之后的電流情況(這里進(jìn)入STOP模式之后電流還是很大是因?yàn)槲覀儼遄舆€接了其他耗電的模塊,我們這對比電流有沒有降下來就可以了),很明顯,電流降下來了:
進(jìn)入STOP模式前的電流
進(jìn)入STOP模式后的電流
3、通過串口發(fā)送一個字符“A”,喚醒了STM32,這時候串口并不會打印字符“A”,因?yàn)閱拘阎笠匦鲁跏蓟冢诙伟l(fā)送字符“A”才能顯示,這時候,我們觀察FinSH打印出來的信息,可以看到count是從9開始打印,說明STOP喚醒之后會從原來進(jìn)入STOP模式之前的地方重新執(zhí)行代碼:
驗(yàn)證代碼的執(zhí)行情況
喚醒之后第二次發(fā)一個字符能正常打印
4、接下來,我們再次按下KEY4重新然STM32進(jìn)入STO模式,然后發(fā)送一個比較長的字符串來喚醒STM32,例如發(fā)“ABCDEFGHIJKLMNOPQ1234567890”
,這時候,我們發(fā)現(xiàn)第一次發(fā)送之后,竟然會有字符出來,不是說沒有嗎?而且這些字符和我們發(fā)送的不一樣,少了,第二次才正常:
喚醒之后打印字符不正常
四、串口喚醒存在的問題
1、上面我們提到,發(fā)送一個字符喚醒就很正常,而發(fā)送比較長的字符串喚醒卻出現(xiàn)了不然正常的現(xiàn)象,這是為什么呢?想象一下m如果你是發(fā)一串很長的數(shù)據(jù)來喚醒串口,這串?dāng)?shù)據(jù)也是通過0101010等二進(jìn)制來發(fā)送的,當(dāng)RX引腳被觸發(fā)中斷喚醒MCU之后,喚醒之后串口初始化完成了,剩余的數(shù)據(jù)也就會接著以010101的高低電平發(fā)給STM32的串口,有可能導(dǎo)致有些字符的01丟失了一部分(例如上面出現(xiàn)了K567890),從而可以接下來的字符會打印出來。如果是發(fā)一個字符,一個字符的01010101其實(shí)也就8位,發(fā)送很快的,喚醒之后都已經(jīng)發(fā)送結(jié)束了,所以就會直接喚醒,也就不會接收這個字符,只有第二次發(fā)送的時候才會接收到這個字符。
-
電源管理
+關(guān)注
關(guān)注
115文章
6192瀏覽量
144774 -
STM32
+關(guān)注
關(guān)注
2270文章
10923瀏覽量
357035 -
GPIO
+關(guān)注
關(guān)注
16文章
1216瀏覽量
52274 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1305瀏覽量
40303 -
ESP8266
+關(guān)注
關(guān)注
50文章
962瀏覽量
45246
發(fā)布評論請先 登錄
相關(guān)推薦
評論