STM32的定时器中断

发布者:JoyfulHearted最新更新时间:2018-04-15 来源: eefocus关键字:STM32  定时器中断 手机看文章 扫描二维码
随时随地手机看文章

实验目的:

让蜂鸣器每隔一秒响一次;


实验步骤:



实验程序:


  1. /************************led.c***********************/  

  2. #include "stm32f4xx.h"  //在SYSTEM目录下可以找到  

  3. #include "sys.h"  

  4.   

  5.   

  6. void LED_Init(void){  

  7.       

  8.     RCC->AHB1ENR |= 1<<5;  //使能GPIO端口的F时钟  

  9.     

  10.     GPIO_Set(GPIOF,PIN9|PIN10,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_25M,GPIO_PUPD_PU);  

  11.     PFout(9) = 1;  

  12.     PFout(10) = 1;  

  13.       

  14. }  


  1. /************************led.h***********************/  

  2. #ifndef _LED_H  

  3. #define _LED_H  

  4.   

  5.   

  6. void LED_Init(void);  

  7.   

  8.   

  9. #endif  


  1. /************************beep.c***********************/  

  2. #include "sys.h"  

  3. #include "beep.h"  

  4.   

  5.   

  6. void Beep_Init(void){  

  7.     RCC->AHB1ENR |= 1<<5;          //使能PORTE时钟   

  8.     GPIO_Set(GPIOF,PIN8,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PD); //PF8设置,下拉  

  9.     PFout(8) =0;                        //关闭蜂鸣器   

  10. }  


  1. /************************beep.h***********************/  

  2. #include "sys.h"  

  3.   

  4.   

  5. #ifndef _BEEP_H  

  6. #define _BEEP_H  

  7.   

  8.   

  9. void Beep_Init(void);  

  10.   

  11.   

  12. #endif  

  13. /************************timer.c***********************/  

  14. #include "sys.h"  

  15. #include "stm32f4xx.h"  

  16.   

  17.   

  18. /* 

  19. 本示例的作用就是, 

  20. 让蜂鸣器每隔一秒响一次; 

  21. */  

  22.   

  23.   

  24. /* 

  25. 关于定时器的操作可参考寄存器版的步骤 

  26. */  

  27.   

  28.   

  29. /* 

  30. 中断初始化函数: 

  31. 主要是关于寄存器的相关配置 

  32. */  

  33. void TIM3_Init(void){  

  34.       

  35.     /************************* 

  36.     定时器中断的设置:    

  37.     *************************/  

  38.       

  39.     //使能TIM3时钟;  

  40.     RCC->APB1ENR |= 1 << 1;    

  41.       

  42.     /*预分频器*/  

  43.     TIM3->PSC = 8400 - 1;  

  44.       

  45.     /*ARR为自动重载寄存器*/  

  46.     TIM3->ARR = 10000 -1 ;  

  47.       

  48.     //使能更新中断  

  49.     TIM3->DIER |= 1;  

  50.       

  51.     //使能计数器  

  52.     TIM3->CR1 |= 1;  

  53.       

  54.       

  55.     /*TIM中断分组设置*/  

  56.       

  57.     //SCB和NVIC,可参考STM32F3与STM32F4系列Cortex M4内核编程手册.pdf  

  58.     SCB->AIRCR |= 0x5 << 8; //设置分组  

  59.     NVIC->IP[29] |= 0; //设置优先级,具体可分析MY_NVIC_Init()函数;  

  60.       

  61.     //若不使能,则中断不会发生  

  62.     NVIC->ISER[0] |= 1 << 29;  //使能中断;  

  63.       

  64. }  

  65.   

  66.   

  67.   

  68. /*每1000ms产生一次中断*/  

  69. void TIM3_IRQHandler(void){  

  70.       

  71.     /* 

  72.     中断处理函数: 

  73.     */  

  74.       

  75.   

  76.     if(TIM3->SR&0X0001){  

  77.         PFout(8) = !PFout(8);  

  78.     }  

  79.       

  80.       

  81.     /* 

  82.     在中断里边最后记得清中断标志: 

  83.     */  

  84.     TIM3->SR &= ~(1 << 0);  

  85. }   


  1. /*************************timer.h**********************/  

  2. #ifndef _TIMER_H  

  3. #define _TIMER_H  

  4.   

  5.   

  6. void TIM3_Init(void);  

  7.   

  8.   

  9. #endif  


  1. /*************************test.c**********************/  

  2. #include "sys.h"  

  3. #include "delay.h"  

  4. #include "beep.h"  

  5. #include "timer.h"  

  6. #include "led.h"  

  7.   

  8.   

  9. int main(void){  

  10.       

  11.     Stm32_Clock_Init(336,8,2,7);//设置时钟,168Mhz  //思考一下为啥要设置整个时钟(到时可参考时钟那章节);  

  12.     delay_init(168);        //初始化延时函数  

  13.     LED_Init();  

  14.     Beep_Init();  

  15.     TIM3_Init();  

  16.       

  17.     while(1){  

  18.         PFout(9) = 0;  

  19.         delay_ms(1000);  

  20.         PFout(9) = 1;  

  21.         delay_ms(1000);  

  22.     }  

  23.       

  24. }  





实验分析:

我们主要分析一下定时器中断中,关于寄存器的设置问题

1. RCC->APB1ENR |= 1 << 1;  

这条语句的作用就是:使能TIM3时钟;

外设这么多,我咋知道,我们应该在哪条总线上去使能响应的外设?

第一种办法就是查看RCC寄存器,看其每个寄存器的每位的解释;

第二种办法就是看对应芯片的整个框图,如:


由上述视图,我们可知:TIM3是挂在APB1总线上的,所以我们只需使能APB1ENR寄存器上的响应的位就可以达到我们使能响应的外设的时钟的效果;

查看APB1ENR寄存器,我们可知:






所以在这里就写成了RCC->APB1ENR |= 1 << 1


2. TIM3->PSC = 8400 - 1;

3. TIM3->ARR = 10000 -1 ;

第2条语句和第3条语句的作用就是设置预分频器和自动重载寄存器;

但是在设置这两个寄存器之前,我们必须要搞清楚一点就是:计数器的时钟频率从哪里来?

查看定时器的框图:




注:由上述的定时器框图,我们可以得知:CK_INT也就是来自RCC的TIMxCLK


再结合第5条语句,其作用就是将CEN位写入1,所以,这样,我们就将预分频器的时钟CK_PSC设置为了内部时钟CK_INT;

此时,我们需要搞清楚CK_INT的时钟多少,在test.c中,我们看到:Stm32_Clock_Init()这个函数,其函数体如下:


  1. void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)  

  2. {    

  3.     RCC->CR|=0x00000001;     //设置HISON,开启内部高速RC振荡  

  4.     RCC->CFGR=0x00000000;        //CFGR清零   

  5.     RCC->CR&=0xFEF6FFFF;     //HSEON,CSSON,PLLON清零   

  6.     RCC->PLLCFGR=0x24003010; //PLLCFGR恢复复位值   

  7.     RCC->CR&=~(1<<18);         //HSEBYP清零,外部晶振不旁路  

  8.     RCC->CIR=0x00000000;     //禁止RCC时钟中断   

  9.     Sys_Clock_Set(plln,pllm,pllp,pllq);//设置时钟   

  10.     //配置向量表                 

  11. #ifdef  VECT_TAB_RAM  

  12.     MY_NVIC_SetVectorTable(1<<29,0x0);  

  13. #else     

  14.     MY_NVIC_SetVectorTable(0,0x0);  

  15. #endif   

  16. }             


接着再追踪Sys_Clock_Set()函数,进到其函数体内,我们可以看到:


  1. //时钟设置函数  

  2. //Fvco=Fs*(plln/pllm);  

  3. //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));  

  4. //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));  

  5.   

  6. //Fvco:VCO频率  

  7. //Fsys:系统时钟频率  

  8. //Fusb:USB,SDIO,RNG等的时钟频率  

  9. //Fs:PLL输入时钟频率,可以是HSI,HSE等.   

  10. //plln:主PLL倍频系数(PLL倍频),取值范围:64~432.  

  11. //pllm:主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.  

  12. //pllp:系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)  

  13. //pllq:USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.  

  14.   

  15. //外部晶振为8M的时候,推荐值:plln=336,pllm=8,pllp=2,pllq=7.  

  16. //得到:Fvco=8*(336/8)=336Mhz  

  17. //     Fsys=336/2=168Mhz  

  18. //     Fusb=336/7=48Mhz  

  19. //返回值:0,成功;1,失败。  

  20. u8 Sys_Clock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq)  

  21. {   

  22.     u16 retry=0;  

  23.     u8 status=0;  

  24.     RCC->CR|=1<<16;                //HSE 开启   

  25.     while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//等待HSE RDY  

  26.     if(retry==0X1FFF)status=1;  //HSE无法就绪  

  27.     else     

  28.     {  

  29.         RCC->APB1ENR|=1<<28;   //电源接口时钟使能  

  30.         PWR->CR|=3<<14;        //高性能模式,时钟可到168Mhz  

  31.         RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);//HCLK 不分频;APB1 4分频;APB2 2分频.   

  32.         RCC->CR&=~(1<<24); //关闭主PLL  

  33.         RCC->PLLCFGR=pllm|(plln<<6)|(((pllp>>1)-1)<<16)|(pllq<<24)|(1<<22);//配置主PLL,PLL时钟源来自HSE  

  34.         RCC->CR|=1<<24;            //打开主PLL  

  35.         while((RCC->CR&(1<<25))==0);//等待PLL准备好   

  36.         FLASH->ACR|=1<<8;      //指令预取使能.  

  37.         FLASH->ACR|=1<<9;      //指令cache使能.  

  38.         FLASH->ACR|=1<<10;     //数据cache使能.  

  39.         FLASH->ACR|=5<<0;      //5个CPU等待周期.   

  40.         RCC->CFGR&=~(3<<0);        //清零  

  41.         RCC->CFGR|=2<<0;       //选择主PLL作为系统时钟     

  42.         while((RCC->CFGR&(3<<2))!=(2<<2));//等待主PLL作为系统时钟成功.   

  43.     }   

  44.     return status;  

  45. }    

在看上述函数时,我们需要结合以下一幅图:




从芯片手册中,我们还可以找到一句话:


而在Sys_Clock_Set()函数中,我们可以对照寄存器的设置,得知:

AHB不分频,APB1 4分频,APB2  2分频,且可得知:AHB的频率为168MHZ;

而定时器3又是挂在APB1总线上的,所以由于APB1预分频器为4,并不为1,所以,

定时器的时钟频率等于APB1的频率的2倍,而APB1的时钟频率等于AHB频率的1/4,

所以可知:定时器的时钟频率为84MHZ;而定时器时钟也就是RCC的TIM3CLK的时钟,

所以,内部时钟CK_INT的时钟频率为84MHZ;由此,我们设置预分频器和计数器才有意义;


注:在这里再唠叨一句的是:在这里将预分频器减一的原因是:查看TIMxPSC寄存器,其下方的

解释可以得知:计数器时钟频率CK_CNT等于CK_PSC的频率/(PSC[15:0] + 1),所以在这里就将

预分频器减一;而将自动装载的值减一的原因是:若我们设置自动装载的值为5000,那么计数器

从0开始计数,然后计数到5000,然后又从5000跳到0,当跳到0时,其中断才会触发,所以,

此时,计数器实际上是计了5001次,所以,我们需要将其减一;






4. TIM3->DIER |= 1;

其作用就是使能更新中断


5. TIM3->CR1 |= 1;

其作用就是使能计数器


6. SCB->AIRCR |= 0x5 << 8;

7. NVIC->IP[29] |= 0;

8. NVIC->ISER[0] |= 1 << 29;

第6,7,8条语句的解释,可参考STM32的外部中断那篇博客中对应部分的解释;



注意事项:

1.在上述中断函数中,若没有加if(TIM3->SR&0X0001)这条语句,
那么蜂鸣器始终不会响,若加了if(TIM3->SR&0X0001)这条语句,
那么蜂鸣器才会如程序中所示,正常工作;理论上,不加这条if语句,
蜂鸣器也会隔一段时间响一次的,但看到的 事实是蜂鸣器根本不会响;

至于其原因,暂时还没有找到合理的解释,现在这里载一笔;


关键字:STM32  定时器中断 引用地址:STM32的定时器中断

上一篇:STM32的输入捕获
下一篇:STM32的LED灯实验

推荐阅读最新更新时间:2024-03-16 15:59

【跟着江科大学Stm32】STM32F103C6T6_实现呼吸灯_代码
PWM.h #ifndef __PWM_H #define __PWM_H void PWM_Init(); void PWM_SetCompare1(uint16_t Compare); #endif PWM.c #include stm32f10x.h // Device header void PWM_Init() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启定时器2 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//通道2时钟使能函数
[单片机]
【跟着江科大学<font color='red'>Stm32</font>】STM32F103C6T6_实现呼吸灯_代码
STM32开发板显示界面添加状态栏
需要完成的主要工作有: 1) 划分显示位置 2) 绘制状态栏背景 3) 绘制电池图标:一共7种图标baticos 4) 绘制时间:只显示时和分 5) 循环检测时间变化,并更改显示时间数值,同步判断电池电量,绘制相应图标 源文件:satusbar.c #include includes.h #include rtc.h const u8* baticos = { 0:/STATUSBAR/BAT/battery0.bmp , 0:/STATUSBAR/BAT/battery1.bmp , 0:/STATUSBAR/BAT/battery2.bmp , 0:/STATUSBAR/BAT/battery3.
[单片机]
<font color='red'>STM32</font>开发板显示界面添加状态栏
AnalogML供应商Aspinity加入ST合作伙伴计划
Aspinity加入意法半导体(ST)合作伙伴计划,为始终在线的边缘处理提供完整的AnalogML解决方案。模拟机器学习先驱与高性能微控制器的领导者合作,以延长IoT设备的电池寿命。 Aspinity已加入ST合作伙伴计划,加速将Aspinity的超低功耗模拟机器学习(analog ML)内核与ST的高性能微控制器(MCU)集成到始终小型,功耗受限的环境中。 Aspinity的产品基于其接近零功率的AnalogML内核,该内核使基于事件的系统唤醒完全在信号链前端的模拟域内发生,从而使大多数系统保持睡眠状态,直到检测到事件发生为止。Aspinity与ST之间的合作使客户能够迅速采用AnalogML,以更有效地弥合模拟物理世界
[单片机]
STM32之GPIO端口输入模式配置举例
什么情况下用到输入模式? 在模拟采样时; 在按键输入时; 常用的输入模式有那些? 模拟输入; 上拉或下拉输入; GPIO上拉输入举例: #include key.h #include sys.h void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //结构体变量声明 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟 GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_3|GPIO_Pin_4); //K0=PE4,K1=
[单片机]
关于STM32软硬件兼容性相关的知识
Ⅰ、写在前面 很多朋友初学STM32的时候,对STM32芯片很多相关知识都不是很了解,导致了在学习的路上很迷茫,甚至半途放弃。希望本文的内容对初学的朋友有一定帮助。 常见问题: 1.我开发板是STM32F103ZE芯片,但网上找到的软件工程基于STM32F103R8芯片的,我能直接将工程下载并调试吗? 2.我有 STM32F205 R8的原理图和封装库,但现在需要画STM32F405RC芯片的板子,能直接替换使用吗? 以上问题在你阅读本文之后就会得到比较明确的答案。 关于本文的更多详情请往下看。 Ⅱ、本文要点 从本文的标题可以看得出来,主要是站在“STM32兼容性”的角度来分析问题。 在开发STM32项目中,
[单片机]
关于<font color='red'>STM32</font>软硬件兼容性相关的知识
stm32 hal can接收大量数据的轰炸后,不能继续接收
原因:若在接收的时候发送数据, 发送中的处理: hal_can_transmit()中会进行hal_lock(hcan);然后更改can状态为HAL_CAN_STATE_BUSY_TX相关的。 再谈一下接收中的处理,不用多说肯定是在接收中断国会开启下一次接收,即hal_can_receive_it();那么这里边又干了什么: /* Check if CAN state is not busy for RX FIFO0 */ if((FIFONumber == CAN_FIFO0) && ((hcan- State == HAL_CAN_STATE_BUSY_RX0) ||
[单片机]
STM32 Cubemax(九) ——利用输入捕获中断实现超声波测距
前言 因为要实现一下卡尔曼滤波,所以这次先写一下超声波,顺便重温一下输入捕获中断。 一、超声波模块原理 但凡在网上搜过超声波这个模块的,对这个图都不陌生,简单的说就是想得到超声波的数据,包含以下几个步骤。 1.发送大于10us的触发信号。 2.检测超声波发出信号时产生的高电平。 3.检测超声波接收到信号时产生的低电平 而我们就是通过后两步,即去检测处因为超声波产生的高电平的时间,从而来得到距离信息的。而输入捕获的作用就是用来去捕获高电平或者低电平的持续时间的 我们的编程就是根据上图来实现的。 二、Cubmax配置 1.配置定时器输入捕获 本实验板子为F407,分频系数选择84-1,则计数精度达到1us。10
[单片机]
<font color='red'>STM32</font> Cubemax(九) ——利用输入捕获<font color='red'>中断</font>实现超声波测距
STM32基础知识:中断系统
中断系统 1 数据传输方式 无条件传输 :处理器不必了解外部设备状态,直接进行数据传输,用于指示灯和按键等简单设备.。 查询方式 :传输前,一方先查询另一方的状态,若已经准备好就传输,否则就继续查询。 中断方式 :一方通过申请中断的方式与另一方进行数据传输,收发双方可以并行工作。 直接存储器访问 :处理器内部建立片内外设和内存之间的数据传输通道,传输过程不需要处理器参与。 2 中断系统的基本概念 2.1 中断全过程 中断发生: 当CPU在处理某一事件A时,发生了另一事件B,请求CPU迅速去处理。 中断处理: CPU暂停当前的工作,转去处理事件B。 中断返回: 当CPU将事件B处理完毕后,再回到事件A中被暂停的地方继
[单片机]
<font color='red'>STM32</font>基础知识:<font color='red'>中断</font>系统
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved