OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1200|回复: 0

cubeIDE使用正交编码器记录

[复制链接]

22

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2014-4-30
在线时间
26 小时
发表于 2023-12-6 14:01:40 | 显示全部楼层 |阅读模式
编码器的配置如附图所示。
其中遇到的一些问题汇总如下:
1.正交编码器计数是4的倍数,比如:旋转1下,得到的数值是4;
解决办法:修改分频系数Prescaler = 4-1.


2.编码器不进中断,
解决办法:应该是要开启如下图所示的中断,而不是之前用的TIM1 capture compare interrupt。这个中断如果是用来判断圈数要注意使用此中断。

初始化:
        HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
        HAL_TIM_Encoder_Start_IT(&htim1, TIM_CHANNEL_ALL); //这里TIM_CHANNEL_1/TIM_CHANNEL_ALL均可
        __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);

3.如何判断圈数增加或减小?
在上述中断回调函数中做如下:
        if (htim->Instance == TIM1) {
                if ((htim->Instance->CR1 >> 4 & 0x01) == 0) //DIR==0
                {
                        encoder.cycles++;  // 圈数++
                } else if ((htim->Instance->CR1 >> 4 & 0x01) == 1) //DIR==1
                {
                        encoder.cycles--; // 圈数--
                }
        }

4.如何判断转动方向
网上找的都是五花八门,大多数是用上面的那个中断中去判断,如果驱动是旋转非常快或者脉冲数比较小的(如电机或者旋钮编码器)这些是可以的,根据溢出圈数的增减,可判断正反转;
但是响应不及时。
通过查找资料,使用了如下方法
        encoder.dir = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1);//可以获得当前电机的转向
5.获得绝对编码值

如下,=圈数*脉冲数+此时编码器的计数值。
encoder.tim_counter = (uint32_t) (__HAL_TIM_GET_COUNTER(&htim1)); //获取定时器的值
   encoder.value = (int)encoder.cycles*encoder.max_counter + encoder.tim_counter;
6.待完善
①加flash和PVD掉电检测,保存掉电时编码器的值,上电加载。
②改变AB项的相序,把原来的减变加。
7.除了cubemx生成的代码,其他的做了封装,如下:

struct drv_encoder{
        char dir;
        int value;
        int tim_counter;
        int cycles;
        float speed;
        int max_counter;
};


struct drv_encoder encoder = {
    .cycles = 0,
    .tim_counter = 0,
    .value = 0,
    .max_counter = 0};


extern TIM_HandleTypeDef htim1;
void drv_encoder_init(struct drv_encoder *encoders) {
        HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
        HAL_TIM_Encoder_Start_IT(&htim1, TIM_CHANNEL_ALL); //这里TIM_CHANNEL_1/TIM_CHANNEL_ALL均可
        __HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
                        // TODO: implement
                        // Init encoder cfg parameters from flash.
        encoder_set_counter(0);
        encoder.max_counter = htim1.Init.Period +1;
        encoders = &encoder;
}


struct drv_encoder* drv_encoder_get_value(void) {
        update_encoder();
        return &encoder;
}


struct drv_encoder* drv_encoder_set_value(int value) {
        // TODO: implement
        // Set value,and set cycles & set hal_TIM_SET_COUNTER;
        encoder_set_counter(value);
        return &encoder;
}


// 该函数请放到 HAL_TIM_PeriodElapsedCallback 里面。
void EncoderPeriodElapsedCallback(TIM_HandleTypeDef *htim) {
        if (htim->Instance == TIM1) {
                if ((htim->Instance->CR1 >> 4 & 0x01) == 0) //DIR==0
                                {
                        encoder.cycles++;
                } else if ((htim->Instance->CR1 >> 4 & 0x01) == 1) //DIR==1
                                {
                        encoder.cycles--;
                }
        }
}






int encoder_get_counter(void)
{
        encoder.tim_counter = (uint32_t) (__HAL_TIM_GET_COUNTER(&htim1)); //获取定时器的值
    encoder.value = (int)encoder.cycles*encoder.max_counter + encoder.tim_counter;
    return encoder.value;
}




void encoder_set_counter(int t)
{
        __HAL_TIM_SET_COUNTER(&htim1, t%htim1.Init.Period);
        encoder.cycles = t/encoder.max_counter;//圈数


}


void update_encoder(void)
{
        encoder.tim_counter = (uint32_t) (__HAL_TIM_GET_COUNTER(&htim1)); //获取定时器的值
        encoder.dir = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1);//可以获得当前电机的转向
        encoder.value = (int)encoder.cycles*encoder.max_counter + encoder.tim_counter;
}


不吝赐教!
timer_incoder配置图.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 03:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表