/* FOR EDUCATIONAL PURPOSES ONLY A TECHNIQUE IS USED THAT IS CONTRARY TO DOCUMENTED INFORMATION BY MICROCHIP AND SO MAY RESULT IN LEGAL LIABILITY. IF LEGAL LIABILITY IS A REAL POSSIBILITY THEN USE ANOTHER APPROACH OR ANOTHER CHIP Sample C program to demonstrate wake up from sleep of a PIC16F886 with UART functionality WITHOUT an additional break character. The chip MUST be configured correctly to use the fast internal oscillator directly and not as a fall back oscillator. For simplicity a globally enabled interrupt is NOT used, even though an individually enabled interrupt is used as wake up source. However a non demo program would use an interrupt that has been globally enabled. All that is required to use a globally enabled interrupt and so interrupt jump code is to also set the GIE bit. Pin RB1 goes low while chip is asleep and goes high chip is awake. Demo board used is from the PIC kit Serial Analyzer. Debugger ued is the PIC kit 2 Debug Express. On the kit RB1 is conencted to LED DS2. No C libraries used to enhancce portability between C compilers PICC STD that comes with a CDROM from Microchip will not work for a PIC16F886 Howevere there is a replacement for this compiler from http://microchip.htsoft.com/products/compilers/piccpro-modes.php Numerous other compilers should also work. There are plenty to choose from If using the Serial Analyzer then avoid sending multiple characters as simulataneous communication in both directions will occur which the Serial Analyzer has problems with. If using the Serial Analyzer with Hidprobe then Hidprobe will close the port. This problem did not occur with an FTDI chip with Hidprobe. Please note using sleep with a debugger may cause problems requiring reconnects With this software, Vdd at 3.0 to 5.0 volts and a plain breadboard in use, current consumption was measured as low at 0.1 or 0.2 micro amps during sleep. For this test unused pins were left as outputs and driven low. Tested at 2400, 57600 and 115200. Both 2400 and 57600 appear to be reliable, 115200 not so. Default BAUD is now 57600 Power tests with the PICkit serial attached will not be valid If the receive pin RC7 (pin 18) is left unconnected then chip will not go to sleep or will keep waking up. If using a breadboard to test power consumption then tie this pin high Two solutions if a serial connection will only be temporary: connect a pull up resistor or connect also to an input pin which has its weak pull up turned on. PIC non break uart low power wake up Version 0.4, 12 January 2009, different BAUD rates tried. Appears reliable up to 57600 but not so at 115200 Version 0.3a, 12 January 2009, fix for file not compiling. Programmer loaded previous version and so previous measurments were invalid. Measured power now as expected or better Version 0.3, 20 December 2008 Version 0.2a, 10 December 2008 Updates to be posted on http://www.zgus.com/pic Reanme file downloaded from http://www.zgus.com/pic/pic_breakless_wakeup_c.txt to pic_breakless_wakeup.c to use in a compiler and IDE Author: John Heenan, Auscyber Pty Ltd Copyright 2008 Auscyber Pty Ltd. All rights reserved. ZGUS is a trading name of Auscyber Pty Ltd No Warranty: No warranty of any kind, such as no warranty of fitness for any purpose, incsluding no warranty of fitness for merchantability. No Liability: Auscyber Pty Ltd shall not be liable for any damage or harm the software may cause by its use, whether from faults or not, - including direct, indirect, incidental, consequential, loss of business profits or special damages Should you have any questions regarding your right to use this Software, contact Auscyber Pty Ltd T/A ZGUS at www.zgus.com. */ #include //for HTC this uses PIC16f887.h for PIC16f886 //The line below with INTIO is ESSENTIAL to ensure the internal osciallator is chosen straight away //instead of being chosen as a backup when another specified oscillator fails //INTIO means internal oscillator with I/O on both OSC1/CLKIN and OSC2/CLKOUT __CONFIG(INTIO & WDTDIS & PWRTDIS & MCLREN & UNPROTECT & DUNPROTECT & BORDIS & IESOEN & FCMDIS & LVPDIS & DEBUGEN); __CONFIG(BORV21 /*& WP0*/); //#define BAUD 2400 #define BAUD 57600 //#define BAUD 115200 #define FOSC 8000000L //internal oscillator frequency char rx(void) { char ch=0; while(RCIF)//empty the buffer (max 2 characters) ch=RCREG;//reading clears RCIF if(OERR)//get rid of any overflow error { CREN=0; CREN=1; } return ch; } void tx(char ch) { while(!TXIF);//wait for TX register to become free TXREG=ch; } void txputs(const char *str) { const char *p=str; char ch; while(ch=*p++) tx(ch);//or TXREG=ch; } volatile char vtemp;//volatile temp to ensure compiler will not optimise away any usage of vtemp void main(void) { INTCON=0; //disable interrupts IRCF0=1;//change FOSC to 8MHz //for low power measurements (chip removed from demo board also) ANSEL=0; ANSELH=0; TRISA=0; PORTA=0; TRISB=0; PORTB=0; TRISC=0; PORTC=0; TRISE=0;//for PIC16F887 PORTE=0; //RC6=1;TRISC6=0;//in case the UART is reset (such as to clear FERR using SPEN), maintain TX pin high //also consider connecting RC7 (RX pin) to an input pin with its weak pull up //turned on (with nRBPU cleared in OPTION register) in case nothing else connected BRG16=1; #if BAUD==115200 SPBRG=16;//2.12% error #elif BAUD==57600 SPBRG=34;//-0.79% error #elif BAUD<=19200 && BAUD >=300 SPBRG = (unsigned char)(FOSC/(4 * BAUD) -1); //4 as BRG16=1 and BRGH=1 SPBRGH= (unsigned char)(((FOSC/(4 * BAUD) -1))>>8); #else #error "Review BAUD rate calculations" #endif RCSTA = 0x90;//SREN=1|CREN=1 TXSTA = 0x24;//TXEN=1|BRGH=1 TRISB1 = 0;//RB1 is output. skipping RB0 to leave free for external interrupt //ANS10 = 0;//make RB1 a digital input pin: not required for digital output use RB1=1;//pin RB1 set high: not asleep RCIE=1;PEIE=1;//ensure an individual interupt will wake up chip even interrupts not globally enabled //GIE bit is NOT set for simplicty. Interrupts can still wake the chip up though txputs("\nPress a key to wake me up from sleep without a break and it will be echoed back"); //FERR errors are not cleared while(1) { if(!RCIF) { while(!TRMT);//make sure TSR register is empty before shutting oscillator down WUE=1;//allow a falling edge or a low to set RCIF early, even while oscillator is off and so wake up chip RB1=0;//pin RB1 set low tp show asleep asm("sleep");//send chip to sleep by stopping its oscillator //according to PIC16f886 data sheet, fast oscillaotr is ready in typically less than 10 microceconds //if nPD of STATUS register is set after a sleep then sleep executed as a NOP due to a posted interrupt RB1=1;//pin RB1 set high as not asleep any more while(!RCIF);//get rid of early RCIF before character received due to set of WUE //while used due to a possible boundary change issue vtemp=rx(); while(!RCIF);//wait for the real RCIF as the wake up character continues txputs("\nRB1 low when asleep. Woke up without a break character. Received: "); tx(rx());//echo character back } else vtemp=rx();//only process received characters that woke up the chip } }