STM32设置闹钟中断

STM32设置闹钟中断,第1张

STM32设置闹钟中断
最近在试验中想用RTC闹钟做低STM32单片机的功耗唤醒,在设置闹钟中断时很走了一段弯路。网上搜到到资料基本也没得到太多帮助,遇到问题其实很简单,现在整理一下,发出来,希望对遇到这问题的朋友有帮助。程序我特意简化了一下,超简单。
主程序,只包含基本的时钟设置、RTC初始化、LED端口设置,循环体只有两条,其实完全可以是一条,T++是本人喜好,不加难受。PCout(13)=LED;完成将LED状态输出到GPIOC13口,驱动LED。
#include "stm32f10x.h" //STM32头文件
#include "sys.h"

extern u8 LED;
u32 T;

int main (void)//主程序
{
	RCC_Configuration(); //时钟设置
	RTC_Config();	//RTC初始化
		   
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //GPIOC外设时钟使能  
	GPIOC->CRH |=0x00100000;		//LED端口设置GPIOC13针,输出模式
	RTC_Alarm_Init();	//RTC闹钟初始化
	RTC_Alarm_Set(5);	//RTC闹钟设置,5秒后闹钟中断
	T=0;
	while(1) 
	{
		PCout(13)=LED;
		T++;
	}//while
}//mian
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;//先占优先级0级 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //从优先级0级 
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure); 
	RTC->CRH |= 0x02;		//ALRIE:允许闹钟中断 
}

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;		//RTC进入配置模式
  	tmp = RTC->CNTL+PY;	
	RTC->ALRH = RTC->CNTH +(tmp>>16);
	RTC->ALRL = tmp;
	RTC->CRL &= 0xEF;		//RTC退出配置模式	
	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、BKP时钟
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){ //RTC时钟全局中断函数(名称固定不可修改)
		if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
		{
			RTC_ClearITPendingBit(RTC_IT_ALR); 	//清Alarm 中断标志位(ALRF)
			LED=(LED==0);						//LED状态翻转
			RTC_Alarm_Set(2);					//设定2s后闹钟
		}	
	}

这里没什么说的了,效果就是连续设置闹钟,通过LED显示效果。整个过程就是复位后LED亮(低电平亮)5S,后续每隔大约2SLED亮灭切换一次。

下面把 RCC_Configuration(); RTC_Config(); //RTC的程序附上,保证大家程序调通,这里没什么讲的了。

void RCC_Configuration(void){ //RCC时钟的设置  
	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_PLLMul_x(枚举2~16)是倍频值。当HSE=8MHZ,RCC_PLLMul_9时PLLCLK=72MHZ   
		   
		RCC_HCLKConfig(RCC_SYSCLK_Div1); //RCC_SYSCLK_Div1——AHB时钟 = 系统时钟(SYSCLK) = 72MHZ(外部晶振8HMZ)   
		RCC_PCLK1Config(RCC_HCLK_Div2); //设置低速AHB时钟(PCLK1),RCC_HCLK_Div2——APB1时钟 = HCLK/2 = 36MHZ(外部晶振8HMZ)   
		RCC_PCLK2Config(RCC_HCLK_Div1); //设置高速AHB时钟(PCLK2),RCC_HCLK_Div1——APB2时钟 = HCLK = 72MHZ(外部晶振8HMZ)   
		FLASH_SetLatency(FLASH_Latency_2); //设置FLASH存储器延时时钟周期数   

		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //选择FLASH预取指缓存的模式,预取指缓存使能   
		RCC_PLLCmd(ENABLE);	//使能PLL
		while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL输出稳定   
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //选择SYSCLK时钟源为PLL
		while(RCC_GetSYSCLKSource() != 0x08); //等待PLL成为SYSCLK时钟源   
	}  
}  

void RTC_First_Config(void){ //首次启用RTC的设置
	RCC->APB1ENR|=(0x10000000+0x08000000);//启用PWR和BKP的时钟(from APB1)	
	PWR->CR|=0x0100;			//后备域解锁
	RCC->BDCR|=0x10000;		//备份寄存器模块复位
	RCC->BDCR=0x0001;			//外部32.768KHZ晶振开启
	while ((RCC->BDCR&0x02) != 0x02);//等待稳定
	RCC->BDCR|=0x00000100;
	RCC->BDCR|=0x8000;//RTC开启
  while ((RTC->CRL&0x08) != 0x08);//开启后需要等待APB1时钟与RTC时钟同步,才能读写寄存器 
		//RTC_SetPrescaler(32762);//设置RTC分频器,使RTC时钟为1Hz,RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)   
	RTC->CRL |= 0x10;		//RTC进入配置模式
	RTC->PRLH = 0x00;
	RTC->PRLL = 32767;
	RTC->CRL &= 0xEF;		//RTC退出配置模式
	RTC_WaitForLastTask();//等待寄存器写入完成
}
void RTC_Config(void){ //实时时钟初始化
  if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)//判断寄存数据是否丢失       
     RTC_First_Config();//重新配置RTC 
	else
	{
		RCC_ClearFlag();//清除RCC中复位标志
		RCC_RTCCLKCmd(ENABLE);//使能RTCCLK        
		RTC_WaitForSynchro();//等待RTC时钟与APB1时钟同步
  }
}

不差这个了,一并送上

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"	 
																	    
	 
//位带 *** 作,实现51类似的GPIO控制功能
//具体实现思想,参考<>第五章(87页~92页).
//IO口 *** 作宏定义
#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)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_base+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_base+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_base+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_base+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_base+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_base+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_base+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_base+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_base+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_base+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_base+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_base+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_base+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_base+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#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); //RCC时钟类的设置


#endif

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5692614.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存