stm32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。(tim1和tim8是能够产生3对pwm互补输出的高级登时其,常用于三相电机的驱动,时钟由apb2的输出产生;tim2-tim5是普通定时器;tim6和tim7是基本定时器,其时钟由apb1输出产生)
本实验要实现的功能是:用普通定时器tim2每一秒发生一次更新事件,进入中断服务程序翻转led1的状态。
预备知识:
① stm32通用定时器tim2是16位自动重装载计数器。
② 向上计数模式:从0开始计数,计到自动装载寄存器(timx_arr)中的数值时,清0,依次循环。
需要弄清楚的两个问题:
1. 计数器的计数频率是什么?
这个问题涉及到rcc时钟部分,如下图所示:
定时器的时钟不是直接来自apb1或apb2,而是来自于输入为apb1或apb2的一个倍频器。
下面以定时器2~7的时钟说明这个倍频器的作用:当apb1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于apb1的频率;当apb1的预分频系数为其它数值(即预分频系数为2、4、8或16)时,这个倍频器起作用,定时器的时钟频率等于apb1的频率两倍。
假定ahb=36mhz,因为apb1允许的最大频率为36mhz,所以apb1的预分频系数可以取任意数值;当预分频系数=1时,apb1=36mhz,tim2~7的时钟频率=36mhz(倍频器不起作用);当预分频系数=2时,apb1=18mhz,在倍频器的作用下,tim2~7的时钟频率=36mhz。
有人会问,既然需要tim2~7的时钟频率=36mhz,为什么不直接取apb1的预分频系数=1?答案是:apb1不但要为tim2~7提供时钟,而且还要为其它外设提供时钟;设置这个倍频器可以在保证其它外设使用较低时钟频率时,tim2~7仍能得到较高的时钟频率。
再举个例子:当ahb=72mhz时,apb1的预分频系数必须大于2,因为apb1的最大频率只能为36mhz。如果apb1的预分频系数=2,则因为这个倍频器,tim2~7仍然能够得到72mhz的时钟频率。能够使用更高的时钟频率,无疑提高了定时器的分辨率,这也正是设计这个倍频器的初衷。
注意:apb1和apb2上挂的外设如图所示:
定时器的计数频率有个公式:
timx_clk = ck_int / (tim_prescaler + 1)
其中:timx_clk 定时器的计数频率
ck_int 内部时钟源频率(apb1的倍频器送出时钟)
tim_prescaler 用户设定的预分频系数,取值范围0~65535。
例如:rcc中ahb=72mhz、apb1=36mhz、apb2=72mhz,则ck_int=72mkz。
2. 如何计算定时时间?
上述公式中tim_prescaler涉及到寄存器timx_psc
如果tim_prescaler设为36000,由上面公式可知:
定时器的计数频率 timx_clk = 72mkz / 36000 = 2000hz,则定时器的计数周期=1/2000hz=0.5ms.
如果要定时1秒,则需要计数2000次,这也是自动重装载的值。又涉及到timx_arr
只要上述两个问题搞清楚了,剩下的就是设置相应寄存器的对应位了。
led硬件连接如下图所示:高电平点亮led。
第一步:配置系统时钟。见stm32f103x rcc寄存器配置
除此之外,还需将gpio和tim2外设时钟打开。
rcc_apb2periphclockcmd(rcc_apb2periph_gpioc, enable);
rcc_apb1periphclockcmd(rcc_apb1periph_tim2, enable);
注意:tim2是挂在apb1上的,打开时钟时别写错了,调用rcc_apb1periphclockcmd函数,而不是rcc_apb2periphclockcmd。
第二步:配置中断向量表。见stm32_exti(含nvic)配置及库函数讲解
void nvic_configuration(void)
{
nvic_inittypedef nvic_initstructure;
#ifdef vect_tab_ram
nvic_setvectortable(nvic_vecttab_ram, 0x0);
#else
nvic_setvectortable(nvic_vecttab_flash, 0x0);
#endif
nvic_prioritygroupconfig(nvic_prioritygroup_1);
nvic_initstructure.nvic_irqchannel = tim2_irqchannel;
nvic_initstructure.nvic_irqchannelpreemptionpriority = 0;
nvic_initstructure.nvic_irqchannelsubpriority = 4;
nvic_initstructure.nvic_irqchannelcmd = enable;
nvic_init(&nvic_initstructure);
}
该函数完成两个功能
1. 决定将程序下载到ram中还是flash中
2. 配置中断分组。(nvic中断分组只能设置一次)
3. 选择中断通道号,抢占式优先级和响应优先级,使能中断
第三步:配置gpio的模式。输入模式还是输出模式。点亮led已讲过,见stm32_gpio配置及库函数讲解——led跑马灯
void gpio_configuration(void)
{
gpio_inittypedef gpio_initstructure;
gpio_initstructure.gpio_pin = gpio_pin_6;
gpio_initstructure.gpio_speed = gpio_speed_50mhz;
gpio_initstructure.gpio_mode = gpio_mode_out_pp;
gpio_init(gpioc, &gpio_initstructure);
}
第四步:定时器配置,本章重点!
void tim2_configuration(void)
{
tim_timebaseinittypedef tim_timebasestructure;
//重新将timer设置为缺省值
tim_deinit(tim2);
//采用内部时钟给tim2提供时钟源
tim_internalclockconfig(tim2);
//预分频系数为36000-1,这样计数器时钟为72mhz/36000 = 2khz
tim_timebasestructure.tim_prescaler = 36000 - 1;
//设置时钟分割
tim_timebasestructure.tim_clockdivision = tim_ckd_div1;
//设置计数器模式为向上计数模式
tim_timebasestructure.tim_countermode = tim_countermode_up;
//设置计数溢出大小,每计2000个数就产生一个更新事件
tim_timebasestructure.tim_period = 2000;
//将配置应用到tim2中
tim_timebaseinit(tim2, &tim_timebasestructure);
//清除溢出中断标志
tim_clearflag(tim2, tim_flag_update);
//禁止arr预装载缓冲器
tim_arrpreloadconfig(tim2, disable); //预装载寄存器的内容被立即传送到影子寄存器
//开启tim2的中断
tim_itconfig(tim2, tim_it_update, enable);
}
该函数完成两个功能
1. 设定预分频系数tim_prescaler = 36000 - 1
2. 设定自动重装载值tim_period = 2000
注意:上述只是配置好了tim2,但还没有开启tim2。
下面给出timer2.c的完整代码
#include “stm32f10x_lib.h”
void rcc_configuration(void);
void nvic_configuration(void);
void gpio_configuration(void);
void tim2_configuration(void);
void delay(vu32 ncount);
int main(void)
{
#ifdef debug
debug();
#endif
rcc_configuration();
nvic_configuration();
gpio_configuration();
tim2_configuration();
tim_cmd(tim2, enable); //开启定时器2
while (1)
{
}
}
void rcc_configuration(void)
{
errorstatus hsestartupstatus;
rcc_deinit();
rcc_hseconfig(rcc_hse_on);
hsestartupstatus = rcc_waitforhsestartup()
if (hsestartupstatus == success)
{
flash_prefetchbuffercmd(flash_prefetchbuffer_enable);
flash_setlatency(flash_latency_2);
rcc_hclkconfig(rcc_sysclk_div1);
rcc_pclk2config(rcc_hclk_div1);
rcc_pclk1config(rcc_hclk_div2);
rcc_pllconfig(rcc_pllsource_hse_div1, rcc_pllmul_9);
rcc_pllcmd(enable);
while(rcc_getflagstatus(rcc_flag_pllrdy) == reset) {}
rcc_sysclkconfig(rcc_sysclksource_pllclk);
while(rcc_getsysclksource() != 0x08) {}
}
rcc_apb2periphclockcmd(rcc_apb2periph_gpioc, enable);
rcc_apb1periphclockcmd(rcc_apb1periph_tim2, enable);
}
void nvic_configuration(void)
{
nvic_inittypedef nvic_initstructure;
#ifdef vect_tab_ram
nvic_setvectortable(nvic_vecttab_ram, 0x0);
#else
nvic_setvectortable(nvic_vecttab_flash, 0x0);
#endif
nvic_prioritygroupconfig(nvic_prioritygroup_1);
nvic_initstructure.nvic_irqchannel = tim2_irqchannel;
nvic_initstructure.nvic_irqchannelpreemptionpriority = 0;
nvic_initstructure.nvic_irqchannelsubpriority = 4;
nvic_initstructure.nvic_irqchannelcmd = enable;
nvic_init(&nvic_initstructure);
}
void gpio_configuration(void)
{
gpio_inittypedef gpio_initstructure;
gpio_initstructure.gpio_pin = gpio_pin_6;
gpio_initstructure.gpio_speed = gpio_speed_50mhz;
gpio_initstructure.gpio_mode = gpio_mode_out_pp;
gpio_init(gpioc, &gpio_initstructure);
}
void tim2_configuration(void)
{
tim_timebaseinittypedef tim_timebasestructure;
//重新将timer设置为缺省值
tim_deinit(tim2);
//采用内部时钟给tim2提供时钟源
tim_internalclockconfig(tim2);
//预分频系数为36000-1,这样计数器时钟为72mhz/36000 = 2khz
tim_timebasestructure.tim_prescaler = 36000 - 1;
//设置时钟分割
tim_timebasestructure.tim_clockdivision = tim_ckd_div1;
//设置计数器模式为向上计数模式
关于MSP430FR2311的特点及应用介绍
功率半导体:现代电子工业的“心脏”与未来趋势
王春晖:美国的“封锁”将加速中国崛起
对于原汁机减速电机,我们该如何选择高品质
MediaTek宣布将进一步深化与海信的长期合作关系
STM32通用定时器TIM2的使用方法解析
RDK X3 Module发布,全新软硬件平台加速实现量产级产品落地
PLC或RTU作为数据采集站点如何通过GPRS进行远程下载
PCB多层板压缩制造中的难点有哪些?
华为在汽车领域的布局迈入2.0时代
最新MSP430 MCU Value Line Launch
RFID计时计圈技术可以做什么用
立柱机器人配件箱子封箱码垛生产线
关于物联网技术的分析和详细介绍
音频先锋xMEMS推出全新研讨会系列 加速全球增长:xMEMS Live – China 2023
一名工程师面试腾讯的经历
电动机点动和连续控制电路图解析
基于JIN AUDIO AP5540的USB 降噪USB Type-C麦克风方案
飞思卡尔推出了两款可适合用于旋转界面的MPR081和MPR082接近传感器
iPhone 9真机曝光外观与iPhone 8相似