前提
在查阅RTthread官方驱动手册的时候发现,官方介绍的方法是使用ENV工具完成对脉冲编码器设备的驱动框架对接,但是使用RTthread Studio部署Pules_encoder发现多次报错无法正常使用,仅用此贴记录一下在RTthread Studio部署Pules_encoder的流程(霍尔编码器、AB相四倍频计数)供参考。
Pules_encoder部署流程
一、RT—Thread Setting 配置
打开RT-Thread Setting,打开使用脉冲编码器设备驱动程序
二、打开CubeMX 配置
配置时钟
先配置时钟HSE,选晶振,System Clock Tree按下图配置,像STM32F1系列是TIM1跟TIM8是高级定时器挂在APB2线上,频率是72MHz,TIM2~TIM7是通用\基础定时器,挂在APB1线上,频率是36MHz,选用定时器的时候注意定时器的频率
配置SYS Mode
选Serial Wire,不配置该选项可能会导致板子在烧录程序后一直处于执行程序状态导致无法二次烧录
配置USART1
在新建工程时我选择了使用USART1 PA9->TX PA10->RX作为RTthread的调试信息输出口,联合CUBEMX编程时要多配置一个USART1不然编译时会报错,这里选择异步通信,参数默认即可
配置定时器TIM
这里我选择的是TIM2跟TIM3,combined Cannels选 Encoder Mode,Encoder Mode选择Encoder Mode TI1 and TI2,通道1跟通道二的Input Filter填0~12都行,该参数主要是减少编码器读取误差,按图配置即可
配置Project Manager
如图配置,个人比较喜欢使用单独的.c\.h文件编写驱动,虽然很方便就能添加驱动程序进RT工程文件中,后期自定义功能函数好分类管理,但是bug很多,如不勾选Generate peripheral initialization as a pair of 'c/.h' files per peripheral这个选项也可以按照其他教程说示打开Keil文件自行添加复制到RTThread工程文件中
最后点击GENERATE CODE生成代码
三、驱动接入RTthread框架
检查驱动源文件
检查drv_pulse_encoder.c和pulse_encoder_config.h文件是否处于drivers文件的相应位置处,如rtthread Studio无自动添加则需要手动添加,RTthread源码库连接如下
GitHub - RT-Thread/rt-thread: RT-Thread is an open source IoT Real-Time Operating System (RTOS).
-
下载rt-thread源代码(我下载的是master版),在
bsp\stm32\libraries\HAL_Drivers
路径下把drv_pulse_encoder.c
复制到Studio生成项目的drivers
目录下,另外。 -
**修改编译错误,在
drv_pulse_encoder.c
文件中添加pulse_encoder.h
的绝对路径#include "rt-thread/components/drivers/include/drivers/pulse_encoder.h"
不太清楚是啥具体原因,必须要添加绝对路径,不然就会编译报错。
此处参考RT-Thread-RT-thread Studio配置使用Pulse EncoderRT-Thread问答社区 - RT-Thread
另外编译时如遇到报错PULSE_ENCODER1_CONFIG undefine,则还需在.\drivers\include\config\pulse_encoder_config.h添加Encoder1的相关结构体,官方驱动文件只定义了PULSE_ENCODER2_CONFIG到PULSE_ENCODER4_CONFIG,其他需自行添加
(写4600+字了忍不了吐槽一下,RTthread官网的驱动添加操作手册或者源文件能不能写详细点全面点,编译出来一堆报错,一顿操作下来我自己写的教程我自己人都看傻了woc)
#ifdef BSP_USING_PULSE_ENCODER1
#ifndef PULSE_ENCODER1_CONFIG
#define PULSE_ENCODER1_CONFIG \
{ \
.tim_handler.Instance = TIM1, \
.encoder_irqn = TIM1_UP_IRQn, \
.name = "pulse1" \
}
#endif /* PULSE_ENCODER1_CONFIG */
#endif /* BSP_USING_PULSE_ENCODER1 */
配置cubemx链接文件
打开cubemx\SConscript文件,添加CubeMX 生成的驱动文件路径,如我这里配置了GPIO、TIM、USART等外设,添加相应文件名后保存
Src/stm32f1xx_hal_msp.c
Src/stm32f1xx_hal_conf.c
Src/main.c
Src/gpio.c
Src/usart.c
Src/tim.c
右键SConscript文件选择同步scons至项目,查看相关驱动的.h文件是否挂载到lnc文件中,.c文件是否挂载到Src文件中
更新board.h文件
打开drivers\board.h文件,在末尾处添加启用PULSE_ENCODER的相关声明,我这里使用的是TIM2_CH1、TIM2_CH2、TIM3_CH1、TIM3_CH2,所以声明调用了BSP_USING_PULSE_ENCODER2
BSP_USING_PULSE_ENCODER3
使用其他TIM的要启用对应的PULSE_ENCODER
//声明使用其他外设
#define RT_USING_PULSE_ENCODER
#define BSP_USING_PULSE_ENCODER2
#define BSP_USING_PULSE_ENCODER3
编写应用函数
打开cubemx\lnc\main.h文件,添加rt驱动库#include <rtdevice.h>
打开cubemx\lnc\tim.h文件,声明设备名和初始化函数
#define PULSE_ENCODER2 "pulse2" /* 脉冲编码器2 */
#define PULSE_ENCODER3 "pulse3" /* 脉冲编码器3 */
int Motor_Encoder_Init(void);
打开cubemx\Src\tim.c文件,填写初始化函数
rt_device_t pulse_encoder_left = RT_NULL; /* 脉冲编码器2句柄 */
rt_device_t pulse_encoder_right = RT_NULL; /* 脉冲编码器3句柄 */
int Motor_Encoder_Init(void)
{
rt_err_t ret = RT_EOK;
/* 查找脉冲编码器设备 */
pulse_encoder_left = rt_device_find(PULSE_ENCODER2);
pulse_encoder_right = rt_device_find(PULSE_ENCODER3);
if (pulse_encoder_left == RT_NULL)
{
rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", PULSE_ENCODER2);
return RT_ERROR;
}
else if (pulse_encoder_right == RT_NULL) {
rt_kprintf("pulse encoder sample run failed! can't find %s device!\n", PULSE_ENCODER3);
return RT_ERROR;
}
/* 以只读方式打开设备 */
ret = rt_device_open(pulse_encoder_left, RT_DEVICE_OFLAG_RDONLY) \
| rt_device_open(pulse_encoder_right, RT_DEVICE_OFLAG_RDONLY);
if (ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n");
return ret;
}
return ret;
}
打开cubemx\Src\main.c文件,复制HAL初始化函数到applications\main.c中,并且往applications\main.c中添加相关HAL库和编写应用函数
整体applications\main.c如下代码
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <rtdevice.h>
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* 声明变量 */
rt_int32_t count1 = 0;
rt_int32_t count2 = 0;
extern rt_device_t pulse_encoder_left;
extern rt_device_t pulse_encoder_right;
int main(void)
{
//初始化
HAL_Init();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM1_Init();
MX_TIM4_Init();
MX_TIM2_Init();
MX_TIM3_Init();
//设备初始化
Motor_Encoder_Init();
while (1)
{
rt_device_read(pulse_encoder_left, 0, &count1, 1);
rt_device_control(pulse_encoder_left, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);
rt_kprintf("get encoder_left %d\n",count1);
rt_device_read(pulse_encoder_right, 0, &count2, 1);
rt_device_control(pulse_encoder_right, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);
rt_kprintf("get encoder_right %d\n",count2);
//rt_kprintf("This is a shandard Project,message sents by UART1\n");
//LOG_D("Hello RT-Thread!");
rt_thread_mdelay(2000);
}
return RT_EOK;
}
最后编译下载,给驱动板上电手动转动一下编码器,测试推动小车读取编码器读数,测试成功
这里只为了测试编码器驱动是否有效,并没有写线程控制电机转速赋值和判断整车速度,STM32C8T6片上Flash只有64kb,SRAM只有20kb跑RTthread标准系统不太够用,编译完Flash满了
Flash: 65636 B 64.10 KB
RAM: 6060 B 5.92 KB
参考文献
这里可以参考一下使用EVN工具部署Plues_encoder到RTthread中
RT-Thread - Pulse Encoder设备框架使用_rt-thread脉冲编码器设备-CSDN博客
官方RT-Thread 文档pulse Encoder设备添加
标准库四倍频部署流程和定时器基本原理介绍STM32—TIMx实现编码器四倍频_stm32编码器4倍频-CSDN博客