没有最佳的说法,一秒一个脉冲也很好,1秒几圈也可以。 |
楼主的代码能分享吗? |
反正工业上的编码器,速度反馈用的,一分钟800转是基本的。4级电机60f/p,减去转差1400转每分钟。 |
感觉基本是成功了。电机调速如丝般顺滑,比一开始好很多,最快手速也有反应了,估计至少一秒两圈吧。一点心得体会: 1、要想快,去电容。要想稳(防抖),加电容。一开始我有点被百度误导了,直接放了2个104(0.1uF),事实证明EC11要想快就直接裸奔,电容两端电压不能突变么。但以后我可能会加两个PF级的电容求个心理安慰。 2、优化代码也很重要。两个方面:一是主程序各函数的顺序;二是数码管显示函数,一定要用数组缓存数据,能极大提升显示质量。我一开始用的74HC245+138驱动数码管,后来换成TM1650,效果一样的。再就是把显示函数放在EC11扫描函数里面,数据变了马上显示出来,要减少一切显示延迟。 3、中断是个好方法,但不适合我现在的程序。我用定时器0中断产生脉冲给电机驱动器,用定时器1中断扫描EC11,两个中断一叠加,电机就啸叫、抖动,时快时慢,根本没法用。我还是用的一开始发的那个扫描函数。 4、至于为什么MCU是89C52,是因为我现在还不会用别的 ![]() 以上,再次感谢各位大侠的建议和指导! |
使用EC11一直都是用外部中断来检测的,不太明白楼主为什么会用到定时器 |
ningsy 发表于 2022-10-9 10:21 你可以先把你现在的代码改一下,试一下效果就知道了 把用作PWM的定时器中断优先级设定为最低,EC11定时器设定为最高,看一下效果就知道了 因为STC89C52的中断优先级默认都是一样等级的 |
ningsy 发表于 2022-10-7 15:53 你以为我不懂什么是EC11?我手上的光电编码器都是400线以上,转速都能超过50圈一秒。 |
对。 我今天把74HC245+138驱动数码管方案换成了TM1650驱动,已经正常显示了,但感觉又进一步拖累了EC11的反应。以前有误区,总想着优化某一部分的代码就行,现在看来要整体考虑了。您说的那个PWM驱动我去了解一下,后续这个项目也准备转移到STC8上来搞。 这个小控制器的事真是越做越多啊。 |
ningsy 发表于 2022-10-8 15:31 我这代码用的也是中断 步进电机也用中断的话,两个之间是有冲突的 而且,我的代码是1KHZ的扫描频率,而你的是最高9.9KHZ的,占用的资源比EC11的还多,自然就慢下来了 就算你用别的EC11代码,结果也是一样的 问题出现在你的代码上,跟什么1T/12T的没有关系 如果要用PWM驱动,你应该用单片机自带的PWM功能,而不是用定时器中断来产生PWM 如果你用的单片机没有PWM功能,那就换一个有PWM功能的单片机,STC89C52早跟这个时代脱节了 |
//************************************************************************************ 祁绪电子 2021年9月 // //编码器扫描旋转 //************************************************************************************ 祁绪电子 2021年9月 void ROTARY_ROTARY_Scan_Drive() { static bit Turn_Left=0,Turn_Right=0,Rotary_Flag=0; if((ROTARY_A==1)&&(ROTARY_B==1)) //A、然后等待两个IO口都是高电平 { Rotary_Flag=1; //A、标志置一 } if(Rotary_Flag==1) //如果标志是1 { if((ROTARY_A==0)&&(ROTARY_B==0)) //C、等待两个IO口都是低电平 { if(Turn_Right==1) //如果右标志是1说明是顺时针 { Rotary_Flag=0; //标志清0 Rotary_Read_Data_Rotary++; //编码器增加 } if(Turn_Left==1) //如果左标志是1说明是逆时针 { Rotary_Flag=0; //标志清0 Rotary_Read_Data_Rotary--; //编码器减少 } } } Turn_Left=ROTARY_A; //B、首先保存2个IO口的电平状态 Turn_Right=ROTARY_B; //B、首先保存2个IO口的电平状态 }//*/ |
Y_G_G 发表于 2022-10-8 11:03 首先说明:我现在用的MCU是89C52,跟您用的Stc8差远了,也没有1T模式,只能12T(6T 也可能行,我没用)。我做这个是步进电机控制器,一上电定时器0中断就不停产生脉冲,频率100~9900Hz连续可调。 我想达到的效果: 1、电机运转中转速连续可调,调速要丝滑无顿挫(操作者感觉好就行,这条基本没问题了); 2、快速转动EC11调速旋钮反应要灵敏无跳码。(现在是每秒1圈没问题,手速特别快就跟不上,这也是我想解决的问题。 用您的代码时,89C52没有的寄存器我全都注释掉了,用的是定时器1中断。运行时结果是可以调速,但调速时电机转速不均,时快时慢;手速快时也反应不过来。 所以我这种情况是不是不能同时用两个定时器中断来控制呢?毕竟控制电机是主要任务,两个中断是不是互相影响?感觉想用好这个EC11编码器好难,也不知是我用的U太差,还是代码、电路哪里有问题,我都想给它安排个芯片单独控制(如果可以的话),不要再占用MCU了。 |
ningsy 发表于 2022-10-8 10:52 IO不需要电容 定时器扫描时间改成500uS或者更短时间的话,反应可以快一点 因为用的是中断,如果其它中断打断的话,可能会慢点 反正,在我这基本是没有出过问题的 |
Y_G_G 发表于 2022-10-7 15:20 您发的代码我测试了,初步可用,但感觉速度还不够,不知是不是我没调好。 我手里有一个成品步进电机控制器,可连续调速,那旋钮真的灵敏,不管手速多快,就是没误码(也许有,但我感觉不到)。不知是怎么做到的。 我这个也可以连续调速,但手速一快就反应不过来了。 |
一直用外部中断做的,硬件部分上拉加电容滤波,没见到有什么异常 |
从自己的代码找问题,最快的是中断处理。查询处理,如果主程序执行的代码比较长,速度肯定跟不上。 |
coody_sz 发表于 2022-10-7 15:34 大侠,你说的是“光电编码器”吧,一个大几十元,用在医疗监控,高端精密设备上那种?那种用不起,我这是一个才2块多包邮的机械编码器。 |
EC11质量好的1秒至少能5圈,即100脉冲一秒,没有任何问题。 |
即便,不接电容,1秒两圈的速度也是没啥问题的,关键看代码,还有焊接问题了,虚焊能让你转了不动,不转乱动。 |
这个是我自己用的,你参考一下,速度不是很快,但正常使用是可以的,定时器扫描速度提高一点,可以读取得快一点 /*────────────────────────────────────────────────────────────────────────────────────────────────── EC11_T0.c 编写:YGG 完成日期:20211118 功能:通过T0定时器来完成EC11编码开关的检测 适用于STC8051单片机T0定时器编码开关函数 完成状态:已经完成 ──────────────────────────────────────────────────────────────────────────────────────────────────*/ #include "Stc8a.h" #include "EC11_T0.h" sbit sa=P2^2; //编码开关的两个端口 sbit sb=P2^1; //编码开关的两个端口 sbit over=P3^2; //过流检测IO sbit buzz=P4^0; //用于蜂鸣器控制 bit fa; //用于标记编码开关两个端口状态 bit fb; // 0 为没有记录,1 为已经记录 unsigned char turn_f=0x00,turn_r=0x00; //用于存放旋转变量的,一个是正反两个方向 //────────────────────────────────────────────────────────────────────────────────────────────────── void Timer0Init(void) //T0定时器初始化,1毫秒@11.0592MHz { AUXR |= 0x80; //定时器时钟1T模式 TMOD &= 0xF0; //设置定时器模式 TL0 = 0x66; //设置定时初始值 TH0 = 0xEA; //设置定时初始值 TF0 = 0; //清除TF0标志 ET0 = 1; //T0定时器中断开启 TR0 = 1; //定时器0开始计时 P_SW2=0x80; // P2PU|=0x06; //P2.1,P2.2上拉电阻启用 P_SW2=0x00; // } //────────────────────────────────────────────────────────────────────────────────────────────────── //────────────────────────────────────────────────────────────────────────────────────────────────── void timer0() interrupt 1 //T0定时器中断 { static unsigned char bm_data; //用于保存两个端口读取到的数据 TL0 = 0x66; //设置定时初始值 TH0 = 0xEA; //设置定时初始值 if(!over)buzz=!buzz; //检测到低电平,蜂鸣器响 else buzz=0; //────────────────────────────────────────────────────────────────────────────────────────────── if(sa&&sb) //如果两个端口都是1,就表示编码开关位于"静止" { if(bm_data==0x12) { turn_f++; } else if(bm_data==0x21) { turn_r++; } bm_data=0; //长期静止状态,端口数据要清除 fa=1; fb=1; } //────────────────────────────────────────────────────────────────────────────────────────────────── else if((fa!=sa)||(fb!=sb)) //如果标志位的上次的一样,就不记录端口数据 { bm_data=(bm_data<<1)|sa; bm_data=(bm_data<<1)|sb; fa=sa; fb=sb; } } //────────────────────────────────────────────────────────────────────────────────────────────────── |
ningsy 发表于 2022-10-7 11:55 它其实就是通过检测哪个引脚先出现电平的变化来区分转动方向的 只要你程序合理,不可能只是1秒一圈的 |
51hei截图20221007145958.png (28.98 KB, 下载次数: 44)
怎么感觉这代码做复杂了,EC11没这么复杂 |
yanjian 发表于 2022-10-7 12:10 那您可以试试我发这个驱动函数。 您有外部中断的例程吗?我找了一段外部中断的代码,可是不能用,可能是有一句代码有问题,编译就过不了;注释掉编译过了,可旋转编码器没反应 ![]() |
你这还好了,我转太快就抓到错的数据. 比如正转时候识别成反转. 想快,用外部中断,一步一脉冲的用下降沿中断 |
支持---反应不过来第一步应该看你的代码。 |
反应不过来第一步应该看你的代码。 |