PDA

View Full Version : Semi-random INT count???



thasatelliteguy
- 23rd June 2014, 20:17
Last night, the azimuth on my dish was counting up 11541 to move the dish 180 deg. I changed NOTHING. I went to bed and came in this morning, and now it's only 3100. Now, in my code, I have it intentionally stepped down to only count every 10th pulse from the encoder, but I did not change it. I did this because on arduino, it was showing ~100,000 pulses @ 180 deg and the PIC I'm using doesn't support LONG.

It was doing this to me on the elevation randomly. Maybe it still is, it just isn't showing itself. The elevation should only be 3600+ counts full travel. That's what it was with an arduino 3 months ago when I started this project. Now it's 7200, but I tweaked that encoder's settings, so I can see that change. But sometimes, at random, it'll overflow a WORD 4 or 5 times @ full travel. That's a far cry from 3600 or 7200! And the kicker is, I do not think it's the encoder. When it would do this, I am watching it on a scope, and there would be zero change. Same PW and freq as it always has been.
PIC16F1829



'************************************************* ***************
'* Name : UNTITLED.BAS *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2014 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 6/7/2014 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************
INCLUDE "DT_INTS-14.bas"
INCLUDE "ReEnterPBP.bas"


DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_SPBRG 129 ' 9600 Baud @ 20MHz, 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
APFCON0.2 = 1
APFCON0.7 = 1
OPTION_REG.6 = 1


#CONFIG
__config _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF
#ENDCONFIG


DEFINE OSC 20

ANSELA = 0
ANSELB = 0
ANSELC = 0




DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTA
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTA
DEFINE LCD_EBIT 1
DEFINE LCD_BITS 4
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 1500
DEFINE LCD_DATAUS 44
LED var PORTC.7
high LED


ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT_INT, _doEncoder, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE INT_INT


stowlight var byte
stowlight = 1
TRISC.6 = 1
DOWN var PORTC.1
TRISC.1 = 0
DOWN = 0
EAST var PORTC.2
TRISC.2 = 0
EAST = 0
WEST var PORTC.5
TRISC.5 = 0
WEST = 0
UP var PORTC.0
TRISC.0 = 0
UP = 0
RX var PORTC.6
TRISC.6 = 1



a0 var byte
a1 var byte
e0 var byte
e1 var byte
i var byte
VerboseMode var byte
cereal var byte
Aencoder0Pos var word
Eencoder0Pos var word
HEL var byte
HAZ var byte
oldpos var word
newpos var word
distance var word
Eoldposition var word
Enewposition var word
stowed var byte
apple var byte
SatLocEl var word
SatLocEl = 6837
SatLocAz var word
SatLocAz = 52198
VerboseMode = 0


goto startup




doEncoder:
if UP = 1 then
' if e0 = 10 then
Eencoder0Pos = Eencoder0Pos + 1
' e0 = 0
lcdout $FE, $01, "EL= ", #Eencoder0Pos
lcdout $FE, $C0, "AZ= ", #Aencoder0Pos
' endif
' e0 = e0 + 1
endif
if down = 1 then
' if e1 = 10 then
Eencoder0Pos = Eencoder0Pos - 1
' e1 = 0
lcdout $FE, $01, "EL= ", #Eencoder0Pos
lcdout $FE, $C0, "AZ= ", #Aencoder0Pos
' endif
e1 = e1 + 1
endif
if EAST = 1 then
if a0 = 5 then
Aencoder0Pos = Aencoder0Pos - 1
A0 = 0
lcdout $FE, $01, "EL= ", #Eencoder0Pos
lcdout $FE, $C0, "AZ= ", #Aencoder0Pos
endif
a0 = a0 + 1
endif
if WEST = 1 then
if a1 = 5 then
Aencoder0Pos = Aencoder0Pos + 1
a1 = 0
lcdout $FE, $01, "EL= ", #Eencoder0Pos
lcdout $FE, $C0, "AZ= ", #Aencoder0Pos
endif
a1 = a1 + 1
endif
@ INT_RETURN


Startup:
gosub CLR
hserout ["Running Startup Procedures!", 13, 10]
hserout ["PLEASE WAIT....", 13, 10]
pause 3000
Eencoder0Pos = 0
Eoldposition = Eencoder0Pos
DOWN = 1
pause 1000
gosub allSTOP
Enewposition = Eencoder0Pos
IF Eoldposition = Enewposition THEN
stowed = 1
apple = 1
Eencoder0Pos = 0
Aencoder0Pos = 40000
gosub CLR
hserout ["Startup Sequence Good!", 13, 10]
hserout ["Continuing to Main Menu...", 13, 10]
pause 5000
goto MainMenu
ENDIF
IF Enewposition <> Eoldposition THEN
stowed = 0
apple = 1
UP = 1
pause 1000
gosub allSTOP
gosub CLR
hserout ["Startup Error!", 13, 10]
hserout ["Dish will need homing before move will be allowed!", 13, 10]
hserout ["Continuing to Main Menu...", 13, 10]
pause 5000
goto Mainmenu
ENDIF


MainMenu:
gosub CLR
HSEROUT ["******** MAIN MENU ********", 13, 10, 10]
HSEROUT [" 1. Start Homing Sequence", 13, 10]
HSEROUT [" 2. Manual JOG Mode", 13, 10]
HSEROUT [" 3. Auto-Acquire Satellite", 13, 10]
HSEROUT [" 4. Stow Dish for Travel", 13, 10, 10]
HSEROUT ["Enter Your Selection:",13,10]
SERIN RX, 2, cereal
if VerboseMode = 1 then HSEROUT [#cereal,13,10]
If cereal = "1" then goto HomeDish
If cereal = "2" then
if apple = 1 then goto JogMenu
if apple <> 1 then gosub ForceHome
endif
If cereal = "3" then
if apple = 1 then goto RoughAcquire
if apple <> 1 then gosub ForceHome
endif
If cereal = "4" then
if apple = 1 then goto StowMenu
if apple <> 1 then gosub ForceHome
endif
goto MainMenu


RoughAcquire:
if Eencoder0Pos < 7000 then
UP = 1
uploop1:
pause 100
if Eencoder0Pos < 7000 then goto uploop1
gosub allSTOP
endif
If Aencoder0Pos < SatLocAz then
WEST = 1
azloop1:
pause 100
if Aencoder0Pos < SatLocAz then goto azloop1
gosub allSTOP
elseif Aencoder0Pos > SatLocAz then
EAST = 1
azloop2:
pause 100
if Aencoder0Pos > SatLocAz then goto azloop2
gosub allSTOP
endif
If Eencoder0Pos > SatLocEl then
DOWN = 1
dnloop1:
pause 100
if Eencoder0Pos > SatLocEl then goto dnloop1
gosub allSTOP
endif
goto MainMenu

HomeDish:
gosub CLR
hserout ["******** HOME DISH ********", 13, 10, 10]
hserout [" 1. Start Homing Sequence", 13, 10, 10]
hserout [" 2 Abort Homing", 13, 10, 10]
hserout ["Enter Your Selection:"]
serin RX, 2, cereal
if cereal = "2" then goto MainMenu
homeloop:
IF cereal = "1" THEN
HAZ = 0
HEL = 0
gosub HomeEL
gosub HomeAZ
'Haz = 1
IF (HEL = 1) AND (HAZ = 1) THEN
gosub clr
hserout ["HOME PROCESS WAS SUCCESSFUL!", 13, 10]
apple = 1
goto MainMenu
ENDIF
IF (HEL = 0) OR (HAZ = 0 ) THEN
gosub clr
hserout ["DIS HOME PROCESS CAN SUCK MY DICK!", 13, 10]
goto MainMenu
ENDIF
ENDIF
pause(200)
if cereal <> "1" then goto HomeDish
goto homeloop
goto HomeDish


HomeAZ:
gosub clr
hserout ["HOMING AZIMUTH - PLEASE WAIT..", 13, 10]
PAUSE(500)
Aencoder0Pos = 0
oldpos = 0
WEST = 1
PAUSE(250)
IF Aencoder0Pos = 0 THEN
gosub allSTOP
EAST = 1
PAUSE(250)
gosub allSTOP
PAUSE(500)
Aencoder0Pos = 0
WEST = 1
PAUSE(500)
IF Aencoder0Pos = 0 THEN goto moveerror
ENDIF
pause 1000
loop4:
pause 250
oldpos = newpos
newpos = Aencoder0POS
if oldpos > newpos then
distance = oldpos - newpos
hserout ["oldpos = ", #oldpos, " newpos = ", #newpos, " --- Distance = ", #distance, 13, 10]
endif
if newpos > oldpos then
distance = newpos - oldpos
hserout ["newpos = ", #newpos, " oldpos = ", #oldpos, " --- Distance = ", #distance, 13, 10]
endif
if (oldpos = newpos) and (oldpos <> 0) then distance = 0
if (distance < 5) or (distance > 500) then
gosub allSTOP
Aencoder0Pos = 54000
newpos = Aencoder0POS

hserout ["HOMING AZIMUTH WAS SUCCESSFUL!", 13, 10]
HAZ = 1
endif
IF HAZ = 0 THEN goto loop4
EAST = 1
loop8:
pause 100
hserout ["Aencoder0Pos = ", #Aencoder0Pos, 13, 10]
if Aencoder0Pos > 50000 then GOTO LOOP8
GOSUB allSTOP
return



HomeEL:
gosub CLR
hserout ["HOMING ELEVATION - PLEASE WAIT..", 13, 10]
PAUSE(500)
Eencoder0Pos = 0
UP = 1
PAUSE(250)
IF Eencoder0Pos = 0 THEN
gosub allSTOP
DOWN = 1
PAUSE(250)
gosub allSTOP
PAUSE(500)
Eencoder0Pos = 0
UP = 1
PAUSE(500)
IF Eencoder0Pos = 0 THEN goto moveerror
ENDIF
pause 1000
loop1:
pause 250
oldpos = newpos
newpos = Eencoder0POS
if oldpos > newpos then distance = oldpos - newpos
if newpos > oldpos then distance = newpos - oldpos
if oldpos = newpos then distance = 0
if distance < 5 then
gosub allSTOP
Eencoder0Pos = 7220
newpos = Eencoder0POS
hserout ["HOMING ELEVATION WAS SUCCESSFUL!", 13, 10]
HEL = 1
endif
IF HEL = 0 THEN goto loop1
DOWN = 1
loop2:
pause 100
'hserout ["Eencoder0Pos = ", #Eencoder0Pos, 13, 10]
if Eencoder0Pos > 7000 then GOTO loop2
oldpos = 0
newpos = 0
GOSUB allSTOP
return


StowMenu:
gosub CLR
hserout ["******** STOW DISH ********", 13, 10, 10]
hserout [" 1. Start STOW Sequence", 13, 10, 10]
hserout [" 2 Abort STOW", 13, 10, 10]
hserout ["Enter Your Selection:"]
serin RX, 2, cereal
if cereal = "2" then goto MainMenu
if (cereal = "1") and (apple = 1) and (stowed <> 1) then goto StowDish
goto moveerror

StowDish:
gosub CLR
hserout ["***** PLEASE WAIT ******", 13, 10]
if Eencoder0Pos < 5500 then
UP = 1
loop3:
pause 250
if Eencoder0Pos < 5500 then goto loop3
gosub allSTOP
endif
If Aencoder0Pos > 40000 then
east = 1
loop5:
pause 250
if Aencoder0Pos > 40000 then goto loop5
gosub allSTOP
elseif Aencoder0Pos < 40000 then
WEST = 1
loop6:
pause 250
if Aencoder0Pos < 40000 then goto loop6
gosub allSTOP
endif
If stowlight = 1 then
down = 1
loop7:
pause 250
oldpos = newpos
newpos = Eencoder0POS
distance = oldpos - newpos
if (Eencoder0Pos > 0) and (distance <> 0) then goto loop7
gosub allSTOP
elseif stowlight <> 1 then
gosub moveerror
gosub forcehome
apple = 0
endif
goto mainmenu




JogMenu:
gosub CLR
pause 250
HSEROUT ["***** JOG MENU *****", 13, 10, 10]
HSEROUT ["U - UP", 13, 10]
HSEROUT ["D - DOWN", 13, 10]
HSEROUT ["E - EAST", 13, 10]
HSEROUT ["W - WEST", 13, 10]
HSEROUT ["S - ALL STOP", 13, 10]
HSEROUT ["X - MAIN MENU", 13, 10, 10]
SERIN RX, 2, cereal
IF cereal = "A" then Eencoder0Pos = 0
if cereal = "B" then Aencoder0Pos = 0
if cereal = "U" Then
gosub allSTOP
UP = 1
endif
if cereal = "D" then
gosub allSTOP
DOWN = 1
endif
if cereal = "E" then
gosub allSTOP
EAST = 1
endif
if cereal = "W" then
gosub allSTOP
WEST = 1
endif
if cereal = "S" then gosub allSTOP
if cereal = "X" then
gosub allSTOP
goto MainMenu
endif
goto JOGMenu


allSTOP:
EAST = 0
UP = 0
DOWN = 0
WEST = 0
if VerboseMode = 1 then GOSUB POS
return


CLR:
if VerboseMode = 0 then
For i = 0 to 30
HSEROUT [10]
next i
endif
return


abort:
gosub allSTOP
gosub clr
HSEROUT ["USER STOP! -- MOVE ABORTED!", 13, 10]
PAUSE(5000)
goto MainMenu


ForceHome:
gosub CLR
hserout ["SYSTEM ERROR!", 13, 10]
hserout ["SYSTEM'S HOMING COORDINATES NOT SET!", 13, 10]
hserout ["SYSTEM CANNOT BE MOVED UNTIL HOMING IS PERFORMED!", 13, 10]
pause 7000
return


moveerror:
gosub allSTOP
gosub clr
HSEROUT ["SYSTEM ERROR! -- MOVE ABORTED!", 13, 10]
PAUSE(5000)
goto MainMenu


POS:
lcdout $FE, $01, "EL= ", #Eencoder0Pos
lcdout $FE, $C0, "AZ= ", #Aencoder0Pos
return

richard
- 24th June 2014, 00:24
most satellite positioner encoders are a reed switch operated by a multipole disc magnet , you have two encoders sharing one interrupt . what happens if one positioner stops with the reed closed ,wont that lead to lost impulses for the other encoder ?
as has been discussed before when you have a multi-byte variable that's altered in a interrupt routine its true value is indeterminate while the isr is active .
the correct procedure to access the var is to
disable isr
examine var (copy compare or whatever)
enable isr

thasatelliteguy
- 24th June 2014, 04:03
Ok... These are quadrature encoders. Each one has two signal wires producing a dual square wave at 50% offset. Which one is first is dependent on which way the encoder is rotating. I am only using one signal wire from each encoder. There will be three. Right now there are only two... Elevation and Azimuth. I have the chip and BT module inside on my breadboard temporarily. The encoders DID join outside onto one wire, but due to growing concerns as to what happens when the unused encoder is in an "other than floating" position, I separated them all the way to the breadboard. They still go into the PIC on just one leg, but are physically separated by a SPDT relay now. I will re-code and put them to their own leg in the end, but at the moment, the relay seems sufficient to separate them so as to eliminate that as the cause of this problem.

It's really baffling to me how I can be looking at the exact same pattern on the scope, and yet the PIC is reading an ENTIRELY different thing. To go from ~7500 pulses from end to end, all the way to 300,000 to 400,000 pulses would cause a MAJOR difference that I just couldn't mistake on the scope, and it's just not the case... it looks like no change at all, but the number count is insanely different.

thasatelliteguy
- 24th June 2014, 04:08
as has been discussed before when you have a multi-byte variable that's altered in a interrupt routine its true value is indeterminate while the isr is active .
the correct procedure to access the var is to
disable isr
examine var (copy compare or whatever)
enable isr
I'm unfamiliar with this black magic you speak of... tell me more...

richard
- 24th June 2014, 04:40
lets have a word var count and a word var pos
count is the one used in your isr , pos will be the " current " position outside the isr

we have a sub to get pos
getpos:

@ INT_DISABLE INT_INT
POS= COUNT
@ INT_ENABLE INT_INT
RETURN

now whenever you wish to use pos just call getpos first to "refresh" its value


some more thoughts
1 are your encoders mechanically switched ( ie contact bounce could be an issue)
2 isr's should be kept as short a possible , lcd routines in isr may cause unexpected issues
3 have you tesed with only one encoder is connected ?
4 have you a schematic of your setup and a link to the positioner encoder data sheet

HenrikOlsson
- 24th June 2014, 06:33
Hi,
A schematic would be nice but I think we've covered this before. Two encoder signals on the same pin, fighting each other, is most likely not a good solution. You mention a relay, switching between the two, and that should be fine. Just make sure the signal at the PIC input is well defined (pulled up/down) and not floating at any point.

And Richard is spot on. If the frequeuncy of the encoder signal is anything above "a couple of Hz" you definitely do not want the LCDOUT statements within the ISR. Those two statments takes at least 5ms to exectute, then there's the rest of the ISR itself (which isn't much but still...) and the system variable save/restore. But let's say 5ms (and that's probably on the LOW side) then your input frequency can't be higher than 200Hz.

If you have a two channel scope you can test this.
1) Scope the input signal to the PIC with channel 1 on the scope.
2) Set a pin high at the beginning of the ISR. Set it LOW at the end of the ISR.
3) Scope this output of this pin with channel 2 on the scope.

The time between the rising edge on Ch1 and the rising edge on Ch2 is the interrupt latency, the time it takes to save the system vars and "get to" the actual ISR code.
The pulse width on Ch2 is the execution time of the ISR itself.
Then there's the time it takes to restore the system vars and "get out" of the ISR. This is pretty much equal to the measured latency.

Add the numbers together, ie 2*latency + ISR execution time and see what you get. Make sure you do this with a LOW(ish) input frequency to ENSURE you're not "overrunning" yourself. Then remove the LCDOUT statements from the ISR and measure again.

/Henrik.

thasatelliteguy
- 24th June 2014, 16:13
OK, bummer! My debugging was buggy.... Those are only there for the moment to see where I am. My fastest encoder, according to the scope is running about 50-60 hz. So that may be the problem. I'm headed out the door, but I'll try to deal with it when I get back this afternoon and see how it goes. I am still skeptical though, since it was the slow encoder that first showed the problem, and I still cant see how it would go from 3500 counts in say 120 seconds, all the way up to multiple WORD stackoverflows in the same time from this issue, but maybe I just still dont see the big picture....