搜索
bottom↓
回复: 4

bascom ATMEGA8 PPM解码后舵机总是微弱抖动

[复制链接]

出0入0汤圆

发表于 2011-7-18 00:07:42 | 显示全部楼层 |阅读模式
大家好!这个PPM解码程序是网上下的,然后经过我的修改直接输出PWM信号驱动舵机。
但是脉宽信号总是会来回跳跃,不知道哪里错了请高手指点迷津。
代码如下:
                                                            '******************************************************
'======================================================
'System settings
'======================================================
'Definition for Mega 8
$regfile "m8def.dat"


'System frequency (8Mhz)
$crystal = 16000000
Config Lcd = 16 * 2
'Config Lcd = 20 * 4
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portb.1 , Db6 = Portb.2 , Db7 = Portb.3 , E = Portb.4 , Rs = Portb.5
Config Lcdmode = Port
Config Servos = 1 , Servo1 = Portc.3 , Reload = 10
'Config Timer0 = Timer , Prescale = 1
Config Portc.3 = Output
'======================================================
'Configurations
'======================================================

'I/O-Ports
'Config Portc = Output
Config Portd.2 = Input

'Size of display
                                       'it is 4x27 really, but the compiler doesn't understand

'Interrup 0
Config Int0 = Falling                                       'timing of pulses on negative flank

'Configuration of timer 1 (16 bit)
Config Timer1 = Timer , Prescale = 8

'======================================================
'Declarations
'======================================================

Dim ___lcde As Byte                                         'for switching between upper and lower LCD half
Dim N_sync As Byte
Dim Rc_value As Word
Dim Channel(7) As Word                                      '9 channels plus the synchonisation pulse
Dim N_ch As Word
Dim Ch_time(6) As Word
Dim Failsafe_value(6) As Word                               'These will be used when no signal is available
Dim I As Integer                                            'Running parameter for loops
Dim Failsafemode As Bit
Dim Signal_up_flag As Bit
Dim Signal_valid_flag As Bit
Dim X As Integer , X1 As String * 3 , Xstr As String * 10
Dim A As Integer , B As Integer , Ax As Integer , Bx As Integer
Dim Ml As Integer , Mr As Integer , Mm As Integer , X2 As Integer       '

'======================================================
'Initialisations
'======================================================

'Interrupt-Service-Routines
On Timer1 Signal_down                                       'overflow of timer occurs when the signal is down
On Int0 Read_signal                                         'On int0 timing of the signal pulses

'Timer-release
Enable Timer1

'Release of interrupts
Enable Int0
Enable Interrupts

'Initialise ports
'Portc = &B00000000                                          'Note: my hardware has non-inverted LED ports: 1 = on, 0 = off

'Initialise variables
Signal_up_flag = 1                                          'Signal available
Signal_valid_flag = 0                                       'Signal not valid
N_ch = 1
N_sync = 0                                                  'Start at channel 1
                                                            'No sybcronisation pulse seen yet

'Failsafe settings
Failsafemode = 0                                            '0 for "keep old signals", 1 for the failsafe values below
Failsafe_value(1) = 1600                                    'Set failsafe value of  channel 1 (roll)
Failsafe_value(2) = 1600                                    'Set failsafe value of  channel 2 (pitch)
Failsafe_value(3) = 1050                                    'Set failsafe value of  channel 3 (yaw)
Failsafe_value(4) = 1600                                    'Set failsafe value of  channel 4 (power)
Failsafe_value(5) = 1600
Failsafe_value(6) = 1600


'Initialise timer channel values
For I = 1 To 6
   Ch_time(i) = Failsafe_value(i)
Next

'Calibration of the internal oscillator.
'Write here the hex value of calibration byte 3 from the locks and fuses tab
Osccal = &HAF                                               'Loading the calibration byte in the OSCCAL register


'======================================================
'Writing LCD headers
'======================================================

Cls                                                         'Clear lines

Cursor Off

'======================================================
'Main program
'======================================================
A = 2
B = -2
Ml = 60
Mr = 70
Do

   X = Ch_time(1)
'  X = X - 63
  '   X1 = X1 + X
   Xstr = Str(x)
   X1 = Left(xstr , 3)
'  Next I
'  X1 = X1 / 10
   X = Val(x1)
   X = X - 175
     X2 = X - Mm



If X < Ml Then
    Ml = X
Elseif X > Mr Then
    Mr = X
End If

  Mm = Ml + Mr
  Mm = Mm / 2

'Calculate timing values in micro sec, only if the signal is up (simple fail safe implementation)
'Otherwise leave old values or use faisafe values
'The ch_time() array would be used for further processing
'The channel() array is only used for measurement and may contain invalid data
   If Signal_valid_flag = 1 Then
      For I = 1 To 6
         Ch_time(i) = Channel(i)
      Next
   Else
      If Failsafemode = 1 Then
         For I = 1 To 6
            Ch_time(i) = Failsafe_value(i)
         Next
         End If
       End If
    'Waitms 100

'Writing timing values to LCD display
  Cls
   Locate 1 , 1
   Lcd X ; " c1"
   Locate 1 , 9
   Lcd Mm ; " mm"
   Locate 2 , 1
   Lcd Ml ; " ml"
    Locate 2 , 9
   Lcd Mr ; " mr"
     If X2 > A Or X2 < B Then

   Servo(1) = Mm + X2
  End If

   Portc.0 = Signal_valid_flag                              'Showing the signal valid flag on port C0
   Portc.1 = Signal_up_flag                                 'Showing the signal up flag on port C1

'waitstate to get readable LCD values
  ' For I = 1 To 10

Loop

End

'******************************************************
'Interrupt Service Routines
'******************************************************
Read_signal:
   Rc_value = Timer1                                        'First thing: store the timer value in an intermediate variable.
   Timer1 = 0                                               'Then reset the timer

   If Rc_value > 6000 Then                                  'If the puls is to long it is the synchronisation pulse,
      N_ch = 6                                              'so set channel number to number of synchonisation pulse
      If N_sync < 2 Then Incr N_sync                        'The sync pulse counter is increased until it is 2
      If N_sync = 2 Then Signal_valid_flag = 1              'If it is the second consequitive sync puls, then the signal is declared valid
   End If
   Channel(n_ch) = Rc_value                                 'Load the measured timer value into the array of measurement data
   Incr N_ch                                                'next channel
   If N_ch = 7 Then N_ch = 1                                'Limit the number of channels to 10
   Signal_up_flag = 1                                       'set the signal up flag
Return


Signal_down:                                                'if no signal is detected for 65 ms
   Signal_up_flag = 0                                       'reset signal_up_flag
   Signal_valid_flag = 0                                    'reset signal valid flag
   N_sync = 0                                               'reset number of syncpulses passed
Return

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

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2011-9-15 23:13:52 | 显示全部楼层
程序用了int0中断,但中断处理过程不够简练,里面用了很影响速度的WORD型变量,还有那么多条件语句,速度跟不上,有效脉宽(可变部分)本来就只有1000us,中断如果用了50us,输出自然受干扰比较厉害。
    据我的经验,最好还是调用BASCOM里的 pulsein 功能,即用轮询方式测量脉宽,当然轮询方式解PPM码的缺点是,当所有脉宽都测完后,距离下一个信号周期已经比较近了,可能用pulseout功能向舵机输出信号的时候比较局促,必须采用同时向4-5个舵机同时开始发高电平,然后各自在正确的时间降为低电平,当时我用的是很可怜的TINY13,内部RC主频9.6M,解出4个通道,稳稳的不会抖。
    如果一定要用中断,最好在中断里全部使用汇编,可参考以下我在电调里使用的方式,但要注意,程序里使用的是TCNT0,最高约60级精度,一般情况下足够用了:

config timer0=timer , prescale = 256

isr_int0:
  'For mega8

in r2, sreg          '保存 SREG,在我的程序里其它地方没使用r2及r18,故不用PUSH,POP,节省了若干时钟周期
in r18,mcucr                                                'get int0 state
in r0,tcnt0                                                 'get tcnt0
inc  r18                                                    'goggle r16.0
andi r18,1                                                  'erash r16.1-7
sts {newrcin},r18                                           'newrcin 为一 BYTE 值,1或0,表明是否收到新的脉冲信号
mul r0,r18                                                  '硬件乘法器
sts {pwmctlppm} ,r0                                         'PWMCTLPPM 为有效脉冲长度值,BYTE 类
ori r18,2
!out mcucr,r18                                              '改变 MCUCR.ISC00 值,即改变下次脉冲触发条件
clr r18                                                     
!out tcnt0,r18                                              'tcnt0 =0
wdr                                                         '喂狗,也可以不用
!out sreg , r2                                              '恢复 SREG

return

    另外,在BASCOM里,用 bit 类值运算,速度很慢,建议全部改为 BYTE 类,可提高效率。

出0入0汤圆

发表于 2011-10-1 17:04:48 | 显示全部楼层
嗯,顶一下,学习ing

出0入0汤圆

发表于 2015-10-9 20:22:41 | 显示全部楼层
看不懂,但还是要谢谢

出0入0汤圆

发表于 2015-11-2 15:02:31 来自手机 | 显示全部楼层
看到汇编直接晕菜。前几天我的车也在弄舵机,不抖,但鸣叫。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-23 08:27

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

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