superplaim 发表于 2014-3-26 17:04:56

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

本帖最后由 superplaim 于 2014-3-26 17:51 编辑

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

superplaim 发表于 2014-3-26 17:05:48

本帖最后由 superplaim 于 2014-3-26 17:09 编辑

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

superplaim 发表于 2014-3-26 17:23:31

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

superplaim 发表于 2014-3-26 17:24:26

本帖最后由 superplaim 于 2014-3-27 10:20 编辑

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

superplaim 发表于 2014-3-26 17:33:47

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

flame123 发表于 2014-3-26 18:00:20

楼主厉害,给顶上去,让论坛的高手出来给大家出出福利{:lol:}

windingway 发表于 2014-3-26 18:06:53

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

donglaile 发表于 2014-3-27 00:58:23

之前下的资料,有程序和原理图,感谢作者!搬运过来
32V103

superplaim 发表于 2014-3-27 01:13:54

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

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

superplaim 发表于 2014-3-27 01:15:45

donglaile 发表于 2014-3-27 00:58
之前下的资料,有程序和原理图,感谢作者!搬运过来

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

superplaim 发表于 2014-3-27 01:20:24

为什么我上传的附件全部挂掉了

zyw19987 发表于 2014-3-27 06:28:12

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

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

zyw19987 发表于 2014-3-27 06:34:05

http://www.amobbs.com/forum.php?mod=viewthread&tid=985613&highlight=595%2B灰度
27楼
理解可以看我在那里的回复234楼

superplaim 发表于 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产生周期

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

superplaim 发表于 2014-3-27 10:22:22

donglaile 发表于 2014-3-27 00:58
之前下的资料,有程序和原理图,感谢作者!搬运过来

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

irobotto 发表于 2014-3-27 13:27:33

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

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

superplaim 发表于 2014-3-27 14:15:05

irobotto 发表于 2014-3-27 13:27
其實未必不可能的,但必須要用匯編,用 c 只能到 5us 級別。

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

irobotto 发表于 2014-3-27 15:52:35

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

irobotto 发表于 2014-3-28 13:37:06

superplaim 发表于 2014-3-27 14:15
原版代码使用gcc和codeversion编译好像嵌入了部分汇编语句

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

superplaim 发表于 2014-3-28 17:20:36

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

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

irobotto 发表于 2014-3-28 17:47:02

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

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

cdl35 发表于 2014-3-28 23:28:02

labview写了串口上位机控制软件,给参考一下

cdl35 发表于 2014-3-28 23:28:37

邮箱:cdl35@sina.com

superplaim 发表于 2014-3-30 12:57:57

irobotto 发表于 2014-3-28 17:47
在做好 sorting 後就可以預先計算好 serial_temp 和 tcnt1 的數值了,用陣列貯存好就可以了。在中斷內只 ...

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

superplaim 发表于 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;//存放各个延时值之间的时间差
//第1组舵机数据
unsigned char Length_Temp;//从小到大存放各路高电平延时值
unsigned char Length={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={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;//临时存放Serial_Num[

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


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*20value的单位是10us
    TCNT1H=(0xffff-Length_Temp*20)/256;//经过排序后,vlaue是最小的数
    TCNT1L=(0xffff-Length_Temp*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*20)/256; //给定时器3赋初值
    TCNT1L=(0xffff-Length_Temp*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=0,Dispersion为value-value
            if(Dispersion==0)
            {
                m=m+1;
                goto spot0;
            }
            else
            {
                TCNT1H=(0xffff-Dispersion+40)/256;//+40为补偿值
                TCNT1L=(0xffff-Dispersion+40)%256;
            }
            //当m=7的时候,dispersion为所有管脚置低后低电平维持的时间
            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被从小到大排序
    {
      for(i=0;i<31-j;i++)
      {
            if(Length_Temp>Length_Temp)
            {
                k=Length_Temp;
                Length_Temp=Length_Temp;
                Length_Temp=k;
                t=Serial_Temp;
                Serial_Temp=Serial_Temp;
                Serial_Temp=t;//相应要置低的管脚也排序
            }
      }
    }
    for(j=0;j<31;j++)//相邻的数之间做差值,总共得到差值7个
    {
      //if(Length_Temp==Length_Temp)
      //Dispersion=6;
      //else
      Dispersion=(Length_Temp-Length_Temp)*20;
    }
    //最后一个值是低电平延时,65536-40000是20ms的定时初值
    Dispersion=40000-Length_Temp*20;
    for(i=0;i<32;i++)
    {
      if(i>0)
      Serial_Temp=Serial_Temp&Serial_Temp;
    }
}

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

irobotto 发表于 2014-3-30 15:06:21

superplaim 发表于 2014-3-30 13:51
#include
#include
#include"AVR_SPI.h"


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

irobotto 发表于 2014-3-30 17:53:22

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

superplaim 发表于 2014-4-28 08:42:06

irobotto 发表于 2014-3-30 17:53
忘了你提到 "另外周期也不准确了,周期倒是比较修正" 的問題, 在程序裡計時是用
      TCNT1H=(0xffff-Disp ...

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

hnege555 发表于 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,现在没有解决的问题是判断高电平时间函数放在主函数,有干扰就舵机跳动的厉害,请指点下,能不能再完美了,如果写的真的很完美了,请发我一份源程序,先谢谢!

hnege555 发表于 2014-4-29 13:13:21

这个代码错了,大家帮忙修改!

hnege555 发表于 2014-4-29 16:23:00

没有人关注这个问题啊~?{:sweat:}

donglaile 发表于 2014-6-28 14:54:27

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

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

superplaim 发表于 2014-6-30 11:01:46

donglaile 发表于 2014-6-28 14:54
原版是使用CodeVisionAVR C Compiler V1.24.6 Standard的工程,找了好久没有找到这个版本的cvavr,前段时 ...

楼上很牛掰啊 佩服佩服

1290519146 发表于 2014-6-30 11:24:01

哪里挖的啊

1178951695 发表于 2015-10-17 10:36:42

楼主,32路控制系统是不是也可以用于控制继电器哈

qzwlj 发表于 2015-11-17 12:23:45

先看了,MARK

guofeng 发表于 2016-7-19 11:44:33

好东西 不错支持个

guofeng 发表于 2016-7-19 11:47:16

好东西 不错支持

jacky82512 发表于 2016-7-29 13:53:25

牛啊 群主群主

zhangfeng0115 发表于 2016-8-23 08:27:02

路数有点多啊

nn5499 发表于 2017-6-30 23:06:13

一个个好厉害的样子,我过来学习。

kz805584774 发表于 2020-3-23 14:07:33

学习大虾,积极向上

t3486784401 发表于 2020-3-23 15:22:39

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

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

如果用上的话可以极大提升加载速度(fosc/2),并且可以实现加载同步运算
页: [1]
查看完整版本: 开源Atmega8+74hc595方案的32路舵机控制板(慎入:软件误差太...