最近在试验中想用RTC闹钟做低STM32单片机的功耗唤醒,在设置闹钟中断时很走了一段弯路。网上搜到到资料基本也没得到太多帮助,遇到问题其实很简单,现在整理一下,发出来,希望对遇到这问题的朋友有帮助。程序我特意简化了一下,超简单。
主程序,只包含基本的时钟设置、RTC初始化、LED端口设置,循环体只有两条,其实完全可以是一条,T++是本人喜好,不加难受。PCout(13)=LED;完成将LED状态输出到GPIOC13口,驱动LED。
#include "stm32f10x.h"
#include "sys.h"
extern u8 LED;
u32 T;
int main (void)
{
RCC_Configuration();
RTC_Config();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIOC->CRH |=0X00100000;
RTC_Alarm_Init();
RTC_Alarm_Set(5);
T=0;
while(1)
{
PCout(13)=LED;
T++;
}
}
RCC_Configuration(); RTC_Config(); 这两个不必说,大家都有,这里不涉及到时钟的具体时间设置,所以也不去列出。现在主要讲讲 RTC_Alarm_Init() ;RTC_Alarm_Set();这两个程序
void RTC_Alarm_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RTC->CRH |= 0x02;
}
RTC_Alarm_Init() 这个程序完全可以加到RTC_Config() 中,但为了清晰问题,所以我单独做 了一个子程序。前面的几句为设置RTC全局中断优先级,最后一句作用为设置RTC->CRH的ALRIE位,来使能闹钟中断 。
void RTC_Alarm_Set(u16 PY)
{
uint32_t tmp = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC->CRL |= 0x10;
tmp = RTC->CNTL+PY;
RTC->ALRH = RTC->CNTH +(tmp>>16);
RTC->ALRL = tmp;
RTC->CRL &= 0xEF;
RTC_WaitForLastTask();
PWR_BackupAccessCmd(DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,DISABLE);
}
RTC_Alarm_Set(u16 PY) ,这个程序完成闹钟设定,其中
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,ENABLE);
PWR_BackupAccessCmd(ENABLE);
这两句最重要,必须加上,因为我们在使用RTC时钟时,基本上电源时钟和后备域使能这两项是禁止的,所以后来想使用闹钟时,直接设置闹钟是不能成功的,因为RTC的特殊性,本身有自己的时钟,所以有无系统时钟和后备域的使能在RTC运行中并无影响。
tmp = RTC->CNTL+PY;
RTC->ALRH = RTC->CNTH +(tmp>>16);
RTC->ALRL = tmp;
中间三句这完成将当前时间(CNT计数值)读出加上闹钟需要延时的时间(单位秒),再写入闹钟寄存器(ALRH,YALRL);这里对RTC_WaitForLastTask(); 说一下我的见解,通过实验及查阅手册,发现现在网上一些代码在使用中存在误区,这个语句其实不必每次写RTC寄存器时都跟上一句,只要在退出配置模式后(RTC->CRL &= 0xEF;),加一句就可以了,因为RTC只有在推出配置模式后才后执行一次写操作。 最后 关闭后备域写保护,关闭PWR、BKP时钟。建议这两句要加上。
下面的一个重要部分就是,在中断服务程序stm32f10x_it.c里的RTC闹钟中断处理程序,
void RTC_IRQHandler(void){
if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_ALR);
LED=(LED==0);
RTC_Alarm_Set(2);
}
}
这里没什么说的了,效果就是连续设置闹钟,通过LED显示效果。整个过程就是复位后LED亮(低电平亮)5S,后续每隔大约2SLED亮灭切换一次。
下面把 RCC_Configuration(); RTC_Config(); //RTC的程序附上,保证大家程序调通,这里没什么讲的了。
void RCC_Configuration(void){
ErrorStatus HSEStartUpStatus;
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS){
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
FLASH_SetLatency(FLASH_Latency_2);
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08);
}
}
void RTC_First_Config(void){
RCC->APB1ENR|=(0x10000000+0x08000000);
PWR->CR|=0x0100;
RCC->BDCR|=0x10000;
RCC->BDCR=0x0001;
while ((RCC->BDCR&0x02) != 0x02);
RCC->BDCR|=0x00000100;
RCC->BDCR|=0x8000;
while ((RTC->CRL&0x08) != 0x08);
RTC->CRL |= 0x10;
RTC->PRLH = 0x00;
RTC->PRLL = 32767;
RTC->CRL &= 0xEF;
RTC_WaitForLastTask();
}
void RTC_Config(void){
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
RTC_First_Config();
else
{
RCC_ClearFlag();
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
}
}
不差这个了,一并送上
#ifndef __SYS_H
#define __SYS_H
#include "stm32f10x.h"
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
#define GPIOA_ODR_Addr (GPIOA_BASE+12)
#define GPIOB_ODR_Addr (GPIOB_BASE+12)
#define GPIOC_ODR_Addr (GPIOC_BASE+12)
#define GPIOD_ODR_Addr (GPIOD_BASE+12)
#define GPIOE_ODR_Addr (GPIOE_BASE+12)
#define GPIOF_ODR_Addr (GPIOF_BASE+12)
#define GPIOG_ODR_Addr (GPIOG_BASE+12)
#define GPIOA_IDR_Addr (GPIOA_BASE+8)
#define GPIOB_IDR_Addr (GPIOB_BASE+8)
#define GPIOC_IDR_Addr (GPIOC_BASE+8)
#define GPIOD_IDR_Addr (GPIOD_BASE+8)
#define GPIOE_IDR_Addr (GPIOE_BASE+8)
#define GPIOF_IDR_Addr (GPIOF_BASE+8)
#define GPIOG_IDR_Addr (GPIOG_BASE+8)
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n)
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n)
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n)
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n)
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n)
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n)
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n)
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n)
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n)
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n)
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n)
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n)
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n)
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n)
void NVIC_Configuration(void);
void RCC_Configuration(void);
#endif
|