在嵌入式系統的設計中,低功耗設計(Low-Power Design)是許多設計人員必須面對的問題,其原因在于嵌入式系統被廣泛應用于便攜式和移動性較強的產品中去,而這些產品不是一直都有充足的電源供應,往往是靠電池來供電,所以設計人員從每一個細節來考慮降低功率消耗,從而盡可能地延長電池使用時間。因此,大部分芯片都會有低功耗模式,以CW32L083為例,它就是一個32位低功耗微控制器。
一、芯片模式介紹
1.CW32L083工作模式
CW32L083 支持三種工作模式,由內嵌的電源管理模塊自動完成電源的統一管理。三種工作模式是:
? 休眠模式(Sleep mode)
? 深度休眠模式(DeepSleep mode)
電源上電后,系統自動進入運行模式。用戶可通過軟件程序,進入休眠或深度休眠兩種低功耗運行狀態;在低功耗運行狀態時,可通過硬件中斷觸發喚醒機制,使系統返回到運行模式。
2.進入休眠模式或深度休眠模式
使用 M0+ 內核的 ARM 等待中斷專用指令,WFI(Wait for Interrupt),配合 M0+ 內核的系統控制寄存器(SCR, System Control Register)的 SLEEPONEXIT 和 SLEEPDEEP 位域,可實現立即進入或退出(中斷服務程序)時進 入休眠模式或深度休眠模式。
? 立即進入
執行 WFI 指令,MCU 將立即進入休眠模式(SLEEPDEEP 為 0 時)或深度休眠模式(SLEEPDEEP 為 1 時)
? 退出時進入
將 SLEEPONEXIT 位置 1,當退出最低優先級的中斷服務程序后,MCU 會進入休眠模式(SLEEPDEEP 為 0 時) 或深度休眠模式(SLEEPDEEP 為 1 時),而不需執行 WFI 指令 。
在深度休眠模式下,系統將自動關閉高速時鐘。如用戶需要在深度休眠模式下使部分外設仍保持運行,則須在進入深度休眠模式前,啟動相應的低速時鐘并將該外設時鐘設置為此低速時鐘。
3.退出休眠模式或深度休眠模式
在休眠模式或深度休眠模式下,均可通過中斷來喚醒 CPU,返回到運行模式。但是,值得注意的是,如果用戶在中斷服務程序中執行 WFI 命令進入休眠(包括深度休眠),則需要比此中斷更高優先級的中斷才能喚醒 CPU,因此,我們強烈建議用戶在準備進入休眠前,應先處理完所有中斷服務程序,并且清除所有中斷請求和中斷標志。
使用中斷退出休眠模式,用戶必須在進入休眠(包括深度休眠)前使能此中斷的允許位。
中斷喚醒退出深度休眠模式時,CPU 運行狀態與退出休眠模式相同。
4.UART控制深度休眠模式
UART控制器工作在雙時鐘域下,支持在深度休眠模式下進行正常的數據收發,并通過接收完成中斷喚醒 MCU回到運行模式。
如果設置了傳輸時鐘 UCLK來源為低速時鐘,當系統進入深度休眠模式后,高速時鐘將停止,低速時鐘保持運行,UART仍可以進行正常的數據收發(波特率僅支持 2400 bps、4800 bps 和 9600 bps)。 要實現深度休眠模式下使用 UART 喚醒功能,需在進入深度休眠模式之前使能 UART 接收完成中斷(即設置 UARTx_IER.RC 為 1),數據接收完成時,接收完成中斷將喚醒MCU恢復到運行模式。
如果設置了傳輸時鐘 UCLK 來源為高速時鐘,當系統進入深度休眠模式后,高速時鐘會停止運行,UAR不會接收數據。此時,仍可通過GPIO中斷喚醒 MCU,實現在深度休眠模式下接收數據,參考配置步驟如下:
步驟 1:使能 UARTx_RXD 對應引腳的 GPIO 下降沿中斷;
步驟 2:設置 UARTx_CR1.START 為 1,選擇 RXD 信號起始位判定方式為低電平;
步驟 3:使能 UART 接收(即設置 UARTx_CR1.RXEN 為 1);
步驟 4:進入深度休眠模式;
步驟 5:等待主機發送數據,產生 GPIO 下降沿中斷,喚醒 MCU;
步驟 6:關閉 RXD 對應引腳的 GPIO 中斷功能,等待 RXD 接收完成。
二、實例演示
UART深度休眠模式示例(傳輸時鐘為LSI)
程序運行一段時間后進入深度休眠模式,PC發送數據可喚醒MCU,喚醒后UART輪詢接收數據,并存儲到TxRxBuffer緩沖區,UART接收到'n'后不再接收數據,然后將TxRxBuffer緩沖區中的數據回傳至PC。傳輸結束后,LED1閃爍5s,并再次進入深度休眠模式。
1.外設時鐘使能
void RCC_Configuration(void)
{
InitTick(8000000); //復位后延時
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); //外設時鐘使能
}
2.配置GPIO
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
DEBUG_UART_AFTX; //UART TX RX 復用
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; // 傳輸時鐘源LSI
UART_InitStructure.UART_UclkFreq = UARTyz_UclkFreq; // 傳輸時鐘UCLK頻率
UART_InitStructure.UART_StartBit = UART_StartBit_FE; // 起始位判定方式
UART_InitStructure.UART_StopBits = UART_StopBits_1; // 停止位長度
UART_InitStructure.UART_Parity = UART_Parity_No ; // 校驗方式
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; // 發送/接收使能
UART_Init(DEBUG_UARTx, &UART_InitStructure);
}
4.配置低功耗模式
void PWR_Configuration(void)
{
PWR_InitTypeDef PWR_InitStructure = {0};//低功耗模式配置結構體指針
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)//進入睡眠模式
{
__WFI();
}
5.配置NVIC中斷
void NVIC_Configuration(void)
{
NVIC_SetPriority(DEBUG_UART_IRQ, 0); //優先級,無優先級分組
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.發送8位數組
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位數組
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喚醒時,保持原系統時鐘來源
UART_SendString(DEBUG_UARTx, "rnCW32L083 UART DeepSleep mode LSE/LSIrn");
while(1)
{
//進入深度休眠模式
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中斷
//喚醒后輪詢收發
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.測試結果
結果顯示,通過PC發送123456后喚醒MCU, 喚醒后UART輪詢接收數據,并存儲到TxRxBuffer緩沖區,UART接收到'n'后不再接收數據,然后將TxRxBuffer緩沖區中的數據回傳至PC收到123456。傳輸結束后,LED1閃爍5s,并再次進入深度休眠模式。
-
嵌入式
+關注
關注
5189文章
20192瀏覽量
329552 -
uart
+關注
關注
22文章
1305瀏覽量
106186 -
CW32
+關注
關注
1文章
281瀏覽量
1691
發布評論請先 登錄

CW32 UART低功耗模式介紹
評論