嵌入式设计与开发项目-TIM应用程序设计
知识扫盲:TIM除了可以实现基本的定时功能外,还可以实现输入捕获和输出比较等功能。 输入捕获可以测量PWM信号的周期和脉宽,输出比较可以输出单脉冲,也可以输出PWM信号。
一、实现的功能
- ①TIM1的通道2(PA9)输出1kHz、占空比为25%的矩形波;
- ②用TIM2通道2(PA1)测量矩形波周期和脉冲宽度的初始化;
二、根据功能实现代码
1、主文件main.c
#include"key.h"
#include"led.h"
#include"lcd.h"
#include "usart.h"
#include "i2c.h"
#include "adc.h"
#include "tim.h"
unsigned int uiTim_Val[2];
unsigned char ucSec,ucSec1;
unsigned char pucStr[21];
unsigned long ulTick_ms;
void TIM_Proc(void);
int main(void)
{
SysTick_Config(72000); //定时1ms(HCLK = 72MHz)
KEY_Init();
LED_Init();
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
USART2_Init(9600);
i2c_init();
ADC1_Init();
TIM1_OCInit();
TIM2_ICInit();
sprintf((char *)pucStr," TIM DEMO");
LCD_DisplayStringLine(Line3,pucStr);
printf("%s\r\n",pucStr);
while(1)
{
LED_Disp(ucSec);
TIM_Proc();
}
}
void TIM_Proc(void)
{
if(ucSec != ucSec1)
{
ucSec1 = ucSec;
TIM2_Cap(uiTim_Val);
sprintf((char *)pucStr," %4u %1ums",
uiTim_Val[0],uiTim_Val[0]/1000);
LCD_DisplayStringLine(Line5,pucStr);
printf("%3u %s",ucSec,pucStr);
sprintf((char *)pucStr," %4u %2u%%",uiTim_Val[1],uiTim_Val[1]*100/uiTim_Val[0]);
LCD_DisplayStringLine(Line6,pucStr);
printf("%s\r\n",pucStr);
}
}
//SysTick 中断处理程序
void SysTick_Handler(void)
{
ulTick_ms++;
if(ulTick_ms % 1000 ==0)
ucSec++;
}
主函数分析:❤️ ❤️ ❤️
- 每隔1s捕获一次矩形波周期和脉冲宽度;
- 通过TIM2_Cap()获取周期和高电平所占的时间,从而计算出脉宽为25%;
2、TIM头文件“tim.h”
#include "stm32f10x.h"
void TIM1_OCInit(void);
void TIM2_ICInit(void);
unsigned char TIM2_Cap(unsigned int* puiTim_Val);
简要分析:❤️ ❤️
- 初始化PA9为复用推挽输出,同时初始化TIM1定时器1和OC比较输出250us高电平的矩形方波;
- 初始化PA1为浮空输入,同时初始化TIM2定时器2和IC上升沿触发并直接映射到TI1上;
- 获取捕获到的PWM的周期和高电平的所占周期;
3、TIM源文件“tim.c”
#include "tim.h"
//TIM1通道2(PA9)输出矩形波初始化子程序
void TIM1_OCInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
//允许GPIOA和TIM1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
//PA9-IN8复用推挽输出
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_AF_PP; //复用推挽输出模式
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_Prescaler = 71; //psc预装分频器的值
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStruct.TIM_Period = 999; //定时器周期,设定自动重载的值
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //时钟不分频
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //溢出重复计数器
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct); //根据指定参数初始化TIM1
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //脉宽调制模式1
TIM_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable; //使能比较输出
TIM_OCInitStruct.TIM_OutputNState =TIM_OutputNState_Disable; //禁止比较互补输出
TIM_OCInitStruct.TIM_Pulse = 250; //比较输出的脉冲宽度,设置占空比
TIM_OCInitStruct.TIM_OCPolarity =TIM_OCPolarity_High; //比较输出的极性为高电平
TIM_OC2Init(TIM1, &TIM_OCInitStruct); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_CtrlPWMOutputs(TIM1, ENABLE); //主动输出使能
TIM_Cmd(TIM1, ENABLE); //使能定时器,计数器开始计数
}
//TIM2通道2(PA1)测量矩形波周期和脉冲宽度初始化子程序
void TIM2_ICInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
//允许GPIOA和TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//PA9-IN8复用推挽输出
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStruct.TIM_Period = 65535; //定时器周期,设定自动重载的值
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2; //选择通道2
TIM_ICInitStruct.TIM_ICPolarity =TIM_ICPolarity_Rising; //设置为上升沿捕获
TIM_ICInitStruct.TIM_ICSelection =TIM_ICSelection_DirectTI; //直接映射到TI1
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分频
TIM_ICInitStruct.TIM_ICFilter =0; //滤波器长度
TIM_PWMIConfig(TIM2,&TIM_ICInitStruct);
TIM_SelectInputTrigger(TIM2,TIM_TS_TI2FP2); //参考TIM结构图选择滤波后的TI2输入作为触发源,触发下面程序的复位
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//复位模式-选中的触发输入(TRGI)的上升沿初始化计数器,并且产生一个更新线号
TIM_Cmd(TIM2,ENABLE);
}
//TIM2测量方波周期和脉冲宽度处理程序
unsigned char TIM2_Cap(unsigned int* puiTim_Val)
{
//状态标志位获取
if(TIM_GetFlagStatus(TIM2,TIM_FLAG_CC2))
{
puiTim_Val[0] = TIM_GetCapture2(TIM2)+1; //获得CCR2的值
puiTim_Val[1] = TIM_GetCapture1(TIM2)+1; //获得CCR1的值
return 1;
}
return 0;
}
简要分析:❤️ ❤️
- 初始化TIM1通道2(PA9)输出矩形波的顺序:①初始化PA9的GPIO结构体(复用推挽输出) → ②初始化TIM和OC结构体→ ③配置TIM1的预分频值、计数模式、分频值、分频系数、重复计数值以及初始化TIM1结构体 → ④配置oc的工作模式、使能比较输出模式、禁止补偿输出、设置pwm占空比为250、设置占空比的电平以及初始化OC结构体 → ⑤主动输出使能以及启动定时器1 ;
- 初始化TIM2通道2(PA1)测量矩形波周期和脉冲宽度的顺序:①初始化PA1的GPIO结构体(浮空输入模式) → ②初始化TIM和IC结构体→ ③配置TIM1的预分频值、计数模式、分频值、分频系数、重复计数值以及初始化TIM1结构体 → ④配置IC的通道、触发条件、直接映射、分频系数、滤波器长度以及初始化IC结构体 → ⑤选择滤波后的TI2输入作为触发源、选中的触发输入(TRGI)的上升沿初始化计数器、启动TIM2 ;
- 获取TIM2的CC2标志位,然后获取方波周期和脉冲宽度;
三、实现功能过程的注意与学习点
1、注意点
- 配置的参数太多,容易配错或者缺少一些配置;
- 当使用IO的复用功能时,需要使能AFIO时钟,开启IO的复用功能;
2、学习的知识点
- ①PWM矩形方波的输出的IO配置为复用推挽输出,输入捕获配置为浮空输入模式;
- ②了解输出PWM输出方波和输入捕获的配置流程;
- ③学会通过预分频值和分频值计算计数的周期,从而可以进行精确的延时以及方波的占空比设置;
❤️ ❤️ ❤️ ❤️ ❤️ ❤️