平衡小车之编码器的使用(深夜学习——单片机)

文章介绍了霍尔编码器的工作原理,如何通过编码器采集电机转速并转化为脉冲信号,以及如何利用单片机进行转速计算。还详细讲解了编码器的倍频概念,如二倍频和四倍频,以提高精度。同时,提供了相关的代码示例,展示如何在STC15系列单片机中实现二倍频计算电机转速。
摘要由CSDN通过智能技术生成

一、平衡小车要编码器干什么?

采集电机的转速,并转化成脉冲信号并发送给单片机,最后计算出小车的速度。

二、编码器原理:(以常用的增量式为例)

  1. 霍尔编码器:

(1)组成:

霍尔编码器主要包括两个部分:霍尔码盘,霍尔元件组成。

霍尔码盘:由多个NS极间隔的圆形磁体,其中你买电机看到xx线,就是指有多少组NS极

霍尔元件:一种基于霍尔效应,能检测磁场的元件(如果不懂霍尔效应,建议先去了解一下),当N极靠近就产生高电平;当S极靠近就产生低电平

(3)工作原理:

假设初始位置如上图所示,则A、B输出的电压如图:

当主轴顺时针旋转时,输出脉冲A通道信号位于B通道之前;

当主轴逆时针旋转时,输出脉冲A通道信号位于B通道之后。

(4)由输出信号得出转速:

假设编码器为13线,也就是每转一圈产生13个脉冲信号,我们只需要在单位时间内对产生的脉冲信号进行计数,再将总数除以13和计数时间,就可以得出转速。

(5)由AB确定转动方向:

通过观察上图可以知道,顺时针转动时,A相会先变化,导致A相上升沿,B相处于高电平;A相下降沿,B相处于低电平。逆时针时,B相会先变化,导致A相上升沿,B相处于低电平,A相下降沿,B相处于低电平。

三、计算方法:

  1. 倍频:

(1)LSB最低有效位:

类似于一个长10cm的尺子,假设平均分为100格,那么最低有效位就是0.1cm

(2)编码器的LSB:

编码器的LSB主要由线数决定,我们知道每经过一组NS极,都会产生一个脉冲信号,而上升沿和下降沿都可以触发单片机的中断,我们只需要在此时计数,就可以将转一圈分为13份(假设为13线)

(3)编码器的倍频:

不知道你们有没有用很多个点拟合一个正弦函数,我们会发现缩小了看,可以看到十分平滑曲线,但是逐渐放大看局部,就会发现崎岖无比的曲线。

推广到编码器的计数,如果我们可以尽可能将转动一圈分为更多份,那么局部的有害干扰就对整体的结果产生的影响就显得微乎其微了

(4)二倍频:

我们知道每经过NS的边界,霍尔传感器就会上升沿和下降沿,而这个变化之间的距离又是相同的,所以我们让单片机对A或B相的上升沿和下降沿都计数,也可以看成输出频率加倍了,也就是二倍频。

(5)四倍频:

如果将一个NS极的角度叫做一个周期的角度,而A、B相之间的角度被设计为相差四分之一个周期的角度。综合起来看,也就是A,B相的上升沿和下降沿之前相差的距离是相同的,如果对A、B相的上升沿和下降沿都进行计数,就能实现四倍频

  1. 电机转速计算:

(1)“13线”:码盘中缺口的个数,每经过一个缺口就会产生一个脉冲信号,也就是说每产生13个脉冲信号相当于码盘转一圈

(2)”减速比1:30“:轮子转一圈,码盘转三十圈

(3)轮子转速 =码盘转速/减速比

码盘转速 = 一定时间内计数值/转一圈的计数值/计数时间

四、参考代码:(以二倍频,STC15系列为例)

  1. 主函数:

#ifndef PUBLIC_H
#define PUBLIC_H

#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
#endif
#include "public.h"
#include "uart.h"
#include "stdio.h"
#include "encoder.h"
#include "intrins.h"
#include "timer.h"
#include "pwm.h"

u8 sign_5ms;
float rpm;//单位:转每分钟
int count_enco,cacl_temp;

void main()
{

    UartInit();
    E_IT1_Init();
    Timer0_Init();
    //驱动电机转动
    PMW_Init();        
    AIN1 = 1;
    AIN2 = 0;
    BIN1 = 1;
    BIN2 = 0; 
    while(1)
    {
        //每5ms计算一次
        if(sign_5ms == 1)
        {
            printf("cacl_temp:%d\r\n",cacl_temp);
            //轮子转速,单位:转/分钟
            rpm =  cacl_temp/26.0/5*1000*60/30;
            printf("rpm:%f\r\n",rpm);
            sign_5ms = 0;
        }
    }
} 

void E_IT1() interrupt 2
{
    //相异为正,相同为负
    if(Encoder1_A ^ Encoder1_B)
        count_enco++;
    else
        count_enco--;
    //指示灯,检测是否正常工作
    P00 ^= 1;
}
void Timer0_Isr(void) interrupt 1
{
    sign_5ms++;
    cacl_temp = count_enco;
    count_enco = 0;
}
  1. 编码器初始化:

#ifndef ENCODER_H
#define ENCODER_H

#include "public.h"

sbit Encoder1_A = P3^3;
sbit Encoder1_B = P2^5; 
void E_IT1_Init();

#endif
#include "encoder.h"

/*
    外部中断0初始化
*/
void E_IT1_Init()
{
    //跳变沿触发
  IT1 = 0;
    //开启中断
    EX1 = 1;
    EA = 1;
}
  1. PWM初始化:

#ifndef PWM_H
#define PWM_H

#include "public.h"

sbit pwm_A = P3^6;
sbit AIN1 = P2^0;
sbit AIN2 = P2^1;

sbit pwm_B = P3^7;
sbit BIN1 = P2^2;
sbit BIN2 = P2^3;

void PMW_Init(void);
#endif
#include "pwm.h"


void PMW_Init(void)        
{
    //CCP1:P36 CCP2:P37
    P_SW1 = P_SW1 & 0xcf | (0x02<<4);
    CL = CH = 0;
    CMOD = 0x08;
    //CCP1:     占空比:70%
    PCA_PWM1 = 0x00;
    CCAP1H = CCAP1L = 0;
    CCAPM1 = 0X42;
    //CCP2:     占空比:70%
    PCA_PWM2 = 0x00;
    CCAP2H = CCAP2L = 0;
    CCAPM2 = 0X42;
    //
    CCON = 0X40;
}
  1. 定时器初始化:

#ifndef     TIMER_H
#define     TIMER_H

#include "public.h"



void Timer0_Init(void);

#endif
#include "timer.h"


void Timer0_Init(void)        //5毫秒@12MHz
{
    AUXR |= 0x80;            //定时器时钟1T模式
    TMOD &= 0xF0;            //设置定时器模式
    TL0 = 0xA0;                //设置定时初始值
    TH0 = 0x15;                //设置定时初始值
    TF0 = 0;                //清除TF0标志
    TR0 = 1;                //定时器0开始计时
    ET0 = 1;                //使能定时器0中断
    EA = 1;
}
  1. 串口通信:

#ifndef UART_H
#define UART_H

#include "public.h"

void UartInit(void);

#endif
#include "uart.h"
#include <stdio.h> 
void UartInit(void)        //9600bps@12MHz
{
    SCON = 0x50;        //8位数据,可变波特率
    AUXR |= 0x40;        //定时器时钟1T模式
    AUXR &= 0xFE;        //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;        //设置定时器模式
    TL1 = 0xC7;            //设置定时初始值
    TH1 = 0xFE;            //设置定时初始值
    ET1 = 0;            //禁止定时器中断
    TR1 = 1;            //定时器1开始计时
}


/*
    重定义putchar函数
*/
char putchar (char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
    return c;
}

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值