bascom ATMEGA8 PPM解码后舵机总是微弱抖动
大家好!这个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 ofchannel 1 (roll)
Failsafe_value(2) = 1600 'Set failsafe value ofchannel 2 (pitch)
Failsafe_value(3) = 1050 'Set failsafe value ofchannel 3 (yaw)
Failsafe_value(4) = 1600 'Set failsafe value ofchannel 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 程序用了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
incr18 '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 类,可提高效率。 嗯,顶一下,学习ing 看不懂,但还是要谢谢 看到汇编直接晕菜。前几天我的车也在弄舵机,不抖,但鸣叫。
页:
[1]