4回答

2收藏

[分享] 初玩GD32F207小红板那些事之平衡小车——正交译码器

GD32 GD32 7195 人阅读 | 4 人回复 | 2016-01-26

    今天和大家分享下基于小红板(GD32F207)送餐机器人的电机测速部分代码。该部分我用的是小红板的定时器正交译码器功能,对左右电机进行测速。
一、光电码盘

图1 编码器示意图
file:///C:\Users\shamozhihuong\AppData\Roaming\Tencent\QQ\Temp\TempPic\VTBBW7K5IK5H0X)$Y4%`GHR.tmp
     中间是一个带光栅的码盘,光通过光栅,接收管接收到高电平,没通过,接收到低电平。电机旋转一圈,码盘上有多少光栅,接受管就会接收多少个高电平。371电机中的码盘就是这样的,他是334线码盘,具有较高的测速精度,也就是电机转一圈输出334个脉冲,芯片上已集成了脉冲整形触发电路,输出的是矩形波,直接接单片机IO就OK。   
     增量式旋转编码器通过内部两个光敏接受管转化其角度码盘的时序和相位关系,得到其角度码盘角度位移量增加(正方向)或减少(负方向)。下图为编码器的原理图:


           图2 增量式旋转编码器
       A,B两点对应两个光敏接受管,A,B两点间距为 S2 ,码盘的光栅间距分别为S0和S1。S0+S1的距离是S2的四倍。这样保证了A,B波形相位相差90度。旋转的反向不同,锯齿波A,B先到达高电平的顺序就会不同,如上图左侧所示,顺序的不同,就可以得到旋转的方向。

二、小红板定时器选择
       通过小红板的用户手册和原理图来确定定时器,用TIM2与TIM3,其它的如TIM4的引脚基本被占用,TIM5的引脚没有引出来等等所以不能选哦。







三、小红板代码解析部分
1、正交译码器
      正交译码器功能使用两个源于TIMERx_CH1和TIMERx_CH2引脚的积分输入TI1和TI2各自相互作用产生计数值。在每个输入源改变期间,DIR位被硬件自动改变。输入源可以是只有TI1,只有TI2或TI1和TI2。选择模式可以设置SMC=0x01, 0x02或0x03来完成。改变计数方向的机制如下图所示。正交译码器可以用作一个带有方向选择的外部时钟,意味着计数器在内部从0到重载值持续计数。因此,用户必须在计数器开始计数前配置TIMERx_CARL寄存器。






我选择为TM3的T1和T2在向上/下边沿计数,这样能知道轮子实际的转向,对后续的位移计算是很有利的。
A、主函数


主要是将左右轮的计数值通过串口打印在串口助手软件上。
B、定时器配置部分
      该部分代码有两地方需要留意,第一个就是引脚的映射问题,我们必须搞清楚是没有映射,部分映射,还是完全映射,而且有时还存在第一部分和第二部分的映射如下图。

如我们小红板的TIM2的引脚映射,我们如果你是选择的第二部分,那我们PA15和PB3就是完全映射,而第一部分,确实是部分映射,所以在选择映射关系时要多加留意。

如我选择的为第一部分,部分映射GPIO_PinRemapConfig(GPIO_PARTIAL_REMAP1_TIMER2, ENABLE);
注:没有映射不要用GPIO_PinRemapConfig函数
      我们第二个需要留意的就是 TIMER_EncoderInterfaceConfig( TIMER2 ,TIMER_ENCODER_MODE_TI12,                                                                TIMER_IC_POLARITY_BOTH_EDGE, TIMER_IC_POLARITY_BOTH_EDGE);
这个中间的TIMER_IC_POLARITY_BOTH_EDGE,在小红板的官方固件库和STM32的固件库函数解释中都没有出现,如下图

当中只有两种选择,上升沿和下降沿计数,但是在我们的寄存中是有第三种的,及边沿向上/ 下计数。

然而我们的TIMER_IC_POLARITY_BOTH_EDGE也确实有定义,只是小红板和STM32固件库函数的解释说明给写漏了,大家可以放心使用。库中可以找到如下定义,如下图


具体代码如下。
/**************************************************************************
函数功能:TM2正交译码器配置函数
入口参数:无
返回  值:无
引脚说明:TIMER2_CH1-->PA15                                IMER2_CH2-->PB3       
**************************************************************************/

void Encoder_Init_TIM2()
{       
       RCC_APB2PeriphClock_Enable( RCC_APB2PERIPH_GPIOA|RCC_APB2PERIPH_GPIOB, ENABLE );
            /* TIMER3 clock enable */
       RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_TIMER2,ENABLE);
        {               
        GPIO_InitPara  GPIO_InitStructure;      
        GPIO_InitStructure.GPIO_Pin     = GPIO_PIN_15;
        GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_IN_FLOATING;
        GPIO_InitStructure.GPIO_Speed   = GPIO_SPEED_50MHZ;
        GPIO_Init( GPIOA , &GPIO_InitStructure);                
        GPIO_PinRemapConfig(GPIO_PARTIAL_REMAP1_TIMER2, ENABLE);               
        GPIO_InitStructure.GPIO_Pin     = GPIO_PIN_3;
        GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_IN_FLOATING;;
        GPIO_Init( GPIOB , &GPIO_InitStructure);
        GPIO_PinRemapConfig(GPIO_PARTIAL_REMAP1_TIMER2, ENABLE);
        }       
  {
    TIMER_BaseInitPara TIM_TimeBaseStructure;
    TIMER_ICInitPara   TIM_ICInitStructure;
    /* TIMER2  configuration */
    TIMER_DeInit(TIMER2);
    TIM_TimeBaseStructure.TIMER_Prescaler     = 0x00;
    TIM_TimeBaseStructure.TIMER_CounterMode   = TIMER_COUNTER_UP;
    TIM_TimeBaseStructure.TIMER_Period        = 65535;
    TIM_TimeBaseStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
    TIMER_BaseInit(TIMER2,&TIM_TimeBaseStructure);
    /* Input capture configuration */
    TIM_ICInitStructure.TIMER_ICPolarity  = TIMER_IC_POLARITY_RISING;
    TIM_ICInitStructure.TIMER_ICSelection = TIMER_IC_SELECTION_DIRECTTI;
    TIM_ICInitStructure.TIMER_ICPrescaler = TIMER_IC_PSC_DIV1;
    TIM_ICInitStructure.TIMER_ICFilter    = 0x0;
    TIMER_ICInit(TIMER2, &TIM_ICInitStructure);
    /* Auto-reload preload enable */
    TIMER_CARLPreloadConfig(TIMER2,ENABLE);
    /*配置为T1T2计数模式,且在上下延计数
    TIMER_EncoderInterfaceConfig( TIMER2 ,TIMER_ENCODER_MODE_TI12,
                                                                TIMER_IC_POLARITY_BOTH_EDGE, TIMER_IC_POLARITY_BOTH_EDGE);
   TIMER_SetCounter( TIMER2 ,0);//清零计数器
    /* TIMER enable counter*/
    TIMER_Enable( TIMER2, ENABLE );
        }
}
/**************************************************************************
函数功能:TM3正交译码器配置函数
入口参数:无
返回  值:无
引脚说明:TIMER3_CH1-->PA6                                IMER3_CH2-->PA7       
**************************************************************************/

void Encoder_Init_TIM3()
{
                RCC_APB2PeriphClock_Enable( RCC_APB2PERIPH_GPIOA, ENABLE );
            /* TIMER3 clock enable */
    RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_TIMER3,ENABLE);
        {               
        GPIO_InitPara  GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Pin     = GPIO_PIN_6;
        GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_IN_FLOATING;
        GPIO_InitStructure.GPIO_Speed   = GPIO_SPEED_50MHZ;
        GPIO_Init( GPIOA , &GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin     = GPIO_PIN_7;
        GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_IN_FLOATING;;
        GPIO_Init( GPIOA , &GPIO_InitStructure);
        }       
  {
    TIMER_BaseInitPara TIM_TimeBaseStructure;
    TIMER_ICInitPara   TIM_ICInitStructure;
    /* TIMER3  configuration */
    TIMER_DeInit(TIMER3);
    TIM_TimeBaseStructure.TIMER_Prescaler     = 0x00;
    TIM_TimeBaseStructure.TIMER_CounterMode   = TIMER_COUNTER_UP;
    TIM_TimeBaseStructure.TIMER_Period        = 65535;
    TIM_TimeBaseStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
    TIMER_BaseInit(TIMER3,&TIM_TimeBaseStructure);
    /* Input capture configuration */
     TIM_ICInitStructure.TIMER_ICPolarity  = TIMER_IC_POLARITY_RISING;
    TIM_ICInitStructure.TIMER_ICSelection = TIMER_IC_SELECTION_DIRECTTI;
    TIM_ICInitStructure.TIMER_ICPrescaler = TIMER_IC_PSC_DIV1;
    TIM_ICInitStructure.TIMER_ICFilter    = 0x0;
    TIMER_ICInit(TIMER3, &TIM_ICInitStructure);
    /* Auto-reload preload enable */
    TIMER_CARLPreloadConfig(TIMER3,ENABLE);
    TIMER_EncoderInterfaceConfig( TIMER3 ,TIMER_ENCODER_MODE_TI12,
                                                                     TIMER_IC_POLARITY_BOTH_EDGE, TIMER_IC_POLARITY_BOTH_EDGE);
                TIMER_SetCounter( TIMER3 ,0);//清零计数器
    /* TIMER enable counter*/
    TIMER_Enable( TIMER3, ENABLE );
        }
}


四、小红板正交编译器实战操练


实物连接图


顺时钟方向旋转车轮


逆时针方向旋转车轮

       大家可以清晰的看到,顺时钟旋转时向上计数,逆时针方向旋转时向下计数,将方向和计数结合了起来。
五、小红板正交编译器源码
电机编码器.rar (7.14 MB, 下载次数: 141)

大家可以将压缩包解压到官方送的代码历程中就可以直接用了,路径如下:
GD32MCU Document\GD32207I-EVALFiles\GD32207I_EVAL_GD32F20x_Firmware_Library_Routine\Project
大家若对工程建立有什么疑问,可以看我的上一个贴https://www.cirmall.com/bbs/thread-45746-1-1.html
六、后续
   即将马上奉上小红板之MPU6050移植篇。
分享到:
回复

使用道具 举报

回答|共 4 个

倒序浏览

沙发

奋斗哥

发表于 2016-1-26 08:23:08 | 只看该作者

不错,多多学习
板凳

糖悦之果飞

发表于 2016-1-26 08:52:54 | 只看该作者

亲,可以将内容一并发到经验频道,这是一个很好的系列,很有机会获得每月之星的呢http://jingyan.eeboard.com/
地板

沙漠之风

发表于 2016-1-26 12:29:27 | 只看该作者

糖悦之果飞 发表于 2016-1-26 08:52
亲,可以将内容一并发到经验频道,这是一个很好的系列,很有机会获得每月之星的呢http://jingyan.eeboard.c ...

嗯嗯,好的,等下再发下
5#

Andy-419672

发表于 2020-11-12 11:45:20 | 只看该作者

学习一下,多谢楼主!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条