一、介绍
通过 RT-Thread 提供的 I/O 设备管理接口来访问脉冲编码器设备,实现正交编码测速。
参考链:Pulse Encoder 设备 、 HWTIMER 设备
正交编码原理这里就不介绍了,网上资料很多,直接进入正题。
硬件平台:AT32F407(需要增加驱动) 或者 STM32F107
系统:RT-thread V4.1.0
二、应用代码
/*
//计算尾轴转速
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define DBG_SECTION_NAME "rot_speed"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define HWTIMER_DEV_NAME "timer3" /* 定时器名称 */
#define PULSE_ENCODER_DEV_NAME "pulse4" /* 脉冲编码器名称 */
rt_device_t pulse_encoder_dev = RT_NULL; /* 脉冲编码器设备句柄 */
#define PERIOD_TIME 2000 //采样周期ms t
#define PULSE_PER 4 //每转采样一次,有四个脉冲(N)
//计算公式:
//每毫秒采样的脉冲数:一定周期(ms)内采样的总脉冲数/周期
//4分频,一圈4个脉冲
//1ms的圈数:一定周期(ms)内采样的总脉冲数/(周期 *4)
//转速(圈/分钟):一定周期(ms)内采样的总脉冲数/(周期 *4) 乘以60*1000(分钟)
/* 定时器超时回调函数 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
rt_int32_t count;
/* 读取脉冲编码器计数值 */
rt_device_read(pulse_encoder_dev, 0, &count, 1);
/* 清空脉冲编码器计数值 */
rt_device_control(pulse_encoder_dev, PULSE_ENCODER_CMD_CLEAR_COUNT, RT_NULL);
int speed = 60*1000*count/(PERIOD_TIME*PULSE_PER);
LOG_D("get count:%d, speed:%d",count,speed);
return 0;
}
//脉冲计数初始化
static int pulse_encoder_init()
{
rt_err_t ret = RT_EOK;
rt_uint32_t index;
/* 查找脉冲编码器设备 */
pulse_encoder_dev = rt_device_find(PULSE_ENCODER_DEV_NAME);
if (pulse_encoder_dev == RT_NULL)
{
LOG_E("pulse encoder sample run failed! can't find %s device!", PULSE_ENCODER_DEV_NAME);
return RT_ERROR;
}
/* 以只读方式打开设备 */
ret = rt_device_open(pulse_encoder_dev, RT_DEVICE_OFLAG_RDONLY);
if (ret != RT_EOK)
{
rt_kprintf("open %s device failed!\n", PULSE_ENCODER_DEV_NAME);
return ret;
}
return ret;
}
//定时周期初始化
static int hwtimer_init()
{
rt_err_t ret = RT_EOK;
rt_hwtimerval_t timeout_s; /* 定时器超时值 */
rt_device_t hw_dev = RT_NULL; /* 定时器设备句柄 */
rt_hwtimer_mode_t mode; /* 定时器模式 */
/* 查找定时器设备 */
hw_dev = rt_device_find(HWTIMER_DEV_NAME);
if (hw_dev == RT_NULL)
{
LOG_E("hwtimer sample run failed! can't find %s device!", HWTIMER_DEV_NAME);
return RT_ERROR;
}
/* 以读写方式打开设备 */
ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
if (ret != RT_EOK)
{
LOG_E("open %s device failed!", HWTIMER_DEV_NAME);
return ret;
}
/* 设置超时回调函数 */
rt_device_set_rx_indicate(hw_dev, timeout_cb);
/* 设置模式为周期性定时器 */
mode = HWTIMER_MODE_PERIOD;
ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
if (ret != RT_EOK)
{
LOG_E("set mode failed! ret is :%d", ret);
return ret;
}
/* 设置定时器超时值为5s并启动定时器 */
timeout_s.sec = 0; /* 秒 */
timeout_s.usec = PERIOD_TIME*1000; /* 微秒 */
if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
{
LOG_E("set timeout value failed");
return RT_ERROR;
}
/* 延时ms */
rt_thread_mdelay(500);
/* 读取定时器当前值 */
rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
LOG_D("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
return ret;
}
int tail_rot_speed_init(){
pulse_encoder_init();
hwtimer_init();
}
三、bsp驱动
如果使用的是STM32的bsp包,驱动是不需要修改的,可以直接使用;如果是AT32的平台需要添加驱动。 注意: 在RT-thread提供的bsp中,在STM32中有脉冲编码器的驱动 bsp\stm32\libraries\HAL_Drivers\drv_pulse_encoder.c 在at32中没有发现脉冲编码器对应的驱动,需要增加,自己根据STM32的驱动进行了修改。
驱动链接地址:基于AT32的RT-thread脉冲编码驱动