笔记整理自B站UP主江科大自化协教程《STM32入门教程-2023持续更新中》,所用单片机也为教程推荐单片机。
大致内容
第一部分:定时器基本定时的功能,定时器每隔这个时间产生一个中断,来实现每隔一个固定时间执行一段程序的目的,比如要做一个时钟、秒表或者使用一些程序算法的时候都需要用到定时中断这个功能
第二部分:定时器输出比较的功能,最常见的用途就是产生PWM波形,用于驱动电机等设备
第三部分:定时器输入捕获的功能,使用输入buhuo这个模块来实现测量方波频率的例子
第四部分:定时器的编码器接口,使用编码器接口能够更加方便地读取正交编码器的输出波形,在编码电机测速中,应用广泛
使用定时器的外部时钟,可以提供一个更加精准的时钟来计时或者也可以把外部时钟当做一个计数器,用来统计引脚上电平翻转的次数。
编码器接口简介
Encoder Interface 编码器接口
编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
每个高级定时器和通用定时器都拥有1个编码器接口
两个输入引脚借用了输入捕获的通道1和通道2
正交编码器
编码器接口基本结构
编码器接口测速代码讲解
第一步——开启RCC时钟,开启GPIO和定时器的时钟
第二步——配置GPIO,PA6和PA7配置成输入模式
第三步——配置时基单元,预分频器不分频,ARR自动重装值65535,CNT计数
第四步——配置输入捕获单元
第五步——配置编码器接口模式
第六步——启动定时器
先看一个库函数TIM_EncoderInterfaceConfig——定时器编码器接口配置
第一步——开启RCC时钟
//第一步开启RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
第二步——配置GPIO
GPIO上拉、下拉、浮空该如何选择?
可以看接这个引脚的外部模块的默认电平,如果外部模块空闲默认输出高电平,就选择上拉输入,默认输入高电平;如果外部模块默认输出低电平,就选择下拉输入,默认输入低电平,和外部模块保持默认状态一致,防止默认电平冲突,如果不确定外部模块输出的默认状态或者外部信号输出功率非常小,尽量选择浮空输入。
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
编码器接口就是一个带方向控制的外部时钟,就不需要内部时钟了
第三步——时基单元配置
//初始化时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数的模式
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR自动重装器的值 16位的计数器可以满量程计数
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //不分频,编码器的时钟直接驱动计数器
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
第四步——输入捕获单元的配置
//初始化输入捕获单元,计划使用TIM3的CH1和CH2
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure); //给结构体赋初始值
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿代表高低电平极性不反转
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ICStructInit(&TIM_ICInitStructure); //给结构体赋初始值
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿代表高低电平极性不反转
TIM_ICInit(TIM3, &TIM_ICInitStructure);
第五步——配置编码器接口
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
第六步——开启定时器
TIM_Cmd(TIM3, ENABLE);
源代码
#include "stm32f10x.h" // Device header
void EnCoder_Init(void)
{
//第一步开启RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//初始化时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数的模式
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARR自动重装器的值 16位的计数器可以满量程计数
TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //不分频,编码器的时钟直接驱动计数器
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//初始化输入捕获单元,计划使用TIM3的CH1和CH2
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure); //给结构体赋初始值
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿代表高低电平极性不反转
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_ICStructInit(&TIM_ICInitStructure); //给结构体赋初始值
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿代表高低电平极性不反转
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_Cmd(TIM3, ENABLE);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3, 0);
return Temp;
}