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

#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时钟的具体时间设置,所以也不去列出。现在主要讲讲 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,后续每隔大约每2秒LED指示灯亮灭切换一次。

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

void RCC_Configuration(void){ //RCC时钟的设置  ErrorStatus HSEStartUpStatus;   RCC_DeInit();              /* RCC system reset(for debug purpose) RCC寄存器恢复初始化值*/   RCC_HSEConfig(RCC_HSE_ON); /* Enable HSE 使能外部高速晶振*/   HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* Wait till HSE is ready 等待外部高速晶振使能完成*/   if(HSEStartUpStatus == SUCCESS){   /*设置PLL时钟源及倍频系数*/   RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //RCC_PLLMul_x(枚举2~16)是倍频值。当HSE=8MHZ,RCC_PLLMul_9时PLLCLK=72MHZ   /*设置AHB时钟(HCLK)*/   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); //使能PLLwhile(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL输出稳定   RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //选择SYSCLK时钟源为PLLwhile(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控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(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

STM32设置闹钟中断相关推荐

  1. stm32 设置systick中断抢先式优先级

    最近使用STM32时希望将systick的中断优先级降低,但是CMSIS里给出的例子都是类似 NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;NVI ...

  2. STM32的RTC闹钟中断 总算整明白了

    转载:http://www.openedv.com/posts/list/22055.htm STM32的RTC闹钟中断 总算整明白了 现在用到了STM32的闹钟中断 去唤醒停机模式下的系统 看STM ...

  3. stm32之实时时钟RTC(掉电计时保持、秒中断、闹钟中断、溢出中断)

    前言:stm32系列产品普遍都有实时时钟RTC模块,它提供一个掉电保持计时功能,掉电后由后备供电区域供电.除了提供时间和日期之外,还可以设置闹钟提醒,且可以在待机模式下设置闹钟唤醒系统.在一些小容量. ...

  4. 将STM32设置睡眠模式(使用中断唤醒)之小白学习笔记

    #include "bsp_exti.h" #include "Led_Key.h" #include "bsp_SysTick.h" in ...

  5. 009 - STM32学习笔记 - 中断

    009 - STM32学习笔记 - 中断 这节的内容,野火的官方视频我反复看了好几次,但是感觉火哥在这块讲解的特别绕,理解起来很吃力,后来在看了一下其他老师的视频,结合一些书本资料和官方手册,才搞清楚 ...

  6. STM32单片机外部中断配置讲解

    2019独角兽企业重金招聘Python工程师标准>>> 单片机外部中断简介 所谓外部中断,就是通过外部信号所引起的中断,如单片机引脚上的电平变化(高电平.低电平).边沿变化(上升沿. ...

  7. stm32入门——定时器中断和中断优先级简介

    stm32入门--定时器中断 产生定时中断是定时器的用法之一,与定时器用来进行PWM输出和输入捕获相比,定时器中断更容易理解.掌握. 原理简介 使用通用定时器进行中断的原理,其实和开发板Systick ...

  8. STM32F030的低功耗案例(RTC闹钟中断定时唤醒喂狗+按键外部中断唤醒)

    最近使用到低功耗方案,采用的是STM32F030C8T6芯片,由于任务开启了看门狗,进入休眠后(采用的是STOP模式),需要及时喂狗,故而使用RTC闹钟中断定时唤醒来喂狗. 对比三种休眠模式:就设备的 ...

  9. STM32 EXTI外部中断及NVIC的抢占优先级和响应优先级解释

    1.中断类型 从之前的串口实验可以看出,STM32总共分为内部中断和外部中断,内部和外部的配置差别不是很大,外部中断只是多了一步,需要通过 GPIO_EXTILineConfig(uint8_t GP ...

最新文章

  1. 在ubuntu系统荣品开发配套JDK安装
  2. 2021 - 9 下旬 数据结构-线性表-循环队列-java实现代码
  3. linux下文件无法删除不能编辑
  4. 十道常见的MyBatis 面试题
  5. intellij选择困难症Spring Batch/Data JPA/Integration/MVC/Security/Web Flow/Web Services到底选哪个?
  6. 循环、格式化输出、数据统计
  7. c语言switch scanf语句,C语言中scanf函数与switch语句
  8. vue 中provide的用法_Vue多级组件provide/inject使用详解
  9. 分享:一篇webpack配置基础绝好文章
  10. [渝粤教育] 中国地质大学 运筹学1 复习题
  11. 【步步为赢】如何使用手机号码批量归属地查询分拣并且分类批量导出TXT文本EXCEL
  12. python弹出滑块怎么验证_python模拟哔哩哔哩滑块登入验证的实现
  13. 一种有趣的弱监督机器学习问题:比例标签学习(Learning from label proportions)
  14. 天体观测位置的计算--方位角和俯仰角
  15. 2020 Python中文社区热门文章 Top 10
  16. 很多情侣看了以后,不在关机
  17. js读Json,JSON与字符串转化,Java读JSON
  18. padStart 和 padEnd的使用
  19. 简述Spring的详细工作原理
  20. 为人处事的19个技巧

热门文章

  1. java 护眼_定时休息护眼神器(EyeDefender)护眼大法
  2. BIM模型文件下载——三层Revit商务办公楼模型
  3. 自媒体人必备运营工具
  4. 618数码好物哪些值得买、2022最新数码产品推荐
  5. JAVA中静态方法的调用
  6. java中的静态方法是什么
  7. 解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
  8. 配置公众号token
  9. BPR算法实战:基于BPR算法实现个性化商品推荐 代码+数据
  10. Docker安装FastDFS分布式文件系统