STM32F103有两个高级定时器,分别是TIM1和TIM8;高级控制定时器(TIM1和TIM8)由一个16位的自动装载计数器组成,它由一个可编程的预分频器驱动。
适用场合:
测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、PWM、嵌入死区时间的互补PWM等);
使用方法
使用定时器预分频器和RCC时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。
接下来以TIM1为例子,结合蜂鸣器来说明如何使用高级定时器,本次主要使用它的计数模式,实现精确的计数功能。
蜂鸣器原理图
解析:
U8A为蜂鸣器,正极连接3.3V电压,负极与PNP三极管相连,当三极管基极为低电平时导通,蜂鸣器鸣叫;故给Buzzer引脚不同时间的脉宽,就可以实现蜂鸣器鸣叫的频率(Buzzer与单片机的PB9引脚相连)
本次实验使用的是有源蜂鸣器,它内部带震荡体,通电就会鸣叫。
TIM1定时器程序的编写
1.创建TIM函数
void TIM1_UserConfig(u16 Period,u16 Prescaler)
//第一个形参用来设置自动重载计数周期值
//第二个形参是用来设置分频系数
//之后计算脉宽会用到
2.定义TIM结构体和中断结构体
TIM_TimeBaseInitTypeDef TIM_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
3.选择TIM1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
4.结构体参数配置
在库文件中,我们可以看到TIM1结构体的定义,包括两个u16类型的重装载值和预分频值、时钟分割、计数模式、u8类型的重复计数次数
TIM_InitStructure.TIM_Period = Period;//重装载值
TIM_InitStructure.TIM_Prescaler = Prescaler;//分频系数
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分割
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_InitStructure.TIM_RepetitionCounter = 0;//只要重装载值计数完毕就产生更新
TIM_TimeBaseInit(TIM1,&TIM_InitStructure);//初始化
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断标志位
TIM_ITConfig(TIM1,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//开启中断更新和触发中断源
TIM_Cmd(TIM1,ENABLE);//开启全局中断
5.中断配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//选择中断分组
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;//选择TIM1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子占优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStructure);//初始化
6.蜂鸣器配置
//beep.c
#include "beep.h"
void BEEP_UserConfig(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = BEEP;//PB9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//2MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式
GPIO_Init(BEEP_PROT,&GPIO_InitStructure);
GPIO_SetBits(BEEP_PROT,BEEP);//起始状态拉高电平
}
//beep.h
#ifndef __BEEP_H
#define __BEEP_H
#include "sys.h"
#define BEEP GPIO_Pin_9
#define BEEP_PROT GPIOB
void BEEP_UserConfig(void);
#endif
7.中断处理函数配置
void TIM1_UP_IRQHandler(void){
//获取TIM1中断状态
//若为1则产生中断
if(TIM_GetITStatus(TIM1,TIM_IT_Update) != RESET){
//获取引脚状态,若为高电平则取反变为低电平
//GPIO_ReadOutputDataBit() 读取GPIO输出状态函数
GPIO_WriteBit(BEEP_PROT,BEEP,(BitAction)(!GPIO_ReadOutputDataBit(BEEP_PROT,BEEP)));
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断
}
}
8.main函数
#include "sys.h"
#include "led.h"
#include "time.h"
#include "beep.h"
int main(void)
{
LED_UserConfig();
BEEP_UserConfig();
TIM1_UserConfig(50-1,7200-1);
while(1){;}
}
脉宽过程计算分析
TIM1_UserConfig(50-1,7200-1);//5ms
我们单片机的频率为72MHz =72 000 000Hz
先对其进行7200分频 ,故分频系数Prescaler为7200
72 000 000/7200 = 1 000 0
我们需要5ms的脉宽 5ms=200hz 故用1 000 0/200=50 既重装载值Period为50
下面是我用逻辑分析仪抓取的波形,脉宽正好为5ms
最后,把程序下载进单片机,就可以听到蜂鸣器鸣叫了
例程代码
链接:https://pan.baidu.com/s/1j49awMoDhJbcSWNuCiR34w
提取码:mow1