18.示例程序(编码器接口测速)

 STM32标准库开发-各章节笔记-查阅传送门_Archie_IT的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_61712829/article/details/132434192?spm=1001.2014.3001.5501

18.示例程序(编码器接口测速)_第1张图片main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "Encoder.h"


uint16_t speed;

int main(void)
{
	
	OLED_Init();	//初始化OLED
	Timer_Init();    //初始化定时器
	Encoder_init();
	
	OLED_ShowString(1,1,"speed:");

	while(1)
	{
		OLED_ShowSignedNum(1,7,speed,5);//每隔一段时间读取一次;用定时中断
	}

}


//定时器2中断函数放在使用中断的main.c文件中;在startup文件中;定时中断每隔1s执行一次
void TIM2_IRQHandler(void) //当定时器产生更新中断时,这个函数就会自动被执行
{
	//检查中断标志位
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
	//执行相应的用户代码
		speed = Encoder_Get();   //定时器每隔1s读取一下速度,存在speed变量里
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除标志位
	}

}

Encoder.c

#include "stm32f10x.h"                  // Device header

//编码器旋转控制CNT自增自减	
//编码器初始化函数,编码器电路初始化后,CNT就会随着编码器旋转而自增自减;直接读出CNT值就能测量编码器的位置;测量编码器的速度和方向就需要每隔一段固定的闸门时间取出一次CNT然后再把CNT清零这就是测频法测量速度了
/*
第一步,RCC开启时钟,开启GPIO和定时器的时钟
第二步,配置GPIO,需将PA6和PA7配置成输入模式
第三步,配置时基单元,预分频器一般选择不分频,ARR一般给最大值655535,只需要CNT执行计数就行了
第四步,配置输入捕获单元,这里只有滤波器和极性两个参数有用,后面的参数没有用到,与编码器无关
第五步,配置编码器接口模式,直接调用一个库函数
最后,调用TIM_Cmd,启动定时器
*/

void Encoder_init(void)
{
	//1.打开时钟,选择内部时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//2.初始化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_InternalClockConfig(TIM3);
	
	//3.配置时基单元 
	/*
	公式:
	PWM 频 率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)
	PWM占空比:Duty = CCR / (ARR + 1)
	PWM分辨率:Reso = 1 / (ARR + 1)
	*/
	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 周期 ,满量程计数,这样计数的范围是最大的而且方便换算成负数
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;  //PSC 预分频器,不分频,编码器的时钟直接驱动计数器
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;  //重复计数器的值
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);	//初始化TIM3
	
	//4.配置输入捕获单元(通道),编码器接口只使用了通道1和2的滤波器和极性选择
	//首先定义结构体变量,然后StructInit给结构体赋一个初始值,再部分修改我们想要的参数,调用ICInit配置一遍电路,结构体变量的配置在调用ICInit函数之后就写入到硬件的寄存器了,所以ICInit之后这个结构体我们可以换个值继续使用、不需要重新定义新的结构体
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);//结构体初始化,防止结构体中出现不确定值可能造成问题,最好用StructInit给结构体赋一个初始值
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;	//通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;	//滤波器为0xF
	//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//电平极性为上升沿,这里的上升沿参数代表的是高低电平极性不反转;等会配置编码器接口的时候也有极性配置,属于重复配置,这个其实可以删掉;这里的上升沿并不代表上升沿有效,因为编码器接口始终都是上升沿、下降沿都有效
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;	//通道2
	TIM_ICInitStructure.TIM_ICFilter = 0xF;	//滤波器为0xF
	//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//电平极性为上升沿,这里的上升沿参数代表的是高低电平极性不反转;等会配置编码器接口的时候也有极性配置,属于重复配置,这个其实可以删掉;这里的上升沿并不代表上升沿有效,因为编码器接口始终都是上升沿、下降沿都有效
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	//5.配置编码器接口,只需调用一个函数就行了;;需保证TIM_EncoderInterfaceConfig在TIM_ICInit函数之后,否则TIM_ICInit覆盖TIM_EncoderInterfaceConfig函数的配置
	TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//选择Rising是通道不反相,选择Falling是通道反相;重复配置TIM_ICPolarity_Rising,后面的参数会覆盖前面的参数配置
	
	//6.启动定时器
	TIM_Cmd(TIM3,ENABLE);
}

int16_t Encoder_Get(void)
{
	//测速,在固定的匝门时间读一次CNT然后把CNT清零
	int16_t temp;//因为要先读取CNT再清零,所以要用temp缓存一下
	temp = TIM_GetCounter(TIM3);//读取CNT
	TIM_SetCounter(TIM3,0);//CNT清零	
	return temp;

}


 

Encoder.h

#ifndef __ENCODER_H
#define __ENCODER_H

void Encoder_init(void);
int16_t Encoder_Get(void);

#endif


你可能感兴趣的:(STM32标准库开发,单片机,嵌入式硬件,嵌入式软件,stm32,c语言)