5iMX宗旨:分享遥控模型兴趣爱好

5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
查看: 2250|回复: 27
打印 上一主题 下一主题

菜鸟眼中的天9PCM,关于解码速度

[复制链接]
跳转到指定楼层
楼主
发表于 2009-3-29 01:59 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
我是菜鸟,刚玩航模,天九我看过,解码就是一片mega8,确实很烂。
PCM编解码并不是什么困难的,关键在于一个通讯协议。
首先编码一般就采用8位二进制的编码,一般一个通道占用一到两个字节,然后加上贞头贞位,用RS232的数据流就能搞定,发射机就是把这个数据流发出去。
其次就是解码,首先解码只需要把数据帧里面对应的通道值提取出来就可以了,然后在对应通道中产生相应脉宽的PWM波。一般PWM波的周期是20毫秒,但是如果是RS232,可以设置波特率,一般38400的波特率,20毫秒内足可以让10多个舵机响应一次。
最后就是解码后,生成PWM波的方式,天9的接收只用了一片mega8,mega8有硬件PWM,但是只能输出2路,如果能用硬件PWM,编码肯定快。但是天9用的IO口模拟PWM波,速度肯定慢。最好的方式是解码芯片+PPM芯片。

欢迎继续阅读楼主其他信息

28
发表于 2009-3-31 21:21 | 只看该作者
多通道舵机信号发生,用delay和用定时器都面临类似的问题,吹毛求疵的讲,都不可能做的很完美的。。。但是抖动如果在容差范围内,就无所谓了。。。

不要轻易说一个东西垃圾:em15:
27
发表于 2009-3-31 19:15 | 只看该作者
我用M8做过一个6路舵机控制的程序,利用一个16位定时器,采用时间分片算法,可以实现,6路同时独立控制,效果很好,从未出现过抖舵,我开发的5自由度机器手就是用的这种算法
26
 楼主| 发表于 2009-3-31 17:29 | 只看该作者

回复md35

我以前做的程序,控制8路舵机。当时的情况是:8路PWM设置的脉宽参数相同,但是输出脉宽有差异,而且脉宽与控制参数不成线性变化,因为单片机判断通道要分支跳转。
20毫秒的周期,只有1.5~2.5毫秒的可调范围。
不过现在跟了这个论坛的一个老鸟,看了他抓的PPM波形,我来了一个灵感。
舵机的控制波形可以看作8个2.5毫秒周期的PWM波组合在一起。
对于通道选择,采用switch case语句,使单片机判断每个通道的分支跳转的时间相等,都在几个周期。
采用定时器中断,不用delay_us,可以在mega8上挂一个加速度传感器。真正的PWM控制值=遥控器参数+加速度传感器参数。
25
发表于 2009-3-31 14:02 | 只看该作者
菜鸟是谁你要搞清楚!对于技术贴我绝对支持,对于LS这种口出狂言的新兵蛋子,不要在这里撒野!
24
发表于 2009-3-31 11:48 | 只看该作者
为啥你们这些菜鸟说的我都看不懂呢:em17:
23
发表于 2009-3-31 00:32 | 只看该作者
原帖由 md35 于 2009-3-31 00:29 发表
硬件PWM当然好,但采用定时中断的时候,有以下时延:4个时钟的中断进入,几个通道判断时延,合计差不多20个时钟周期,采用10M晶体,最大误差有2US,不到半程的200分之一,完全能接受!不抖舵就可以了。。。

完全同意:em00:。一般的国产舵机(例如Esky 8g),跟不感觉不到1~2uS的变化的。
22
发表于 2009-3-31 00:29 | 只看该作者
硬件PWM当然好,但采用定时中断的时候,有以下时延:4个时钟的中断进入,几个通道判断时延,合计差不多20个时钟周期,采用10M晶体,最大误差有2US,不到半程的200分之一,完全能接受!不抖舵就可以了。。。
21
发表于 2009-3-30 23:48 | 只看该作者
关于delay的应用,楼主可以参考这个贴子:
http://www.ouravr.com/bbs/bbs_co ... caolong&bbs_id=9999
用变量作为delay.h中定义的delya函数的输入参数,是不稳定的。

[ 本帖最后由 greenbay 于 2009-3-30 23:49 编辑 ]
20
发表于 2009-3-30 23:46 | 只看该作者
也许吧,用ICC AVR以及GCC AVR 自带的delay_us()是不支持变量的参数输入的,这一点我用示波器验证过。但是用自写的delay_us()函数作为输出,是不会有任何问题的。
19
发表于 2009-3-30 23:41 | 只看该作者
只要你理解了就可以。

lz说的用delay_us做输出会抖舵从理论上和实践上都是正确的
18
发表于 2009-3-30 23:32 | 只看该作者
关于jitter,这里有一个权威的文档,您也可以去看一下。
ftp://ftp.t11.org/t11/member/fc/jitter_meth/99-151v2.pdf
17
发表于 2009-3-30 23:10 | 只看该作者
呵呵
spektrum有个技术,servo sync你可以去看一下
16
发表于 2009-3-30 22:57 | 只看该作者
多个通道输出时,依次输出,为何不稳定?用delay_us()输出,把所有中断关闭,很好用的。
jitter?您对jitter有研究?
15
发表于 2009-3-30 22:48 | 只看该作者
他是说多个通道同时输出时会产生不稳定, jitter
14
发表于 2009-3-30 21:37 | 只看该作者
原帖由 罗菜鸟 于 2009-3-29 23:43 发表

mega8可以模拟PPM的波形,delay_us这样的函数控制舵机,精度并不高,我第一个PPM 4通配了2个舵机,我试过用mega8去控制舵机,如果用delay_us会造成抖舵,但是用定时器+比较器则不会。我用示波器测试发现用定时器+比 ...

楼主,我用GCC,_delay_us()是不能使用变量作为输入参数的。因此我自己定义了一个delay_us(),如下:
void  delay_us(uint16_t dd)    //Only for 8MHz Cristal
             {while(dd)
               {dd--;
               asm("nop");
               asm("nop");
              }
           }
输出的脉冲是相当的稳定的。用delay的方式输出脉宽,简单实用,为何不用?附上示波器实测效果,您看delay做的稳定么?

Resolution.png (19.26 KB, 下载次数: 17)

Resolution.png
13
发表于 2009-3-30 12:06 | 只看该作者

看来楼主还得学习、学习。

12
 楼主| 发表于 2009-3-29 23:43 | 只看该作者
原帖由 greenbay 于 2009-3-29 18:54 发表
呵呵,楼主可能有所不知。MEGA8做解码已经奢侈了。用一个delay_us()就可以完成每个通道的脉宽输出了。何需专门去找一个支持9路PWM输出的不烂的单片机?

mega8可以模拟PPM的波形,delay_us这样的函数控制舵机,精度并不高,我第一个PPM 4通配了2个舵机,我试过用mega8去控制舵机,如果用delay_us会造成抖舵,但是用定时器+比较器则不会。我用示波器测试发现用定时器+比较器的波形很稳定,delay_us波形有抖动。
mega8在解码时,最后少用分支操作,否则会造成不同的通道输出的波形周期差异悬殊。
11
 楼主| 发表于 2009-3-29 23:35 | 只看该作者

反推的mega8解码的程序

//ICC-AVR application builder : 2009-3-29 23:17:41
// Target : M48
// Crystal: 8.0000Mhz

#include <iom48v.h>
#include <macros.h>

unsigned char RxPCM[8];

void port_init(void)
{
PORTB = 0x00;
DDRB  = 0x00;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0x00;
}

//TIMER1 initialize - prescale:8
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 2.5mSec
// actual value:  2.500mSec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xF6; //setup
TCNT1L = 0x3C;
OCR1AH = 0x09;
OCR1AL = 0xC4;
OCR1BH = 0x09;
OCR1BL = 0xC4;
ICR1H  = 0x09;
ICR1L  = 0xC4;
TCCR1A = 0x00;
TCCR1B = 0x02; //start Timer
}

#pragma interrupt_handler timer1_compa_isr:12
void timer1_compa_isr(void)
{
PORTB = 0;
//compare occured TCNT1=OCR1A
}

#pragma interrupt_handler timer1_ovf_isr:14
void timer1_ovf_isr(void)
{
static unsigned char channel;
OCR1A = RxPCM[channel];     //set end time
//TIMER1 has overflowed
TCNT1H = 0xF6; //reload counter high value
TCNT1L = 0x3C; //reload counter low value
switch(channel)
{
  case 0:PORTB |= 0x01;
  case 1:PORTB |= 0x02;
  case 2:PORTB |= 0x04;
  case 3:PORTB |= 0x08;
  case 4:PORTB |= 0x10;
  case 5:PORTB |= 0x20;
  case 6:PORTB |= 0x40;
  case 7:PORTB |= 0x80;
}
channel++;
if(channel==8)
channel=0;

}

//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer1_init();

MCUCR = 0x00;
EICRA = 0x00; //extended ext ints
EIMSK = 0x00;

TIMSK0 = 0x00; //timer 0 interrupt sources
TIMSK1 = 0x07; //timer 1 interrupt sources
TIMSK2 = 0x00; //timer 2 interrupt sources

PCMSK0 = 0x00; //pin change mask 0
PCMSK1 = 0x00; //pin change mask 1
PCMSK2 = 0x00; //pin change mask 2
PCICR = 0x00; //pin change enable
PRR = 0x00; //power controller
SEI(); //re-enable interrupts
//all peripherals are now initialized
}

//
void main(void)
{
init_devices();
//insert your functional code here...
}
10
发表于 2009-3-29 21:15 | 只看该作者
又来了!!!!!!!!!!!!!!:em17:
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

关闭

【站内推荐】上一条 /1 下一条

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