PDA

View Full Version : Simple "Time-out" routine



JacoMuller
- 4th May 2010, 01:43
I have a project where I have to move a small trolley on a rail forwards until it reach a proximity switch A. I then need to move the trolley backwards until it reach proximity switch B. Once again, I have to change the direction to move the trolley forwards. Because of the weight of the trolley I have used PWM to accelerate the trolley rather than to switch it hard on or off. This has to run continuously for weeks in order to test a laser scanner.

Everything works fine but I would like to add a time out function should the next proximity switch not be reached in 20 seconds. It should then just stop motor and the application.



'************************************************* ***************
'* Name : 12F675_Motor_Control_SoftStart_and Brake *
'* Author : Jaco Muller *
'* Notice : Copyright (c) 2010 Jaco Muller *
'* : All Rights Reserved *
'* Date : 01/04/10 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************
@ DEVICE PIC12F675,MCLR_OFF,INTRC_OSC_NOCLKOUT,WDT_OFF,BOD_ OFF
Include "modedefs.bas" ' Mode definitions for Serout

'-------------------------------------------------------------------
' PIC12F675 on Transtoll Motor Control Board Part Number 4410A
'-------------------------------------------------------------------
' PIN NAME USE/CONNECTION
' 1 Vdd +5VDC
' 2 GPIO.5 Q3 +24V on Output +
' 3 GPIO.4 Input IN1
' 4 GPIO.3 Input IN2
' 5 GPIO.2 Q8 0V on Output -
' 6 GPIO.1 Q4 +24V on Output -
' 7 GPIO.0 Q7 0V on Output +
' 8 VSS GROUND
'-------------------------------------------------------------------

DEFINE OSC 4 ' Internal Clock to 4 Mhz

ANSEL.0=0 ' AN0 to digital
ANSEL.1=0 ' AN1 to digital
ANSEL.2=0 ' AN2 to digital
ANSEL.3=0 ' AN3 to digital
ANSEL.4=0 '\
ANSEL.5=0 ' clock derived from a dedicated internal oscillator
ANSEL.6=0 '/
ANSEL.7=0 ' Unimplemented

TRISIO.0 = 0 ' GPIO.0 Output
TRISIO.1 = 0 ' GPIO.1 Output
TRISIO.2 = 0 ' GPIO.2 Output
TRISIO.3 = 1 ' GPIO.3 Input
TRISIO.4 = 1 ' GPIO.4 Input
TRISIO.5 = 0 ' GPIO.5 Output
TRISIO.6 = 0 ' Unimplemented
TRISIO.7 = 0 ' Unimplemented

ADCON0.0 = 0 ' ADON: A/D Conversion STATUS bit
ADCON0.1 = 0 ' GO/DONE: A/D Conversion Status bit
ADCON0.2 = 0 ' \ AN 0
ADCON0.3 = 0 ' / AN 0
ADCON0.4 = 0 ' Unimplemented
ADCON0.5 = 0 ' Unimplemented
ADCON0.6 = 0 ' Reference to Vdd
ADCON0.7 = 1 ' Right justify result

CMCON = 7 ' Analog comparators off


Q3 Var GPIO.5 ' High side Power MOSFET Switch for Direction 1 (IPS511)
Q4 var GPIO.1 ' High side Power MOSFET Switch for Direction 2 (IPS511)
Q7 var GPIO.0 ' Low side Power MOSFET for Direction 2 (VNP5N07)
Q8 var GPIO.2 ' Low side Power MOSFET for Direction 1 (VNP5N07)
IN1 var GPIO.4 ' Input of Limit Switch 1
IN2 VAR GPIO.3 ' Input of Limit Switch 2
Direct1 var bit ' Movement away from switch 1
Direct2 VAR bit ' Movement away from switch 2
Stat var byte
DutyC var byte ' Byte size variable for Duty cycle
Cycles var byte ' Byte size variable for number of cycles per duty cycle

stat=0

' Stat=0 when no switch is pressed and there is no movement
' Stat=1 when switch 1 is pressed and there is no movement
' Stat=2 when switch 2 is pressed and there is no movement
' Stat=3 when switch 1 & switch 2 are pressed and there is no movement
' Stat=4 when no switch is pressed and there is movement in direction 1
' Stat=5 when switch 1 is pressed and there is movement in direction 1
' Stat=6 when switch 2 is pressed and there is movement in direction 1
' Stat=7 when switch 1 & switch 2 are pressed and there is movement in direction 1
' Stat=8 when no switch is pressed and there is movement in direction 2
' Stat=9 when switch 1 is pressed and there is movement in direction 2
' Stat=10 when switch 2 is pressed and there is movement in direction 2
' Stat=11 when switch 1 & switch 2 are pressed and there is movement in direction 2


low q3
low q4
low q7
low q8

pause 50

high q8
pwm q3,127,8 ' Pulse Width Modulate High side, dc% for cycles

pause 50

low q3
low q8

pause 50

high q7
pwm q4,127,8 ' Pulse Width Modulate High side, dc% for cycles

pause 50
low q4
low q7


cycles = 10 ' Set cycles per duty cycle


MAIN:
if in1=1 then
stat.0=0
else
stat.0=1
endif
if in2=1 then
stat.1=0
else
stat.1=1
endif
stat.2=Direct1
stat.3=Direct2


select case stat
case 0
'do nothing
case 1
goto left
case 2
goto right
case 3
'do nothing
case 4
'do nothing
case 5
'do nothing
case 6
goto right
case 7
goto brake
case 8
'do nothing
case 9
goto left
case 10
'do nothing
case 11
goto brake
end select
GOTO MAIN ' DO IT AGAIN
end

left:
low q4 ' Set High side Right off
low q7 ' Set Low side Right off
pause 1 ' Wait for Switch

high q8 ' Set Low side Left on
high q7 ' Set Low side Right on
pause 300 ' Wait for System to stop

low q8 ' Set Low side Left off
low q7 ' Set Low side Right off
pause 1 ' Wait for Switch

high q8 ' Set Low side Left on
for DutyC = 0 to 255 step 4 ' Step duty cycle from 0% to 100%
pwm q3,DutyC,cycles ' Pulse Width Modulate High side, dc% for cycles
if in2=0 and in1 = 0 then ' Check if both switches were pressed
DutyC = 255 ' If true, set DC = 255
goto brake ' exit sub goto brake
endif
next DutyC
Direct1=1
direct2=0
high q3 ' Set High side to 100%
goto main
end

right:
low q3 ' Set High side Left off
low q8 ' Set Low side Left off
pause 1 ' Wait for Switch

high q8 ' Set Low side Left on
high q7 ' Set Low side Right on
pause 300 ' Wait for System to stop

low q8 ' Set Low side Left off
low q7 ' Set Low side Right off
pause 1 ' Wait for Switch



high q7
for DutyC = 0 to 255 step 4 ' Step duty cycle from 0% to 100%
pwm q4,DutyC,cycles ' Pulse Width Modulate High side, dc% for cycles
if in2=0 and in1 = 0 then ' Check if both switches were pressed
DutyC = 255 ' If true, set DC = 255
goto brake ' exit sub goto brake
endif
next DutyC
Direct1=0
direct2=1
high q4
goto main
END ' END PROGRAM

Brake:
Direct1=0
direct2=0
low q3
low q8
low q7
low q4
pause 5000
goto main
END ' END PROGRAM

HenrikOlsson
- 4th May 2010, 06:32
Hi Jaco,
I haven't looked into your code very deeply but here's an idea that might work.
Have a "counter" variable that you increment in each of the states where you have movement but not yet detected "the other" switch.

Figure out the magic number that matches ~20 seconds and if the "counter" ever reaches that number you abort the whole thing. When you go from a state of movement but no switch to a state where you detect a s switch you reset the "counter".

The timing may not be super accurate depending on how long your various subroutines takes but for a "simple timeout" it may suffice?

/Henrik.

JacoMuller
- 4th May 2010, 08:06
Hi Hendrik

Thanks for the response. I have used two variables, Micro VAR WORD and Milli VAR WORD. For each cycle in the main loop where no switch was activated, the Micro (~micro second) increased by 1 until 999 by which time the Milli is increased by 1 and the micro is reset to 0. I had to do this because of the the varaible type word max 65 535 and that is not long enough. It just seemed very clumsy. I though it will be more elegant to use an internal timer which is reset each time the switch is activated. If a switch is not activated within 20 seconds, the system must stop the motor and end the application.

Does that make sense?

The reason why I am after a good solution, is that I might use this circuit in another application where timing is a bit more critical.



Hi Jaco,
I haven't looked into your code very deeply but here's an idea that might work.
Have a "counter" variable that you increment in each of the states where you have movement but not yet detected "the other" switch.

Figure out the magic number that matches ~20 seconds and if the "counter" ever reaches that number you abort the whole thing. When you go from a state of movement but no switch to a state where you detect a s switch you reset the "counter".

The timing may not be super accurate depending on how long your various subroutines takes but for a "simple timeout" it may suffice?

/Henrik.

HenrikOlsson
- 4th May 2010, 09:02
Hi,
Sure, it makes sense. If you need accurate timing you'll have to resort to a timer based interrupt. However, if timing isn't that critical you can set up the hardware timer and just check the interrupt flag in software (ie. not actaully enabling the interrupt).

You can use TMR1 of the 12F675, with a 1:8 prescaler and 4Mhz clock it will overflow at a rate of (4000000/4/8/65536) = ~1.9Hz. Unfortunately the highest prescaler ratio is 1:8 so that's as "slow" as it gets. Having it "time" 20 seconds intervals would require an external clock x-tal for the timer oscillator which would cost you two I/O pins that you don't have.... :-(

For accurate timing, as already been said, you'll have to resort to an interrupt based routine. In this case you set up the timer so it overflows at a rate high enough for your timing purposes, lets say 100Hz. Then you keep track of the time pretty much as you already did - with variables like Days, Hours, Minutes, Seconds, ms.

Have a look at Darrel Taylors Elapsed Time routine (http://www.pbpgroup.com/modules/wfsection/article.php?articleid=8) I think it pretty much fits your need perfectly.

/Henrik.

Ioannis
- 4th May 2010, 09:16
In the attached file, you can use the Timer1 with Interrupts. Just Start Timer1 by setting t1con.0 bit and then either check flag or stop whatevere your are doing in the ISR routine, inside the IF-THEN.

Thanks to Darrel once again for his DT-INTS.

Don't forget to include the files in the directory of your code and use MPASM as an assembler.

Ioannis