C PROGRAMMING LANGUAGE 1143 TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION void Delay100TCYx(unsigned Delay in multiples of 100 instruction cycles. char units) void Delay1KTCYx(unsigned Delay in multiples of 1,000 instruction cycles. char unit) void Delay10KTCYx(unsigned Delay in multiples of 10,000 instruction cycles. char unit) void DisablePullups(void) Disable PORTB’s internal pull-up resistors. unsigned char EEAckPolling(#) Generate acknowledge for Microchip EEPROM (unsigned char control) I2C memory devices. unsigned char EEByteWrite(#) Write a single byte to the Microchip EEPROM (unsigned char control, I2C memory device. unsigned char address, unsigned char data) unsigned int Read a single byte from the Microchip EEPROM EECurrentAddRead(#) I2C memory device. (unsigned char control) unsigned char EEPageWrite(#) Write a string of data to the Microchip EEPROM (unsigned char control, I2C memory device. unsigned char address, unsigned char * wrptr) unsigned int EERandomRead(#) Read a single byte from an arbitrary address (unsigned char control, from a Microchip EEPROM I2C memory unsigned char address) device. unsigned char Read a string of data length long starting at an EESequentialRead(#) arbitrary address in a Microchip EEPROM I2C (unsigned char control, memory device. unsigned char address, unsigned char * rdptr, unsigned char length) void EnablePullups(void) Enable PORTB’s internal pull-up resistors. unsigned char getsI2C(#) Read a fixed-length string from the I2C(#) bus (unsigned char * rdptr, operating in master I2C mode. unsigned char length) void getsMwire(#) Read a string from the Microwire device. (unsigned char * rdptr, unsigned char length) void getsSPI(#) Read a string from the SPI bus. (unsigned char * rdptr, unsigned char length) ( Continued ) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1144 APPENDIX F TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION void getsUART(char * Read a string from the software USART. buffer, unsigned char len) void gets(#)USART(char * Return a string from the specified USART. buffer, unsigned char length) void IdleI2C(#)(void) Return when specified I2C bus is available. char isBOR(void) Returns nonzero if reset was caused by a brown-out detect. unsigned char iscntrl Return nonzero if the character is a control (unsigned char ch) character. unsigned char isgraph Return nonzero if the character is a graphic (unsigned char ch) character. unsigned char islower Return nonzero if the character is a lower-case (unsigned char ch) alphabetic character. char isLVD(void) Returns nonzero if reset was caused by low- voltage detect. char isMCLR(void) Returns nonzero if reset was caused by MCLR pin. char isPOR(void) Returns nonzero if reset was caused by power-on reset. unsigned char Return nonzero if the character is printable. isprint(unsigned char ch) unsigned char Return nonzero if the character is a punctuation ispunct(unsigned char ch) character. unsigned char Return nonzero if the character is a white isspace(unsigned char ch) space character. unsigned char Return nonzero if the character is an isupper(unsigned char ch) upper-case alphabetic character. unsigned char Return nonzero if the character is a isxdigit(unsigned char ch) hexadecimal digit. char isWDTTO(void) Return nonzero if reset was caused by watchdog timer timeout. char isWDTWU(void) Return nonzero if reset was caused by wakeup caused by the watchdog timer. char isWU(void) Return nonzero if reset was caused by sleep wakeup through MCLR or interrupt. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com C PROGRAMMING LANGUAGE 1145 TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION char * itoa(int value, Convert a 16-bit signed integer to a string. char * string) char * ltoa(long value, Convert a signed long integer to a string. char * string) void NotAckI2C(#)(void) Generate I2C not acknowledge condition. void OpenADC(unsigned char Select the pin to connect the ADC and enable config, unsigned char config2) the ADC in the correct mode; see documentation for config and config2 values for different devices. void OpenCapture#(unsigned Configure and enable input capture #. char config) void OpenECapture# Configure and enable enhanced input (unsigned char config) capture #. void OpenI2C(#) Configure the SSP(#) module. (unsigned char sync_mode, unsigned char slew) void OpenMwire(#) Configure the SSP(#) module for Microwire (unsigned char sync_mode) operations. void OpenPORTB Configure PORTB’s interrupts and internal (unsigned char config) pull-up resistors. void Enable PORTB interrupt request hardware. OpenPORTB#INT(unsigned char config) void OpenEPWM1(char period) Configure the enhanced PWM channel. void OpenPWM#(char period) Configure the specified PWM channel. void OpenSPI(#) Initialize SSP(#) module for SPI (unsigned char sync_mode, communications. unsigned char bus_mode) void OpenSWSPI(void) Configure the I/O pins of the software SPI. void OpenTimer# Configure and enable timer#. (unsigned char config) void OpenUART(void) Configure the I/O pins for the software USART. void Open(#)USART Configure and enable the specified USART. (unsigned char config, unsigned int spbrg) ( Continued ) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1146 APPENDIX F TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION void OpenXLCD Configure PIC MCU I/O pins and initialize LCD (unsigned char lcdtype) controller. unsigned char putsI2C(#) Write a data string to the I2C(#) bus in either (unsigned char * wrptr) master or slave mode. void putsSPI(#) Write a string to the SPI(#) device. (unsigned char * wrptr) void putsUART(char * buffer) Write a string to the software USART. void puts(#)USART(char * Write ASCIIZ string of characters to the data) specified USART. void putrs(#)USART Write ASCIIZ string, defined in program memory, (const rom char * data) of characters to the specified USART void putsXLCD(char * buffer) Write a string to LCD controller. int rand(void) Return a pseudorandom integer. int ReadADC(void) Return the 16-bit result of the ADC operation. unsigned char Return the address byte from the LCD ReadAddrXLCD(void) controller. void ReadCapture# Read the result of a capture event from input capture #. void ReadECapture# Read the result of a capture event from enhanced input capture #. char ReadDataXLCD(void) Read a data byte from the LCD controller. unsigned char ReadI2C(#) Read a single byte from the I2C(#) bus; this (void) function also may be known as getcI2C(#). unsigned char ReadSPI(#) Read a single byte from the SPI(#) device; this (void) function also may be known as getcSPI(#). unsigned int ReadTimer# Read the value of Timer#. (void) char Read(#)USART(void) Read a byte from the specified USART; this function also may be known as getc(#)USART. char ReadUART(void) Read a byte from the software USART; this function also may be known as getcUSART. unsigned char ReadWire(#) Read a single byte from the Microwire(#) (unsigned char high_byte, device; this function also may be known as unsigned char low_byte) getcMwire(#). void RestartI2C(#)(void) Generate restart condition for the I2C(#) bus. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com C PROGRAMMING LANGUAGE 1147 TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION void SetCGRamAddr Specify the LCD character generator address. (unsigned char addr) void SetChanADC Select the channel to be used for the ADC (unsigned char channel) operation. void SetCSSWSPI(void) Set the software SPI interface’s chip select pin. void SetDDRamAddr Specify the LCD display data area address. (unsigned char addr) void SetOutputPWM# Set the PWM output configuration bits for ECCP. (unsigned char outputconfig, unsigned char outputmode) void SetOutputEPWM1 Set the enhanced PWM output configuration (unsigned char outputconfig, bits for ECCP. unsigned char outputmode) void srand(unsigned int seed) Specify the starting seed for the rand function. void StartI2C(#)(void) Generate a start condition for the I2C(#) bus. void StopI2C(#)(void) Generate stop operation for I2C(#) bus. char SWAckI2C(void) Generate an I2C bus acknowledge. char SWGetsI2C(unsigned char Read a string from the I2C bus. *rdptr, unsigned char length) char SWNotAckI2C(void) Generate an I2C bus not acknowledge. char SWPutsI2C(unsigned char Write a string to the I2C bus. *wrptr) char SWReadIC(void) Read a byte from the I2C bus; this function also may be known as SWGetcI2C. void SWRestartI2C(void) Generate an I2C bus restart condition. void SWStartI2C(void) Generate an I2C bus start condition. void SWStopI2C(void) Generates an I2C bus stop condition. char Write a byte to the I2C bus; this function also SWWriteI2C(unsigned char may be known as SWPutcI2C. dataout) char tolower(char c) Convert upper-case character to lower case or leave alone. char toupper(char c) Convert lower-case character to upper case or leave alone. ( Continued ) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1148 APPENDIX F TABLE F.8 MICROCHIP C18 C COMPILER LIBRARY FUNCTIONS (CONTINUED) FUNCTION PROTOTYPE DESCRIPTION void WriteCmdXLCD Write a command to the LCD controller. (unsigned char cmd) void WritedataXLCD Write a byte to the LCD data area. (char data) unsigned char WriteI2C(#) Write a single byte to the I2C(#) bus. (unsigned char data_out) unsigned char WriteMwire(#) Write a single byte to the Microwire(#) device. (unsigned char data_out) unsigned char WriteSPI(#) Write a single byte to the SPI(#) bus; this (unsigned char data_out) function also may be known as putcSPI(#). char WriteSWSPI(char data) Write a byte to the software SPI; this function also may be known as putcSWSPI. void WriteTimer# Write a value to timer#. (unsigned int tmr_value) void WriteUART(char data) Write a byte to the software USART; this function also may be known as putcUSART. void Write(#)USART(char data) Write a byte to the specified USART; this function also may be known as putc(#)USART. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1149 G REUSE, RETURN, AND RECYCLE The most efficient programmers I have ever met never write any new code. Instead, they have built up a library of code snippets that can be reused for different applications. These snippets are usually well known by the programmer in terms of operation, parameters, and peculiarities. In this appendix I have included a fair number of snippets and macros that I have found to be useful in developing my own PIC ® microcontroller applications. One of the biggest strengths of the PIC microcontroller is its ability to provide digi- tal input/output (I/O) efficiently in a number of different ways. This flexibility can be used to implement I/O functions in the PIC microcontroller that weren’t designed in orig- inally. As part of this appendix, I present a number of simple I/O “bit banging” func- tions that provide commonly required functions for the PIC microcontroller that can be included into your code along with the other snippets provided. The different features of the snippets can be modified for use in your applications with a bit of cut and pasting in an editor. You also should be able to find useful and clever code from other sources, including magazines, other books, and the Internet. This recy- cling of code is why I have named this appendix after the conservationist’s “three R’s.” While I’m not a total “free software” advocate, I do believe that small pieces of useful code should be shared freely to help and encourage others. In this spirit, I ask that if you find or develop a useful function out of a few instructions, please share it with other people. If you don’t know how to do this, you can share the code with a list-server (such as the PICList) community and let other people put it up on the Web for you. I’ll always be happy to look at what you have come up with. The most important piece of hardware in the PIC microcontroller used in applications is the I/O pins. When accessing the I/O pins, remember that there are three different ways of reading and writing them. The byte or port wide access method uses the movf and movwf instructions to read and write to the full I/O port. Along with these instructions, the arithmetic and bitwise instructions can be used with the port as the result’s desti- nation to simplify and optimize the operations. The second method is to access the I/O port pins individually using the bcf, bsf, btfsc, and btfss instructions. These instructions work well, but when using bcf Copyright © 2008, 2002, 1997 by The McGraw-Hill Companies, Inc. Click here for terms of use. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1150 APPENDIX G and bsf, remember that they also can change the output value of a bit if the port bit is at an unexpected or unwanted value. The last method is to use the rotate instructions rlf and rrf to pass data in and out of the I/O ports using the STATUS register’s carry flag. Using this method means that either bit 0 or bit 7 of the I/O port will be accessed, but this method is very effective and efficient. To do this, the I/O situation has to be planned so that shifting data in and out does not affect the operation of the output values of the I/O port. This is not hard to do—the most obvious way of doing it is to set the rest of the bits on a port as input. With a bit of planning, shifting can be done on mixed input and output very effectively. Useful Snippets Here are a number of useful pieces of code that you can use in your applications. In some cases, I am the originator of the code; in others, when I know who the originator was, I have given him or her credit. NEGATING THE CONTENTS OF A FILE REGISTER Converting the contents of a file register to its twos complement value without affect- ing the w register is simply accomplished by comf Reg, f ; Invert the bits in the Register incf Reg, f ; Add One to them to turn into 2’s ; Complement This code should not be used on any special hardware control registers. NEGATING THE CONTENTS OF THE W REGISTER If you have to negate the contents of the w register, you could use the preceding code (after saving the value in w into a register), or you could use for low-end devices (16C5x or 12C5xx) addwf Reg, w ; w = w + Reg subwf Reg, w ; w = Reg - w ; w = Reg - ( w + Reg ) ; w = -w Any file register can be used for this code because its contents are never changed. In mid-range parts, the single instruction sublw 0 ; w = 0 - w could be used. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com REUSE, RETURN, AND RECYCLE 1151 INCREMENTING/DECREMENTING THE W REGISTER Here are a couple of snippets that will allow you to increment and decrement the w reg- ister without affecting any file registers if you don’t have addlw/sublw instructions (i.e., in the case of low-end processors). Reg can be any register that does not change during execution of the three instructions. For low-end parts, any file register can be used because there is no danger of them being updated by an interrupt handler. To increment: xorlw 0x0FF ; Get 1s Complement of Number addwf Reg, w ; w = Reg + (w^0x0FF) subwf Reg, w ; w = Reg + ((Reg + (w^0x0FF))^0x0FF) + 1 ; w = w + 1 To decrement, the instructions are rearranged: subwf Reg, w ; w = Reg + (2^0x0FF) + 1 xorlw 0x0FF ; Get 1s Complement of Result addwf Reg, w ; w = w - 1 ROTATING A BYTE IN PLACE These two lines will rotate the contents of a file register in a low-end or mid-range PIC microcontroller without losing data in the carry flag. When working with the PIC18, the rlncf and rrncf instructions can be used for the same function. Rotates right and left can be implemented with this snippet. Note that the carry flag is changed. rlf Register, w ; Load Carry with the high bit rlf Register, f ; Shift over with high bit going low COPY BITS FROM ONE REGISTER TO ANOTHER Here is a fast way to save specific bits from one register into another: movf Source, w xorwf Destination, w andlw B’xxxxxxxx’ ; Replace “x” with “1” to Copy the Bit xorwf Destination, f CONVERTING A NYBBLE TO ASCII This is a question that comes up all the time when the contents of a byte are to be displayed/output. The most obvious way of doing this is to use a table read: NybbletoASCII: addwf PCL, f ; Add the Contents of the Nybble to PCL/ dt “0123456789ABCDEF” ; return the ASCII as a Table Offset Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 1152 APPENDIX G However, I think a much better way of doing this is NybbletoASCII: ; Convert a Nybble in “w” to ASCII addlw 0x036 ; Add ‘0’ + 6 to Value btfsc STATUS, DC ; If Digit Carry Set, then ‘A’ - ‘F’ addlw 7 ; Add Difference Between ‘9’ and ‘A’ addlw 0-6 return ; Return the ASCII of Digit in “w” This method will take three instruction cycles longer than the previous code, but it requires 12 fewer instructions. CONVERTING AN ASCII BYTE TO A HEX NYBBLE The code below is really a rearrangement of the preceding snippet. Using the aspect that the high nybble of ASCII A to F is one greater than the high nybble of 0 to 9, a value is conditionally added to make the result 0x000 to 0x00F. ASCIItoNybble: addlw 0x0C0 ; If “A” to “F”, Set the Carry Flag btfss STATUS, C ; If Carry Set, then ‘A’ - ‘F’ addlw 7 ; Add Difference Between ‘9’ and ‘A’ addlw 9 return ; Return the ASCII of Digit in “w” Note that ASCII characters other than 0 to 9 and A to F will result in an incorrect result. USING T0CKI AS AN INTERRUPT SOURCE PIN Some time ago, a question came up on the PICList asking if the timer input pin could be used as an interrupt source pin. The answer to this is yes—if the timer (and prescaler) is set up so that the next transition will increment the timer and cause an interrupt. Here’s some code to do it in a mid-range PIC microcontroller: movlw B’11000000’ ; First Setup with Instruction Clock option ; as TMR0 Source movlw B’11100000’ ; Option Setup for TOCK1 TMR0 Source clrf TMR0 ; Set TMR0 to 0x0FF decf TMR0, f option ; Enable Timer on Outside Interrupt ; Edge ; NOTE - Executing this Instruction ; after “decf” will Load the ; Synchronizer with a “1” Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... in where DataPort is the 8-bit I/O port EPort and EPin are the E clock definition RSPort and RSPin are the RS LCD data type input RWPort and RWPin are the pins used to poll the LCD for data reply (and are essentially unused) Frequency is the PIC microcontroller operating speed and is used to calculate the delay values The only variable required for the LCD8 and LCD8Poll macros is the 8-bit variable Dlay... into the w register and use the andlw and iorlw instructions to change the bit before writing the new value back to the register The intermediate value could initiate some hardware operation that is not desired Setting a bit by ANDing two others together is accomplished by bsf Result btfsc BitA btfss BitB bcf Result ; ; ; ; Assume the result is True If BitA != 1 then result is False If BitB == 0 then... Save the Result ORing two bits together is similar to the AND operation, except that the result is expected to be false, and when either bit is set, the result is true bcf Result btfss BitA btfsc BitB bsf Result ; ; ; ; Assume the result is False If BitA != 0 then result is True If BitB == 0 then result is False Result is True, Set the Bit The final operation is the NOT There are two ways of implementing... the maximum value possible for a bit value in DlayCount For example, setting bit 2 of DlayCount will cause the loop code to execute four times If bit 6 is used, DlayCount will loop 64 times Instead of dividing the total number by 3 (which is the number of loops required) and then loading the w register with the value (which changes the w register) and then writing to the DlayCount variable, I set the. .. where the input value is relative to the output value If they are the same (i.e., the operation is to complement a specific bit), the code to be used is simply movlw 1 . the total number by 3 (which is the number of loops required) and then loading the w register with the value (which changes the w register) and then writing to the DlayCount variable, I set the. sure that you read the register’s contents into the w register and use the andlw and iorlw instructions to change the bit before writing the new value back to the register. The intermediate value. reading and writing them. The byte or port wide access method uses the movf and movwf instructions to read and write to the full I/O port. Along with these instructions, the arithmetic and bitwise instructions