GD32正交译码

本文介绍了GD32芯片如何实现增量编码器的正交译码,讲解了编码器的ab相信号相位差来源,以及利用相位差判断电机旋转方向的方法。在GD32F305VE芯片上,通过配置高级定时器的正交译码模式,简化了判断电机正反转的复杂性,并提供了处理计数器溢出的策略。文章还分享了代码片段,强调了rt_thread操作系统的实用性和中断处理细节。

GD32正交译码

这篇文章记录我之前用正交编码的过程,分享经验。
对了,以下我是站在程序员(或者说是工程师)的角度,或者说是应用者的角度来看所有的问题,重点在于把这项功能用出来,而不是去深究原理(当然,搞清一些原理才可以更好地实现我们的目的)。

增量式编码器

先说一下这个编码器输出的ab相信号是这怎么回事吧,我之前一直没有搞懂,直到看了别人画的板子才算是明白了。不感兴趣的可以跳过这段。
首先我们知道增量式编码器是输出ab相的,那么有两个问题,
1. ab相的相位差是怎么来的
2. 如何利用ab相的相位差来判断电机旋转方向呢
先来看第一个问题:
下面我说明的是磁编码器,其实光编码器大同小异。
我们知道一个磁铁,当NS极经过霍尔传感器的时候,霍尔传感器会输出一段信号,(至于原理,就涉及到关于磁场的物理知识了,我有点不太记得了,你有余力的话可以去了解,但还是那句话,站在工程师的角度,你更应该先关注你手上有什么,可以去用它去做什么。就像你写代码的时候,调用了库,你会去深究底层实现吗,也许有一些会,但如果对于每个库都去这么做,是不可能的。),这段信号就是我们说的脉冲,如果你只有一个NS,一个霍尔传感器,那么转一圈,你就只有一个脉冲,也就是常说的编码器线数为1。
ab相,意思就是你要有两个霍尔传感器,只要摆放角度合理,你就可以得到有相位差的信号,如果是绝对正交的话,相位差应该刚好是T/4。但是这个角度并不是霍尔传感器的物理摆放角度,看下面这个示意图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6BnQhoMV-1651042086546)(/磁盘示意图.jpg)]在这里插入图片描述

我这有一个磁盘,上面有8对NS,也就是一圈有8线。从黑线开始,信号的t为0,那么码盘上就有8个t为0的点,周期为T,a霍尔如果放在黑线上,为了让相位差有T/4,那么b霍尔就可以放在如图中的任一红线位置,这样就可以让相位差为T/4。
看到这里你应该就大概明白这个角度是怎么来的。(不得不感慨现代工艺的强大,我这还只是8线的,如果线数上去了,这个角度的要求更高,另外,光编码器的精细程度更是有过之而无不及的。)

gd32正交编码

解决第二个问题:
从上面我们知道,ab相信号,在一个电机往一个方向旋转时,一个领先(假设a),而改变方向后,另一个(b)会领先。
有了这个区别,相信你心中就大概有了区别方向的方案,无非不是说,a领先就正转,b领先就反转。但你细想一下又会比较麻烦,假设你没有用上gd32正交译码功能的情况下,你会怎么做呢?
没有正交译码的功能,那么我们能用的只有普通的定时器,通过中断函数和维护一些变量貌似很难做判断ab谁先来这个事,甚至可能还需要计时,挺麻烦的。
那么就需要用到正交译码的功能,我用的是GD32F305VE的芯片。
我这款的资源是只有高级定时器才有正交译码的功能,也就是定时器1和7。
由于一些的原因,我就不能和你展示源码了,这里简单给你手写一下:

最重要的配置就是:
timer_quadrature_decoder_mode_config(timer->timer_x, TIMER_ENCODER_MODE2, TIMER_IC_POLARITY_FALLING, TIMER_IC_POLARITY_RISING);
timer_slave_mode_select(timer->timer_x, TIMER_ENCODER_MODE2);
这是gd32库函数里的,你只要调用一下这个,就算是打开了正交编码的功能,其他的timer配置,相信你是知道的

还有几个注意的点:
1.高级定时器和普通定时器不同,他的中断函数名是这样的:void TIMER7_UP_TIMER12_IRQHandler(void),包括他的中断number是这样的TIMER7_UP_TIMER12_IRQn(这个你需要去看你用的是哪种类型的30x,可以到gd32f30x.h下去看),这里我相当于是告诉你有这个要注意的点,剩下的要靠你自己了。中断函数名你需要去链接脚本里看,小技巧是:你打开一个工程,通过全局搜索的方式去找,就可以定位到文件,然后再找你需要的东西
2.关于溢出处理,你只要在溢出的时候看计数器的方向,来加减65535即可
这个地方我细讲一下吧:
当你正确打开了正交译码之后,你通过读计数器的值,你会发现,电机正转的时候,值递增,反转的时候递减。如果你的timer_initpara.period = 65535,那么就是0到65535。想想看,我的是8*4=32线,算上齿轮的减速比的话,你的轮子没转几圈计数器就会溢出了。所以溢出你必须做处理:

1. 首先打开溢出中断,我说了高级定时器不一样,irq_num = TIMER7_UP_TIMER12_IRQn, 中断函数是TIMER7_UP_TIMER12_IRQHandler(void),不一样在,普通定时器是全局中断共用一个函数接口和number,你需要在中断函数里判断是哪个中断标志被置位了,但是高级定时器不需要,你看它的名字都告诉你了它是UP中断,也就是更新事件中断,而更新事件我们只设置溢出事件,并且gd32f305vet6 没有定时器12,所以我这个中断函数进来就只可能是timer7的溢出中断了,溢出中断还需要设置timer_interrupt_enable(timer, TIMER_INT_UP),这些应该都是你阅读芯片手册能知道的。
2.
设两个变量,current_cnt, last_cnt, 那么速度就是pulse_cnt_diff = current_cnt - last_cnt,方向直接体现在出来的结果是正还是负上了。
假设你现在反转电机,计数器是递减,那么会出现这个情况,last_cnt = 48, current_cnt = 65530, 这时候需要做溢出处理,你需要在溢出时设置一个标志位,一旦标志位满足,pulse_cnt_diff += 65535,对于正转 -= 65535。
而正传反转你可以通过读取(TIMER_CTL0(cfg->timer->timer_x) & 0x10) >> 4,这个是读寄存器的第4位的值,具体的去看芯片手册吧。
贴一下我的代码

static rt_int32_t pulse_encoder_get_count(struct rt_pulse_encoder_device *pulse_encoder) 
{
    const pulse_encoder_cfg_t *cfg = pulse_encoder->parent.user_data;
    if (cfg->if_using_quadrature_decoding) {
        int32_t pulse_cnt_diff = 0;
        int32_t *current_pulse_cnt = &cfg->param_ptr->pulse_encoder_cnt;
        int32_t *last_pulse_cnt = &cfg->param_ptr->last_pulse_encoder_cnt;
        
        *current_pulse_cnt = TIMER_CNT(cfg->timer->timer_x);
        pulse_cnt_diff = *current_pulse_cnt - *last_pulse_cnt;
        if (cfg->param_ptr->if_timer_overflowed) {
            //这个溢出标志位是你自己维护的,在中断函数里设置,在读取的时候清零
            cfg->param_ptr->if_timer_overflowed = RT_FALSE;
            uint8_t dir = (TIMER_CTL0(cfg->timer->timer_x) & 0x10) >> 4;
            if (dir) {
                pulse_cnt_diff -= 65535;
            } else {
                pulse_cnt_diff += 65535;
            }
        }
        *last_pulse_cnt = *current_pulse_cnt;
        return pulse_cnt_diff;
    } else {
        return cfg->param_ptr->pulse_encoder_cnt;
    }
}
在这里强力安利一波rt_thread操作系统,很好用。

到这里就差不多结束了,你有pulse_cnt_diff就可以接着算速度了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值