Tips For c18
Tips For c18
Basic Info:
Hello all, my name is Jason Lopez. I am the creator of this document and am also known as AtomSoft at various
locations. I have created this document to remind myself of certain things in the C18 programming language. I have a
bad memory and seem to forget a lot so I was thinking why not make a cheat sheet that I can print and use when i
program. Almost all the code in this booklet was compiled on a PIC18F2525 or PIC18F4525.
Bitwise Operators
AND OR XOR NOT RIGHT SHIFT LEFT SHIFT
& | ^ ~ >> <<
Interrupt (ISR)
High ISR Low ISR
#pragma code high_vector = 0x08 #pragma code low_vector = 0x18
void high_interrupt (void){ void low_interrupt (void){
_asm goto high_ISR _endasm _asm goto low_ISR _endasm
} }
Page 1
AtomSoftTech – C18 Tips & Tricks
Program Flow
If If-else Else-if For
Main Useful
Header for Auto PIC Define Pragma’s Inline ASM
#include <p18cxxx.h> #define label constant #pragma code [overlay] _asm … _endasm
[section-name] [location]
Bit Set/Clear
Code Example Outcome
#define bitset(var,bitno) (var|=1<<bitno) #define SpecialBit 2 MyVar would be 0 to start then after the bitset
unsigned char MyVar; command, MyVar equals 00000100.
#define bitclr(var,bitno) (var&=~(1<<bitno))
MyVar = 0;
bitset(MyVar,SpecialBit);
Delays – <delays.h>
Delay 1 Cycle aka NOP Delay 10 Cycles Delay 100 Cycles Delay 1,000 Cycles Delay 10,000 Cycles
Delay1TCY(); Delay10TCYx(n); Delay100TCYx(n); Delay1KTCYx(n); Delay10KTCYx(n);
PORTB - <portb.h>
ClosePORTB CloseRBxINT OpenPORTB OpenRBxINT
Disable the interrupts Disable the interrupts for Configure the interrupts and internal pull- Enable interrupts for the specified INTx
and internal pull-up the specified INTx pin. up resistors on PORTB. pin.
resistors for PORTB.
void ClosePORTB( void ); void CloseRB0INT( void ); void OpenPORTB( unsigned char config); void OpenRB0INT( unsigned char config );
void CloseRB1INT( void ); void OpenRB1INT( unsigned char config );
void CloseRB2INT( void ); void OpenRB2INT( unsigned char config );
Page 2
AtomSoftTech – C18 Tips & Tricks
Using Pointers
Using a Pointer: Get a String of characters
void main(void)
{
GetString((unsigned rom char*)" AtomSoftTech"); //Send the string AtomSoftTech as a Rom Char to the function
}
void GetString(unsigned rom char *datapointer) //The data is pointed to, using *datapointer rom char.
{
char CurrentCharacter; //Setup a 1 char buffer
Page 3
AtomSoftTech – C18 Tips & Tricks
Using a 74(LS/HC)164 - 8-Bit Serial In/Parallel Out Shift Register
Shifting data out MSB/LSB First into a 74xx164 - Also Shifting a Single Bit
#include <p18Cxxx.h>
#include <delays.h>
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF
}
}
void ShiftBit(char myBit){
SDO = myBit; //Set the pin high/low depending on user
SCL = 1; //Set the clock high
Delay10TCYx(10); //small delay
SCL = 0; //set the clock low to trigger complete bit
}
void ShiftByte(unsigned char data, char MLSBF)
{
char tmp,x;
for(x=0;x<8;x++){
SDO = 0; //Prepare the port with a 0
if(MLSBF == 1) tmp = data & 0x80; //if we are using MSB First then AND with a 0x80
if(MLSBF == 0) tmp = data & 0x01; //if we are using LSB First then AND with a 0x01
if(MLSBF == 1) data <<= 1; //if using MSB First then SHIFT LEFT 1
if(MLSBF == 0) data >>= 1; //if using LSB First then SHIFT RIGHT 1
}
}
Page 4
AtomSoftTech – C18 Tips & Tricks
Setting up the ADC and Collecting data from AN0 (Using ADC Header file) A bit more confusing … Part 2 of 2
while( BusyADC() ); // Wait for completion
result = ReadADC(); // Read result
}
CloseADC(); // Disable A/D converter
}
void main(void){
OSCCON = 0x72; //8MHz clock
while(!OSCCONbits.IOFS); //Wait for OSC to become stable
while(1){
ADCON0bits.GO = 1; //Start the conversion
while(ADCON0bits.DONE); //Wait until it’s done
result = ADRESH; //Load ADRESH into result
result <<= 8; //Shift over Result 8 bits to the left
result |= ADRESL; //OR in our LOW byte to finish off out INT
Delay10TCYx( 5 ); // Delay for 50TCY (precaution)
}
}
#define PWM_Tris TRISCbits.TRISC2 //Define a nice name for the PWM TRIS bit.
while(1){
if(DutyCyc == 0x12) //Check if we reached our minimum. If so set direction (up)
direction = 1;
if(DutyCyc == 0x66) //Check if we reached our maximum. If so clear direction (down)
direction = 0;
if(direction == 1) //based on direction if 1 (up) add 2 each time to the duty cycle
DutyCyc+=2;
else // if 0 (down) minus 2 each time to the duty cycle
DutyCyc-=2;
Delay10KTCYx(3); //small delay (15mS)
}
}
Page 5
AtomSoftTech – C18 Tips & Tricks
Using I2C – Bit Bang - X2402PI: 256x8 EEPROM
Bit Bang I2C … Part 1 of 3
#include <p18Cxxx.h>
#include <delays.h>
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF
// DELAYS NOTE:
// 10TCY @ 8Mhz = 5uS
// Delay10TCYx(3); would then = 15uS
void i2c_start(void);
void i2c_stop(void);
char i2c_ack(void);
void i2c_write(unsigned char byte);
unsigned char i2c_read(void);
WriteX2402PI(0x00,0x4A); //Write the letter J aka 0x4A to the device @ address 0x00
temp = ReadX2402PI(0x00); //Read from address 0x00 and temp should be the J aka 0x4A
while(1); //Loop Forever
}
void i2c_start(void){
SCLT = 0; //Clock = Output
SCL = 0; //Clock = Low
SDOT = 1; //Data = input(pulled high) so Data = 1
Delay10TCY(); //user may need to modify based on Fosc
SCLT = 1; //Clock = input(pulled high) so Clock = 1
Delay10TCY(); //user may need to modify based on Fosc
if(!SCK) //Check if the clock is low. If so then delay
Delay10TCYx(3); //user may need to modify based on Fosc
SDOT = 0; //Data = Output
SDO = 0; //Data = Low
Delay10TCY(); // user may need to modify based on Fosc
}
void i2c_stop(void){
SCLT = 0; //Clock = Output
SCL = 0; //Clock = Low
SDOT = 0; //Data = Output
SDO = 0; //Data = Low
Delay10TCY(); //user may need to modify based on Fosc
SCLT = 1; //Clock = input(pulled high) so Clock = 1
Delay10TCY(); //user may need to modify based on Fosc
if(!SCK) //Check if the clock is low. If so then delay
Delay10TCYx(3); //user may need to modify based on Fosc
SDOT = 1; //Data = input(pulled high) so Data = 1
Delay1TCY(); //user may need to modify based on Fosc
Delay1TCY(); //user may need to modify based on Fosc
}
char i2c_ack(void){
SCLT = 0; //Clock = Output
SCL = 0; //Clock = Low
SDOT = 1; //Data = input(pulled high) so Data = 1
Delay10TCY(); //user may need to modify based on Fosc
SCLT = 1; //Clock = input(pulled high) so Clock = 1
Delay1TCY(); //1 cycle delay
Delay1TCY(); //1 cycle delay
if(!SCK) //Check if the clock is low. If so then delay
Delay10TCYx(3); //user may need to modify based on Fosc
Page 6
AtomSoftTech – C18 Tips & Tricks
Bit Bang I2C … Part 2 of 3
return ( 1 ); //return with acknowledge error
else
return ( 0 ); // return with no error
if((byte & 0x80) != 0){ //BYTE AND 0x80 (0b10000000) (test if BIT7 != 0)
SCLT = 0; //Clock = Output
SCL = 0; //Clock = Low
SDOT = 1; //Data = input(pulled high) so Data = 1
Delay10TCY(); //user may need to modify based on Fosc
SCLT = 1; //Clock = input(pulled high) so Clock = 1
Delay10TCY(); //user may need to modify based on Fosc
if(!SCK) //Check if the clock is low. If so then delay
Delay10TCYx(3); //user may need to modify based on Fosc
} else {
SCLT = 0; //Clock = Output
SCL = 0; //Clock = Low
SDOT = 0; //Data = Output
SDO = 0; //Data = Low
Delay10TCY(); //user may need to modify based on Fosc
SCLT = 1; //Clock = input(pulled high) so Clock = 1
Delay10TCY(); //user may need to modify based on Fosc
if(!SCK) //Check if the clock is low. If so then delay
Delay10TCYx(3); //user may need to modify based on Fosc
}
Page 7
AtomSoftTech – C18 Tips & Tricks
Bit Bang I2C … Part 3 of 3
i2c_write(WAdd); //Send our Device Address with the Write BIT
result = i2c_ack(); //Test for ACK
i2c_write(Address);
result = i2c_ack(); //Test for ACK
return tmp;
}
void main(void);
void initSPI(void);
unsigned char ReadSPI(unsigned char address);
void WriteSPI(unsigned char address, unsigned char data);
unsigned char SPI_RByte(void);
void SPI_WByte(unsigned char data);
unsigned char BCDtoDEC(unsigned char BCD, char type);
unsigned char DECtoBCD(unsigned char DEC);
unsigned char DECtoASCII(unsigned char DEC,char part);
while(1){
temp = ReadSPI(0); //Read register 0 aka seconds
Seconds = BCDtoDEC(temp,'s'); //Convert The BCD to Decimal... now the user can just +1 or use as actual time to manipulate
SecondBCD = DECtoBCD(Seconds); //convert back to BCD to place back in the device
SecH = DECtoASCII(Seconds,'h'); //Convert to ASCII so you can display on a LCD, GLCD, UART etc. TENS POSITION
SecL = DECtoASCII(Seconds,'l'); //Convert to ASCII so you can display on a LCD, GLCD, UART etc. ONES POSITION
}
}
unsigned char DECtoASCII(unsigned char DEC,char part){
unsigned char temp;
unsigned char myData;
Page 8
AtomSoftTech – C18 Tips & Tricks
Using Bit Bang SPI and controlling a DS1305. Include BCD to DEC to BCD to ASCII conversions… Part 2 of 3
//leaving the low part intact.
if(part == 'h') //If part = h (HIGH PART)
myData = (temp >> 4) & 0x0F; //Shift the byte to the right by 4 and then clear the high part (just incase)
templ = DEC % 10; //Get the remainder of the Decimal dived by 10 aka if DEC = 13 then 13 % 10 = 3
temph = DEC / 10; //Divide Decimal by 10 to get a count of 10's so if DEC = 13 then 13/10 = 1
myData = (temph << 4) | templ; //but them into 1 byte by shifting the high by to left by 4 and loading the low
//part into the byte so if templ = 3 and temph = 1 you should get 0x13
return myData; //Return myData
}
unsigned char BCDtoDEC(unsigned char BCD, char type){
unsigned char temp;
unsigned char myData;
char x;
Page 9
AtomSoftTech – C18 Tips & Tricks
Using Bit Bang SPI and controlling a DS1305. Include BCD to DEC to BCD to ASCII conversions… Part 3 of 3
Delay10TCY(); //Delay 5uS
if(SDI) //if the Serial Data In is HIGH do below if not then leave it 0
data |= 1; //OR in a 1 into out byte
}
return data; //return our data
}
void WriteSPI(unsigned char address, unsigned char data){
SCL = 1; //Clock High
CS = 1; //Chip Select High
SPI_WByte(address); //Write our address
SPI_WByte(data); //write our data
CS = 0; //Chip Select Low
}
unsigned char ReadSPI(unsigned char address){
unsigned char tmp;
Page 10
AtomSoftTech – C18 Tips & Tricks
LCD Control (2x16 – HD44780)
Setting up the LCD and Sending Strings… Part 1 of 2
#include <p18Cxxx.h>
#include <delays.h>
#pragma config WDT = OFF, LVP = OFF, OSC = INTIO67, XINST = OFF
while(1){
}
}
void LCD_String(unsigned rom char *string){
while(*string != 0){ //While the data pointed to isnt a 0x00 do below
SendLCD(*string++,1); //Send out the current byte pointed to
}
}
void LCD_Init(void){
LCDT = 0x00; //Set LCD Pins as output
LCD &= 0xF0; //clear only te db4:db7 pins
Page 11
AtomSoftTech – C18 Tips & Tricks
Setting up the LCD and Sending Strings… Part 2 of 2
void SendLCD(unsigned char Byte, char type){
char ByteL;
LCD_RS = type; //Set whether it is a Command (0) or Data/Char (1)
ByteL = Byte & 0x0F; //Place Byte in ByteL and Clear the high part of byte
Byte >>= 4; //Shift over Byte by 4
LCD &= 0xF0; //Clear the LCD portion on the PORTA only
LCD |= Byte; //OR the new data to the LCD portion of PORTA (sending high part of byte)
E_TOG(); //Toggle the E(enable)
Delay10TCY(); //Delay 5uS
LCD &= 0xF0; //Same as above
LCD |= ByteL; //Same as above (sending low part of byte)
E_TOG(); //same as above
}
void SendNyb(unsigned char Byte){
Byte &=0x0F; //Clear the top half of byte
LCD &= 0xF0; //Clear the LCD half of PORTA
LCD |= Byte; //OR the new data into LCD part of PORTA
E_TOG(); //Toggle E(enable)
}
Page 12