找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2821|回复: 9
打印 上一主题 下一主题
收起左侧

51单片机编码器编程问题请教

[复制链接]
跳转到指定楼层
楼主
我用51单片机连接直流电机的编码器(带码盘385直流电机 AB相编码器,96线码盘,A相和B相输出可直接单片机IO口识别,我只接了A相),用二个四段共阴数码管的后五位显示编码器输出了多少次脉冲,用手工转动电机,当转速很慢的时候,一圈可以读取96个数,是正确的,但当转速稍快一点时,一圈就只能读20-30左右个数,丢了很多,更别说通电旋转每分钟6000转了,丢的更多,不知道为什么,请高手帮忙指教。

单片机源程序如下:
#include "reg52.h"

typedef unsigned int u16;        //对系统默认数据类型进行重定义
typedef unsigned char u8;

#define SMG_A_DP_PORT        P0        //使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                                0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//定义输入控制脚
sbit bianma=P3^1;

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能                 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出             : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
        while(ten_us--);        
}

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能                 : 动态数码管显示
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void smg_display(u8 dat[])
{
        u8 i=0;

        for(i=3;i<8;i++)
        {
                   switch(i)//位选
                {
                        case 0: LSC=1;LSB=1;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[0]];break;
                        case 1: LSC=1;LSB=1;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[1]];break;
                        case 2: LSC=1;LSB=0;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[2]];break;
                        case 3: LSC=1;LSB=0;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[3]];break;
                        case 4: LSC=0;LSB=1;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[4]];break;
                        case 5: LSC=0;LSB=1;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[5]];break;
                        case 6: LSC=0;LSB=0;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[6]];break;
                        case 7: LSC=0;LSB=0;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[7]];break;
                }
                delay_10us(1);//延时一段时间,等待显示稳定
                SMG_A_DP_PORT=0x00;//消音
        }
}



/*******************************************************************************
* 函 数 名       : main
* 函数功能                 : 主函数
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void main()
{        
        u16 roll_11=0;
        u16 roll;
        u8 key=0;
        u8 rollb8[8];

        while(1)
        {
                if(key==0&&bianma==0)//有接地脉冲
                {
                        delay_10us(1);//消抖
                        key=1;
                        if(bianma==0)roll_11++;
                }
                else if(bianma==1)        //无接地脉冲
                {
                        delay_10us(1);//消抖
                        key=0;                        
                }
                roll=roll_11;
                rollb8[3]=roll/100000;                        //读取万位数
                rollb8[4]=roll%10000/1000;                //读取千位数
                rollb8[5]=roll%1000/100;                  //读取百位数
                rollb8[6]=roll%100/10;                 //读取十位数
                rollb8[7]=roll%10;                             //读取个位数
                smg_display(rollb8);                //调用数码管显示
        }               
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1005338 发表于 2022-4-23 16:26 | 只看该作者
电机图片见附图

51hei图片_20220423162220.png (1.2 MB, 下载次数: 58)

51hei图片_20220423162220.png
回复

使用道具 举报

板凳
ID:1005338 发表于 2022-4-23 16:31 | 只看该作者
本帖最后由 niejiangong 于 2022-4-23 16:34 编辑

补充一下,我只测其中一相A或者B,本来的目的是:想通过编码器的输出的脉冲数除以96,计算出来电机转动的圈数,当圈数达到预定值后,表明电机带的齿轮在齿条上走到设定位置,然后给电机断电。但读数总不正常就没法继续操作了
回复

使用道具 举报

地板
ID:688692 发表于 2022-4-23 18:28 | 只看该作者
在主循环里面监测编码器信号,采样率不够。
要将编码器的信号接到外部中断上,当中断发生时,进行加减计数,可支持到1MHz。
如果使用软采样,采样频率必须高于信号频率2倍以上,也就是编码器如果最高输出脉冲频率1kHz,那采样率至少要2kHz才不会丢脉冲。
你的主循环跑一圈多长时间知道吗?
建议还是用中断来做。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

5#
ID:213173 发表于 2022-4-23 21:11 | 只看该作者
niejiangong 发表于 2022-4-23 16:31
补充一下,我只测其中一相A或者B,本来的目的是:想通过编码器的输出的脉冲数除以96,计算出来电机转动的圈 ...

用定时器外部计数功能可以做到准确计数。由于机械惯性不可能以此精确控制电机转动的圈数。需要改用步进电机。
回复

使用道具 举报

6#
ID:514254 发表于 2022-4-23 21:13 | 只看该作者
建议用中断或者捕捉啊,用软的方法后期肯定会受到其他程序的影响,不过测试下原理是可以的。
回复

使用道具 举报

7#
ID:1005338 发表于 2022-4-24 09:44 | 只看该作者
wulin 发表于 2022-4-23 21:11
用定时器外部计数功能可以做到准确计数。由于机械惯性不可能以此精确控制电机转动的圈数。需要改用步进电 ...

位置精度要求不是特别高,加上减速比有50,惯性造成一点点误差可以接受,直流电机体积小,步时电机体积大成本高
回复

使用道具 举报

8#
ID:1005338 发表于 2022-4-24 09:45 | 只看该作者
dazhige 发表于 2022-4-23 21:13
建议用中断或者捕捉啊,用软的方法后期肯定会受到其他程序的影响,不过测试下原理是可以的。

这个建议非常好,我再用中断调试一下
回复

使用道具 举报

9#
ID:1074495 发表于 2023-5-4 12:39 | 只看该作者
如果中断没有其他外设的话,用中断的话会比较好吧!!!
回复

使用道具 举报

10#
ID:883242 发表于 2023-5-5 15:23 | 只看该作者
不光是要外部中断,还要判断方向,比如用A相做外部中断,进入后要立刻读取B相的电平,才能知道电机往哪个方向旋转。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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