PIC16F505 won't go to sleep. - SOLVED! - Page 1
Forum section: electronics / general

author: Ralph S.
author_rank: Newbie
timestamp: December 05, 2015, 08:30:32 pm
content: Hi!I'm currently working on a small 5x6 LED matrix, driven by a PIC 16F505. The problem is it won't enter sleep mode when (I think) it should. The program displays 3 messages.In theory:If the button is pressed the PIC wakes up and displays message#1 and then enters sleep mode, unless the button is pressed again. If so message#2 is displayed, and after it finishes scrolling, PIC is going to sleep. If the button is pressed one more time (while displaying m#2) message#3 appears and finally PIC can enter sleep mode (this time for good).What happens is:After it finishes scrolling through message#1 it immediately repeats it, on and on.If I press the button while displaying m#1 for the first time, message#2 appears. When m#2 is done, m#1 comes back again. Pressing the button causes m#1 to reset and start over.If I somehow manage to get to message#3 it finally ends and the PIC enters sleep mode (I think).I bet there's some extremely stupid newbie mistake, but I can't figure it out. Can You please help me? Thank you in advance.MPLab8.92, XC8 v1.33, PICKit3Config bits set in MPLabCode:#include <pic16f505.h>#include <xc.h>#define _XTAL_FREQ 4000000void txt(const char array[], char size);const char m1 = {hex numbers, 1 byte = 1 column};const char m2 = {...};const char m3 = {...};char t=0;char dummy;void main(void){OPTION=0b01010111; //wake-up on pin change enabled, T0 source is internal oscTRISC=0;TRISB=0b00001000;//all output except RB3t=0; //this variable changes the displayed messagesif(t==0) txt(m1, 74);if(t==1) txt(m2, 57);if(t==2) txt(m3, 107);PORTB=0;PORTC=0; //clear all before sleepdummy=PORTB; //read the port, required for wake-up on pin changeasm("sleep");//goodnight, sleep tight}void txt(const char array[], char size){char i=0; //column pointerwhile(i<size) //work 'till we run out of bytes in array{for(char k=0; k<5; k++) //display each frame 5 times{for(char j=0; j<6; j++) //displaying 1 frame - multiplexing 6 columns{PORTB=0;PORTC=0;PORTC=array[i+j]; //choose proper byteif(j==0) RC5=1; //enable column0if(j==1) RB4=1; //enable column1if(j==2) RB5=1; //etc...if(j==3) RB0=1;if(j==4) RB1=1;if(j==5) RB2=1;__delay_ms(2);}}i++; //shift everything leftif(RB3==0) //if button is pressed...{t++; //...move on to next message...i=0xff; //...but first exit this 'while' loop, since 255 is always greater than 'size'}}}

author: Andy Watson
author_rank: Super Contributor
timestamp: December 05, 2015, 09:03:10 pm
content: When the processor has been woken from sleep, what is it expected to do?I'm not familiar with the compiler but I think you want to implement something like:Code:#... as before ...t=0; //this variable changes the displayed messageswhile (1) {if(t==0) txt(m1, 74);if(t==1) txt(m2, 57);if(t==2) txt(m3, 107);PORTB=0;PORTC=0; //clear all before sleepdummy=PORTB; //read the port, required for wake-up on pin changeasm("sleep");//goodnight, sleep tight} // end of while loop to catch process when sleep expires... etc.

author: mikeselectricstuff
author_rank: Super Contributor
timestamp: December 05, 2015, 09:13:19 pm
content: QuoteWhy would you not set the config in the code?Remember the WDT will wake from sleep and start executing after the SLEEP instruction.You code exits from main, which is an undefined action.

author: Ralph S.
author_rank: Newbie
timestamp: December 05, 2015, 09:40:55 pm
content: Thank you for your replies.The datasheet says that the device resets on wake-up. I thought that after it wakes up it starts from the beginning and I could get away without the main loop.I'll put the config line in the code (I was too lazy back then, but now it does seem like a bad idea). The Watchdog Timer is disabled - this is not a crucial application, so why bother?I'll try to fix the code and program the thing tomorrow.

author: Andy Watson
author_rank: Super Contributor
timestamp: December 05, 2015, 09:56:07 pm
content: Quote from: Ralph S. on December 05, 2015, 09:40:55 pmYes, I believe you're right - I was forgetting this is the 5xx family In that case, I think you need to make the setting of "t=0" dependent on the cause of the reset.

author: Ralph S.
author_rank: Newbie
timestamp: December 06, 2015, 03:12:31 pm
content: Hah! I've got it! Just as I expected it was a foolish mistake.The program couldn't exit whe 'while' loop in 'txt' function. The loop condition was (i<size), but a few lines later the program grabbed 'i+1'th, 'i+2'th (... etc.) element of the array. If the given array's size was for example 74, and the loop counted to 73, it loaded the 74+j'th element. Also it happened that the 'txt' function was stored just next to message#1 array in the memory, so when the program reached out of its boundary the function repeated itselfI've changed the condition to (i<(size-5)) and the problem is goneNo need for an infinite loop in main, because the processor starts over after it wakes up.Was:Code:void txt(const char array[], char size){char i=0;while(i<size) //if 'i' gets any near to 'size'...{for(char k=0; k<5; k++){for(char j=0; j<6; j++){PORTB=0;PORTC=0;PORTC=array[i+j]; //...we reach to '(size+1)'th element which happens to be the 'txt' function addressif(j==0) RC5=1;if(j==1) RB4=1;if(j==2) RB5=1;if(j==3) RB0=1;if(j==4) RB1=1;if(j==5) RB2=1;__delay_ms(2);}}i++;if(RB3==0){t++;i=0xff;}}}Should be:Code:oid txt(const char array[], char size){char i=0;while(i<(size-5)) // now it stays within its boundary{for(char k=0; k<5; k++){for(char j=0; j<6; j++){PORTB=0;PORTC=0;PORTC=array[i+j];if(j==0) RC5=1;if(j==1) RB4=1;if(j==2) RB5=1;if(j==3) RB0=1;if(j==4) RB1=1;if(j==5) RB2=1;__delay_ms(2);}}i++;if(RB3==0){t++;i=0xff;}}I hope that someone will learn from my silly mistake. One again, thank you all for taking your time to help me