在嵌入式系統(tǒng)的設(shè)計(jì)中,低功耗設(shè)計(jì)(Low-Power Design)是許多設(shè)計(jì)人員必須面對的問題,其原因在于嵌入式系統(tǒng)被廣泛應(yīng)用于便攜式和移動(dòng)性較強(qiáng)的產(chǎn)品中去,而這些產(chǎn)品不是一直都有充足的電源供應(yīng),往往是靠電池來供電,所以設(shè)計(jì)人員從每一個(gè)細(xì)節(jié)來考慮降低功率消耗,從而盡可能地延長電池使用時(shí)間。因此,大部分芯片都會(huì)有低功耗模式,以CW32L083為例,它就是一個(gè)32位低功耗微控制器。
一、芯片模式介紹
1.CW32L083工作模式
CW32L083 支持三種工作模式,由內(nèi)嵌的電源管理模塊自動(dòng)完成電源的統(tǒng)一管理。三種工作模式是:
? 休眠模式(Sleep mode)
? 深度休眠模式(DeepSleep mode)
電源上電后,系統(tǒng)自動(dòng)進(jìn)入運(yùn)行模式。用戶可通過軟件程序,進(jìn)入休眠或深度休眠兩種低功耗運(yùn)行狀態(tài);在低功耗運(yùn)行狀態(tài)時(shí),可通過硬件中斷觸發(fā)喚醒機(jī)制,使系統(tǒng)返回到運(yùn)行模式。
2.進(jìn)入休眠模式或深度休眠模式
使用 M0+ 內(nèi)核的 ARM 等待中斷專用指令,WFI(Wait for Interrupt),配合 M0+ 內(nèi)核的系統(tǒng)控制寄存器(SCR, System Control Register)的 SLEEPONEXIT 和 SLEEPDEEP 位域,可實(shí)現(xiàn)立即進(jìn)入或退出(中斷服務(wù)程序)時(shí)進(jìn) 入休眠模式或深度休眠模式。
? 立即進(jìn)入
執(zhí)行 WFI 指令,MCU 將立即進(jìn)入休眠模式(SLEEPDEEP 為 0 時(shí))或深度休眠模式(SLEEPDEEP 為 1 時(shí))
? 退出時(shí)進(jìn)入
將 SLEEPONEXIT 位置 1,當(dāng)退出最低優(yōu)先級的中斷服務(wù)程序后,MCU 會(huì)進(jìn)入休眠模式(SLEEPDEEP 為 0 時(shí)) 或深度休眠模式(SLEEPDEEP 為 1 時(shí)),而不需執(zhí)行 WFI 指令 。
在深度休眠模式下,系統(tǒng)將自動(dòng)關(guān)閉高速時(shí)鐘。如用戶需要在深度休眠模式下使部分外設(shè)仍保持運(yùn)行,則須在進(jìn)入深度休眠模式前,啟動(dòng)相應(yīng)的低速時(shí)鐘并將該外設(shè)時(shí)鐘設(shè)置為此低速時(shí)鐘。
3.退出休眠模式或深度休眠模式
在休眠模式或深度休眠模式下,均可通過中斷來喚醒 CPU,返回到運(yùn)行模式。但是,值得注意的是,如果用戶在中斷服務(wù)程序中執(zhí)行 WFI 命令進(jìn)入休眠(包括深度休眠),則需要比此中斷更高優(yōu)先級的中斷才能喚醒 CPU,因此,我們強(qiáng)烈建議用戶在準(zhǔn)備進(jìn)入休眠前,應(yīng)先處理完所有中斷服務(wù)程序,并且清除所有中斷請求和中斷標(biāo)志。
使用中斷退出休眠模式,用戶必須在進(jìn)入休眠(包括深度休眠)前使能此中斷的允許位。
中斷喚醒退出深度休眠模式時(shí),CPU 運(yùn)行狀態(tài)與退出休眠模式相同。
4.UART控制深度休眠模式
UART控制器工作在雙時(shí)鐘域下,支持在深度休眠模式下進(jìn)行正常的數(shù)據(jù)收發(fā),并通過接收完成中斷喚醒 MCU回到運(yùn)行模式。
如果設(shè)置了傳輸時(shí)鐘 UCLK來源為低速時(shí)鐘,當(dāng)系統(tǒng)進(jìn)入深度休眠模式后,高速時(shí)鐘將停止,低速時(shí)鐘保持運(yùn)行,UART仍可以進(jìn)行正常的數(shù)據(jù)收發(fā)(波特率僅支持 2400 bps、4800 bps 和 9600 bps)。 要實(shí)現(xiàn)深度休眠模式下使用 UART 喚醒功能,需在進(jìn)入深度休眠模式之前使能 UART 接收完成中斷(即設(shè)置 UARTx_IER.RC 為 1),數(shù)據(jù)接收完成時(shí),接收完成中斷將喚醒MCU恢復(fù)到運(yùn)行模式。
如果設(shè)置了傳輸時(shí)鐘 UCLK 來源為高速時(shí)鐘,當(dāng)系統(tǒng)進(jìn)入深度休眠模式后,高速時(shí)鐘會(huì)停止運(yùn)行,UAR不會(huì)接收數(shù)據(jù)。此時(shí),仍可通過GPIO中斷喚醒 MCU,實(shí)現(xiàn)在深度休眠模式下接收數(shù)據(jù),參考配置步驟如下:
步驟 1:使能 UARTx_RXD 對應(yīng)引腳的 GPIO 下降沿中斷;
步驟 2:設(shè)置 UARTx_CR1.START 為 1,選擇 RXD 信號起始位判定方式為低電平;
步驟 3:使能 UART 接收(即設(shè)置 UARTx_CR1.RXEN 為 1);
步驟 4:進(jìn)入深度休眠模式;
步驟 5:等待主機(jī)發(fā)送數(shù)據(jù),產(chǎn)生 GPIO 下降沿中斷,喚醒 MCU;
步驟 6:關(guān)閉 RXD 對應(yīng)引腳的 GPIO 中斷功能,等待 RXD 接收完成。
二、實(shí)例演示
UART深度休眠模式示例(傳輸時(shí)鐘為LSI)
程序運(yùn)行一段時(shí)間后進(jìn)入深度休眠模式,PC發(fā)送數(shù)據(jù)可喚醒MCU,喚醒后UART輪詢接收數(shù)據(jù),并存儲(chǔ)到TxRxBuffer緩沖區(qū),UART接收到'n'后不再接收數(shù)據(jù),然后將TxRxBuffer緩沖區(qū)中的數(shù)據(jù)回傳至PC。傳輸結(jié)束后,LED1閃爍5s,并再次進(jìn)入深度休眠模式。
1.外設(shè)時(shí)鐘使能
void RCC_Configuration(void) { InitTick(8000000); //復(fù)位后延時(shí) SysTickDelay(1000); RCC_HSI_Enable(RCC_HSIOSC_DIV6); //SYSCLK = HSI = 8MHz = HCLK = PCLK RCC_LSI_Enable(); RCC_AHBPeriphClk_Enable(DEBUG_UART_GPIO_CLK | RCC_AHB_PERIPH_GPIOC, ENABLE); DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE); //外設(shè)時(shí)鐘使能 }
2.配置GPIO
void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; DEBUG_UART_AFTX; //UART TX RX 復(fù)用 DEBUG_UART_AFRX; GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN; GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP; GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pins = GPIO_PIN_3; //PC3 LED1 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(CW_GPIOC, &GPIO_InitStructure); PC03_SETLOW(); }
3.配置UART
void UART_Configuration(void) { UART_InitTypeDef UART_InitStructure = {0}; UART_InitStructure.UART_BaudRate = UARTyz_BaudRate; // 波特率 UART_InitStructure.UART_Over = UART_Over_sp; // 專用采樣 UART_InitStructure.UART_Source = UART_Source_LSI; // 傳輸時(shí)鐘源LSI UART_InitStructure.UART_UclkFreq = UARTyz_UclkFreq; // 傳輸時(shí)鐘UCLK頻率 UART_InitStructure.UART_StartBit = UART_StartBit_FE; // 起始位判定方式 UART_InitStructure.UART_StopBits = UART_StopBits_1; // 停止位長度 UART_InitStructure.UART_Parity = UART_Parity_No ; // 校驗(yàn)方式 UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; // 發(fā)送/接收使能 UART_Init(DEBUG_UARTx, &UART_InitStructure); }
4.配置低功耗模式
void PWR_Configuration(void) { PWR_InitTypeDef PWR_InitStructure = {0};//低功耗模式配置結(jié)構(gòu)體指針 PWR_InitStructure.PWR_Sevonpend = PWR_Sevonpend_Disable; PWR_InitStructure.PWR_SleepDeep = PWR_SleepDeep_Enable; //Deep Sleep使能 PWR_InitStructure.PWR_SleepOnExit = PWR_SleepOnExit_Disable; PWR_Config(&PWR_InitStructure);// 低功耗模式配置 } void PWR_GotoLpmMode(void)//進(jìn)入睡眠模式 { __WFI(); }
5.配置NVIC中斷
void NVIC_Configuration(void) { NVIC_SetPriority(DEBUG_UART_IRQ, 0); //優(yōu)先級,無優(yōu)先級分組 NVIC_EnableIRQ(DEBUG_UART_IRQ); //UARTx中斷使能 } void UART2_UART5_IRQHandler(void) { if(UART_GetITStatus(CW_UART5, UART_IT_RC) != RESET) { UART_ClearITPendingBit(CW_UART5, UART_IT_RC); } }
6.發(fā)送8位數(shù)組
void UART_SendBuf_Polling(UART_TypeDef* UARTx, uint8_t *TxBuf, uint8_t TxCnt) { while(TxCnt) { UART_SendData_8bit(UARTx, *TxBuf); while(UART_GetFlagStatus(UARTx, UART_FLAG_TXE) == RESET); TxBuf++; TxCnt--; } while(UART_GetFlagStatus(UARTx, UART_FLAG_TXBUSY) == SET); }
7.接收8位數(shù)組
uint8_t UART_RecvBuf_Polling(UART_TypeDef* UARTx, uint8_t *RxBuf) { uint8_t RxCnt = 0; RxBuf[RxCnt] = UART_ReceiveData_8bit(UARTx); RxCnt++; do { while(UART_GetFlagStatus(UARTx, UART_FLAG_RC) == RESET); //等待RC UART_ClearFlag(UARTx, UART_FLAG_RC); //清RC if(UART_GetFlagStatus(UARTx, UART_FLAG_PE|UART_FLAG_FE)) //ERROR: PE or FE { UART_ClearFlag(UARTx, UART_FLAG_PE|UART_FLAG_FE); RxCnt = 0x00; } else { RxBuf[RxCnt] = UART_ReceiveData_8bit(UARTx); RxCnt++; } } while(RxBuf[RxCnt-1] != 'n'); return RxCnt; }
8.主程序
int32_t main(void) { RCC_Configuration();//配置RCC GPIO_Configuration();//配置GPIO UART_Configuration();//配置UART PWR_Configuration();//配置低功耗模式 NVIC_Configuration();//配置NVIC InitTick(HCLKFREQ); //初始化SysTick RCC_WAKEUPCLK_Config(RCC_SYSCTRL_WAKEUPCLKDIS); //DeepSleep喚醒時(shí),保持原系統(tǒng)時(shí)鐘來源 UART_SendString(DEBUG_UARTx, "rnCW32L083 UART DeepSleep mode LSE/LSIrn"); while(1) { //進(jìn)入深度休眠模式 UART_SendString(DEBUG_UARTx, "rnEnter DeepSleep modern"); UART_SendString(DEBUG_UARTx, "rnPC send data to wake up MCUrn"); UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE); //使能UARTx RC中斷 PWR_GotoLpmMode(); UART_ITConfig(CW_UART5, UART_IT_RC, DISABLE); //失能UARTx RC中斷 //喚醒后輪詢收發(fā) TxRxBufferSize = UART_RecvBuf_Polling(DEBUG_UARTx, TxRxBuffer); UART_SendBuf_Polling(DEBUG_UARTx, TxRxBuffer, TxRxBufferSize); for(int i = 0; i10; i++) //閃燈 { PC03_TOG(); SysTickDelay(500); } } }
9.測試結(jié)果
結(jié)果顯示,通過PC發(fā)送123456后喚醒MCU, 喚醒后UART輪詢接收數(shù)據(jù),并存儲(chǔ)到TxRxBuffer緩沖區(qū),UART接收到'n'后不再接收數(shù)據(jù),然后將TxRxBuffer緩沖區(qū)中的數(shù)據(jù)回傳至PC收到123456。傳輸結(jié)束后,LED1閃爍5s,并再次進(jìn)入深度休眠模式。
-
嵌入式
+關(guān)注
關(guān)注
5174文章
19973瀏覽量
324335 -
uart
+關(guān)注
關(guān)注
22文章
1286瀏覽量
105506 -
CW32
+關(guān)注
關(guān)注
1文章
278瀏覽量
1542
發(fā)布評論請先 登錄
【應(yīng)用筆記】CW32 自舉程序中使用的 ISP 協(xié)議
基于低功耗32位MCU CW32系列的智能溫控器的應(yīng)用
CW32為表計(jì)數(shù)智化助力,現(xiàn)身青島環(huán)球表計(jì)大會(huì)
CW32單片機(jī)在智能馬桶的應(yīng)用介紹
基于低功耗32位MCU CW32系列的智能溫控器的應(yīng)用

評論