




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
尚硅谷嵌入式技術(shù)之STM32單片機(jī)(尚硅谷研究院)版本:V1.0電源控制電源控制(PWR:PowerControl)。電源對(duì)電子設(shè)備來(lái)說(shuō)非常重要,它是保證系統(tǒng)穩(wěn)定運(yùn)行的基礎(chǔ)。在保證系統(tǒng)能穩(wěn)定運(yùn)行的同時(shí),對(duì)嵌入式設(shè)備一般又有低功耗的需求。在一些應(yīng)用場(chǎng)合中,對(duì)電子設(shè)備的功耗要求非??量?,如某些傳感器信息采集設(shè)備,僅靠小型的電池提供電源,要求工作長(zhǎng)達(dá)數(shù)年之久,且期間不需要任何維護(hù);由于智慧穿戴設(shè)備的小型化要求,電池體積不能太大導(dǎo)致容量也比較小,所以也很有必要從控制功耗入手,提高設(shè)備的續(xù)行時(shí)間。鑒于低功耗的需求,STM32有專門(mén)的電源管理外設(shè)監(jiān)控電源并管理設(shè)備的運(yùn)行式,確保系統(tǒng)正常運(yùn)行,并盡量降低器件的功耗。電源框圖VDDA供電區(qū)域主要負(fù)責(zé)模擬部分的供電。為了提高轉(zhuǎn)換的精確度,ADC使用一個(gè)獨(dú)立的電源供電,過(guò)濾和屏蔽來(lái)自印刷電路板上的毛刺干擾。主要給A/D轉(zhuǎn)換器,溫度傳感器,復(fù)位模塊,PLL等供電。VDDA是正極,VSSA是負(fù)極。VREF+和VREF是A/D轉(zhuǎn)換器的參考電壓,VREF必須接到VSSA上。對(duì)引腳比較少的芯片,沒(méi)有VREF+和VREF引腳,他們?cè)谛酒瑑?nèi)部與ADC的電源(VDDA)和地(VSSA)相聯(lián)。VDD供電區(qū)域VDD是數(shù)字電的正極,VSS是數(shù)字電的負(fù)極,電壓3.3V。給I/O電路,待機(jī)電路和電壓調(diào)節(jié)器供電。1.8V低電壓區(qū)域從這里可以看出,CPU核心,內(nèi)部存儲(chǔ)器,內(nèi)置的數(shù)字外設(shè)都是工作在1.8V的電壓。1.8V的低電壓是由從電壓調(diào)節(jié)器得到的。后備供電區(qū)域VBAT引腳會(huì)接電池和其他電源,當(dāng)VDD斷電時(shí),可以保存?zhèn)浞菁拇嫫鞯膬?nèi)容和給RTC供電。VBAT腳也為RTC、LSE振蕩器和PC13至PC15供電,這保證當(dāng)主要電源被切斷時(shí)RTC能繼續(xù)工作。切換到VBAT供電由復(fù)位模塊中的掉電復(fù)位功能控制。如果應(yīng)用中沒(méi)有使用外部電池,VBAT必須連接到VDD引腳上。電壓調(diào)節(jié)器復(fù)位后,電壓調(diào)節(jié)器總是工作使能的。有3種不同的工作模式:運(yùn)轉(zhuǎn)模式:調(diào)節(jié)器以正常功耗模式提供1.8V電源(內(nèi)核,內(nèi)存和外設(shè))。停止模式:調(diào)節(jié)器以低功耗模式提供1.8V電源,用于保存寄存器和SRAM的內(nèi)容。待機(jī)模式:調(diào)節(jié)器停止供電。除了備用電路和備份域外,寄存器和SRAM的內(nèi)容全部丟失上電復(fù)位和掉電復(fù)位當(dāng)VDD/VDDA低于指定的限位電壓VPOR/VPDR時(shí),系統(tǒng)保持為復(fù)位狀態(tài),而無(wú)需外部復(fù)位電路。復(fù)位和解除復(fù)位有一個(gè)40mv的遲滯電壓。當(dāng)電壓大于VPOR時(shí)解除復(fù)位,當(dāng)電壓小于VPDR時(shí)進(jìn)入復(fù)位。設(shè)置2個(gè)閾值的作用是當(dāng)電壓在附近抖動(dòng)的時(shí)候防止頻繁的復(fù)位和解除復(fù)位??删幊屉妷簷z測(cè)器(PVD)PVD(Programmablevoltagedetector)。PVD也是監(jiān)測(cè)VDD/VDDA的供電電壓,它的閾值電壓可以編程。用戶可以利用PVD對(duì)VDD電壓與電源控制寄存器(PWR_CR)中的PLS[2:0]位進(jìn)行比較來(lái)監(jiān)控電源。當(dāng)電壓達(dá)到閾值的時(shí)候,不是產(chǎn)生復(fù)位,而是產(chǎn)生中斷??梢栽谥袛囗憫?yīng)函數(shù)內(nèi)做一些緊急處理。低功耗在系統(tǒng)或電源復(fù)位以后,微控制器處于運(yùn)行狀態(tài)。當(dāng)CPU不需繼續(xù)運(yùn)行時(shí),可以利用多種低功耗模式來(lái)節(jié)省功耗,例如等待某個(gè)外部事件時(shí)。用戶需要根據(jù)最低電源消耗、最快速啟動(dòng)時(shí)間和可用的喚醒源等條件,選定一個(gè)最佳的低功耗模式。STM32F10xxx有三種低功耗模式:睡眠模式進(jìn)入睡眠模式通過(guò)執(zhí)行WFI(WaitforInterrupt)或WFE(WaitforEvent)指令進(jìn)入睡眠狀態(tài)。根據(jù)Cortex?M3系統(tǒng)控制寄存器中的SLEEPONEXIT位的值,有兩種選項(xiàng)可用于選擇睡眠模式進(jìn)入機(jī)制:SLEEPNOW:如果SLEEPONEXIT位被清除,當(dāng)WRI或WFE被執(zhí)行時(shí),微制器立即進(jìn)入睡眠模式。SLEEPONEXIT:如果SLEEPONEXIT位被置位,系統(tǒng)從最低優(yōu)先級(jí)的中斷處理程序中退出時(shí),微控制器就立即進(jìn)入睡眠模式。注意:在睡眠模式下,所有的I/O引腳都保持它們?cè)谶\(yùn)行時(shí)的狀態(tài)。退出睡眠模式如果執(zhí)行WFI指令進(jìn)入睡眠模式,任意一個(gè)被嵌套向量中斷控制器響應(yīng)的外設(shè)中斷都能將系統(tǒng)從睡眠模式喚醒。如果執(zhí)行WFE指令進(jìn)入睡眠模式,則一旦發(fā)生喚醒事件時(shí),微處理器都將從睡眠模式退出。停機(jī)(停止)模式停止模式是在Cortex?M3的深睡眠模式基礎(chǔ)上結(jié)合了外設(shè)的時(shí)鐘控制機(jī)制,在停止模式下電壓調(diào)節(jié)器可運(yùn)行在正?;虻凸哪J?。此時(shí)在1.8V供電區(qū)域的的所有時(shí)鐘都被停止,PLL、HSI和HSERC振蕩器的功能被禁止,SRAM和寄存器內(nèi)容被保留下來(lái)。注意:在停止模式下,所有的I/O引腳都保持它們?cè)谶\(yùn)行模式時(shí)的狀態(tài)。進(jìn)入停止模式在停止模式下,通過(guò)設(shè)置電源控制寄存器(PWR_CR)的LPDS位使內(nèi)部調(diào)節(jié)器進(jìn)入低功耗模式,能夠降低更多的功耗。如果正在進(jìn)行閃存編程,直到對(duì)內(nèi)存訪問(wèn)完成,系統(tǒng)才進(jìn)入停止模式。如果正在進(jìn)行對(duì)APB的訪問(wèn),直到對(duì)APB訪問(wèn)完成,系統(tǒng)才進(jìn)入停止模式。退出停止模式待機(jī)模式待機(jī)模式可實(shí)現(xiàn)系統(tǒng)的最低功耗。該模式是在CortexM3深睡眠模式時(shí)關(guān)閉電壓調(diào)節(jié)器。整個(gè)1.8V供電區(qū)域被斷電。PLL、HSI和HSE振蕩器也被斷電。SRAM和寄存器內(nèi)容丟失。只有備份寄存器和待機(jī)電路維持供電。這么說(shuō)吧,能停的全停。注意:在待機(jī)模式下,所有的I/O引腳處于高阻態(tài),除了以下的引腳:復(fù)位引腳(始終有效)當(dāng)被設(shè)置為防侵入或校準(zhǔn)輸出時(shí)的TAMPER引腳被使能的喚醒引腳低功耗案例1:睡眠模式需求描述讓MCU進(jìn)入睡眠模式,然后通過(guò)串口發(fā)送消息來(lái)喚醒MCU退出睡眠模式。觀察LED在進(jìn)入休眠模式后是否仍然開(kāi)啟。軟件設(shè)計(jì)(寄存器)main.c#includestm32f10x.hstm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"voidenter_sleep_mode(void){
/*1.設(shè)置普通睡眠模式*/
SCB>SCR&=~SCB_SCR_SLEEPDEEP;
/*2.進(jìn)入睡眠模式,等待中斷喚醒*/
__WFI();}intmain(void){usart1_init();
LED_Init();
/*開(kāi)啟LED燈*/
LED_On();
Delay_s(3);
while(1)
{
printf("正常代碼執(zhí)行完畢,5s后進(jìn)入睡眠模式\r\n");
Delay_s(5);
printf("開(kāi)始睡眠\(yùn)r\n");
enter_sleep_mode();
Delay_s(1);
printf("從睡眠模式被喚醒...\r\n");
}}usart.h#ifndef__USART_H#define__USART_H#include"stm32f10x.h"#include"stdio.h"/*初始化串口1*/voidusart1_init(void);/*
通過(guò)串口1發(fā)送數(shù)據(jù):
參數(shù)1:要發(fā)送的數(shù)據(jù)
參數(shù)2:要發(fā)送的數(shù)據(jù)的長(zhǎng)度
*/voidsend_string(uint8_t*str,uint32_tlen);/*
從串口1接收一個(gè)字符
返回值:接收到的字符*/uint8_treceive_char(void);/*
向串口1發(fā)送一個(gè)字符*/voidsend_char(uint8_tc);intfputc(intch,FILE*f);#endifusart.c#include"usart.h"/*初始化串口1*/voidusart1_init(void){
/*1開(kāi)啟時(shí)鐘
1<<14=0x4000*/
/*1.1開(kāi)啟usart1時(shí)鐘*/
RCC>APB2ENR|=RCC_APB2ENR_USART1EN;
/*1.2開(kāi)啟GPIOA時(shí)鐘*/
RCC>APB2ENR|=RCC_APB2ENR_IOPAEN;
/*2配置引腳:PA9(Tx)和PA10(Rx)*/
/*2.1PA9配置為推挽輸出mode=11cnf=10*/
GPIOA>CRH|=(GPIO_CRH_MODE9|GPIO_CRH_CNF9_1);
/*2.2PA10配置為浮空輸入*/
GPIOA>CRH|=GPIO_CRH_CNF10_0;
/*3配置波特率為:*/
USART1>BRR=0x271;
/*4使能usart1的發(fā)送和接收*/
USART1>CR1|=(USART_CR1_TE|USART_CR1_RE);
/*5使能usart1接收中斷
*/
USART1>CR1|=USART_CR1_RXNEIE;
/*6.設(shè)置NVIC*/
NVIC_SetPriorityGrouping(4);
NVIC_SetPriority(USART1_IRQn,2);
NVIC_EnableIRQ(USART1_IRQn);
/*7使能usart1*/
USART1>CR1|=USART_CR1_UE;}/*
通過(guò)串口1發(fā)送數(shù)據(jù):
參數(shù)1:要發(fā)送的數(shù)據(jù)
參數(shù)2:要發(fā)送的數(shù)據(jù)的長(zhǎng)度
*/voidsend_string(uint8_t*str,uint32_tlen){
uint32_ti;
for(i=0;i<len;i++)
{
send_char(str[i]);
}}/*
從串口1接收一個(gè)字符
返回值:接收到的字符*/uint8_treceive_char(void){
/*等待接收緩沖區(qū)非空*/
while((USART1>SR&USART_SR_RXNE)==0)
{
}
returnUSART1>DR;}/*
向串口1發(fā)送一個(gè)字符*/voidsend_char(uint8_tc){
/*等待發(fā)送緩沖區(qū)為空。SR_TXE為1表示已經(jīng)移到移位寄存器,0表示還沒(méi)有*/
while((USART1>SR&USART_SR_TXE)==0)
{
}
/*把要發(fā)送的數(shù)據(jù)寫(xiě)入到數(shù)據(jù)寄存器*/
USART1>DR=c;}/*中斷服務(wù)函數(shù)*/voidUSART1_IRQHandler(void){
if(USART1>SR&USART_SR_RXNE)
{
/*獲取接收到的數(shù)據(jù):只取低8位*/
uint8_tc=USART1>DR&0xff;
/*回顯給上位機(jī)*/
send_char(c);
}
/*可以不用清除中斷標(biāo)志位,因?yàn)樽x取DR寄存器值的時(shí)候會(huì)自動(dòng)清零*/
//USART1>SR&=~USART_SR_RXNE;}/*
printf函數(shù)底層會(huì)調(diào)用fputc
重定向c庫(kù)函數(shù)printf到串口,重定向后可使用printf函數(shù)打印數(shù)據(jù)*/intfputc(intch,FILE*f){
send_char((uint8_t)ch);
return(ch);}LED.h#ifndef__LED_H#define__LED_H#include"stm32f10x.h"/*對(duì)led進(jìn)行初始化*/voidLED_Init(void);/*點(diǎn)亮led*/voidLED_On(void);/*熄滅led*/voidLED_Off(void);/*翻轉(zhuǎn)led的狀態(tài)*/voidLED_Toggle(void);#endifLED.c#include"LED.h"/*對(duì)led進(jìn)行初始化*/voidLED_Init(void){
/*1.使能GPIOA時(shí)鐘*/
RCC>APB2ENR|=RCC_APB2ENR_IOPAEN;//1<<2
/*2.設(shè)置PA0為通用推挽輸出,速度50MHzMODE=11CNF=00*/
GPIOA>CRL|=GPIO_CRL_MODE1;
GPIOA>CRL&=~GPIO_CRL_CNF1;}/*點(diǎn)亮led*/voidLED_On(void){
GPIOA>ODR&=~GPIO_ODR_ODR1;}/*熄滅led*/voidLED_Off(void){
GPIOA>ODR|=GPIO_ODR_ODR1;}/*翻轉(zhuǎn)led的狀態(tài)*/voidLED_Toggle(void){
if(GPIOA>IDR&GPIO_IDR_IDR1)
{
LED_On();
}
else
{
LED_Off();
}}測(cè)試軟件設(shè)計(jì)(HAL庫(kù))STM32CubeMX設(shè)置添加其他代碼uint8_tbuff[100];//串口收到數(shù)據(jù)的時(shí)候回調(diào)這個(gè)函數(shù)voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){
if(huart>Instance==USART1)
{
printf("%c",buff[0]);
HAL_UART_Receive_IT(&huart1,buff,1);//繼續(xù)接收
}}intmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/*USERCODEBEGIN2*/
printf("尚硅谷低功耗實(shí)驗(yàn):睡眠模式\r\n");
/*點(diǎn)亮LED*/
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
//利用串口中斷接收消息
HAL_UART_Receive_IT(&huart1,buff,1);
while(1)
{
HAL_Delay(3000);
printf("正常代碼執(zhí)行完畢,5s后進(jìn)入睡眠模式\r\n");
HAL_Delay(5000);
printf("開(kāi)始睡眠\(yùn)r\n");
/*1.暫停滴答定時(shí)器,防止被自動(dòng)喚醒*/
HAL_SuspendTick();
/*2.進(jìn)入睡眠模式:參數(shù)1:要不要關(guān)閉電壓調(diào)節(jié)器(睡眠模式無(wú)效)參數(shù)2:進(jìn)入指令wfiorwfe*/
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
/*3.被喚醒后要恢復(fù)滴答時(shí)鐘*/
HAL_ResumeTick();
HAL_Delay(1);
printf("從睡眠模式被喚醒...\r\n");
}}低功耗案例2:停機(jī)模式需求描述讓MCU進(jìn)入停機(jī)模式。停機(jī)模式需要外部中斷才能喚醒,所以要開(kāi)啟外部中斷。(串口不是外部中斷)硬件電路設(shè)計(jì)我們按下按鍵來(lái)產(chǎn)生外部中斷。軟件設(shè)計(jì)(寄存器)復(fù)制實(shí)驗(yàn)1項(xiàng)目,新增外部中斷相關(guān)配置。使用寄存器實(shí)現(xiàn)。main.c#include"stm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"#include"key.h"#include"LED.h"voidenter_stop_mode(void){
/*1.開(kāi)啟PWR時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
/*2.清除電源控制器中的PDDS位進(jìn)入深睡眠時(shí),進(jìn)入停機(jī)模式*/
PWR>CR&=~PWR_CR_PDDS;
/*3.設(shè)置電壓調(diào)節(jié)器的模式0:電壓調(diào)節(jié)器開(kāi)啟1:電壓調(diào)節(jié)器處于低功耗模式*/
PWR>CR|=PWR_CR_LPDS;
/*4.
系統(tǒng)控制寄存器的深度睡眠模式*/
SCB>SCR|=SCB_SCR_SLEEPDEEP;
/*5.進(jìn)入睡眠模式,等待被中斷喚醒*/
__WFI();}/**
*@description:從stop模式恢復(fù)后,重新設(shè)置系統(tǒng)時(shí)鐘
*@return{*}
*/voidconfig_system_clock(void){
/*1.使能HSE*/
RCC>CR|=RCC_CR_HSEON;
/*2.由于時(shí)鐘啟用需要一定時(shí)間,需要等待HSE準(zhǔn)備就緒*/
while(!(RCC>CR&RCC_CR_HSERDY))
;
/*3.使能PLL*/
RCC>CR|=RCC_CR_PLLON;
/*4.等待PLL準(zhǔn)備就緒*/
while(!(RCC>CR&RCC_CR_PLLRDY))
;
/*
5.選擇PLL作為系統(tǒng)時(shí)鐘源CFGR_SW位控制
00:HSI作為系統(tǒng)時(shí)鐘;
01:HSE作為系統(tǒng)時(shí)鐘;
10:PLL輸出作為系統(tǒng)時(shí)鐘;
11:不可用。
*/
RCC>CFGR|=RCC_CFGR_SW_1;
RCC>CFGR&=~RCC_CFGR_SW_0;
/*6.等待PLL被選為系統(tǒng)時(shí)鐘源*/
while(!(RCC>CFGR&RCC_CFGR_SWS_PLL))
;}/**
*@description:獲取各個(gè)時(shí)鐘頻率
*/voidget_clock_freq(uint32_t*sys_clock,
uint32_t*AHB_clock,
uint32_t*APB1_clock,
uint32_t*APB2_clock){
/*1.獲取時(shí)鐘源RCC_CFGR_SWS用來(lái)獲取當(dāng)前時(shí)鐘源*/
uint32_tsystem_clock_source=RCC>CFGR&RCC_CFGR_SWS;
/*2.根據(jù)時(shí)鐘源獲取主時(shí)鐘頻率*/
if(system_clock_source==RCC_CFGR_SWS_HSE)
{
*sys_clock=HSE_VALUE;
}
elseif(system_clock_source==RCC_CFGR_SWS_HSI)
{
*sys_clock=HSI_VALUE;
}
elseif(system_clock_source==RCC_CFGR_SWS_PLL)
{
/*倍頻系數(shù)*/
uint32_tmull=((RCC>CFGR&RCC_CFGR_PLLMULL)>>18)+2;
*sys_clock=HSE_VALUE*mull;/*默認(rèn)情況PLL時(shí)用HSE的9倍頻*/
}
/*3.獲取AHB總線時(shí)鐘頻率默認(rèn)情況AHB等于系統(tǒng)頻率*/
uint32_thpre=(RCC>CFGR&RCC_CFGR_HPRE)>>4;
if(hpre&0x8)//有分頻
{
*AHB_clock=*sys_clock>>((hpre&0x7)+1);
}
else
{
//沒(méi)有分頻
*AHB_clock=*sys_clock;
}
/*4.APB1的頻率默認(rèn)是系統(tǒng)頻率2分頻*/
uint32_tppre1=(RCC>CFGR&RCC_CFGR_PPRE1)>>8;
if(ppre1&0x4)//有分頻
{
*APB1_clock=*AHB_clock>>((ppre1&0x3)+1);
}
else
{
//沒(méi)有分頻
*APB1_clock=*AHB_clock;
}
/*4.APB2的頻率默認(rèn)是系統(tǒng)頻率*/
uint32_tppre2=(RCC>CFGR&RCC_CFGR_PPRE2)>>11;
if(ppre2&0x4)//有分頻
{
*APB2_clock=*AHB_clock>>((ppre2&0x3)+1);
}
else
{
//沒(méi)有分頻
*APB2_clock=*AHB_clock;
}}intmain(void){
usart1_init();
key_init();
LED_Init();
LED_On();
Delay_s(1);
while(1)
{
printf("正常代碼執(zhí)行完畢,5s后進(jìn)入停機(jī)模式\r\n");
Delay_s(5);
printf("開(kāi)始進(jìn)入停機(jī)模式,按下按鍵喚醒\r\n");
Delay_ms(1);
enter_stop_mode();
/*獲取喚醒后的時(shí)鐘頻率*/
uint32_tpre_system_clock,pre_AHB_clock,pre_APB1_clock,pre_APB2_clock;
get_clock_freq(&pre_system_clock,&pre_AHB_clock,&pre_APB1_clock,&pre_APB2_clock);
/*
從停機(jī)模式恢復(fù)后,會(huì)啟用HSI(高速內(nèi)部時(shí)鐘8M)作為系統(tǒng)時(shí)鐘,與我們正常使用的有差別的。
所以需要恢復(fù)到HSE(高速外部時(shí)鐘)
*/
config_system_clock();
/*獲取重置后的時(shí)鐘頻率*/
uint32_tpost_system_clock,post_AHB_clock,post_APB1_clock,post_APB2_clock;
get_clock_freq(&post_system_clock,&post_AHB_clock,&post_APB1_clock,&post_APB2_clock);
printf("從停機(jī)模式被喚醒...\r\n");
printf("重置前的時(shí)鐘頻率:pre_system_clock=%d,pre_AHB_clock=%d,pre_APB1_clock=%d,pre_APB2_clock=%d\r\n",
pre_system_clock,
pre_AHB_clock,
pre_APB1_clock,
pre_APB2_clock);
printf("重置后的時(shí)鐘頻率:post_system_clock=%d,post_AHB_clock=%d,post_APB1_clock=%d,post_APB2_clock=%d\r\n",
post_system_clock,
post_AHB_clock,
post_APB1_clock,
post_APB2_clock);
}}key.h#ifndef__KEY_H#define__KEY_H/*初始化按鍵:外部中斷*/voidkey_init(void);#endifkey.c#include"key.h"#include"stm32f10x.h"#include"usart.h"/*初始化按鍵:外部中斷*/voidkey_init(void){
/*1開(kāi)啟時(shí)鐘(EXTI和NVIC時(shí)鐘始終開(kāi)啟,無(wú)需手動(dòng)開(kāi)啟)*/
/*1.1開(kāi)啟GPIOF時(shí)鐘(PF10)*/
RCC>APB2ENR|=RCC_APB2ENR_IOPFEN;
/*1.2開(kāi)啟AFIO時(shí)鐘*/
RCC>APB2ENR|=RCC_APB2ENR_AFIOEN;
/*2配置PF10
設(shè)置為輸入下拉(cnf:10mode:00)。另外還需要把ODR寄存器對(duì)應(yīng)的位設(shè)為0*/
GPIOF>CRH&=~GPIO_CRH_MODE10;
GPIOF>CRH|=GPIO_CRH_CNF10_1;
GPIOF>CRH&=~GPIO_CRH_CNF10_0;
GPIOF>ODR&=~GPIO_ODR_ODR10;
/*3
配置AFIO,用于引腳復(fù)用為外部中斷
PF10*/
AFIO>EXTICR[2]|=AFIO_EXTICR3_EXTI10_PF;
/*4.配置EXTI*/
/*4.1PF10的上升沿觸發(fā)中斷
*/
EXTI>RTSR|=EXTI_RTSR_TR10;
/*4.2開(kāi)啟EXTI10線*/
EXTI>IMR|=EXTI_IMR_MR10;
/*5.配置NVIC*/
/*5.1配置中斷優(yōu)先級(jí)組*/
NVIC_SetPriorityGrouping(4);
/*5.2配置中斷優(yōu)先級(jí)*/
NVIC_SetPriority(EXTI15_10_IRQn,2);
/*5.3使能中斷線1510中斷*/
NVIC_EnableIRQ(EXTI15_10_IRQn);}/*中斷服務(wù)函數(shù)*/voidEXTI15_10_IRQHandler(void){
/*清除中斷標(biāo)志*/
EXTI>PR|=EXTI_PR_PR10;}測(cè)試軟件設(shè)計(jì)(HAL庫(kù))復(fù)制實(shí)驗(yàn)2,新增外部中斷相關(guān)配置。STM32CubeMX的配置添加其他代碼intmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
/*USERCODEBEGIN2*/
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
printf("尚硅谷低功耗實(shí)驗(yàn):停機(jī)模式HAL庫(kù)\r\n");
while(1)
{
printf("正常任務(wù)執(zhí)行完畢,5s后進(jìn)入停止模式...\r\n");
HAL_Delay(5000);
printf("開(kāi)始進(jìn)入停止模式...\r\n");
//1.暫停滴答定時(shí)器(防止退出停止模式)
HAL_SuspendTick();
//2.進(jìn)入停止模式:
//參數(shù)1:要不要關(guān)電壓調(diào)節(jié)器
//參數(shù)2:進(jìn)入指令:wfi還是wfe
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);
//3.重新配置系統(tǒng)時(shí)鐘(如果不配置時(shí)鐘,串口打印不正常,因?yàn)闀r(shí)鐘頻率變化了,波特率計(jì)算也不對(duì)了)
SystemClock_Config();
//4.恢復(fù)滴答定時(shí)器
HAL_ResumeTick();
printf("系統(tǒng)被喚醒...\r\n");
}}低功耗案例3:待機(jī)模式需求描述寄存器操作進(jìn)入待機(jī)模式。待機(jī)模式的喚醒方式比較有限。我們這次使用WKUP引腳的上升沿喚醒。PA0就是WKUP引腳。當(dāng)然PA0仍然需要工作在下拉輸入模式,只有這樣當(dāng)按鍵按下的時(shí)候才會(huì)有一個(gè)上升沿。由于我們電路中PA0已經(jīng)連接了LED1,所以要產(chǎn)生上升沿需要先用杜邦線連接GND,然后再連接3.3V電源即可。另外也可以使用NRST引腳實(shí)現(xiàn)喚醒。軟件設(shè)計(jì)(寄存器)Copy實(shí)驗(yàn)3,進(jìn)行修改。#include"stm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"#include"led.h"/**
*@description:進(jìn)入待機(jī)模式
*/voidenter_standby_mode(void){
/*1.使能PA0的喚醒功能*/
PWR>CSR|=PWR_CSR_EWUP;/*引腳會(huì)被強(qiáng)制設(shè)置下拉輸入*/
/*3.CPU進(jìn)入深睡眠時(shí)進(jìn)入待機(jī)模式。*/
PWR>CR|=PWR_CR_PDDS;
/*4.
系統(tǒng)控制寄存器的深度睡眠模式*/
SCB>SCR|=SCB_SCR_SLEEPDEEP;
/*5.進(jìn)入待機(jī)模式,等待喚醒*/
__WFI();}intmain(void){
led_init();
led_on();
usart1_init();
/*1.開(kāi)啟PWR時(shí)鐘
*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
/*檢測(cè)復(fù)位來(lái)源:按下reset和從待機(jī)恢復(fù)都會(huì)重新執(zhí)行main函數(shù)*/
/*PWR_CSR_SBF是待機(jī)標(biāo)志位:1表示曾經(jīng)待機(jī)過(guò)*/
if(PWR>CSR&PWR_CSR_SBF)
{
printf("待機(jī)喚醒復(fù)位\r\n");
/*1.清除待機(jī)標(biāo)志位,然后才可以進(jìn)入待機(jī),通過(guò)CR_CSBF寫(xiě)1清除*/
PWR>CR|=PWR_CR_CSBF;
/*2.清除喚醒標(biāo)記,通過(guò)CR_CWUF*/
PWR>CR|=PWR_CR_CWUF;
}
else
{
printf("非待機(jī)喚醒復(fù)位\r\n");
}
while(1)
{
printf("正常代碼執(zhí)行完畢,3s后進(jìn)入待機(jī)模式\r\n");
Delay_s(3);
printf("開(kāi)始進(jìn)入待機(jī)模式,所有燈光將關(guān)閉,按下按鍵喚醒\r\n");
Delay_ms(1);
enter_standby_mode();
}}注意:待機(jī)期間是不能程序的,需要喚醒之后再燒錄。所以務(wù)必注意一定要加延時(shí),在這期間燒錄程序,否則一啟動(dòng)就進(jìn)入待機(jī)模式,就沒(méi)有辦法燒錄程序了。軟件設(shè)計(jì)(HAL庫(kù))STM32CubeMX配置添加其他代碼intmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
//檢測(cè)復(fù)位來(lái)源。當(dāng)從待機(jī)恢復(fù)的時(shí)候,會(huì)重新開(kāi)始執(zhí)行main函數(shù)
if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)==SET)//從待機(jī)恢復(fù)
{
//清除待機(jī)標(biāo)志位
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
printf("\r\n待機(jī)喚醒復(fù)位\r\n");
}
else
{
printf("\r\n非待機(jī)喚醒復(fù)位\r\n");
}
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
while(1)
{
printf("正常代碼執(zhí)行完畢,5s后進(jìn)入待機(jī)模式...\r\n");
HAL_Delay(5000);
//1.清除喚醒標(biāo)記位
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
//2.使能PA0的待機(jī)喚醒功能
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
//3.停止滴答定時(shí)器
HAL_SuspendTick();
//4.進(jìn)入待機(jī)模式
HAL_PWR_EnterSTANDBYMode();
}}RTC(實(shí)時(shí)時(shí)鐘)RTC簡(jiǎn)介RTC(RealTimeClock,實(shí)時(shí)時(shí)鐘)。是一個(gè)掉電后仍然可以繼續(xù)運(yùn)行的獨(dú)立定時(shí)器。RTC模塊擁有一個(gè)連續(xù)計(jì)數(shù)的計(jì)數(shù)器,在相應(yīng)的軟件配置下,可以提供時(shí)鐘日歷的功能。修改計(jì)數(shù)器的值可以重新設(shè)置當(dāng)前時(shí)間和日期RTC還包含用于管理低功耗模式的自動(dòng)喚醒單元。RTC實(shí)質(zhì)是一個(gè)掉電后還繼續(xù)運(yùn)行的定時(shí)器,從定時(shí)器的角度來(lái)看,相對(duì)于通用定時(shí)器TIM外設(shè),它的功能十分簡(jiǎn)單,只有計(jì)時(shí)功能(也可以觸發(fā)中斷)。但其高級(jí)指出也就在于掉電之后還可以正常運(yùn)行。掉電能運(yùn)行,不是說(shuō)它不需要電能,而是它有一套專門(mén)的供電系統(tǒng)。掉電繼續(xù)運(yùn)行這里所說(shuō)的掉電是指的VDD掉電。VDD掉電后,由VBAT負(fù)責(zé)給后備區(qū)域供電。VBAT由電路中的紐扣電池來(lái)供電,一般的電路設(shè)計(jì)中都會(huì)加上備用電池。只要這個(gè)電池有電,則后備區(qū)域就一直會(huì)有電供應(yīng)。RTC功能框圖RTC的時(shí)鐘源RTC有3路時(shí)鐘來(lái)源:HSE(8MHz)/128,LSE(32.768KHz),LSI(40KHz)。其中,如果使用HSE或LSI的話,當(dāng)主電源掉電的話,這兩個(gè)始終都會(huì)受到影響,RTC就無(wú)法正常工作。所以,一般的通用做法是使用LSE。2個(gè)原因:一是LSE不受主電源掉電的影響,二是它的頻率是我們都是選擇32768Hz,正好是2^15,分頻容易實(shí)現(xiàn)。APB1接口用來(lái)和APB1總線相連。此單元還包含一組16位寄存器,可通過(guò)APB1總線對(duì)其進(jìn)行讀寫(xiě)操作。APB1接口由APB1總線時(shí)鐘驅(qū)動(dòng),用來(lái)與APB1總線連接。通過(guò)APB1接口可以訪問(wèn)RTC的相關(guān)寄存器(預(yù)分頻值,計(jì)數(shù)器值,鬧鐘值)。RTC預(yù)分頻模塊這個(gè)模塊是RTC預(yù)分頻模塊,屬于后備區(qū)域,VDD掉電后,可以在VBAT下繼續(xù)運(yùn)行。包含了一個(gè)20位的可編程分頻器(RTC預(yù)分頻器)。它可編程產(chǎn)生1秒的RTC時(shí)間基準(zhǔn)TR_CLK。如果在RTC_CR寄存器中設(shè)置了相應(yīng)的允許位,則在每個(gè)TR_CLK周期中RTC產(chǎn)生一個(gè)中斷(秒中斷)。32位可編程計(jì)數(shù)器這個(gè)模塊也屬于后備區(qū)域,是一個(gè)32位的可編程計(jì)數(shù)器,可被初始化為當(dāng)前的系統(tǒng)時(shí)間。一個(gè)32位的時(shí)鐘計(jì)數(shù)器,按秒鐘計(jì)算,可以記錄4294967296秒,約合136年左右,作為一般應(yīng)用,這已經(jīng)是足夠了的。中斷從圖中可以看到一共有3個(gè)中斷:秒中斷:每計(jì)時(shí)1s產(chǎn)生一次中斷。計(jì)數(shù)器溢出中斷。136年才會(huì)產(chǎn)生溢出,一般用不上。RTC鬧鐘中斷。RCT_CN和RTC_ALR會(huì)比較相等,如果相等表示鬧鐘時(shí)間到,會(huì)產(chǎn)生鬧鐘中斷。備份寄存器(BKP)備份寄存器介紹備份寄存器簡(jiǎn)介BKP(backupregister,備份寄存器)。備份寄存器是42個(gè)16位的寄存器,可用來(lái)存儲(chǔ)84個(gè)字節(jié)的用戶應(yīng)用程序數(shù)據(jù)。他們處在備份域里,當(dāng)VDD電源被切斷,他們?nèi)匀挥蒝BAT維持供電。當(dāng)系統(tǒng)在待機(jī)模式下被喚醒,或系統(tǒng)復(fù)位或電源復(fù)位時(shí),他們也不會(huì)被復(fù)位。此外,BKP控制寄存器用來(lái)管理侵入檢測(cè)和RTC校準(zhǔn)功能。復(fù)位后,對(duì)備份寄存器和RTC的訪問(wèn)被禁止,并且備份域被保護(hù)以防止可能存在的意外的寫(xiě)操作。執(zhí)行以下操作可以使能對(duì)備份寄存器和RTC的訪問(wèn):通過(guò)設(shè)置寄存器RCC_APB1ENR的PWREN和BKPEN位來(lái)打開(kāi)電源和后備接口的時(shí)鐘電源控制寄存器(PWR_CR)的DBP位來(lái)使能對(duì)后備寄存器和RTC的訪問(wèn)侵入檢測(cè)功能當(dāng)TAMPER(PC13)引腳上的信號(hào)從0變成1或者從1變成0(取決于備份控制寄存器BKP_CR的TPAL位),會(huì)產(chǎn)生一個(gè)侵入檢測(cè)事件。侵入檢測(cè)事件將所有數(shù)據(jù)備份寄存器內(nèi)容清除。設(shè)置BKP_CSR寄存器的TPIE位為"1",當(dāng)檢測(cè)到侵入事件時(shí)就會(huì)產(chǎn)生一個(gè)中斷。RTC校準(zhǔn)為方便測(cè)量,RTC時(shí)鐘可以經(jīng)64分頻輸出到侵入檢測(cè)引腳TAMPER上。通過(guò)設(shè)置RTC校驗(yàn)寄存器(BKP_RTCCR)的CCO位來(lái)開(kāi)啟這一功能。備份數(shù)據(jù)寄存器用來(lái)存儲(chǔ)用戶數(shù)據(jù)。一共42個(gè)16位寄存器(大容量和互聯(lián)型是42個(gè),中小容量產(chǎn)品是20個(gè)),可以存84個(gè)字節(jié)的數(shù)據(jù)。其他寄存器RTC時(shí)鐘校準(zhǔn)寄存器,備份控制寄存器,備份控制/狀態(tài)寄存器。參考手冊(cè)49頁(yè)。備份寄存器案例:讀寫(xiě)備份寄存器需求描述基于寄存器操作。程序啟動(dòng)后向后備寄存器寫(xiě)入值,按下按鍵1從備份寄存器讀出數(shù)據(jù),驗(yàn)證是否一致。Reset設(shè)備,然后按下按鍵1是否能讀到數(shù)據(jù),驗(yàn)證掉電不丟失。關(guān)機(jī),再啟動(dòng),然后按下按鍵1是否能讀到數(shù)據(jù),驗(yàn)證掉電不丟失。硬件電路設(shè)計(jì)軟件設(shè)計(jì)(寄存器)main.c#include"stm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"#include"key.h"#include"bkp.h"intmain(void){
usart1_init();
printf("尚硅谷后備寄存器實(shí)驗(yàn)基于寄存器實(shí)現(xiàn)...\r\n");
key_init();
/*初始化RTC和后備寄存器*/
rtc_bkp_init();
/*向后備寄存器寫(xiě)入值,只寫(xiě)一次,注釋掉。然后測(cè)試rest和掉電重啟數(shù)據(jù)是否丟失*/
//BKP>DR1=9999;
while(1)
{
}}/*按鍵按下時(shí)的中斷服務(wù)函數(shù)*/voidEXTI15_10_IRQHandler(void){
printf("DK1=%d\r\n",BKP>DR1);
/*清除中斷標(biāo)志*/
EXTI>PR|=EXTI_PR_PR10;}bkp.h#ifndef__BKP_H#define__BKP_H#include"stm32f10x.h"voidrtc_bkp_init(void);#endifbkp.c#include"bkp.h"/**
*@description:初始化rtc和后備寄存器
*@return{*}
*/voidrtc_bkp_init(void){
/*1.使能PWR時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
/*
2.允許先RTC寄存器和后備寄存器寫(xiě)入數(shù)據(jù)PWR_CR_DBP位
0:禁止寫(xiě)入RTC和后備寄存器
1:允許寫(xiě)入RTC和后備寄存器
*/
PWR>CR|=PWR_CR_DBP;
/*3.使能BKP時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_BKPEN;
/*4.如果已經(jīng)向DR1寄存器寫(xiě)入過(guò)值,證明備份域已經(jīng)復(fù)位過(guò)??梢灾苯臃祷亓?/
if(BKP>DR1)return;
/*5.復(fù)位備份域*/
RCC>BDCR|=RCC_BDCR_BDRST;
/*6.解除備份域復(fù)位*/
RCC>BDCR&=~RCC_BDCR_BDRST;
/*7.使能RTC時(shí)鐘*/
RCC>BDCR|=RCC_BDCR_RTCEN;
/*8.使能LSE*/
RCC>BDCR|=RCC_BDCR_LSEON;
/*
9.使用LSE(外部低俗時(shí)鐘)作為RTC時(shí)鐘
00:無(wú)時(shí)鐘;
01:LSE振蕩器作為RTC時(shí)鐘;
10:LSI振蕩器作為RTC時(shí)鐘;
11:HSE振蕩器在128分頻后作為RTC時(shí)鐘。
如果要修改時(shí)鐘源:
1.先復(fù)位后備域(所有數(shù)據(jù)丟失)復(fù)位后變?yōu)?0
2.這兩位必須同時(shí)更改.如果先改高位,則低位就無(wú)法更改了
一旦RTC時(shí)鐘選定,在備份域復(fù)位之前就不能再更改了。
*/
RCC>BDCR|=(0x1<<8);}軟件設(shè)計(jì)(HAL庫(kù))STM32CubeMX配置添加其他代碼//按鍵按下下時(shí)的中斷處理函數(shù)voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){
if(GPIO_Pin==GPIO_PIN_10)
{
uint32_tdata=HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1);
printf("從后備寄存器讀取的值是:%d\r\n",data);
}}intmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
//向后備寄存器寫(xiě)入值,為了測(cè)試,只寫(xiě)一次,第一次寫(xiě)入之后,注釋掉此代碼
//HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,1314);
while(1)
{
}}RTC實(shí)驗(yàn)RTC案例1:使用鬧鐘喚醒待機(jī)模式需求描述執(zhí)行完畢正常代碼之后,讓MCU進(jìn)入待機(jī)模式,設(shè)置鬧鐘,自動(dòng)讓MCU從待機(jī)模式中被喚醒。可以用led點(diǎn)亮熄滅顯示是否喚醒。應(yīng)用場(chǎng)景:比如設(shè)計(jì)一個(gè)野外溫度自動(dòng)采集的設(shè)備,規(guī)定每小時(shí)采集一次溫度,就可以定義一個(gè)1小時(shí)的鬧鐘,定時(shí)喚醒,采集溫度,采集完進(jìn)入待機(jī)模式,可以大大降低設(shè)備功耗。軟件設(shè)計(jì)(寄存器)main.c#include"stm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"#include"led.h"#include"alarm.h"/**
*@description:進(jìn)入待機(jī)模式
*/voidenter_standby_mode(void){
/*1.使能PA0的喚醒功能*/
//PWR>CSR|=PWR_CSR_EWUP;/*引腳會(huì)被強(qiáng)制設(shè)置下拉輸入*/
/*3.CPU進(jìn)入深睡眠時(shí)進(jìn)入待機(jī)模式。*/
PWR>CR|=PWR_CR_PDDS;
/*4.
系統(tǒng)控制寄存器的深度睡眠模式*/
SCB>SCR|=SCB_SCR_SLEEPDEEP;
/*5.進(jìn)入待機(jī)模式,等待喚醒*/
__WFI();}intmain(void){
LED_Init();
LED_On();
usart1_init();
Alarm_Init();
/*1.開(kāi)啟PWR時(shí)鐘
*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
/*檢測(cè)復(fù)位來(lái)源:按下reset和從待機(jī)恢復(fù)都會(huì)重新執(zhí)行main函數(shù)*/
/*PWR_CSR_SBF是待機(jī)標(biāo)志位:1表示曾經(jīng)待機(jī)過(guò)*/
if(PWR>CSR&PWR_CSR_SBF)
{
/*1.清除待機(jī)標(biāo)志位,然后才可以進(jìn)入待機(jī),通過(guò)CR_CSBF寫(xiě)1清除*/
PWR>CR|=PWR_CR_CSBF;
/*2.清除喚醒標(biāo)記,通過(guò)CR_CWUF*/
PWR>CR|=PWR_CR_CWUF;
}
while(1)
{
printf("溫度測(cè)試完畢,5s后進(jìn)入待機(jī)....\r\n");
Delay_s(5);
printf("開(kāi)始進(jìn)入待機(jī)模式,所有燈光將關(guān)閉...\r\n");
/*設(shè)置20s后執(zhí)行的鬧鐘*/
Alarm_SetXSecond(20);
Delay_ms(1);
enter_standby_mode();
}}alarm.h#ifndef__ALARM_H#define__ALARM_H#include"stm32f10x.h"voidAlarm_Init(void);voidAlarm_SetXSecond(uint32_tx);#endifalarm.c#include"alarm.h"/**
*@description:鬧鐘的初始化
*@return{*}
*/voidAlarm_Init(void){
/*1.使能PWR時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
/*2.使能BKP時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_BKPEN;
/*
3.允許向RTC寄存器和后備寄存器寫(xiě)入數(shù)據(jù)PWR_CR_DBP位
0:禁止寫(xiě)入RTC和后備寄存器
1:允許寫(xiě)入RTC和后備寄存器
*/
PWR>CR|=PWR_CR_DBP;
/*4.使能RTC時(shí)鐘*/
RCC>BDCR|=RCC_BDCR_RTCEN;
/*5.使能LSE外部低速時(shí)鐘*/
RCC>BDCR|=RCC_BDCR_LSEON;
/*6.等待RTC進(jìn)入初始化狀態(tài)(上次的寫(xiě)操作已經(jīng)完成)*/
while(!(RTC>CRL&RTC_CRL_RTOFF))
;
/*7.進(jìn)入配置模式.
允許配置RTC的計(jì)數(shù)器,預(yù)分頻系數(shù)和鬧鐘寄存器。*/
RTC>CRL|=RTC_CRL_CNF;
/*
8.設(shè)置RTC預(yù)分頻系數(shù):我們產(chǎn)生一個(gè)1s的信號(hào),讓計(jì)數(shù)器每s加1
時(shí)鐘頻率是32768Hz,所以預(yù)分頻系數(shù)應(yīng)該是=0x7FFF
*/
RTC>PRLH=0x0;
RTC>PRLL=0x7FFF;
/*9.退出配置模式。前面的數(shù)據(jù)才會(huì)真正更新到寄存器中*/
RTC>CRL&=~RTC_CRL_CNF;}/**
*@description:設(shè)置一個(gè)x秒之后到時(shí)的鬧鐘
*/voidAlarm_SetXSecond(uint32_tx){
/*1.先清除鬧鐘標(biāo)志*/
RTC>CRL&=~RTC_CRL_ALRF;
/*2.等待RTC進(jìn)入初始化狀態(tài)*/
while(!(RTC>CRL&RTC_CRL_RTOFF))
;
/*3.進(jìn)入配置模式*/
RTC>CRL|=RTC_CRL_CNF;
/*4.等待秒標(biāo)志位*/
while(!(RTC>CRL&RTC_CRL_SECF))
;
/*5.RTC計(jì)數(shù)器寄存器的值。我們可以從1開(kāi)始計(jì)數(shù),則大概136年才會(huì)溢出(32位計(jì)數(shù)器)*/
RTC>CNTH=0;
RTC>CNTL=0;
/*6.設(shè)置鬧鐘:
*/
x=1;
RTC>ALRH=(x>>16)&0xFFFF;
RTC>ALRL=x&0xFFFF;
/*7.退出配置模式*/
RTC>CRL&=~RTC_CRL_CNF;}軟件設(shè)計(jì)(HAL庫(kù))STM32CubeMX配置添加其他代碼rtc.c中添加代碼/*USERCODEBEGIN1*/voidAlarm_SetXSecond(uint32_tx){
/*
獲取當(dāng)前時(shí)間*/
RTC_TimeTypeDeftimeTypeDef={0};
HAL_RTC_GetTime(&hrtc,&timeTypeDef,RTC_FORMAT_BIN);
/*設(shè)置鬧鐘*/
RTC_AlarmTypeDefsAlarm={0};
sAlarm.AlarmTime.Hours=timeTypeDef.Hours;
sAlarm.AlarmTime.Minutes=timeTypeDef.Minutes;
sAlarm.AlarmTime.Seconds=timeTypeDef.Seconds+x1;
HAL_RTC_SetAlarm(&hrtc,&sAlarm,RTC_FORMAT_BIN);}/*USERCODEEND1*/main.cintmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
//檢測(cè)復(fù)位來(lái)源。當(dāng)從待機(jī)恢復(fù)的時(shí)候,會(huì)重新開(kāi)始執(zhí)行main函數(shù)
if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)==SET)//從待機(jī)恢復(fù)
{
//清除待機(jī)標(biāo)志位
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
//清除喚醒標(biāo)記
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
}
while(1)
{
printf("正常代碼執(zhí)行完畢,5s后進(jìn)入待機(jī)模式...\r\n");
HAL_Delay(5000);
printf("開(kāi)始進(jìn)入待機(jī)模式,20s后被喚醒...\r\n");
//1.設(shè)置鬧鐘:20s后到時(shí)
Alarm_SetXSecond(20);
//2.停止滴答定時(shí)器
HAL_SuspendTick();
//3.進(jìn)入待機(jī)模式
HAL_PWR_EnterSTANDBYMode();
}}RTC案例2:實(shí)時(shí)時(shí)鐘(掉電不丟失)需求描述顯示時(shí)間。通過(guò)串口把時(shí)間發(fā)送給電腦顯示。即使關(guān)機(jī)很多天,再啟動(dòng)后也能正確顯示時(shí)間。軟件設(shè)計(jì)(寄存器)main.c#include"stm32f10x.h"http://Deviceheader#include"usart.h"#include"Delay.h"#include"led.h"#include"rtc_datetime.h"intmain(void){
usart1_init();
printf("尚硅谷實(shí)時(shí)時(shí)鐘實(shí)驗(yàn).....\r\n");
RTC_Init();
/*在window的powshell獲取unix時(shí)間戳命令:[int][double]::Parse((GetDateUFormat%s))*/
/*設(shè)置一次就行了,以后時(shí)鐘就可以正常運(yùn)行了*/
//RTC_SetUnixTimestampSecond(1700478670);
DateTimeDefTypedateTime;
while(1)
{
RTC_GetDateTime(&dateTime);
printf("%04d年%02d月%02d日%02d:%02d:%02d\r\n",
dateTime.year,
dateTime.month,
dateTime.day,
dateTime.hour,
dateTime.mintue,
dateTime.second);
Delay_s(1);
}}rtc_datetime.h#ifndef__RTC_DATETIME_C#define__RTC_DATETIME_C#include"stm32f10x.h"#include"time.h"typedefstruct{
uint16_tyear;
uint8_tmonth;
uint8_tday;
uint8_thour;
uint8_tmintue;
uint8_tsecond;}DateTimeDefType;voidRTC_Init(void);voidRTC_SetUnixTimestampSecond(uint32_tunixTimestampSecond);voidRTC_GetDateTime(DateTimeDefType*dateTime);#endifrtc_realtime.c#include"rtc_datetime.h"/**
*@description:rtc的初始化
*@return{*}
*/voidRTC_Init(void){
/*1.使能PWR時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_PWREN;
RCC>BDCR&=~RCC_BDCR_RTCEN;
/*
2.使用LSE(外部低速時(shí)鐘)作為RTC時(shí)鐘
00:無(wú)時(shí)鐘;
01:LSE振蕩器作為RTC時(shí)鐘32.768KHz;
10:LSI振蕩器作為RTC時(shí)鐘;
11:HSE振蕩器在128分頻后作為RTC時(shí)鐘。
*/
RCC>BDCR|=RCC_BDCR_RTCSEL_1;
RCC>BDCR|=RCC_BDCR_RTCSEL_0;
/*3.使能BKP時(shí)鐘*/
RCC>APB1ENR|=RCC_APB1ENR_BKPEN;
/*
4.允許向RTC寄存器和后備寄存器寫(xiě)入數(shù)據(jù)PWR_CR_DBP位
0:禁止寫(xiě)入RTC和后備寄存器
1:允許寫(xiě)入RTC和后備寄存器
*/
PWR>CR|=PWR_CR_DBP;
/*5.使能RTC時(shí)鐘*/
RCC>BDCR|=RCC_BDCR_RTCEN;
/*6.使能LSE*/
RCC>BDCR|=RCC_BDCR_LSEON;
/*7.等待RTC進(jìn)入初始化狀態(tài)(上次的寫(xiě)操作已經(jīng)完成)*/
while(!(RTC>CRL&RTC_CRL_RTOFF))
;
/*8.進(jìn)入配置模式.
允許配置RTC的計(jì)數(shù)器,預(yù)分頻系數(shù)和鬧鐘寄存器。*/
RTC>CRL|=RTC_CRL_CNF;
/*
9.設(shè)置RTC預(yù)分頻系數(shù):我們產(chǎn)生一個(gè)1s的信號(hào),讓計(jì)數(shù)器每s加1
時(shí)鐘頻率是32768Hz,所以預(yù)分頻系數(shù)應(yīng)該是=0x7FFF
*/
RTC>PRLH=0x0;
RTC>PRLL=0x7FFF;
/*10.退出配置模式。前面的數(shù)據(jù)才會(huì)真正更新到寄存器中*/
RTC>CRL&=~RTC_CRL_CNF;}/**
*@description:把計(jì)數(shù)器的值設(shè)置位unix時(shí)間戳
*/voidRTC_SetUnixTimestampSecond(uint32_tunixTimestampSecond){
/*1.等待RTC進(jìn)入初始化狀態(tài)*/
while(!(RTC>CRL&RTC_CRL_RTOFF))
;
/*2.進(jìn)入配置模式*/
RTC>CRL|=RTC_CRL_CNF;
/*3.等待秒標(biāo)志位*/
while(!(RTC>CRL&RTC_CRL_SECF))
;
/*4.設(shè)置位unix時(shí)間戳*/
RTC>CNTH=unixTimestampSecond>>16;
RTC>CNTL=unixTimestampSecond&0xFFFF;
/*5.退出配置模式*/
RTC>CRL&=~RTC_CRL_CNF;}/**
*@description:獲取年月日時(shí)分秒
*@param{DateTimeDefType}*dateTime年月日時(shí)分秒會(huì)存儲(chǔ)到這個(gè)結(jié)構(gòu)體中
*/voidRTC_GetDateTime(DateTimeDefType*dateTime){
/*1.等待寄存器同步*/
while(!(RTC>CRL&RTC_CRL_RSF))
;
/*2.讀取計(jì)數(shù)器中的值*/
uint32_tsecond=RTC>CNTH<<16|RTC>CNTL;
/*3.根據(jù)傳入的秒得到一個(gè)時(shí)間結(jié)構(gòu)體
*/
structtm*timeinfo=localtime(&second);
/*年是由1900開(kāi)始計(jì)算的兩位年份,所以需要再加個(gè)1900*/
dateTime>year=timeinfo>tm_year+1900;
/*月份是從0開(kāi)始,所以+1*/
dateTime>month=timeinfo>tm_mon+1;
dateTime>day=timeinfo>tm_mday;
dateTime>hour=timeinfo>tm_hour;
dateTime>mintue=timeinfo>tm_min;dateTime>second=timeinfo>tm_sec;}軟件設(shè)計(jì)(HAL庫(kù))復(fù)制上個(gè)項(xiàng)目,適當(dāng)做些修改。STM32CubeMX設(shè)置添加其他代碼intmain(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
RTC_DateTypeDefdateTypeDef;
RTC_TimeTypeDeftimeTypeDef;
while(1)
{
//一定要先獲取時(shí)間,再獲取日期。獲取時(shí)間的時(shí)候會(huì)對(duì)日期進(jìn)行操作,比如增加一天
HAL_RTC_GetTime(&hrtc,&timeTypeDef,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&dateTypeDef,RTC_FORMAT_BIN);
printf("20%02d年%02d月%02d日%02d:%02d:%02d\r\n",
dateTypeDef.Year,
dateTypeDef.Month,
dateTypeDef.Date,
timeTypeDef.Hours,
timeTypeDef.Minutes,
timeTypeDef.Seconds);
HAL_Delay(1000);
}}看門(mén)狗什么是看門(mén)狗看門(mén)狗是一種計(jì)時(shí)硬件電路。當(dāng)系統(tǒng)環(huán)境比較惡劣復(fù)雜的時(shí)候,程序可能會(huì)出現(xiàn)一些不可預(yù)料的錯(cuò)誤,導(dǎo)致程序卡死,崩潰等情況??撮T(mén)狗就可以及時(shí)的重置程序,使程序重新從頭開(kāi)始運(yùn)行。STM32的看門(mén)狗STM32有2個(gè)看門(mén)狗,獨(dú)立看門(mén)狗和窗口看門(mén)狗。獨(dú)立看門(mén)狗號(hào)稱寵物狗,窗口看門(mén)狗號(hào)稱警犬。獨(dú)立看門(mén)狗IWDG(Independentwatchdog,獨(dú)立看門(mén)狗)。獨(dú)立看門(mén)狗用通俗一點(diǎn)的話來(lái)解釋就是一個(gè)12位的遞減計(jì)數(shù)器,當(dāng)計(jì)數(shù)器的值從某個(gè)值一直減到0的時(shí)候,系統(tǒng)就會(huì)產(chǎn)生一個(gè)復(fù)位信號(hào),即IWDG_RESET。如果在計(jì)數(shù)沒(méi)減到0之前,刷新了計(jì)數(shù)器的值的話,那么就不會(huì)產(chǎn)生復(fù)位信號(hào),這個(gè)刷新計(jì)數(shù)器值的動(dòng)作就是我們經(jīng)常說(shuō)的喂狗。計(jì)數(shù)器時(shí)鐘獨(dú)立看門(mén)狗的時(shí)鐘由獨(dú)立的RC振蕩器LSI提供,即使主時(shí)鐘發(fā)生故障它仍然有效,非常獨(dú)立(叫獨(dú)立看門(mén)狗的由來(lái))。LSI的頻率一般在30~60KHZ之間,根據(jù)溫度和工作場(chǎng)合會(huì)有一定的漂移,我們一般取40KHZ,所以獨(dú)立看門(mén)狗的定時(shí)時(shí)間并不一定非常精確,只適用于對(duì)時(shí)間精度要求比較低的場(chǎng)合。預(yù)分頻寄存器這里存儲(chǔ)著我們想要的預(yù)分頻值。12位遞減計(jì)數(shù)器獨(dú)立看門(mén)狗的計(jì)數(shù)器是一個(gè)12位的遞減計(jì)數(shù)器,最大值為0XFFF,當(dāng)計(jì)數(shù)器減到0時(shí),會(huì)產(chǎn)生一個(gè)復(fù)位信號(hào):IWDG_RESET,讓程序重新啟動(dòng)運(yùn)行,如果在計(jì)數(shù)器減到0之前刷新了計(jì)數(shù)器的值的話,就不會(huì)產(chǎn)生復(fù)位信號(hào),重新刷新計(jì)數(shù)器值的這個(gè)動(dòng)作我們俗稱喂狗。重裝載寄存器重裝載寄存器是一個(gè)12位的寄存器,里面裝著要刷新到計(jì)數(shù)器的值,這個(gè)值的大小決定著獨(dú)立看門(mén)狗的溢出時(shí)間。這里的超時(shí)時(shí)間是指如果超過(guò)這個(gè)時(shí)間不喂狗,就會(huì)產(chǎn)生復(fù)位信號(hào)。超時(shí)時(shí)間的計(jì)算公式:T注意:時(shí)鐘頻率是40KHz。預(yù)分頻系數(shù)只有表中固定的這些值(3位PR值決定)。RL的值就是重裝載寄存器中的值。計(jì)數(shù)器的初始值。鍵寄存器鍵寄存器IWDG_KR獨(dú)立看門(mén)狗的一個(gè)控制寄存器,只能寫(xiě)入015位,讀永遠(yuǎn)是0。三種控制方式,往這個(gè)寄存器寫(xiě)入下面三個(gè)不同的值有不同的效果。寫(xiě)入鍵寄存器的值作用0xCCCC軟件啟動(dòng)看門(mén)狗。若啟用了硬件看門(mén)狗,則此命令無(wú)效??撮T(mén)狗一旦啟動(dòng),無(wú)法停止。0xAAAA重裝載計(jì)數(shù)器的值加入到計(jì)數(shù)器中。(喂狗)0x5555允許訪問(wèn)IWDG_PR(預(yù)分頻計(jì)數(shù)器)和IWDG_RLR(重裝載計(jì)數(shù)器)寄存器。其他值開(kāi)啟IWDG_PR(預(yù)分頻計(jì)數(shù)器)和IWDG_RLR(重裝載計(jì)數(shù)器)寄存器的寫(xiě)保護(hù)。狀態(tài)寄存器
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年姿態(tài)敏感器項(xiàng)目資金申請(qǐng)報(bào)告代可行性研究報(bào)告
- 營(yíng)異常名錄管理暫行辦法
- 薊州區(qū)房屋土地管理辦法
- 蚌埠市基金管理辦法細(xì)則
- 行政預(yù)算與管理暫行辦法
- 衢州市排澇泵站管理辦法
- 西寧市市民中心管理辦法
- 西藏合同制工人管理辦法
- 設(shè)備管理與保養(yǎng)管理辦法
- 評(píng)標(biāo)專家?guī)旃芾頃盒修k法
- 品牌授權(quán)使用協(xié)議合同書(shū)
- 2024年天津市公安局濱海分局招聘警務(wù)輔助人員考試真題
- 報(bào)廢汽車(chē)回收拆解前景
- 2025年廣東省中考生物試卷真題(含答案解析)
- 2025至2030停車(chē)場(chǎng)項(xiàng)目發(fā)展趨勢(shì)分析與未來(lái)投資戰(zhàn)略咨詢研究報(bào)告
- 第10課+遼夏金元的統(tǒng)治(大概念教學(xué)課件)2024-2025學(xué)年高一歷史上冊(cè)教學(xué)課件(統(tǒng)編版2019)
- 裝置保運(yùn)方案(3篇)
- 重癥心臟超聲指南解讀
- 中國(guó)聚丙烯酰胺行業(yè)市場(chǎng)發(fā)展分析及前景趨勢(shì)與投資研究報(bào)告2025-2028版
- 青年教師教學(xué)工作坊組織計(jì)劃
- 職工訴求服務(wù)管理制度
評(píng)論
0/150
提交評(píng)論