STM32定时器编码器模式实现直流有刷电机测速(HAL库)
前言
最近在做一个单片机大作业,要用到直流有刷,在这里把学习编码器的知识记录一下,学习参考资料:
正点原子DMF407电机控制专题教程_V1.0
编码器测速原理
我所使用的编码器是市面上常见的磁电增量式编码器,其有AB两相,用于输出电机转动时的脉冲数,AB两相的先后顺序决定了电机的转动方向
这其实就是单片机的外部计数器模式,51中也带有同样的功能
信号从通道被采样后的处理过程如下
编码器的计数接口是利用脉冲的边沿来计数的,我们知道AB两相都有脉冲且相位差为90度,那么一次检测最多可以得到四个边沿,此时我们可以通过配置计数的方式来实现不同的边沿计数
由图可以看出,总共有三种计数方式供我们选择,不同的模式对应了不同的计数形式,这里我选用的是第三种,因此会产生四个边沿,相当于对信号进行了四倍频,即一个脉冲信号会计数4次,在计算时要注意
寄存器部分
在编码过程中有几个重要的寄存器要简单介绍一下
TIMx_CR1控制寄存器
我们要关注这里的DIR位,通过判断DIR来判断计数器所处的模式是递增还是递减,流程大致为:配置好定时器的装载值为65536,不分频,那么每一次接收到65536个脉冲后定时器就会溢出进入定时器中断,此时通过判断DIR是0还是1来判断是正转还是反转,进而将得到的脉冲数累积到总脉冲数中进行速度计算
同时还要注意 CEN位,该位用于使能计数器的工作,也就是相当于选择模式,对应硬件就是内部的开关,用于判断是外部定时器模式还是内部定时器模式,当该位置1为外部定时器模式
TIMx_CCMR1捕获/比较模式寄存器1
在这里IC1F为滤波器,其实现方法为通过配置寄存器来设定滤波系数,例如在一个采样周期下,当N=2时代表要两个相同的事件(比如两个相同电位的高电平信号)才能视为一个有效边沿,这个过程基于数字滤波器实现,寄存器配置如下
IC1PSC是输入捕获预分频器,和上述原理类似,这里我和教程一样,选择一个边沿就触发一次计数
CC1S用于配置定时器通道,这里不做多要求,IC1映射到TI1就可以了
TIMx_SMCR从模式控制器
SMS代表的三位用于配置编码器模式123,具体对应关系如下
至此要用到的所有寄存器就介绍完了,接下来我们来进行CUBEMX工程的创建
硬件信息
主控芯片我选择的是STM32F103C8T6,电机用的是常见的自带编码器的直流有刷减速电机,编码器线数为11,电机驱动选用L298N,同时用OLED屏幕显示电机转速信息
工程创建
首先配置时钟树,直接拉满,再初始化几个IO口用于驱动电机
剩下的流程就是选择对应的IDE生成工程即可
代码部分
初始化外设
/* USER CODE BEGIN 2 */run_left_motor(50,1); //左轮电机启动OLED_Init(); //OLED初始化OLED_Clear();HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //开启定时器编码器通道HAL_TIM_Base_Start_IT(&htim4); //开启定时中断通道/* USER CODE END 2 */
初始化电机以及编码器
#define ROTO_RATIO 44 //编码器线数11*分频系数4
#define REDUTATION_RATIO 30 //电机减速比30//编码器结构体
typedef struct
{int encode_old;int encode_new;float speed;
}ENCODE_TypeDef;
//电机结构体
typedef struct
{float speed;
}Motor_TypeDef;extern ENCODE_TypeDef g_encode_left;
extern Motor_TypeDef g_motor_left;
电机转动
void run_left_motor(uint8_t speed,unsigned char dir)
{uint32_t arr;HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);if(dir == 1){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);}else{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);}HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);arr = __HAL_TIM_GET_AUTORELOAD(&htim2);__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,(1.0*speed/100)*arr);
}
电机速度计算
//encoder_now为定时器编码器模式下的计数值,ms代表每隔多少ms进入一次计算公式
void left_speed_compute(int32_t encode_now,uint8_t ms)
{uint8_t i=0,j=0;float temp = 0.0; //用于后续冒泡排序static uint8_t sp_count=0,k=0; //用于判断隔多长时间进一次计算,静态变量,不会随着函数调用被刷新static float speed_array[10]={0.0}; //上面的k为数组的索引值if(sp_count == ms) //当调用函数次数超过50次即每间隔50ms进入一次计数{g_encode_left.encode_new = encode_now; //编码器值更新g_encode_left.speed = (g_encode_left.encode_new - g_encode_left.encode_old); //脉冲变化数计算//通过脉冲计算速度,公式:(50ms内记录的脉冲数/50ms*60)/减速比/编码器线数/分频系数 = 每分钟的脉冲数/已知常量speed_array[k++] = (float)(g_encode_left.speed*((1000/ms)*60.0)/(REDUTATION_RATIO*ROTO_RATIO));g_encode_left.encode_old = g_encode_left.encode_new; //更新编码器计数值//冒泡排序法if(k==10){for(i=10;i>=1;i--){for(j=0;j<(i-1);j++) {if (speed_array[j] > speed_array[j + 1]) {temp = speed_array[j];speed_array[j] = speed_array[j + 1];speed_array[j + 1] = temp;}}}temp = 0.0; //初始化temp//去除两边高低数据for(i=2;i<8;i++){temp += speed_array[i];}temp = (float)(temp/6);/** 一阶低通滤波 Y(n)= qX(n) + (1-q)Y(n-1)* 其中 X(n)为本次采样值;Y(n-1)为上次滤波输出值;Y(n)为本次滤波输出值,* q 为滤波系数*/g_motor_left.speed = (float)((g_motor_left.speed)*(float)0.52)+((float)0.48*temp);//显示当前速度unsigned char Tx_Buf[20];sprintf((char *)Tx_Buf,"Left: %.2f",g_motor_left.speed);OLED_ShowString(1,2,Tx_Buf,5);k = 0;}sp_count = 0;}sp_count++;
}
溢出计数统计以及调用计算
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{//判断编码器的溢出方向if(htim->Instance == TIM1){if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1)){g_tim1_encode_count--;}else{g_tim1_encode_count++;}}//每间隔1ms更新一次脉冲数if(htim->Instance == TIM4){int Left_encode_now = gtim_get_encode();left_speed_compute(Left_encode_now,50);}
}
//更新脉冲数
int gtim_get_encode(void)
{return ( int32_t )__HAL_TIM_GET_COUNTER(&htim1) + g_tim1_encode_count * 65536; /* 当前计数值+之前累计编码器的值=总的编码器值 */
}
实验现象验证
转动时转速为20r/min
不转动时转速为0
STM32定时器编码器模式实现直流有刷电机测速(HAL库)相关推荐
- STM32 定时器编码器模式时,如何理解编码器计数
编码器的使用 增量式编码器倍频技术 增量式编码器输出的脉冲波形信号形式常见的有两种: 一种是占空比 50% 的方波,通道 A 和 B 相位差为 90°: 另一种则是正弦波这类模拟信号,通道 A 和 B ...
- 学习笔记STM32F429使用编码器测速HAL库版本
void TIM4_Init(u16 arr,u16 psc) { TIM4_Handler.Instance=TIM4; TIM4_Handler.Init.Prescaler=psc; ...
- 电机控制基础——定时器编码器模式使用与转速计算
上篇电机控制基础--定时器捕获单输入脉冲原理介绍了定时器捕获输入脉冲的原理,那种方式是根据捕获的原理,手动切换上升沿与下降沿捕获,计算脉冲宽度的过程原理比较清晰,但编程操作起来比较麻烦. 对于电机测速 ...
- linux直流电机测试,带霍尔传感器编码器的直流减速电机测速原理讲解(附源码)...
查看: 14294|回复: 83 带霍尔传感器编码器的直流减速电机测速原理讲解(附源码) 高级会员, 积分 891, 距离下一级还需 109 积分 积分金钱891 注册时间2019-4-22 在线时间 ...
- STM32定时器溢出模式计时设置
STM32定时器溢出模式设置 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:MDK4.23 MCU:STM32F10 ...
- STM32定时器溢出模式设置
STM32定时器溢出模式设置 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:MDK4.23 MCU:STM32F10 ...
- 【32单片机学习】(3)霍尔编码器减速直流电机控制及测速
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.实验现象 2.实验接线及原理图 接线图 原理图 电机接线图 3.代码部分 1.主函数 main.c 2.按键部分 ke ...
- 有刷电机驱动专题-直流有刷电机调速电路分析
最近有一个项目要求驱动一个60V的直流有刷电机调速,之前做的都是低压电的驱动,48V的已经是较高的,现在需要做一个60V的驱动,不好搞. 网上买了一个别人的调压模块来研究: 可以看到接口非常简单,只有 ...
- STM32之通用定时器编码器模式
1.编码器原理 如果两个信号相位差为90度,则这两个信号称为正交.由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向.根据每个信号脉冲数量的多少及整个编码轮的周长就可以算出当前行走的距 ...
最新文章
- java tostringutils_StringUtils
- 2019牛客提前批一血:猝不及防的java实习面经
- Boost:使用静态c ++内核语言扩展以进行编译和 执行模板化的c ++内核
- css编写的技巧效果总结
- IT、OT融合趋势下,西门子举办“第一届西门子工业边缘生态大会”
- Pidgin 新QQ插件:pidgin-lwqq
- ff14离线查看客户端日志小技巧
- 虚拟仿真实验室管理系统
- 【ENSP模拟器】ENSP——VLAN的配置
- 怎么批量删除 Word、Excel 以及文本文档中的空白行?
- 手游无限多开器安卓版_无限多开版!使用叶子猪手游模拟器玩大话西游手游教程...
- admob html5,admob移动广告phonegap插件使用教程
- react-Suspense工作原理分析
- windows网上邻居功能,局域网内文件共享步骤,问题总结,看不到共享文件夹
- HX711 24位A/D模块计算公式
- props传递对象_vue组件中使用props传递数据的实例详解
- 计算机个人swot分析报告,个人swot分析报告.doc
- [USACO]1.2.2Milking Cows
- tools自动登录签到脚本
- 【视频分类】3D-ResNets-PyTorch复现