Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC 16F887 sleep mode and timer 0 interrupt

Status
Not open for further replies.

revave

Member
Hello,

I have a problem with the combination of the sleep mode functionality and a timer 0 interrupt with a PIC16F887.

My wish is as followed:
For normal use in the program i am using a timer 0 interrupt for creating a 1 second pulse.
As soon as porta.5 will be high, the PIC has to go in sleepmode. A signal change at portB.7 has to wake up the PIC.
So, timer 0 will NOT be used for wake up function and can be stopped during sleep mode!
If i only program the sleep and awake function without the interrupt config for timer 0 it works fine.
But together with the timer 0 interrupt configuration it doesn't work properly.
This is what happens:

'pic is just starting up when portB.7 is connected to GND
'Also the t0 interupt and sleepmode is working.
'As soon as portb.7 is diconnected from GND, the PIC will not work properly
'It seems to me that the main program is not running and only the interrupt routine is working very fast
'Porta.0 - porta.6 are connected to GND

Does anyone have any idea what is going wrong here?

Below the complete code of my test program

Regards,
Reijnko

Code:
'PIC16F887;  crystal 20Mhz; LCD 16x1
Define CONFIG = 0x23c2
Define CONFIG2 = 0x3eff
'Define SIMULATION_WAITMS_VALUE = 10  'Only for testing
AllDigital
Define CLOCK_FREQUENCY = 20

TRISA = %11100000  'PORTA.5,6 and 7 as inputs, others as outputs
TRISB = %11111111  'PORTB as inputs

'Sleepmode wake up configuration at portb.7
INTCON.RBIE = 1  'Set port B interupt
IOCB.IOCB7 = 1  'Use portb.7 for interrupt on change
OPTION_REG.NOT_RBPU = 0  'Enable pullupps voor portb

'Timer0 Registers:
'Prescaler=1:32; TMR0 Preset=100; Freq=1.001,60256Hz; Period=0,9984 ms
OPTION_REG.T0CS = 0  'bit 5 TMR0 Clock Source Select bit:0=Internal Clock (CLKO) / 1=Transition on T0CKI pin
OPTION_REG.T0SE = 0  'bit 4 TMR0 Source Edge Select bit: 0=low/high / 1=high/low
OPTION_REG.PSA = 0  'bit 3 Prescaler Assignment bit: 0=Prescaler is assigned to the Timer0
OPTION_REG.PS2 = 1  'bits 2-0  PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0
OPTION_REG.PS0 = 0
TMR0 = 100  'preset for timer register

'interrupts configuration for timer 0
INTCON.GIE = 1  'global interrupt enable
INTCON.PEIE = 1
INTCON.T0IE = 1  'timer 1 interrupt enable
INTCON.T0IF = 0  'timer 1 interrupt flag
Enable

'lcd configureren
Define LCD_BITS = 4  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTD
Define LCD_DBIT = 4  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 2
Define LCD_EREG = PORTD
Define LCD_EBIT = 3
Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device

'initialize LCD module;
Lcdinit 0
Lcdcmdout LcdClear  'clear LCD display
Lcdcmdout LcdLine2Pos(1)
Lcdout "Running     "

'declare variabelen
Dim dummy As Byte  'for sleepmode
Dim sec_cnt As Word
Dim cnt As Word
Dim val As Byte

'init
cnt = 0
sec_cnt = 0
'__________
main:
Lcdcmdout LcdLine1Pos(1)
Lcdout #sec_cnt

If PORTA.5 = True Then Gosub sleep
val = val + 1  'main program running counter
Goto main
End
'__________
                               
sleep:
Lcdcmdout LcdLine2Pos(1)
Lcdout "Sleep   "
PORTA = 0  'disable output portA
dummy = PORTB
INTCON.RBIF = 0  'reset interrupt flag
ASM:        sleep  'bring PIC in sleep mode
Lcdcmdout LcdLine2Pos(1)
Lcdout "Running "

Return                                       
'__________
On Interrupt  'called by timer 0 (or by wake up from sleepmode)
Save System
INTCON.T0IF = 0  'reset interrupt flag

cnt = cnt + 1  'interrupt counter (about 1 ms)

If cnt >= 1000 Then  'about 1 second
    sec_cnt = sec_cnt + 1  'increase seconds counter
    cnt = 0
    Toggle PORTA.0  'visualising interrupt counter is working
Endif

TMR0 = 100
Resume
'__________                                 
'pic is just starting up when portB.7 is connected to GND
'Also the t0 interupt and sleepmode is working.
'As soon as portb.7 is diconnected from GND, the PIC will not work properly
'It seems to me that the main program is not running and only the interrupt routine is working very fast
'Porta.0 - porta.6 are connected to GND
 
Last edited:
The IOC interrupt is a bit weird... If you change the port for any reason the interrupt will only fire once!! You need to read the port to clear the interrupt.

I'm not saying this is the fault, only make sure you read PORTB after wake up!
 
Hello Ian,

I knew about the IOC mistake of PORTB.
There seems to be a conflict between the INTCON.RBIE bit and the timer 0 interrupt.
If i load the PIC with only the sleep routine or only the timer 0 interrupt routine, both functions are working fine.
But together it doesn't work.. Only if i disable the INTCON.RBIE = 1 instruction, the program runs with the interrupt. Of course the wake up function will not work in this situation... Just to be clear for everyone, i work with a real device. Not with the simulator, because the sleep instruction will only stop the simulation, without the possibility to wake up (and thus start the simulation)..
 
Okay... Finished messing..

When you wake the device from sleep the interrupt is constantly firing... That's why the LED goes nuts..

Two fixes are available to you... A) only enable the RBIE before the sleep and re-enable after wakeup.
OR!!! read the portb directly in the interrupt

I used the later..

Code:
'PIC16F887;  crystal 20Mhz; LCD 16x1
Define CONFIG = 0x23c2
Define CONFIG2 = 0x3eff
'Define SIMULATION_WAITMS_VALUE = 10  'Only for testing
AllDigital
Define CLOCK_FREQUENCY = 20

TRISA = %11100000  'PORTA.5,6 and 7 as inputs, others as outputs
TRISB = %11111111  'PORTB as inputs

INTCON.RBIE = 1  'Sleepmode wake up configuration at portb.7
IOCB.IOCB7 = 1  'Use portb.7 for interrupt on change
OPTION_REG.NOT_RBPU = 0  'Enable pullupps voor portb

'Timer0 Registers:
'Prescaler=1:32; TMR0 Preset=100; Freq=1.001,60256Hz; Period=0,9984 ms
OPTION_REG.T0CS = 0  'bit 5 TMR0 Clock Source Select bit:0=Internal Clock (CLKO) / 1=Transition on T0CKI pin
OPTION_REG.T0SE = 0  'bit 4 TMR0 Source Edge Select bit: 0=low/high / 1=high/low
OPTION_REG.PSA = 0  'bit 3 Prescaler Assignment bit: 0=Prescaler is assigned to the Timer0
OPTION_REG.PS2 = 1  'bits 2-0  PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0
OPTION_REG.PS0 = 0
TMR0 = 100  'preset for timer register

'interrupts configuration for timer 0
INTCON.GIE = 1  'global interrupt enable
INTCON.PEIE = 1
INTCON.T0IE = 1  'timer 1 interrupt enable
INTCON.T0IF = 0  'timer 1 interrupt flag
Enable

'lcd configureren
Define LCD_BITS = 4  'allowed values are 4 and 8 - the number of data interface lines
Define LCD_DREG = PORTD
Define LCD_DBIT = 4  '0 or 4 for 4-bit interface, ignored for 8-bit interface
Define LCD_RSREG = PORTD
Define LCD_RSBIT = 2
Define LCD_EREG = PORTD
Define LCD_EBIT = 3
Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 100  'delay used by LCDINIT, default value is 100
'the last three Define directives set the values suitable for simulation; they should be omitted for a real device

'initialize LCD module;
Lcdinit 0
Lcdcmdout LcdClear  'clear LCD display
Lcdcmdout LcdLine2Pos(1)
Lcdout "Running  "

'declare variabelen
Dim dummy As Byte  'for sleepmode
Dim sec_cnt As Word
Dim cnt As Word
Dim val As Byte

'init
cnt = 0
sec_cnt = 0
'__________
main:
Lcdcmdout LcdLine1Pos(1)
Lcdout #sec_cnt

If PORTA.5 = True Then Gosub sleep
val = val + 1  'main program running counter
Goto main
End   
'__________

sleep:
Lcdcmdout LcdLine2Pos(1)
Lcdout "Sleep  "

PORTA = 0  'disable output portA
dummy = PORTB
INTCON.RBIF = 0  'reset interrupt flag

ASM:  sleep  'bring PIC in sleep mode
Lcdcmdout LcdLine2Pos(1)


Lcdout "Running "

Return   
'__________
On Interrupt  'called by timer 0 (or by wake up from sleepmode)
Save System
dummy = PORTB  ' <----- Here
INTCON.RBIF = 0 '<------And Here
INTCON.T0IF = 0  'reset interrupt flag

cnt = cnt + 1  'interrupt counter (about 1 ms)

If cnt >= 1000 Then  'about 1 second
sec_cnt = sec_cnt + 1  'increase seconds counter
cnt = 0
Toggle PORTA.0  'visualising interrupt counter is working
Endif

TMR0 = 100
Resume   
'__________
'pic is just starting up when portB.7 is connected to GND
'Also the t0 interupt and sleepmode is working.
'As soon as portb.7 is diconnected from GND, the PIC will not work properly
'It seems to me that the main program is not running and only the interrupt routine is working very fast
'Porta.0 - porta.6 are connected to GND
 
Hello Ian,

Thanks for your reply and good work!
Your solution works very fine. With this solution I can still use the pins of portb in the main program...
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top