Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] PIC12F683 Trouble with GPIO and Interrupt

Status
Not open for further replies.

walumbe

Junior Member level 2
Joined
Oct 15, 2013
Messages
20
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
174
Hi,

I have written code for a PIC12F683 using a 4.0Mhz crystal. The pins are configured as follows:
GP0 - Phototransistor tied to ground via a resistor. Another resistor tied from this pin to +5V
GP1 - a vibration sensor switch (Shot Circuit when there is no vibration) tied to ground with a resistor tied from this pin to +5V
GP2 - tied to a transistor that turns on an LED board when on.

I am trying to turn ON the LED board via GP2 when either GP0 AND GP1 are high for a given period. So far I have it working, but I'm unable to turn off GP2 when the program goes into the interrupt routine for sensing the vibration. I stays on as long as there is vibration even if there is light. Any suggestions on how I could do this would be appreciated.

Code Basic4GL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
dim Count as word
dim Temp as byte
dim DarkValue as word
 
sub procedure Interrupt
  if GPIF_bit = 1 then
    Temp = GPIO       ' Any access to the GPIO register will reset the IOC
    Count = 0         ' Each time an edge is detected at GP1, reset the timer
  end if
  GPIF_bit = 0        ' Clear the Interrupt flag
end sub
 
main:
  ANSEL = %00000001   ' Set AN0 as analog and the rest digital
  ADCON0 = %00000001
  CMCON0 = 7
  IOC1_bit = 1        ' Enable Interrupt-on-change feature at GP1
  GPIE_bit = 1        ' Enable peripheral interrupts
 
  TRISIO = %00000011  ' Set GP0 and GP1 as inputs , GP2 as output
  GPIO.B0 = 0         ' Initial GP0 value -> Input Dark Sensor
  GPIO.B1 = 0         ' Initial GP1 value -> Input Vibration Sensor
  GPIO.B2 = 0         ' Initial GP2 value -> Output LED
  Count = 0           ' Initialize count
 
  while TRUE
  DarkValue = ADC_read(0)
    if (DarkValue > 286) and (Button(GPIO, 1, 5, 1)) then ' Checks for voltage >1.4V at GP0 and a high at GP1
      GPIO.B2 = 1      ' Turn on transistor to power the LED board
      GIE_bit = 1      ' Enable interrupts before entering the counter loop
      do
        Delay_ms(12)       'Delay for 12ms
        Inc(Count)
      loop until Count = 10000 
      GIE_bit = 0              ' And disable them after leaving
      Count = 0        ' Reset counter when the loop ends
      GPIO.B2 = 0      ' Turns off the LEDs
    end if
  wend
end

 
Last edited by a moderator:

remove your interrupt routine, test the gpio.b1 bit inside your main delay routine it will be easier
dont bother with interrupts if you dont need to.
 

I need the interrupt to test the vibration sensor each time it is activated to reset the counter. I already tried doing in the main part of the program without the interrupt, but the LEDs flicker at the end of the counter before re-entering into it. Could there be a way to use IOC-GP0? Looking at the interrupt chart on the datasheet it looks like that can be set to sense the value at GP0, but I am not sure how it works

remove your interrupt routine, test the gpio.b1 bit inside your main delay routine it will be easier
dont bother with interrupts if you dont need to.
 


Code Basic4GL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
dim Count as word
dim Temp as byte
dim DarkValue as word
 
//sub procedure Interrupt
//  if GPIF_bit = 1 then
//    Temp = GPIO       ' Any access to the GPIO register will reset the IOC
//    Count = 0         ' Each time an edge is detected at GP1, reset the timer
//  end if
//  GPIF_bit = 0        ' Clear the Interrupt flag
//end sub
 
main:
  ANSEL = %00000001   ' Set AN0 as analog and the rest digital
  ADCON0 = %00000001
  CMCON0 = 7
  IOC1_bit = 1        ' Enable Interrupt-on-change feature at GP1
//  GPIE_bit = 1        ' Enable peripheral interrupts
 
  TRISIO = %00000011  ' Set GP0 and GP1 as inputs , GP2 as output
  GPIO.B0 = 0         ' Initial GP0 value -> Input Dark Sensor
  GPIO.B1 = 0         ' Initial GP1 value -> Input Vibration Sensor
  GPIO.B2 = 0         ' Initial GP2 value -> Output LED
  Count = 0           ' Initialize count
 
  while TRUE
  DarkValue = ADC_read(0)
    if (DarkValue > 286) and (Button(GPIO, 1, 5, 1)) then ' Checks for voltage >1.4V at GP0 and a high at GP1
      GPIO.B2 = 1      ' Turn on transistor to power the LED board
//      GIE_bit = 1      ' Enable interrupts before entering the counter loop
      do
        Delay_ms(12)       'Delay for 12ms
        if GPIO.B1 = 1 then Count = 0
        Inc(Count)
      loop until Count = 10000 
//      GIE_bit = 0              ' And disable them after leaving
      Count = 0        ' Reset counter when the loop ends
      GPIO.B2 = 0      ' Turns off the LEDs
    end if
  wend
end

 
Last edited by a moderator:

There is (may be) a problem with the GPIO Change Interrupts. See the datasheet (12.4.3):

"If a change on the I/O pin should occur when any GPIO operation is being executed, then the GPIF interrupt flag may not get set."

In my opinion use the external interrupt on the GP2/INT (datasheet 12.4.1) for sensing the vibration, and use GPIO.B1 for LED output.
 
Zuisti,

I already have a PCB board designed and I'm testing with it. For now I would like to make the changes via code if possible to save on time and cost. From my testing the Vibration sensing is working fine and is resetting the counter each time there is an interrupt. Then issue is the dark sensor not being read once once it enters the interrupt routine.
There is (may be) a problem with the GPIO Change Interrupts. See the datasheet (12.4.3):

"If a change on the I/O pin should occur when any GPIO operation is being executed, then the GPIF interrupt flag may not get set."

In my opinion use the external interrupt on the GP2/INT (datasheet 12.4.1) for sensing the vibration, and use GPIO.B1 for LED output.
 

Sorry, I misunderstood you.
But:
you wrote this:
"Then issue is the dark sensor not being read once once it enters the interrupt routine"
Of course, since this is the logic of your program.

When the interrupt is (re)occured (a new sensor event), the internal do loop (the 120.000 ms = 2 min delay) always restarts, and stays here, regardless of the adc value since it is not measured here.

In other words, if the sensor signal switching is repeated within two minutes, the program remains in the internal timer loop and never get to the LED off.

The vibration sensor is likely provides repeating signals I think.

I do not know exactly what you want, but you have to change your program logic, for example, be sure to turn off the LED over a given ADC value, regardless of the value of the timer counter.

Other: what compiler you are using? What does exactly the Button function? Is it a debounced pin-reading? I do not like such high-level things because I don't know exactly what's happening...

zuisti
 
I am using MikroBasic Pro to write the program. The Button command is for debouncing as the switch that I'm using has two rolling balls inside it and does not instantaneously change its state when tilted/vibrated.

Just a simple explanation of what I want my circuit to do...If the values of the vibration AND dark sensor (> 1.4V) pins are both HIGH, then the LED board will be turned on via a transistor on GP2 and will stay on for a given period (e.g 2 min) before turning off. If the vibration sensor is re-triggered before the 2 min time period AND the Dark Pin is still HIGH then it will restart the counter.

The vibration sensor is providing repeating signals as you mentioned. The application of this program is for a circuit that only works at night and turns off the LEDs in the day.


Sorry, I misunderstood you.
But:
you wrote this:
"Then issue is the dark sensor not being read once once it enters the interrupt routine"
Of course, since this is the logic of your program.

When the interrupt is (re)occured (a new sensor event), the internal do loop (the 120.000 ms = 2 min delay) always restarts, and stays here, regardless of the adc value since it is not measured here.

In other words, if the sensor signal switching is repeated within two minutes, the program remains in the internal timer loop and never get to the LED off.

The vibration sensor is likely provides repeating signals I think.

I do not know exactly what you want, but you have to change your program logic, for example, be sure to turn off the LED over a given ADC value, regardless of the value of the timer counter.

Other: what compiler you are using? What does exactly the Button function? Is it a debounced pin-reading? I do not like such high-level things because I don't know exactly what's happening...

zuisti
 

The Button command is for debouncing as the switch that I'm using has two rolling balls inside it and does not instantaneously change its state when tilted/vibrated.
I was afraid of. In my opinion this Button function is unsuitable for read such a repeating signal, since it gives (can give) a random result due to its operation principle (the debouncing), when the signal is oscillating. Instead use an another method, eg a flag, see below.

GP1 - a vibration sensor switch (Shot Circuit when there is no vibration) tied to ground with a resistor tied from this pin to +5V
It is not clear to me (sorry), what's the GP1 pin's resting state (when no vibration). Is it LOW?


Once again I suggest you to modify your program flow according to my above posts. And (for example) use a "changed" flag in the interrupt routine (clear it outside, repeatedly if necessary), and do not turn on and off the interrupt.

Granted, this is not such as easy task as seems (many pitfalls, to resolve them use other flags also), but try it.
Good luck ...
zuisti
 
GP1 resting state is LOW. I have it set to check if there's any change in state to reset the counter as it is to be used in a moving car and will vibrate constantly when in motion. The goal is to check this input for any change and if GP0(dark) is LOW then turn off the LEDs.

I'm new to PICs and I'm not familiar with the "changed" flag and how start using it. Examples or links to them would help.
 

... I'm not familiar with the "changed" flag and how start using it. Examples or links to them would help.
In my opinion you could do, have to a bit of logic.
But OK, contrary to my principles, now I wrote to you a whole program, hope it will help:

Code Visual Basic - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
' PIC12F683 Led control, using darkness and vibration sensor
' Written by zuisti, copyright © Istvan K. 2013
 
dim DarkValue, DarkCompare, Count as word
' DarkValue will be compared by a "software Schmitt-trigger"
' to avoid any switching uncertainties at dusk or at dawn :-)
#define DARK 286 ' switching point (value)
#define HYST 5   ' switching hysteresis (now appr +- 2% ?)
 
dim Changed_fl  as bit ' set in interrupt (sensor 'event' was occured)
dim LedState_fl as bit ' to avoid undesirable IOC resets
 
sub procedure Interrupt
  if GPIF_bit = 1 then
    ' an "anti-prell" loop (micro-debouncing)
    do
      GPIO.B3 = 1 ' no Temp but an unused input-only pin
      ' Any access to the GPIO register will reset the IOC
      GPIF_bit = 0      ' try to clear the Interrupt flag (in a loop)
      GPIO.B3 = 1
    loop until GPIF_bit = 0
    Changed_fl = 1      ' indicates a new sensor input changing (vibrating?)
  end if
end sub
 
main:
  ANSEL = %00000001   ' Set AN0 as analog and the rest digital
  ADCON0 = %00000001
  CMCON0 = 7
 
  TRISIO = %00000011  ' Set GP0 and GP1 as inputs , GP2 as output
  GPIO.B0 = 1         ' Initial GP0 value -> Input Dark Sensor
  GPIO.B1 = 1         ' Initial GP1 value -> Input Vibration Sensor
  GPIO.B2 = 0         ' Initial GP2 value -> Output LED
  Count = 0           ' Initialize count
  Changed_fl = 0
  LedState_fl = 0
  DarkCompare = DARK
  IOC1_bit = 1        ' Enable Interrupt-on-change feature at GP1
  GPIE_bit = 1        ' Enable peripheral interrupts
  GIE_bit = 1         ' lastly enable global interrupts
 
  while TRUE          ' main loop
 
    ' determine and compare darkness in every cycle
    DarkValue = ADC_read(0)
    ' the "software Schmitt-trigger":
    ' assuming a photoresistor type darkness sensor, which 
    ' gives a higher voltage when the darkness is increasing.
    if DarkValue < DarkCompare then
       ' no darkness
       DarkCompare = DARK + HYST ' positive feedback
       Count = 0
       GPIO.B2 = 0    ' always turns off the LEDs
       LedState_fl = 0
       Delay_ms(12)   ' need ?
       Changed_fl = 0 ' ignore any sensor changing
       continue       ' again
       ' if no "continue" in this language then use a goto or a big else, instead
    end if
    DarkCompare = DARK - HYST    ' the other direction positive feedback
 
    if Changed_fl = 0 then
       ' sensor resting state, timed led-off if it's on
       Inc(Count)
       if Count = 1200 then  ' 2 min delay to off
          Count = 0          ' Reset counter
          if LedState_fl = 1 then
             'to avoid undesirable GPIO accesses (IOC resets), only once:
             GPIO.B2 = 0       ' Turns off the LEDs
             LedState_fl = 0
          end if
       end if
    else ' (sensor 'event' was occured)
       Changed_fl = 0
       Count = 0            ' every (new) changing resets the counter
       if LedState_fl = 0 then
          LedState_fl = 1
          'to avoid undesirable GPIO accesses (IOC resets), also only once:
          GPIO.B2 = 1     ' Turn on transistor to power the LED board
       end if
    end if
    ' enough time to receive a new changing if any (to avoid led flashing?)
    Delay_ms(100)
 
  wend ' end main loop
end


I do not know the mikroBasic compiler, but hope that the program is syntactically correct and runs as you wanted. Your original program was used as a skeleton ...
Try it (I cannot), and let us know the outcome.

zuisti
 
Thanks Zuisti.

I went through your modifications to try to understand the logic. I tested the code with my circuit but it produces inconsistent behavior. The LEDs flicker for a fractioin of a second each time the sensor is vibrated in the dark. Could there be a point where GP2 is being turned off before the counter is reset?
 

The LEDs flicker for a fractioin of a second each time the sensor is vibrated in the dark.
Hi. I'm surprised because the program itself can not do such a thing.
I'm sure the problem lies elsewhere ...
Could there be a point where GP2 is being turned off before the counter is reset?
Such a point does not exist in the program, as you also can (not :)) see. In addition to the counter expiry only the light growth (decreasing of the 'DarkValue') or a full system restart can turn off the LED.
Just some malfunctions can cause such unexpected periodic switch-off.

Most likely the PIC (the program) restarts periodically by the watchdog. Are you sure the watchdog is off in the PIC's CONFIG word? Examine the project settings and your burning program settings too.

Malfunction can be caused by a lot of hardware deficiencies too. For example:
- unstable external quartz oscillator (if any)
- too sensitive reset circuit
- too long or not filtered wiring
- wrong or missing filter capacitors (on adc input too)
- switched load is too high (try only one LED)
- too weak or not sufficiently filtered power supply
- other impulse disorders (eg due to ground loops)

I suggest you to do a simple experiment:
Temporarily ground the ADC input pin (GP0) to simulate a constant high light and to exclude the possible ADC and sw comparing errors. Now, if so the program works well then you can exclude out almost all of above kinds of HW mistakes.
But if the LED flashes as before, it is almost certain the HW error.

That's it! See you next year.
Happy New Year!
zuisti
 
Last edited:
Apparently, yesterday I was already in an alcoholic mood :wink:. Of course, the suggested experiment should simulate a constant darkness: should be temporarily removed the photo sensor to force the GP0 pin to +5v (not to 0v). Sorry.
 
Zuisti,

Happy New Year! Now that I too have settled have expelled all the festive drinks I can now conduct the experiment as you suggested. I will let you know how I fair.
 

Hey,

I did as you suggested and removed the phototransistor from GP0 (ADC input) to force it HIGH. With GP0 set at high the circuit works fine, but when the phototransistor is added there is flickering. I added a 0.1uF filter capacitor from this pin to ground and is seems to stop/reduce the frequency of the flickering. The LEDs turn on for about a second then turn off when it is not completely dark, but works perfectly when the phototransistor is completely dark.
 

I added a 0.1uF filter capacitor from this pin to ground and is seems to stop/reduce the frequency of the flickering. The LEDs turn on for about a second then turn off when it is not completely dark.
It seems your analogue input signal is unstable. I wrote above:

Malfunction can be caused by ...
...
- wrong or missing filter capacitors (on adc input too)
...
- other impulse disorders (eg due to ground loops)


You have to apply a big filter capacitor (eg 1 uF tantalum) on the GP0 pin (to GND).
It can not be that the light of the LEDs is sensed by the phototransistor? This would be a classic light-feedback oscillator :???:

But the good news is that (seems) can be excluded all the other HW error, the watchdog is also switched off.

Try to measure the (yet unfiltered) analog signal with an external sensitive DVM too. The value must be very (!) stable if the external light does not change.

As a last resort, you could try to remove the "software Smitt-trigger" operation: have to comment out the 52 and 61 lines (hysteresis removing). But I do not think that's the problem, even ...
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top