VE7ZNU
- 26th August 2010, 04:58
The program below runs a DC motor with a turns counter attached. RB0 detects ext interrupt of the turns counter.
Buttons attached to RB6 and RB7 manually drive the motor up and down. The initialization sequence drives the motor down until it stalls which is detected by A/D and sets the cnt =0. When the motor is driven by either RB0 or RB6 the interrupt counts accurately in both the up and down direction.
However, when the motor is driven by the cnt<> bandcnt code the count is off by almost 50 %. For example, if I manually drive the motor "up" from zero and mark the distance travelled and move back to zero, then make bandcnt=100 the motor will drive and count to 100 but the distance travelled is only equal to 60 turns of distance. I'm at my wits end. I have tested this 100's of times. I checked the code an equal number of times. The interrupt is simple. The code is simple and the mechanics are simple. I hate to make the next statement !
I'm at a lose; it seems like its counting faster in the "auto" mode than the manual mode.
'16F877
Include "modedefs.bas" ' Include serial modes
'================================================= ===========================================
Define OSC 20
' Define LCD pins
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
'================================================= ===========================================
' Allocate variables
z var byte
cnt var word
dirflag var byte
freq var word
xband var word
Band var word
flag var byte
top var word
bot var word
zeroflag vAR BYTE
banddone var byte
bandcnt var word
'================================================= ===========================================
freqtrim con 42 'freq correction
cnt=0
bandcnt=0
'================================================= ===========================================
ADCON1 = 4 ' Set PortA 0, 1, 3 to analog inputs
'Interrupt on falling edge of RB0/INT pin
OPTION_REG=%10000000
On Interrupt Goto myint ' Define interrupt handler
INTCON = $90 ' Enable INTE interrupt
Low PORTE.2 ' LCD R/W line low (W)
Pause 100 ' Wait for LCD to start
lcdout $fe,1,"Initializing........"
low portc.1
low portc.2
pause 100
zeroflag=1 'go down to bottom of coil
while zeroflag=1
Dirflag=0 'down
high portc.1
low Portc.2 'go down
gosub getad
gosub getz
if z>50 then 'this on the edge of stall current
low portc.2
low portc.1
Dirflag=1 'go up
zeroflag=0 'stop
cnt=0
endif
wend
mainloop:
'====================================this code is for Motor Down
If portb.6 =0 Then 'this code works for key press
high Portc.1
Dirflag=0
else
low Portc.1
endif
'=====================================this code is for motor up
If portb.7 =0 Then 'this code works for key press
high Portc.2
Dirflag=1
else
low Portc.2
Endif
'================================================= ===========================================
gosub get_freq ' Calc freq
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout " " ' print blanks to clear
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout #cnt
Lcdout $fe, $C0+12 'set location to 17th position of 2nd line
Lcdout " "
Lcdout $fe, $C0+12 'set location to 17th position of 2nd line
Lcdout #bandcnt
Lcdout $fe, $80+15 'set location to 17th position of 2nd line
Lcdout " "
Lcdout $fe, $80+15 'set location to 17th position of 2nd line
Lcdout #Z
'================================================= ===========================================
if cnt=bandcnt then 'done
goto mainloop
endif
if cnt<bandcnt and="" freq="">0 then 'go up
Dirflag=1 'up
while cnt<>bandcnt
low portc.1
high portc.2
wend
endif
if cnt>bandcnt and freq >0 then
Dirflag=0 'down
while cnt<>bandcnt
high portc.1
low Portc.2 'go down
wend
endif
'================================================= ===========================================
Goto mainloop ' Do it forever
Disable ' No interrupts past this point
myint:
if dirflag=1 then
cnt=cnt+1
ENDIF
IF dirflag=0 then
cnt=cnt-1
endif
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout " " ' print blanks to clear
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout #cnt
INTCON.1 = 0 ' Clear interrupt flag
Resume 'mainloop ' Return to main program
Enable
'================================================= ===========================================
' Subroutine to read a/d convertor
getad:
Pauseus 50 ' Wait for channel to setup
ADCON0.2 = 1 ' Start conversion
Pauseus 50 ' Wait for conversion
Return
' Subroutine to get pot z value
getz:
ADCON0 = $59 ' Set A/D to Fosc/8, Channel 3, On
Gosub getad
z = ADRESH
Return
'================================================= ===========================================
get_freq: 'count frequency on portc.7
count portc.0,200,freq
if freq=0 then
return
endif
freq=(freq*10)/2
freq=freq+(freq/freqtrim)
' freq=3780
lookdown2 freq,<[1800,2001,3500,4001,7000,7351,10100,10201,14000,14 351,18068,18169,21000,21145,24890,24991,29701],xband
branchl xband, [get_freq,band160, get_freq, band80, get_freq,band40, get_freq, band30,get_freq, band20,get_freq, band17, get_freq, band15,get_freq, band12,get_freq, band10]
band160:
band=160
bandcnt= 20
goto loop
band80:
band=80
bandcnt=50
goto loop
band40:
band=40
bandcnt=108
goto loop
band30:
goto loop
band20:
goto loop
band17:
goto loop
band15:
goto loop
band12:
goto loop
band10:
loop:
return
</bandcnt>
Buttons attached to RB6 and RB7 manually drive the motor up and down. The initialization sequence drives the motor down until it stalls which is detected by A/D and sets the cnt =0. When the motor is driven by either RB0 or RB6 the interrupt counts accurately in both the up and down direction.
However, when the motor is driven by the cnt<> bandcnt code the count is off by almost 50 %. For example, if I manually drive the motor "up" from zero and mark the distance travelled and move back to zero, then make bandcnt=100 the motor will drive and count to 100 but the distance travelled is only equal to 60 turns of distance. I'm at my wits end. I have tested this 100's of times. I checked the code an equal number of times. The interrupt is simple. The code is simple and the mechanics are simple. I hate to make the next statement !
I'm at a lose; it seems like its counting faster in the "auto" mode than the manual mode.
'16F877
Include "modedefs.bas" ' Include serial modes
'================================================= ===========================================
Define OSC 20
' Define LCD pins
Define LCD_DREG PORTD
Define LCD_DBIT 4
Define LCD_RSREG PORTE
Define LCD_RSBIT 0
Define LCD_EREG PORTE
Define LCD_EBIT 1
'================================================= ===========================================
' Allocate variables
z var byte
cnt var word
dirflag var byte
freq var word
xband var word
Band var word
flag var byte
top var word
bot var word
zeroflag vAR BYTE
banddone var byte
bandcnt var word
'================================================= ===========================================
freqtrim con 42 'freq correction
cnt=0
bandcnt=0
'================================================= ===========================================
ADCON1 = 4 ' Set PortA 0, 1, 3 to analog inputs
'Interrupt on falling edge of RB0/INT pin
OPTION_REG=%10000000
On Interrupt Goto myint ' Define interrupt handler
INTCON = $90 ' Enable INTE interrupt
Low PORTE.2 ' LCD R/W line low (W)
Pause 100 ' Wait for LCD to start
lcdout $fe,1,"Initializing........"
low portc.1
low portc.2
pause 100
zeroflag=1 'go down to bottom of coil
while zeroflag=1
Dirflag=0 'down
high portc.1
low Portc.2 'go down
gosub getad
gosub getz
if z>50 then 'this on the edge of stall current
low portc.2
low portc.1
Dirflag=1 'go up
zeroflag=0 'stop
cnt=0
endif
wend
mainloop:
'====================================this code is for Motor Down
If portb.6 =0 Then 'this code works for key press
high Portc.1
Dirflag=0
else
low Portc.1
endif
'=====================================this code is for motor up
If portb.7 =0 Then 'this code works for key press
high Portc.2
Dirflag=1
else
low Portc.2
Endif
'================================================= ===========================================
gosub get_freq ' Calc freq
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout " " ' print blanks to clear
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout #cnt
Lcdout $fe, $C0+12 'set location to 17th position of 2nd line
Lcdout " "
Lcdout $fe, $C0+12 'set location to 17th position of 2nd line
Lcdout #bandcnt
Lcdout $fe, $80+15 'set location to 17th position of 2nd line
Lcdout " "
Lcdout $fe, $80+15 'set location to 17th position of 2nd line
Lcdout #Z
'================================================= ===========================================
if cnt=bandcnt then 'done
goto mainloop
endif
if cnt<bandcnt and="" freq="">0 then 'go up
Dirflag=1 'up
while cnt<>bandcnt
low portc.1
high portc.2
wend
endif
if cnt>bandcnt and freq >0 then
Dirflag=0 'down
while cnt<>bandcnt
high portc.1
low Portc.2 'go down
wend
endif
'================================================= ===========================================
Goto mainloop ' Do it forever
Disable ' No interrupts past this point
myint:
if dirflag=1 then
cnt=cnt+1
ENDIF
IF dirflag=0 then
cnt=cnt-1
endif
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout " " ' print blanks to clear
Lcdout $fe, $C0+5 'set location to 17th position of 2nd line
Lcdout #cnt
INTCON.1 = 0 ' Clear interrupt flag
Resume 'mainloop ' Return to main program
Enable
'================================================= ===========================================
' Subroutine to read a/d convertor
getad:
Pauseus 50 ' Wait for channel to setup
ADCON0.2 = 1 ' Start conversion
Pauseus 50 ' Wait for conversion
Return
' Subroutine to get pot z value
getz:
ADCON0 = $59 ' Set A/D to Fosc/8, Channel 3, On
Gosub getad
z = ADRESH
Return
'================================================= ===========================================
get_freq: 'count frequency on portc.7
count portc.0,200,freq
if freq=0 then
return
endif
freq=(freq*10)/2
freq=freq+(freq/freqtrim)
' freq=3780
lookdown2 freq,<[1800,2001,3500,4001,7000,7351,10100,10201,14000,14 351,18068,18169,21000,21145,24890,24991,29701],xband
branchl xband, [get_freq,band160, get_freq, band80, get_freq,band40, get_freq, band30,get_freq, band20,get_freq, band17, get_freq, band15,get_freq, band12,get_freq, band10]
band160:
band=160
bandcnt= 20
goto loop
band80:
band=80
bandcnt=50
goto loop
band40:
band=40
bandcnt=108
goto loop
band30:
goto loop
band20:
goto loop
band17:
goto loop
band15:
goto loop
band12:
goto loop
band10:
loop:
return
</bandcnt>