PDA

View Full Version : program crashes: is it my code or the chip?



keithv
- 24th March 2014, 17:36
This program works, sometimes for a couple minutes, some times only for a few seconds, but always crashes eventually. I'm using a PIC12F675 and I've read that it is not the most reliable chip. So I'm wondering if there's something wrong with my code or maybe it's the chip. If it were my code, I would think it would be more consistent in the point at which it crashed or simply wouldn't work at all.

This is what happens:
Push button1 and its LEDs work perfectly all the time. It's Push button2 that causes the problems. Eventually Push Button2 and its LEDs lock up and will not respond. When this happens, the LEDs associated with Push button1 toggle once. If I press Push button1, this seems to reset Push Button 2, and Push Button 2 and its LEDs will work fine until it locks up again.

The code for push button2 is identical to push button1, it just uses different variable names and I/Os

' Name : BUTTONTEST2.pbp
' Compiler : PICBASIC PRO Compiler 3.0
' Assembler : PM
' Target PIC : 8-pin PIC12F675 or similar type
' Hardware : Kee
' Oscillator : 4MHz internal
' Keywords : HIGH, LOW
' Description : use a push button to toggle two LEDs. THere are two push buttons.
'each push button toggles a separate set of LEDs. Program also debounces


#config
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
#endconfig


Define OSCCAL_1K 1 ' PIC12F675, Calibrate internal oscillatordefine MCLRE_OFF
define BUTTON_PAUSE 5


LED Con 0 'Alias GPIO.0 to LED
LED2 con 1 'Alias GPIO.1 to LED2
LED3 con 4 'Alias GPIO.4 to LED3
LED4 con 5 'Alias GPIO.5 to LED4
PB Var GPIO.2 'Alias GPIO.2(pin 5) to PB(push button1)
PB2 var GPIO.3 'Alias GPIO.3(pin 4) to PB2(push button2)
LEDstate var bit 'LED on = 1, LED off = 0
LEDstate2 var bit 'LED4 on = 1, LED4 off = 0


ANSEL = 0 'Set all digital
CMCON = 7 'Analog comparators off
high LED 'begin with LED on
low LED2 'begin with LED2 off
high LED4 'begin with LED4 on
low LED3 'begin with LED2 off
LEDstate = 1 'begin with LED recognized as on
LEDstate2 = 1 'begin with LED4 recognized as off


main:
If (PB = 0) and (LEDstate = 1) Then 'push button1 is pressed when LED is on
low LED 'toggle LED off
high LED2 'toggle LED2 on
pause 10 'wait 10ms for debounce
goto WaitForRelease1 'go to subroutine for releasing push button1
endif

if (PB = 0) and (LEDstate = 0) then 'push button1 is pressed when LED is off
high LED 'toggle LED on
low LED2 'toggle LED2 off
pause 10 'wait 10ms for debounce
goto WaitForRelease2 'go to subroutine for releasing push button1
Endif

If (PB2 = 0) and (LEDstate2 = 1) Then 'push button2 is pressed when LED4 is on
low LED4 'toggle LED4 off
high LED3 'toggle LED3 on
pause 10 'wait 10ms for debounce
goto WaitForRelease3 'go to subroutine for releasing push button2
endif

if (PB2 = 0) and (LEDstate2 = 0) then 'push button2 is pressed when LED4 is off
high LED4 'toggle LED4 on
low LED3 'toggle LED3 off
pause 10 'wait 10ms for debounce
goto WaitForRelease4 'go to subroutine for releasing push button2
Endif

goto main


'subroutines for action upon release of push buttons. Debounces, changes LEDstate() variable,
'and prevents looping when button is pressed and held


WaitForRelease1:
if PB = 1 then 'push button1 is released after toggling LED off
pause 10 'wait 10ms for debounce
LEDstate = 0 'recognize LED as off
endif
goto main

WaitForRelease2:
if PB = 1 then 'push button1 is released after toggling LED on
pause 10 'wait 10ms for debounce
LEDstate = 1 'recognize LED as on
endif
goto main


WaitForRelease3:
if PB2 = 1 then 'push button2 is released after toggling LED4 off
pause 10 'wait 10ms for debounce
LEDstate2 = 0 'recognize LED4 as off
endif
goto main

WaitForRelease4:
if PB2 = 1 then 'push button2 is released after toggling LED4 on
pause 10 'wait 10ms for debounce
LEDstate2 = 1 'recognize LED4 as on
endif
goto main


'end of subroutines


End

HenrikOlsson
- 24th March 2014, 20:30
Hi,
I don't see how the WaitForRelease routines is supposed to wait for the button to actually BE released.

Yes, at the point of entering the routine it does check if the button IS released but then it GOTOs main no matter what. So, the only way to have LEDState set to the correct state is if the button is already released at the time the program enters the routine. If the button is NOT released when the program enters the routine it'll just skip what's inside the IF/ENDIF block and go right to the GOTO main.

/Henrik.

Acetronics2
- 25th March 2014, 10:54
first ...




#config
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
#endconfig


LED Con 0 'Alias GPIO.0 to LED
LED2 con 1 'Alias GPIO.1 to LED2
LED3 con 4 'Alias GPIO.4 to LED3
LED4 con 5 'Alias GPIO.5 to LED4



changed to



#config
__CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
#endconfig



LED VAR GPIO.0 'Alias GPIO.0 to LED
LED2 VAR GPIO.1 'Alias GPIO.1 to LED2
LED3 VAR GPIO.4 'Alias GPIO.4 to LED3
LED4 VAR GPIO.5 'Alias GPIO.5 to LED4


to be sure ...

now ... your sketch looks somewhat ... surprising, and not obvious at all.

could you post a scheme and a description ( in words ) of what you intend to have like a functionning scheme ???

Alain

keithv
- 25th March 2014, 16:59
I see what you are saying, Henrik. @ Acetronics2: I have been reading the reference manual and better understand now that a CONSTANT would not be the best modifier for this situation. I am trying to use a single push button switch to toggle between 2 different LEDs X 2, so that one half of the 1/2 PIC12F675a (GPIO.0,1,2) performs this function and the other half of 1/2 PIC12F675b (GPIO.3,4,5) performs the exact same function with an entirely different push button and set of LEDs. And also that both halves perform separate from one another.

Here is my new code. The toggle of the LEDs works good, but I am still having the same problem as before.



LED1 var GPIO.0 ' Alias GPIO.0 to LED1
LATCH1 var GPIO.1 'Alias GPIO.1 to LATCH1
PB1 Var GPIO.2 ' Alias GPIO.2 to push button
LED1on var word
LED1off var word
LED2 var GPIO.5
LATCH2 var GPIO.4
PB2 var GPIO.3
LED2on var word
LED2off var word

ANSEL = 0 ' Set all digital
CMCON = 7 ' Analog comparators off
TRISIO = %11001100
LED1 = 0
LATCH1 = 1
LED1off = LED1
LED1on = LATCH1
LED2 = 0
LATCH2 = 1
LED2off = LED2
LED2on = LATCH2


main:
if PB1 = 0 then
pause 10
gosub LED1status
LED1on = 1
LED1off = 0
endif

if PB2 = 0 then
pause 10
gosub LED2status
LED2on = 1
LED2off = 0
endif

do until PB1 = 1
pause 5
loop

do until PB2 = 1
pause 5
loop

pause 10


goto main
End

LED1status:
if LED1 = 1 then
LATCH1 = LED1on
LED1 = LED1off
elseif LED1 = 0 then
LED1 = LED1on
LATCH1 = LED1off
endif
return

LED2status:
if LED2 = 1 then
LATCH2 = LED2on
LED2 = LED2off
elseif LED2 = 0 then
LED2 = LED2on
LATCH2 = LED2off
endif
return

HenrikOlsson
- 25th March 2014, 20:42
Hi,
I'm really struggling to follow that code with port bits being read into WORD variables and vice versa. I understand that you want to know WHY your code doesn't work but, and please don't take this the wrong way, that's just WAY to convoluted IMHO.

The following compiles OK for a 12F675 but I have not tested it. Please see if you can follow the logic behind it, then try it on the actual hardware.

LED1 var GPIO.0 ' Alias GPIO.0 to LED1
LATCH1 var GPIO.1 ' Alias GPIO.1 to LATCH1
PB1 Var GPIO.2 ' Alias GPIO.2 to push button

LED2 var GPIO.5 ' Same as aboove for second "port"
LATCH2 var GPIO.4
PB2 var GPIO.3

Debounce VAR BYTE ' Counter for the debounce rotutine.

ANSEL = 0 ' Set all digital
CMCON = 7 ' Analog comparators off
GPIO = 0 ' All outputs OFF
TRISIO = %11001100 ' Set ins and outs

'-------------------------------------------------------------------------------

Main:
IF PB1 = 0 THEN ' Button 1 pressed?

TOGGLE LED1
TOGGLE LATCH1

Debounce = 0 ' Clear counter variable

While Debounce < 99 ' Signal must be stable for 100 counts in a row.
IF PB1 = 1 THEN ' Button is released (or bouncing).
Debounce = Debounce + 1
ELSE
Debounce = 0 ' If button still active, clear counter.
ENDIF
PAUSEUS 100 ' 100 counts * 100us = 10ms "silence" before continuing
WEND
ENDIF

'-------------------------------------------------------------------------------

IF PB2 = 0 THEN ' Button 2 pressed?

TOGGLE LED2
TOGGLE LATCH2

Debounce = 0 ' Clear counter variable

While Debounce < 99 ' Signal must be stable for 100 counts in a row.
IF PB2 = 1 THEN ' Button is released (or bouncing).
Debounce = Debounce + 1
ELSE
Debounce = 0 ' If button still active, clear counter.
ENDIF
PAUSEUS 100 ' 100 counts * 100us = 10ms "silence" before continuing
WEND
ENDIF
'-------------------------------------------------------------------------------

Goto Main

Now, this is ALSO a bit convoluted and can certainly be made more "compact" but I wanted to keep it as simple as possible for starters. Let me know if you try it out.

/Henrik.

Acetronics2
- 25th March 2014, 22:11
and What about this one, using the Button command ?



'************************************************* ******************************
' Name : BUTTONTEST2.pbp
' Compiler : PICBASIC PRO Compiler 3.0
' Assembler : PM
' Target PIC : 8-pin PIC12F675 or similar type
' Hardware : Kee
' Oscillator : 4MHz internal
' Keywords : HIGH, LOW
' Description : use a push button to toggle two LEDs. THere are two push buttons.
'each push button toggles a separate set of LEDs. Program also debounces
'************************************************* ******************************
#config
__CONFIG _CP_OFF & _WDT_ON & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
#endconfig

DEFINE OSCCAL_1K 1 ' PIC12F675, Calibrate internal oscillatordefine MCLRE_OFF
DEFINE BUTTON_PAUSE 255
Delay VAR Byte
Button1 VAR GPIO.2
Button2 VAR GPIO.3
LED1 VAR GPIO.0 'Alias GPIO.0 to LED
LED2 VAR GPIO.1 'Alias GPIO.1 to LED2
LED3 VAR GPIO.4 'Alias GPIO.4 to LED3
LED4 VAR GPIO.5 'Alias GPIO.5 to LED4
CMCON = 7
ANSEL = 0
ADCON0 = 0
GPIO = %00001100
TRISIO = %00001100
CLEAR
'************************************************* ******************************
Main:
'************************************************* ******************************
WHILE 1
FIRST:' let's check Button1 ...
Delay = 0
button Button1, 0, 255, 0, Delay, 1,yes1
no1:
Pause 20 ; pace the scanning ... not compulsory
goto Second
yes1:
toggle LED1
' Stop until Button1 released
WHILE !Button1
WEND

SECOND:' let's check Button2
Delay = 0
button Button2, 0, 255, 0, Delay, 1,yes2
no2:
Pause 20 ; pace the scanning ... not compulsory
goto Update
yes2:
toggle LED3
'Stop until Button2 released
WHILE !Button2
WEND
Update:
led2 = ! LED1 : LED4 = !LED3
WEND
END

Alain

keithv
- 26th March 2014, 01:02
Below is what I was working on today. It's only for 1 switch and set of LEDs, but it was working well for 2 if you repeat everything, give the variables new names, and assign things to new I/Os. Because of physical implementation, I'll most likely need to use something like the 6 pin 10F202. This will also make the next problem easier to deal with. If I were to use 1 PIC to read n number of switches, it would need to be able to allow one switch to perform its operation even if another switch was being pressed and held.


#config
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _CPD_OFF
#endconfig

Define OSCCAL_1K 1 ' PIC12F675, Calibrate internal oscillatordefine MCLRE_OFF

LED1 var GPIO.0 ' Alias GPIO.0 to LED1
LATCH1 var GPIO.1 'Alias GPIO.1 to LATCH1
PB1 Var GPIO.3 ' Alias GPIO.2 to push button
LED1on var word
LED1off var word


ANSEL = 0 ' Set all digital
CMCON = 7 ' Analog comparators off
TRISIO = %11001100
LED1 = 0
LATCH1 = 1
LED1off = LED1
LED1on = LATCH1
pause 10
LATCH1 = 0



main:
switchpress1:
if PB1 = 0 then
pause 40
gosub LED1status
LED1on = 1
LED1off = 0
pause 5
LATCH1 = 0
gosub switchrelease1
pause 40
endif

goto main
End

LED1status:
if LED1 = 1 then
LATCH1 = LED1on
LED1 = LED1off
elseif LED1 = 0 then
LED1 = LED1on
LATCH1 = LED1off
endif
return


switchrelease1:
do until PB1 = 1
pause 5
loop
return

keithv
- 26th March 2014, 01:14
Yes, my code is quite convoluted, Henrik. I haven't written code for at least 15 years, and I have never written code for PIC. Because of certain physical limitations, the canned BUTTON and TOGGLE commands don't work well or could create potential problems. The latching relay could be accidentally flipped by ESD or a magnetic field or a power spike, which would cause the relay's state to be out of sync with the LED. Instead of adding some sort of reset code or feature, I've tried to create my own "toggle" command that inherently resets the LATCH variable every time the button is pressed according to the state of the LED. That is the reason for the use of the word variable. But perhaps a bit or byte variable would work just as well. I don't know. That is my lack of experience.

keithv
- 26th March 2014, 17:32
I tried your code, Henrik. It's not working. I do not understand why. It looks like it should work. LED1 and LATCH1 light up on start. LED2 and LATCH2 are off. Neither push button does anything. I haven't tried your code yet, Acetronics, but I will.

Thank you very much for all the help you have been giving me, BTW. I appreciate it very much.

keithv
- 26th March 2014, 18:00
update:

Actually, both your codes work! However there is something weird. Both behave identical after the chip has first been programed, plugged into the circuit and powered on: the side with PB1/LED1&2 comes on and the other side does not come on(only LED1 comes on with Ace's code, but this is to be expected). The push buttons do nothing. But if I remove the 10k pull up resistor from the switching circuit and put it back, the circuit comes to life and the program behaves the way you would expect it to.

Very odd...

Any ideas as to why this happens?

HenrikOlsson
- 26th March 2014, 19:56
Hi,
> Any ideas as to why this happens?

No, not really I'm afraid and I'm not in a position where I can wire it up and test here....
Since both mine and Alains code experience the same issue it feels like a hardware problem or a configuration problem but as far as I can see you've got CMCON, ANSEL and MCLR covered so I don't know.

Or it might be something completely obvious - which we're all missing at the moment.

Couple of, perhaps completely unrelated, questions:
* Does it do the same thing for both "sides" or only one? (If only one, which?)
* Do you program the chip in circuit and is the device programmer still connected to the target when this happens?
* Can you post a schematic of how you have it wired?

/Henrik.

keithv
- 26th March 2014, 20:24
No. It does not do the same thing for both sides. The GPIO0,1,2 side lights up, but does not toggle when PB1 goes low. The GP3,4,5 side does not light up at all and does not do anything when PB2 goes low. I have a momentary switch connected to ground. I have a 10k resistor to VDD(+5v). Those two components connect to GPIO2 or 3 via a 220ohm resistor. If I pull the 10k resistor that is part of PB1 and then put it back in, the circuit suddenly starts working. This has to be done every time power is turned off.

The device programmer is separate. I program the chip in a pin wiggler, take it out, and then put it in the circuit.

keithv
- 26th March 2014, 20:44
I've got some 12F609. I'll give them a try and see if the dual switch program works any better.

I have a question about the next phase of my project. I'd like to have multiple relay/LED combos, each controlled by either a single 10F202 or each pair controlled by a 12Fxxx. But have them all controlled by a 16C (probably) master chip. So that lets say I have relay/LED 1, 2, 5, 7, and 8 turned on. I then press a program button and it remembers 1,2,5,7 and 8.

What command would work best for something like that? I was thinking read/write array? Is there something that would work better? Does anyone know of any good example programs that will help me learn how to to something like this?

Acetronics2
- 27th March 2014, 08:06
your answer is here ...

_WDT_OFF

did you notice the configs Henrik and I have used ???
one more Holy manual chapter to learn ...

never been a hardware/software problem ...

looks you've been using "C" programming before, and Basic shows "little" differences in program flows.

looks you've forgotten some "CLRWD" commands ... as you decided to place them by yourself ...

so the final answer is ...

It's your code !!!
Alain

PS: BTW ... your "Programming style " looks very close to MikroC ( Mikroelektronica ) C examples ...

keithv
- 28th March 2014, 02:51
My background is actually in VisualBASIC, but that was a long time ago. I tried MikroBasic but I prefer PBP3. The hardest part for me is learning the configuration and registers. I am slowly learning to make sense of all the datasheets though. Not very well, but getting better. I had been using BASIC Stamp. That was very easy. It takes care of all the configs and registers for you. But it is not very good for developing cost effective products.

I had the WDT off because that was the config from the example program found here: http://melabs.com/samples/LABX4-12F675/BUTX4.htm I'm still not really sure what a watch dog timer does.

keithv
- 28th March 2014, 03:43
EDIT: I was thinking about why you would think I am writing in C. I realize that the code that clears LATCH1 may seem a little confusing. There is a very specific reason for this. I am not clearing the variable. I am setting the I/O low. LATCH1 turns a latching relay on and it only needs a very short single pulse to actuate. No need to use a PULSE command. I want to turn it off after its job is done because keeping current consumption to a minimum is very important.

This is also another reason behind my logic for wanting to use a secondary variable for LED1 and LATCH1. The "toggling" of LED1 and LATCH1 are done by LEDon and LEDoff, but after that I want to be able to turn LATCH1 off directly without affecting the LEDon and LEDoff variable. The higher level TOGGLE command does not allow for this.

And as for BUTTON....I just don't like it. It does not seem that much more difficult to simply write the code out one level down. That way it allows you to customize it more easily. At least that is my inexperienced opinion thus far.