二、读取编码器数值实现电机测速—3、速读

电机系列

二、读取编码器数值实现电机测速

3、速度;

测速原理:

单位时间内,根据脉冲走过的距离计算电机实际速度,这里采用5ms定时器中断。

采集数据:

就是获得到轮子转一圈的编码器个数;
注意电机参数:
减速比:30:1
编码器线数:13线,也称编码器分辨率;

使用四倍频提高测量精度;

代码见下载区。

速度计算思路:

在这里插入图片描述

单位时间内获得的编码器脉冲变化数:可以通过代码得到,定为 e 个 ; (反应电机正反转)

单位时间:定时器设定为5ms,即0.005s;

电机转动一圈的脉冲数:n 个

电机轮子半径:R 单位:m(米)

圆周率:PI 单位:无

速度:speed 单位: m/s

在这里插入图片描述
此处:

轮子半径 R:0.03m(米);

PI:3.1415926;

手动转一圈的脉冲数 n:1560 个;

e: 通过函数得到;

可得:
speed = 0.024166 * e

代码:
结构如下:
在这里插入图片描述

encoder.h

将2中部分改为一下代码;

#ifndef __ENCODER_H
#define __ENCODER_H
#include <sys.h>	
#include "stm32f10x_tim.h"
 
/**************************************************************************
作者:chance
**************************************************************************/

#define ENCODER_TIM_PERIOD (u16)(65535)   //不可大于65535 因为F103的定时器是16位的。

//定时器编码器初始化;
void Encoder_Init_TIM2(u16 arr,u16 psc);
void Encoder_Init_TIM3(u16 arr,u16 psc);
void Encoder_Init_TIM4(u16 arr,u16 psc);
void Encoder_Init_TIM5(u16 arr,u16 psc);

//5ms 定时器中断服务函数
void TIM7_Int_Init(u16 arr,u16 psc);

//编码器计数函数;
int Read_Encoder_TIM2(void);
int Read_Encoder_TIM3(void);
int Read_Encoder_TIM4(void);
int Read_Encoder_TIM5(void);

int Read_Encoder_test(TIM_TypeDef * TIMx);

//speed
void Get_Motor_Speed(int *A_Speed,int *B_Speed,int *C_Speed,int *D_Speed);

#endif
encoder.c
#include "encoder.h"
#include "stm32f10x_gpio.h"

/**************************************************************************
作者:chance
**************************************************************************/

int Encoder_A,Encoder_B,Encoder_C,Encoder_D;  //编码器的脉冲计数

void Encoder_Init_TIM2(u16 arr,u16 psc)
{
	//1) 定义相关结构体:
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
	
	//2) 使能相关时钟:
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);// 需要使能AFIO时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟	
  GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);	//禁止JTAG功能,把PB3,PB4作为普通IO口使用
	
	//3) 初始化 GPIO:(用于AB相,脉冲计数)
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根据设定参数初始化GPIOA
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB
  
	//4) 设置并初始化定时器 TIM2:
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	//5) 设置并初始化定时器编码器:
  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM2,0);
	
	//6) 使能定时器:
  TIM_Cmd(TIM2, ENABLE); 
}

/**************************************************************************
函数功能:把TIM3初始化为编码器接口模式
入口参数:无
返回  值:无
**************************************************************************/
void Encoder_Init_TIM3(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根据设定参数初始化GPIOA
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM3, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  TIM_SetCounter(TIM3,0);
  TIM_Cmd(TIM3, ENABLE); 
}

void Encoder_Init_TIM4(u16 arr,u16 psc)
{
	//1) 定义相关结构体:
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
	
	//2) 使能相关时钟:
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
	
	//3) 初始化 GPIO:
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB
  
	//4) 设置并初始化定时器 TIM4
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = psc;  // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
	
	//5) 设置并初始化定时器编码器:
  TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式 3:CH1、CH2 同时计数,四分频
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM4, &TIM_ICInitStructure);
	
  TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  //Reset counter
  TIM_SetCounter(TIM4,0);
	
	//6) 使能定时器:
  TIM_Cmd(TIM4, ENABLE); 
}

void Encoder_Init_TIM5(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
  TIM_ICInitTypeDef TIM_ICInitStructure;  
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//使能定时器5的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	//端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);					      //根据设定参数初始化GPIOA
  
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器 
  TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
  TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
  TIM_EncoderInterfaceConfig(TIM5, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 10;
  TIM_ICInit(TIM5, &TIM_ICInitStructure);
  TIM_ClearFlag(TIM5, TIM_FLAG_Update);//清除TIM的更新标志位
  TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
  TIM_SetCounter(TIM5,0);
  TIM_Cmd(TIM5, ENABLE); 
}

/**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回  值:速度值
**************************************************************************/
int Read_Encoder_test(TIM_TypeDef * TIMx)
{ 
	int Encoder_TIM;
	Encoder_TIM = TIMx -> CNT;
	if(Encoder_TIM>0xefff)Encoder_TIM=Encoder_TIM-0xffff; //转化计数值为有方向的值,大于 0 正转,小于 0 反转。
	                                                      //TIM4->CNT 范围为0-0xffff,初值为 0。
	
	TIMx->CNT=0; //读取完后计数清零
	return Encoder_TIM; //返回值
}

void Get_Motor_Speed(int *ASpeed,int *BSpeed,int *CSpeed,int *DSpeed)
{
	static int AWheelEncoderNow   = 0;
	static int BWheelEncoderNow   = 0;
	static int CWheelEncoderNow   = 0;
	static int DWheelEncoderNow   = 0;
	
	static int AWheelEncoderLast  = 0;
	static int BWheelEncoderLast  = 0;	
	static int CWheelEncoderLast  = 0;
	static int DWheelEncoderLast  = 0;	
	
	//记录本次左右编码器数据
	AWheelEncoderNow += Read_Encoder_test(TIM2);
	BWheelEncoderNow += Read_Encoder_test(TIM3);
	CWheelEncoderNow += Read_Encoder_test(TIM4);
	DWheelEncoderNow += Read_Encoder_test(TIM5);
	
	//5ms测速    (	*1000 )单位改为mm/s  串口助手读数变化显示更清楚
	*ASpeed  = (AWheelEncoderNow - AWheelEncoderLast)* 1000*0.024166;  
	*BSpeed  = (BWheelEncoderNow - BWheelEncoderLast)* 1000*0.024166;
	*CSpeed  = (CWheelEncoderNow - CWheelEncoderLast)* 1000*0.024166;  
	*DSpeed  = (DWheelEncoderNow - DWheelEncoderLast)* 1000*0.024166;

	//记录上次编码器数据
	AWheelEncoderLast = AWheelEncoderNow;                    
	BWheelEncoderLast = BWheelEncoderNow;  
    CWheelEncoderLast = CWheelEncoderNow;                    
	DWheelEncoderLast = DWheelEncoderNow; 	
	
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H

#include "stm32f10x.h"

void TIM7_Int_Init(u16 arr,u16 psc); 
 
#endif
timer.c
#include "timer.h"
#include "sys.h"
#include "encoder.h"
#include "led.h"


//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
//TIM7_Int_Init(5000-1,7200-1); 500ms
void TIM7_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); //时钟使能

	TIM_TimeBaseStructure.TIM_Period = arr;              //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc;            //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;         //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);      //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(  //使能或者失能指定的TIM中断
		TIM7,      //TIM2
		TIM_IT_Update ,
		ENABLE     //使能
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;            //TIM7中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;         //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);                            //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM7, ENABLE);  //使能TIMx外设
							 
}
main.c
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "motor.h"
#include "control.h"
#include "usart.h"
#include "encoder.h"
#include "stdio.h"
#include "timer.h"

int ASpeedNow = 0;
int BSpeedNow = 0;
int CSpeedNow = 0;
int DSpeedNow = 0;

 int main(void)
 {	
	  delay_init();	    	            //=====延时函数初始化	
	  //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	  MY_NVIC_PriorityGroupConfig(2);	//=====设置中断分组
	  LED_Init();                     //=====初始化与 LED 连接的硬件接口
	  MiniBalance_PWM_Init(7199,0);  
	  Set_Pwm(1000,1000,1000,1000);	  //驱动电机

	  USART3_Init(9600);
	 
	  Encoder_Init_TIM2(0xffff,0);            //=====编码器接口
	  Encoder_Init_TIM3(0xffff,0);            //=====编码器接口
	  Encoder_Init_TIM4(0xffff,0);            //=====编码器接口
      Encoder_Init_TIM5(0xffff,0);            //=====初始化编码器
	  
	  TIM7_Int_Init(5000-1,7200-1);
	 
		while(1)
	{
		Led_Flash(30);
		//Set_Pwm(3000,2000,1000,1000);	
		printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\r\n");
		//delay_ms(150);
		
		
		printf("encoder222=%d\r\n",Read_Encoder_test(TIM2));
		printf("encoder333=%d\r\n",Read_Encoder_test(TIM3));
		printf("encoder444=%d\r\n",Read_Encoder_test(TIM4));
		printf("encoder555=%d\r\n",Read_Encoder_test(TIM5));
	    printf("A=%d,B=%d,C=%d,D=%d\r\n",ASpeedNow,BSpeedNow,CSpeedNow,DSpeedNow);
		printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n");
		delay_ms(100);                  //=====延时
	}
 }
 
//5ms 定时器中断服务函数
void TIM7_IRQHandler(void)                            //TIM7中断
{
	if(TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
	{
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update);   //清除TIMx的中断待处理位:TIM 中断源 
		Get_Motor_Speed(&ASpeedNow,&BSpeedNow,&CSpeedNow,&DSpeedNow);
		Led_Flash(100);
	}
}


此时转动电机就可以看到相应的速度了

代码见下载区。

  • 91
    点赞
  • 677
    收藏
    觉得还不错? 一键收藏
  • 31
    评论
Linux fbtft是一个用于驱动液晶显示屏的开源框架。它通过在Linux内核中添加相应的驱动程序和设备树节点来实现对液晶显示屏的控制。fbtft的核心功能是将显示屏作为一个Frame Buffer设备来操作,并提供了一些函数来进行初始化、刷新、绘制等操作。 一个重要的概念是platform_driver,它会与设备树中带有 "sitronix,st7735r" 属性的节点进行匹配,并触发fbtft-core.c / fbtft_probe_common()函数。这个函数是fbtft的核心逻辑,它会执行液晶显示屏的初始化操作。 在初始化操作中,通过执行par->fbtftops.init_display(par)函数来进行tft-lcd的初始化。这个函数会根据具体的液晶显示屏型号和配置,设置相关的参数并进行初始化操作。 总的来说,Linux fbtft是一个用于驱动液晶显示屏的开源框架,通过在Linux内核中添加驱动程序和设备树节点来实现对液晶显示屏的控制。它提供了一些函数来进行初始化、刷新、绘制等操作,通过platform_driver与设备树中的节点进行匹配来触发相关操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux驱动开发 / fbtft源码速读](https://blog.csdn.net/wuweidonggmail/article/details/110914325)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值