PDA

View Full Version : Problem with 12F629, servo and EEPROM



Atom058
- 28th February 2008, 21:10
Hello - I am trying to get this VERY simple program to work, but after hours of banging my head on it, I can't see what I am doing wrong. I'm sure that I will be embarrased when someone points out what I need to do...

What I want to do is use a 12F629 to drive a servo via a pot. There are 2 pushbuttons to set the minimum and maximum travel limits for the servo and a switch to enable the user to enter the min and max settings. I can drive the servo with the pot without any problem. The problem arises when I try to set the min and max limits. This process consists of switching the Limit Set Enable slide switch to ON, which pulls GPIO.1 high. This tells the PIC to start monitoring the Min and Max pushbuttons. When the user presses one of the buttons, the PIC takes the current position of the servo and stores it in the appropriate variable and then writes the value to internal EEPROM. After setting the Min and Max values and the Limit Set Enable switch is switched off, the servo movement should be limited to between the min and max limits that were just set. Seems simple enough... What is happening when I set a min or max limit is that the servo will not move from that position. For example, I have the total range of movement set from 100 to 250 (1 to 2.5 ms). I get nice movement over this range. If I move the servo to the middle position (let's say 125) and then enable limit setting and then press the Min button, the movement should then be limited to 125 - 250. Well, it acts as though the min and max limits were both set to 125 - the servo won't move from this position. I'm baffled... Another problem that I am having is that the values for the min and max positions are not being written to the internal memory. I do this so that the PIC will remember the last min/max settings. But when I cycle the power, the settings go back to the original min max values (100 & 250). Following is my code and I have attached my circuit. I would appreciate any insight - again, I fully expect to be embarrased....

@ DEVICE pic12F629, INTRC_OSC_NOCLKOUT ; Using Internal Clock, no clock out
@ DEVICE pic12F629, WDT_ON ; Enable Watch dog timer
@ DEVICE pic12F629, PWRT_ON ; Enable Power-up timer
@ DEVICE pic12F629, MCLR_OFF ; Disable MCLR pin
@ DEVICE pic12F629, BOD_ON ; Enable Brown-out detect
@ DEVICE pic12F629, CPD_OFF ; EEPROM Protect
@ DEVICE pic12F629, PROTECT_OFF ; Code Protect off

TRISIO = %11111110
INTCON.6=0 ' Disable all unmasked Interrupts
INTCON.7=0 ' Disable Global Interrupts
CMCON = 7 ' Disable analog comparator

ServoOut var GPIO.0
SetLimitSw var GPIO.1
PotIn var GPIO.2
MinSw var GPIO.4
MaxSw var GPIO.5

Posit var word
MinPosit var word
MaxPosit var word

'load starting min and max positions at program time
data @ 0, 0, 100
data @ 2, 0, 250

'************************************************* ***************
low Servoout

'read in stored min and max limits
read 0, MinPosit.byte0
read 1, minposit.byte1
read 2, MaxPosit.byte0
read 3, maxposit.byte1

Start:
gosub GetServoPosition
pulsout servoout, posit
pause 20

if setlimitsw = 1 then 'check min max buttons
if minsw = 1 then
MinPosit = Posit
write 0, MinPosit.byte0
write 1, minposit.byte1
pause 250
endif

if maxsw = 1 then
MaxPosit = Posit
write 2, MaxPosit.byte0
write 3, maxposit.byte1
pause 250
endif
endif

goto start

'************************************************* ***************
GetServoPosition:
high potin
pause 1
rctime potin, 1, Posit 'at 4 mhz, returns 0 - 120

'adjust posit to get values between 75 and 250
posit = posit + 75 + (posit / 2)

'now limit posit to 100 - 250 (1 ms - 2.5 ms)
if posit < 100 then posit = 100
if posit > 250 then posit = 250

if setlimitsw = 0 then 'apply limits
if Posit < MinPosit then Posit = MinPosit
if Posit > MaxPosit then Posit = MaxPosit
endif

return

'************************************************* ***************

End

skimask
- 28th February 2008, 21:58
@ DEVICE pic12F629, INTRC_OSC_NOCLKOUT ; Using Internal Clock, no clock out
@ DEVICE pic12F629, WDT_ON ; Enable Watch dog timer
@ DEVICE pic12F629, PWRT_ON ; Enable Power-up timer
@ DEVICE pic12F629, MCLR_OFF ; Disable MCLR pin
@ DEVICE pic12F629, BOD_ON ; Enable Brown-out detect
@ DEVICE pic12F629, CPD_OFF ; EEPROM Protect
@ DEVICE pic12F629, PROTECT_OFF ; Code Protect off
data 0, 100 , 250
trisio=$fe:intcon=0:cmcon=7:servoout var gpio.0:serlimitsw var gpio.1
potin var gpio.2:minsw var gpio.4:maxsw var gpio.5:posit var byte
minposit var byte:maxposit var byte:low servout
read 0,MinPosit:read 1,MaxPosit
Start: gosub GetServoPosition : pulsout servoout, posit : pause 20
if setlimitsw = 1 then 'check min max buttons
if minsw = 1 then MinPosit = Posit : write 0, MinPosit : pause 25
if maxsw = 1 then MaxPosit = Posit : write 1, MaxPosit : pause 25
endif
goto start
GetServoPosition: high potin:pause 1:rctime potin,1,Posit:posit=posit*2
if posit < 100 then posit = 100
if posit > 250 then posit = 250
if setlimitsw = 0 then 'apply limits
if Posit < MinPosit then Posit = MinPosit
if Posit > MaxPosit then Posit = MaxPosit
endif
return

Give that a shot, see what happens. The scaling is 'fixed' for now, and needs to be worked on...

Atom058
- 28th February 2008, 23:14
Skimask - Thanks for the reply. I tried your code but am getting the same result. If the Set Limit Enable switch is on, I can control the servo movement with the pot (I had to change the scaling back to what I originally had, first). When it is at this point, it is not applying the limits (100 & 250). As soon as I turn off the switch (applying the limits), the servo does not move from the current position. It is acting like the minposit and maxposit variables are the same number. And the memory stuff still doesn't work either. This is such a simple design, I am truly baffled... Any other thoughts?

Acetronics2
- 29th February 2008, 12:33
Any other thoughts?


Yes !

Elektor Magazine published such a device ... lots of years ago !!! Was April 1999 issue ...
But the processor was a ST62T65B.

Now you want that with a Pic ans PbP Written ...

I just have one question : Why do you use a 12F629 instead of a 12F675 ??? ... that would give you a nice pot following servo position ...

or do you intend to add a retrieving table ti linearize the RCTime result ???

While you look at those lines ... I look at your code - OR - Organigram failure.

Alain

skimask
- 29th February 2008, 13:26
Skimask - Thanks for the reply. I tried your code but am getting the same result. If the Set Limit Enable switch is on, I can control the servo movement with the pot (I had to change the scaling back to what I originally had, first). When it is at this point, it is not applying the limits (100 & 250). As soon as I turn off the switch (applying the limits), the servo does not move from the current position. It is acting like the minposit and maxposit variables are the same number. And the memory stuff still doesn't work either. This is such a simple design, I am truly baffled... Any other thoughts?

The data statement is wrong-ish...
data @0,100,250
The original would put: 0,100,250 into eeprom, this way puts 100,250 starting at location 0.

And you might want to try 'unrolling' your code, put it all in-line, get rid of the gosub. I believe if you 'unroll' your code, you may find your logic problem. Then you can put it back into a more modular format.

Acetronics2
- 29th February 2008, 14:14
Hi, Atom

Those lines Have Passed the MPSIM Test ...




@ DEVICE pic12F629, INTRC_OSC_NOCLKOUT ; Using Internal Clock, no clock out
@ DEVICE pic12F629, WDT_ON ; Enable Watch dog timer
@ DEVICE pic12F629, PWRT_ON ; Enable Power-up timer
@ DEVICE pic12F629, MCLR_OFF ; Disable MCLR pin
@ DEVICE pic12F629, BOD_ON ; Enable Brown-out detect
@ DEVICE pic12F629, CPD_OFF ; EEPROM Protect
@ DEVICE pic12F629, PROTECT_OFF ; Code Protect off

'@ __CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _BODEN_ON & _MCLRE_OFF

DEFINE OSCCAL_1K 1
DEFINE BUTTON_PAUSE 20

GPIO = %00000000
TRISIO = %11111110

INTCON.6=0 ' Disable all unmasked Interrupts
INTCON.7=0 ' Disable Global Interrupts
CMCON = 7 ' Disable analog comparator

ServoOut var GPIO.0
SetLimitSw var GPIO.1
PotIn var GPIO.2
MinSw var GPIO.4
MaxSw var GPIO.5

Delay var Byte

Posit var Byte
MinPosit var Byte
MaxPosit var Byte

'load starting min and max positions at program time
data @ 0,100
data @ 2,250

'************************************************* ***************
low Servoout

'read in stored min and max limits

read 0, MinPosit
read 2, MaxPosit

Start:

gosub GetServoPosition

Low servoout
pulsout servoout, posit



Delay = 0
BUTTON setlimitsw, 0, 255, 0, Delay, 1, Start

Delay = 0
BUTTON minsw, 1, 255, 0, Delay, 1, MinL '20 ms
Delay = 0
BUTTON maxsw, 1, 255, 0, Delay, 1, MaxL ' 20 ms

pause 20 ' no button pushed
Goto Start

MinL:
IF maxsw = 1 THEN Start '1 Button pushed at a Time !!!

IF Posit <> MinPosit THEN

MinPosit = Posit
write 0, MinPosit '10 ms

ENDIF

goto start

MaxL:

IF minsw = 1 THEN Start '1 Button pushed at a Time !!!

IF Posit <> Maxposit THEN

MaxPosit = Posit
write 2, MaxPosit ' 10 ms

ENDIF

goto start

'************************************************* ***************
GetServoPosition:

high potin
pause 1
rctime potin, 1, Posit 'at 4 mhz, returns 3 - 123 :: 1.23 ms max

'adjust posit to get values between 75 and 250
posit = posit + 75 + (posit / 2)

'now limit posit to 100 - 250 (1 ms - 2.5 ms)

if posit < 100 then posit = 100
if posit > 250 then posit = 250

if setlimitsw = 0 then 'apply limits

if Posit < MinPosit then Posit = MinPosit
if Posit > MaxPosit then Posit = MaxPosit

endif

return

'************************************************* ***************

End



Try those lines ... should work !!!

Alain

Atom058
- 29th February 2008, 16:09
Alain - Thanks for your suggestion. I tried it and got different results. Still getting good servo response to the pot, but it does not seem to be registering the min and max values when the buttons are pressed. The servo continues to move to the full limits.

Just to be clear, the SetLimitSw is a slide switch. When it is slid to the On position, the program will monitor for the pressing of either the min or max pushbuttons (momentary). When the SetLimitSw is slid to Off, the program will apply the limits that were set.

The concept is so simple (at least should be) that I am embarassed that I can't get this to work - I have done projects that are a hundred times more complex than this. I know the answer is staring me in the face - I just can't see it!

I appreciate all the comments and encourage more!

Bruce
- 29th February 2008, 17:07
You're reading EEPROM values into your word vars in reverse.

data @0, 0, 100
read 0, MinPosit.byte0 ' low byte now = 0
read 1, minposit.byte1 ' high byte now = 100

Then if Posit < MinPosit then Posit = MinPosit will always = true
since MinPosit starts out at 25,600 or 6400h.

Acetronics2
- 29th February 2008, 17:27
Hi,

Did you check ( W/Multimeter ) GPIO 4 and 5 state when your Min and Max Buttons are pushed ???

stupid question , ehhhh ???

MPSIM shows memory is well written ... so, I do suspect a harware problem !!!

I'll give a try with a '675 ... to be sure ( no 629 home ! )

Alain

Atom058
- 29th February 2008, 19:05
Bruce - Good catch on the Data statement (DUH!)! However, if I run my original code as in my first post (with the change in the data statement), I still get the same results: perfect servo movement when first booted up, but when I move the servo to the center position, switch on the SetLimitSw, press the Min button and then switch off the SetLimitSw, the servo no longer responds to the pot - as though both the min and max buttons were pressed at the same position.

I am beginning to think I have some underlying hardware issue (as Alain suggests). I will do some metering to see if I see anything fishy. If I don't, I'm going to rebuild the board with new components. If it still does it after all that, I'll shoot myself! (just kidding!).

Thanks guys - let me know if you think of anything else!

Atom058
- 29th February 2008, 20:16
Well, just as I expected, it was me and yes, I'm embarassed! I started metering the min and max buttons and noticed that if I pressed either button, both pins went high - explaining why the servo just stayed in one spot when either the min or max button was pressed. After scratching my head over how that could possibly be happening, I noticed that my pull-down resistors were put in vertically instead of horizontally. If you look at the circuit diagram in my first post, you will see what I mean. How stupid was that! Anyway, I rotated the resistors and everything works perfectly! Go figure!

I'd like to thank those who helped me and apologize for wasting their time. I knew it would be something like this...

Well, I made a few changes to the code and here it is in it's final form:

@ DEVICE pic12F629, INTRC_OSC_NOCLKOUT ; Using Internal Clock, no clock out
@ DEVICE pic12F629, WDT_ON ; Enable Watch dog timer
@ DEVICE pic12F629, PWRT_ON ; Enable Power-up timer
@ DEVICE pic12F629, MCLR_OFF ; Disable MCLR pin
@ DEVICE pic12F629, BOD_ON ; Enable Brown-out detect
@ DEVICE pic12F629, CPD_OFF ; EEPROM Protect
@ DEVICE pic12F629, PROTECT_OFF ; Code Protect off

TRISIO = %11111110
INTCON.6=0 ' Disable all unmasked Interrupts
INTCON.7=0 ' Disable Global Interrupts
CMCON = 7 ' Disable analog comparator

ServoOut var GPIO.0
SetLimitSw var GPIO.1
PotIn var GPIO.2
MinSw var GPIO.4
MaxSw var GPIO.5

wPosit var word
Posit var byte
MinPosit var byte
MaxPosit var byte

'load starting min and max positions
data @ 0, 100
data @ 1, 250

'************************************************* ***************
low Servoout

'read in stored min and max limits
read 0, MinPosit
read 1, MaxPosit

'for power-on reset of positions:
if minsw = 1 then
minposit = 100
write 0, minposit
endif
if maxsw = 1 then
maxposit = 250
write 1, maxposit
endif
pause 1000

Start:
gosub GetServoPosition
pulsout servoout, posit
pause 20

if setlimitsw = 1 then 'check min max buttons
if minsw = 1 then
MinPosit = Posit
write 0, MinPosit
pause 250
endif

if maxsw = 1 then
MaxPosit = Posit
write 1, MaxPosit
pause 250
endif
endif

goto start

'************************************************* ***************
GetServoPosition:
high potin
pause 1
rctime potin, 1, wPosit 'at 4 mhz, returns 0 - 120

'adjust posit to get values between 75 and 250
'use word-sized variable because calculation might exceed 255
wposit = wposit + 75 + (wposit / 2)

'now limit posit to 100 - 250 (1 ms - 2.5 ms)
'and put into byte-sized variable
if wposit > 250 then
posit = 250
else
posit = wposit
endif

if posit < 100 then posit = 100

if setlimitsw = 0 then 'apply limits
if Posit < MinPosit then Posit = MinPosit
if Posit > MaxPosit then Posit = MaxPosit
endif

return

'************************************************* ***************

End

BrianT
- 1st March 2008, 09:13
PULSOUT is a toggle. Sooner or later you will get some interference that flips the state of the SERVOOUT line and your system will be off in the weeds.

To guarantee correct working of the PULSOUT command you should first force the SERVOOUT line to a defined state.

For example, put
SERVOOUT = 0
or
LOW SERVOOUT
before calling the Pulsout command.

One of my RC aircraft went berserk because of that little oversight.

HTH
Brian

skimask
- 1st March 2008, 09:29
One of my RC aircraft went berserk because of that little oversight.
HTH
Brian

You mean like pulling UP out of an inverted low pass? :D
I lost a hopped-up clipped wing (+an extra bay) Goldberg Cub that way....(sigh).... :(

Acetronics2
- 1st March 2008, 09:53
Hi, BrianT

To fullfill your Pulsout knowledge ...

You are to use LOW Output ...

with some Hot plugged servos ( Graupner i.e.) or High capacitive loads ( some µF ) , Output = 0 is not enough to have a neat O level prior to Pulsin.
I know it's not supposed to happen in flight ... but, ...

Service,Sir ...

Alain