搜索
bottom↓
回复: 42

开源Atmega8+74hc595方案的32路舵机控制板(慎入:软件误差太...

[复制链接]

出0入0汤圆

发表于 2014-3-26 17:04:56 | 显示全部楼层 |阅读模式
本帖最后由 superplaim 于 2014-3-26 17:51 编辑

Atmega8+74hc595方案的32路舵机控制板(慎入:软件误差太大)
  想做个机器人,自己设计一款舵机控制器,也插了很多资料(大多是本论坛的实例,有硬件也有软件)
最后确定了舵机的方案利用成熟的atmega8+4片74HC595利用spi总线的方式传输数据来控制32路舵机
废话不说先上个原理图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)

出0入0汤圆

 楼主| 发表于 2014-3-26 17:05:48 | 显示全部楼层
本帖最后由 superplaim 于 2014-3-26 17:09 编辑

原理图和PCB都看不太清楚我把文件传进来

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-3-26 17:23:31 | 显示全部楼层
这个系统用来控制8路舵机也就是只用一个74HC595的精度还是可以的,pwm也比较稳定
但是如果扩展的32路基本可以输出Pwm但是精度极差,这肯定是由于软件的原因引起的
但是研究了好久也不知道怎么去优化,两种编程方案都不是太理想,现在都想放弃整个方案重新用STM32做一个引脚直接输出的,估计精度会提高很多
现在把代码贴出来,希望给能对别人有些参考,也希望高手做过类似方案的能给指导一下看能不能重新优化一下,毕竟PCB已经打样放弃也怪浪费的
编译用的是ICC8.0,等下把软件也贴出来,这个软件的8.05版当时还很不好找,需要的人可以下载

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-3-26 17:24:26 | 显示全部楼层
本帖最后由 superplaim 于 2014-3-27 10:20 编辑

另外先前还用labview写了串口上位机控制软件,如果有人需要请留言我可以开源,下面是Proteus的仿真图仿真的效果跟实测的效果基本一致

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-3-26 17:33:47 | 显示全部楼层
控制板的硬件部分与SSC-32开源控制板(说明书上写的精度能达到1us,我认为如果达到的话,程序员一定逆天了)基本一致只不过没有加入动作存储和波特率选择的部分,如果谁有需要我可以把资料都贴出来,希望哪位高手能给指导一下,论坛中的实例大部分都是来控制8路的

出0入0汤圆

发表于 2014-3-26 18:00:20 | 显示全部楼层
楼主厉害,给顶上去,让论坛的高手出来给大家出出福利

出0入0汤圆

发表于 2014-3-26 18:06:53 | 显示全部楼层
我用PIC做过,用的是CCP的Compare模式,把舵机脉冲时间排序后,启动定时器,定时器与比较寄存器一致时,触发中断,然后更新比较寄存器.实现依次更新相应舵机通道为低电平.
跟楼主的模式应该是一样的.追求精度可以尝试用汇编写排序完成后的代码.

出0入0汤圆

发表于 2014-3-27 00:58:23 | 显示全部楼层
之前下的资料,有程序和原理图,感谢作者!搬运过来
[attach]32V103[/attach]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-3-27 01:13:54 | 显示全部楼层
windingway 发表于 2014-3-26 18:06
我用PIC做过,用的是CCP的Compare模式,把舵机脉冲时间排序后,启动定时器,定时器与比较寄存器一致时,触发中断 ...

就是这个原理,这是借鉴了论坛某位兄弟的程序,汇编语言好难上手,C还是比较习惯

出0入0汤圆

 楼主| 发表于 2014-3-27 01:15:45 | 显示全部楼层
donglaile 发表于 2014-3-27 00:58
之前下的资料,有程序和原理图,感谢作者!搬运过来

哥们 这个附件不能下载了啦

出0入0汤圆

 楼主| 发表于 2014-3-27 01:20:24 | 显示全部楼层
为什么我上传的附件全部挂掉了

出0入0汤圆

发表于 2014-3-27 06:28:12 | 显示全部楼层
superplaim 发表于 2014-3-26 17:23
这个系统用来控制8路舵机也就是只用一个74HC595的精度还是可以的,pwm也比较稳定
但是如果扩展的32路基本可 ...

沒看LZ的思路,能否用文字描述一下思路。PWM周期和位数是多少?
建议搜索"595 灰度"
一个位权控制LED灰度的方法可以降低对硬件的速度要求。

出0入0汤圆

发表于 2014-3-27 06:34:05 | 显示全部楼层
http://www.amobbs.com/forum.php? ... mp;highlight=595%2B灰度
27楼
理解可以看我在那里的回复234楼

出0入0汤圆

 楼主| 发表于 2014-3-27 10:16:35 | 显示全部楼层
zyw19987 发表于 2014-3-27 06:34
http://www.amobbs.com/forum.php?mod=viewthread&tid=985613&highlight=595%2B灰度
27楼
理解可以看我在那 ...

首先将各路的pwm的高电平时间按照从小到大的时间排序,然后计算这32个时间之间的差值生成一个延时差值的32数组,先让各路输出先为高电平 然后将时间差值数组送给定时器T1,依次产生延时,每20ms进入外部中断INT0产生周期

这个灰度的例子我还没有看到,我现在研究一下

出0入0汤圆

 楼主| 发表于 2014-3-27 10:22:22 | 显示全部楼层
donglaile 发表于 2014-3-27 00:58
之前下的资料,有程序和原理图,感谢作者!搬运过来

上传的附件代码应该是SSC-32的原版程序 是用codevision编译的 我用这个软件总是编译通不过,能不能麻烦你给编译一下,最好能生成hex文件

出0入0汤圆

发表于 2014-3-27 13:27:33 | 显示全部楼层
superplaim 发表于 2014-3-26 17:33
控制板的硬件部分与SSC-32开源控制板(说明书上写的精度能达到1us,我认为如果达到的话,程序员一定逆天了 ...

其實未必不可能的,但必須要用匯編,用 c 只能到 5us 級別。

出0入0汤圆

 楼主| 发表于 2014-3-27 14:15:05 | 显示全部楼层
irobotto 发表于 2014-3-27 13:27
其實未必不可能的,但必須要用匯編,用 c 只能到 5us 級別。

原版代码使用gcc和codeversion编译好像嵌入了部分汇编语句

出0入0汤圆

发表于 2014-3-27 15:52:35 | 显示全部楼层
研究舵機是很久的事了,匯編也只懂皮毛,看不明白的。但這方向是對的。當時還在用89c2051, 11.0592 MHz 晶振,跑一個指令要12個時鐘周期,很慢的。但用得好最多可以控制13個舵機(其中2支要上拉電阻),訊號之間相隔最少是10us.

出0入0汤圆

发表于 2014-3-28 13:37:06 | 显示全部楼层
superplaim 发表于 2014-3-27 14:15
原版代码使用gcc和codeversion编译好像嵌入了部分汇编语句

剛抽空看了一下樓主的程序,寫得很工整。第一步要想是中斷內要處理的事情是否太多?必須要在中斷內做的?因為這個直接影響程序的效能。例如 計算 Serial_temp , TCNT1等都花了太多時間了。 留意 16 MHz 代表每做 16個單周期指令,便花了 1us 時間啦!先試改一下吧

出0入0汤圆

 楼主| 发表于 2014-3-28 17:20:36 | 显示全部楼层
irobotto 发表于 2014-3-28 13:37
剛抽空看了一下樓主的程序,寫得很工整。第一步要想是中斷內要處理的事情是否太多?必須要在中斷內做的? ...

以前也考虑过这个问题,也不知道怎么解决,请教一下有没有好的建议

出0入0汤圆

发表于 2014-3-28 17:47:02 | 显示全部楼层
superplaim 发表于 2014-3-28 17:20
以前也考虑过这个问题,也不知道怎么解决,请教一下有没有好的建议

在做好 sorting 後就可以預先計算好 serial_temp 和 tcnt1 的數值了,用陣列貯存好就可以了。在中斷內只調用,不計算。

出0入0汤圆

发表于 2014-3-28 23:28:02 来自手机 | 显示全部楼层
labview写了串口上位机控制软件,给参考一下

出0入0汤圆

发表于 2014-3-28 23:28:37 来自手机 | 显示全部楼层
邮箱:cdl35@sina.com

出0入0汤圆

 楼主| 发表于 2014-3-30 12:57:57 | 显示全部楼层
irobotto 发表于 2014-3-28 17:47
在做好 sorting 後就可以預先計算好 serial_temp 和 tcnt1 的數值了,用陣列貯存好就可以了。在中斷內只 ...

有道理啊 我怎么没有想到 现在去改改

出0入0汤圆

 楼主| 发表于 2014-3-30 13:51:03 | 显示全部楼层
irobotto 发表于 2014-3-28 17:47
在做好 sorting 後就可以預先計算好 serial_temp 和 tcnt1 的數值了,用陣列貯存好就可以了。在中斷內只 ...


#include<iccioavr.h>
#include<AVRdef.h>
#include"AVR_SPI.h"
unsigned char m=0,a=0;
unsigned int Dispersion[32];//存放各个延时值之间的时间差
//第1组舵机数据
unsigned char Length_Temp[32];//从小到大存放各路高电平延时值
unsigned char Length[32]={50,60,60,80,90,100,130,130,
                          50,60,60,80,90,100,130,30,
                          50,60,60,80,90,100,130,130,
                          50,60,60,80,90,100,130,130};//高电平时间 单位10us

unsigned long Serial_Num[32]={0xfffffffe,0xfffffffd,0xfffffffb,0xfffffff7,0xffffffef,0xffffffdf,0xffffffbf,0xffffff7f,
                              0xfffffeff,0xfffffdff,0xfffffbff,0xfffff7ff,0xffffefff,0xffffdfff,0xffffbfff,0xffff7fff,
                              0xfffeffff,0xfffdffff,0xfffbffff,0xfff7ffff,0xffefffff,0xffdfffff,0xffbfffff,0xff7fffff,
                              0xfeffffff,0xfdffffff,0xfbffffff,0xf7ffffff,0xefffffff,0xdfffffff,0xbfffffff,0x7fffffff};
unsigned long Serial_Temp[32];//临时存放Serial_Num[[8]

void Timer1_Init(void);//定时器3初始化
void Int0_Init(void);//外部中断0初始化,下降沿触发
void Sorting(void);//冒泡法排序函数 主要对Length_Temp0[8]排序


void main(void)
{
    SPI_MasterInit();//SPI总线初始化
    DDRD|=0x08;//设置PD0为输出
        PORTD|=0x08;//置PD0为高电平
        Timer1_Init();//初始化定时器3 8分频
        Int0_Init();//初始化外部中断0 1分频
    Sorting();//对初始值进行排序,确定dispersion数组的值
    //因为vlaue的值是0—255,外部晶振为16M,定时器的计数频率设为8分频。这样每计一个值
    //耗费的时间是0.5us.舵机要求的高电平时间是500us到2500us之间,对定时器赋初值
    //就以应该是65536-500*2=64536到65536-2500*2=60536之间。对应的value的值就是50-250
    //所以,给定时器赋初值就是vlaue*20  value的单位是10us
    TCNT1H=(0xffff-Length_Temp[0]*20)/256;//经过排序后,vlaue[0]是最小的数
    TCNT1L=(0xffff-Length_Temp[0]*20)%256;//给定时器3赋初值
    HC595_OUT_BANK0(0xff);
    HC595_OUT_BANK1(0xff);
    HC595_OUT_BANK2(0xff);
    HC595_OUT_BANK3(0xff);
    //定时器开始计时,对外部16M晶振进行8分频,定时器计数为0.5us一个增量,
    //单片机的指令执行速度仍然是1/16m=62.5ns一个指令周期
    TCCR1B=0x02; //T1定时器8分频
    SREG|=BIT(7);//总中断使能
    while(1)
    ;
}
#pragma interrupt_handler Int0:2//中断0处理程序
void Int0(void)
{
    TCCR1B=0x00;
    PORTD|=0x08;//恢复PD3口为高电平,开始响应中断0
    Sorting();
    m=0;
    TCNT1H=(0xffff-Length_Temp[0]*20)/256; //给定时器3赋初值
    TCNT1L=(0xffff-Length_Temp[0]*20)%256;
    HC595_OUT_BANK0(0xff);//PORTB=0xff;//置所有位为高
    HC595_OUT_BANK1(0xff);
    HC595_OUT_BANK2(0xff);
    HC595_OUT_BANK3(0xff);
    TCCR1B=0x02;//打开定时器1,8分频,每计一位为0.5us
}

#pragma interrupt_handler Timer1_Time:9//定时器1的溢出中断处理程序
void Timer1_Time(void)
{
    TCCR1B=0x00;
    if(m==32)
    {
        TCCR1B=0x00;//一个周期结束,关闭定时器1
        PORTD&=0xf7; //PD0置低位,引发外部中断0
    }
    else
    {
      spot0:HC595Output(Serial_Temp[m]);
            //第一次中断溢出时,m=0,Dispersion[0]为value[1]-value[0]
            if(Dispersion[m]==0)
            {
                m=m+1;
                goto spot0;
            }
            else
            {
                TCNT1H=(0xffff-Dispersion[m]+40)/256;//+40为补偿值
                TCNT1L=(0xffff-Dispersion[m]+40)%256;
            }
            //当m=7的时候,dispersion[7]为所有管脚置低后低电平维持的时间
            m=m+1;
    }
    TCCR1B=0x02;
}
void Timer1_Init(void)
{
    TCCR1A=0x00;//
    TCCR1B=0x02;//8 frequency division
    TIMSK|=(1<<TOIE1);//TOIE1=1
}

void Int0_Init(void)
{
    GICR|=0X40;//ENABLE INT0
    MCUCR|=0X02;//drop edge trigger
}

//冒泡法将Length_Temp和Serial_Num从小到大排序
void Sorting(void)
{
    unsigned char i,j,k;
    unsigned long t;
    for(i=0;i<32;i++)
    Length_Temp=Length;//将时常数据传送给临时数组Length_Temp
    for(i=0;i<32;i++)
    Serial_Temp=Serial_Num;//将时常数据传送给临时数组Serial_Temp
    for(j=0;j<31;j++)//冒泡算法,Length_Temp[8]被从小到大排序
    {
        for(i=0;i<31-j;i++)
        {
            if(Length_Temp>Length_Temp[i+1])
            {
                k=Length_Temp[i+1];
                Length_Temp[i+1]=Length_Temp;
                Length_Temp=k;
                t=Serial_Temp[i+1];
                Serial_Temp[i+1]=Serial_Temp;
                Serial_Temp=t;//相应要置低的管脚也排序
            }
        }
    }
    for(j=0;j<31;j++)//相邻的数之间做差值,总共得到差值7个
    {
        //if(Length_Temp[j+1]==Length_Temp[j])
        //Dispersion[j]=6;
        //else
        Dispersion[j]=(Length_Temp[j+1]-Length_Temp[j])*20;
    }
    //最后一个值是低电平延时,65536-40000是20ms的定时初值
    Dispersion[31]=40000-Length_Temp[31]*20;
    for(i=0;i<32;i++)
    {
        if(i>0)
        Serial_Temp=Serial_Temp&Serial_Temp[i-1];
    }
}

将函数改了一下在 Sorting中将Serial_Temp和TCNT1计算 在T1中断中用:HC595Output(Serial_Temp[m]);调用发现误差依然很大 误差依然很大,是不是说明HC595Output()会的调用会占用很多时间?另外周期也不准确了,周期倒是比较修正

出0入0汤圆

发表于 2014-3-30 15:06:21 | 显示全部楼层
superplaim 发表于 2014-3-30 13:51
#include
#include
#include"AVR_SPI.h"

有輕微改善, 但思路是要盡量縮短處理 "把訊號線拉低" 時用的 時鐘周期。
仍看到這計算在 中斷內, 是不是可以預先計算好在陣列內? 應該可以減省少許 時鐘周期。
            else
            {
                TCNT1H=(0xffff-Dispersion[m]+40)/256;//+40为补偿值
                TCNT1L=(0xffff-Dispersion[m]+40)%256;
            }
之後仍要 縮短時鐘周期的。
另外你是對的, 用 595 肯定是會慢一點的, 因為是 串行的, 但不知會慢多少, 這裡用滙編會高效一點罷。

出0入0汤圆

发表于 2014-3-30 17:53:22 | 显示全部楼层
忘了你提到 "另外周期也不准确了,周期倒是比较修正" 的問題, 在程序裡計時是用
      TCNT1H=(0xffff-Dispersion[m]+40)/256;//+40为补偿值
      TCNT1L=(0xffff-Dispersion[m]+40)%256;
因為在中斷內已花了很多時間, 所以計時要加數值 40 作補償, ( 40/2 = 20 us)
亦即實際計時減 20 us, (20us *16 = 320 個時鐘周期, 亦即原先的中斷時間太長了)
而且 20us 是很不準確的, 運算的耗時跟要計的數字有關。
當你按建議縮短了中斷程序所用的時間後, 40 這數值應要減少一點的, 可試著用 38, 35 , 30, ...   

出0入0汤圆

 楼主| 发表于 2014-4-28 08:42:06 | 显示全部楼层
irobotto 发表于 2014-3-30 17:53
忘了你提到 "另外周期也不准确了,周期倒是比较修正" 的問題, 在程序裡計時是用
      TCNT1H=(0xffff-Disp ...

这个方案暂时放弃了,现在用stm32的4个定时器利用定时器分时法可以产生精度很高的pwm波形
labview上位机也完成的才差不多了但是初学labview程序框图画的乱七八糟的,有兴趣可以讨论一下

出0入0汤圆

发表于 2014-4-29 13:05:36 | 显示全部楼层
superplaim 发表于 2014-4-28 08:42
这个方案暂时放弃了,现在用stm32的4个定时器利用定时器分时法可以产生精度很高的pwm波形
labview上位机 ...

这个就这么放弃了,先别,这个先看看,或许能解决一些问你,程序可能有些简单,主要通过595分别更新,32路分4组,每组8路,4组同时给个00000001,然后看高电平那路高电平时间到了没,到了就输出00000000,然后4组同时给00000010。。。如此循环,因为周期20ms,所以8路每路就是2.5ms,现在没有解决的问题是判断高电平时间函数放在主函数,有干扰就舵机跳动的厉害,请指点下,能不能再完美了,如果写的真的很完美了,请发我一份源程序,先谢谢!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-29 13:13:21 | 显示全部楼层
这个代码错了,大家帮忙修改!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-4-29 16:23:00 | 显示全部楼层
没有人关注这个问题啊~?

出0入0汤圆

发表于 2014-6-28 14:54:27 | 显示全部楼层
superplaim 发表于 2014-3-27 10:22
上传的附件代码应该是SSC-32的原版程序 是用codevision编译的 我用这个软件总是编译通不过,能不能麻烦你 ...

原版是使用CodeVisionAVR C Compiler V1.24.6 Standard的工程,找了好久没有找到这个版本的cvavr,前段时间找到了一种方法可以编译该工程,见附件。
先按要求安装cvavr,再打开源文件,修改两个地方就可以了,修改的地方有截图。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-6-30 11:01:46 | 显示全部楼层
donglaile 发表于 2014-6-28 14:54
原版是使用CodeVisionAVR C Compiler V1.24.6 Standard的工程,找了好久没有找到这个版本的cvavr,前段时 ...

楼上很牛掰啊 佩服佩服

出0入0汤圆

发表于 2014-6-30 11:24:01 | 显示全部楼层
哪里挖的啊

出0入0汤圆

发表于 2015-10-17 10:36:42 | 显示全部楼层
楼主,32路控制系统是不是也可以用于控制继电器哈

出0入0汤圆

发表于 2015-11-17 12:23:45 | 显示全部楼层
先看了,MARK

出0入0汤圆

发表于 2016-7-19 11:44:33 | 显示全部楼层
好东西 不错  支持个

出0入0汤圆

发表于 2016-7-19 11:47:16 | 显示全部楼层
好东西 不错  支持

出0入0汤圆

发表于 2016-7-29 13:53:25 | 显示全部楼层
牛啊 群主  群主

出0入0汤圆

发表于 2016-8-23 08:27:02 | 显示全部楼层
路数有点多啊

出0入0汤圆

发表于 2017-6-30 23:06:13 | 显示全部楼层
一个个好厉害的样子,我过来学习。

出0入4汤圆

发表于 2020-3-23 14:07:33 | 显示全部楼层
学习大虾,积极向上

出200入2554汤圆

发表于 2020-3-23 15:22:39 | 显示全部楼层
superplaim 发表于 2014-3-26 17:23
这个系统用来控制8路舵机也就是只用一个74HC595的精度还是可以的,pwm也比较稳定
但是如果扩展的32路基本可 ...

我看了下 LZ 的代码,最大的问题在于:没用硬件 SPI 加载 595.

如果用上的话可以极大提升加载速度(fosc/2),并且可以实现加载同步运算
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-16 18:52

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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