PIC18F4620

This page provides some basic information about programming and using the PIC18F4620 microcontroller.  You’ll find information on:

Basic breadboard circuit for PIC18F4620

The hardware and components required to build this circuit are:

  • PICkit2 USB programmer
  • Breadboard
  • 6-pin header
  • PIC18F4620 microcontroller
  • Some single-core wire: red, black and at least one other colour
  • Snips and pliers

When you’re getting started, an LED is the simplest way to see if the circuit is working, so it will be useful to include the following also:

  • 1 resistor of about 330 Ohms (anything between about 220 and 1000 Ohms is probably fine)
  • 1 LED

This is the basic circuit for the PIC18F4620:

Circuit diagram for connecting the PICkit 2 to a 18F4620 microcontroller

This shows the numbers and labels of the pins on the PIC18F4620 :

pic18f pin numbers and labels

What to download / install

The program that will ultimately run on the PIC18F4620 microcontroller is written and compiled on a PC. We need to install some software on the PC to compile and transfer the program to the microcontroller.

    • Download the zip file on to your PC or, preferably, a USB key
    • Extract the files to a folder on your PC or USB key

The extracted folder contains the xc8 compiler files (modified to work with the pic18f4620 only), the pk2cmd software tool which is used to communicate with the PICkit2, and Notepad++, which can be used to write and modify code.

To create a new project do the following:

        1. First create a new folder inside the “robosumo_files” folder and copy the build.bat file into that folder.
        2.  Run the Notepad++  editor and paste the example code (flashing LED) given below. Save the code in the new folder as a file called “main.c” (don’t include quotes in the filename).
        3. Make sure the PICkit2 programmer is correctly connected to the PIC18f4620 and finally double click the build.bat file.
        4. If there are no errors in the code and the hardware is set up correctly then the PIC18f4620 will be programmed.

robosumo_build_result

Example Code – Flashing LED

This is a pared back example program for the PIC18F4620. It blinks an LED connected to pin 19 (RD0).

//
// PIC18F4620 example program
// Written by Ted Burke (ted.burke@dit.ie)
// Last update 28-2-2013
//

#include <xc.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF

int main(void)
{
	// Make RD0 a digital output
	TRISD = 0b11111110;

	while(1)
	{
		LATDbits.LATD0 = 1; // Set pin RD0 high
		_delay(125000);     // 0.5 second delay
		LATDbits.LATD0 = 0; // Set pin RD0 low
		_delay(125000);     // 0.5 second delay
	}
}

Digital Input controlling LED flash rate

Here is the circuit and code to flash an LED a different rate depending on whether RD4 is high or low.
LED and switch

// Flash LED at a different rate depending on whether RD4 is high or low
#include <xc.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF

int main(void)
{
    // Make RD0 a digital output - all other PORT D are inputs
    TRISD = 0b11111110;

    while(1)
    {
        if(PORTDbits.RD4 == 1)
        {
            LATDbits.LATD0 = 1; // Set pin RD0 high
            _delay(60000);
            LATDbits.LATD0 = 0; // Set pin RD0 low
            _delay(60000);
        }
        else
        {
            LATDbits.LATD0 = 1; // Set pin RD0 high
            _delay(125000);
            LATDbits.LATD0 = 0; // Set pin RD0 low
            _delay(125000);
        }
    }
}

Motor Control

Here’s a circuit and code to get the motors turning!

The capacitor is used to power the PIC18f4620 when the motors switch direction. When the motors switch direction they draw a large amount of current from the battery. If the capacitor wasn’t in place the PIC18f4620 would be ‘starved’ of current and reset. The diode is in place to prevent the capacitor discharging to the power chip.

motor control

//This code will turn one of the motors shown in the circuit
#include <xc.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF

int main(void)
{
    // Make RD0, RD1, RD2 and RD3 outputs
    TRISD = 0b11110000;

    while(1)
    {

        if(PORTDbits.RD4 == 1)
        {
            LATDbits.LATD0 = 1;
            LATDbits.LATD1 = 0;
        }
        else //Reverse motor direction
        {
            LATDbits.LATD0 = 0;
            LATDbits.LATD1 = 1;
        }
    }
}

A more complex template program for the PIC18F4620

This is a more complex example program for the PIC18F4620. Like the previous example, it basically just flashes an LED connected to pin 20 (RD1) – the duration the LED is on is controlled by the voltage on pin 1 (AN0). However, this example provides a good starting point for many more complex programs because it sets up the following features:

          • The clock speed is set to 8MHz, giving an instruction cycle, Tcy = 0.5us.
          • 8 pins are enabled as analog inputs (AN0-7, pins 2, 3, 4, 5, 7, 8, 9, 10).
          • 10 pins are enabled as digital outputs (RB0-5, RD0-3).
          • 6 pins are enabled as digital inputs (RB6-7, RD4-7).
          • 2 pins are enabled as PWM outputs (CCP1 and CCP2, pins 16 and 17).
          • The USART is enabled on pins 25 (Tx) and 26 (Rx).

There are two example circuits shown below the code. The first uses a potentiometer to vary the voltage applied to ANO and the other uses the voltage from a colour sensor.

//
// PIC18F4620 template program
// Written by Ted Burke (ted.burke@dit.ie)
// Last update 3-3-2013
//

#include <xc.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int);

void main(void)
{
	setup(); // Configure the PIC
	unsigned int analog_val;
	while(1)
	{
		analog_val = read_analog_channel(0);
		LATDbits.LATD1 = 1;  // Set RD1 high
		Delay1KTCYx(analog_val);
		LATDbits.LATD1 = 0;  // Set RD1 low
		Delay1KTCYx(1000);   // 500ms delay
	}
}

void setup(void)
{
	// Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
	// Set Fosc = 8MHz, which gives Tcy = 0.5us
	OSCCON = 0b01110000;

	// Set up ADC (section 19 of the PIC18F4620 Data Sheet)
	// Enable AN0-7 as analog inputs
	ADCON1 = 0b00000111;
	// Left justified result, manual acquisition time,
	// AD clock source = 8 x Tosc
	ADCON2 = 0b00000001;

	// Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
	// RB0-5 outputs, RB6-7 inputs
	LATB = 0b00000000;
	TRISB = 0b11000000;

	// Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
	// RD0-3 digital outputs, RD4-7 digital inputs
	LATD = 0b00000000;
	TRISD = 0b11110000;

	// Set up PWM (section 15 of the PIC18F4620 Data Sheet)
	// Set PWM frequency=36kHz and duty cycle=50% on both channels
	CCP1CON = 0b00001100;	// PWM on CCP1
	CCP2CON = 0b00001100;	// PWM on CCP2
	TRISC = 0b11111001;		// CCP1, CCP2 as outputs
	T2CON = 0b00000100;		// Enable TMR2 with prescale = 1:1
	PR2 = 55;				// period = (PR2+1) * Tcy * prescale
	CCPR1L = 27;			// Ch 1 duty cycle = CCPR1L / PR2
	CCPR2L = 27;			// Ch 2 duty cycle = CCPR1L / PR2

	// Set up USART (section 18 of the PIC18F4620 Data Sheet)
	// baud_rate = Fosc/(16*(spbrg+1))
	//           = 8000000/(16*(207+1)) = 2403.846 bits/s
	OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF
		& USART_ASYNCH_MODE & USART_EIGHT_BIT
		& USART_CONT_RX & USART_BRGH_HIGH, 207);
}

// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n)
{
	unsigned int voltage;

	ADCON0 = n << 2;
	ADCON0bits.ADON = 1;
	Delay10TCYx(3); // 15us charging time
	ADCON0bits.GO = 1;
	while (ADCON0bits.GO); // Await result (11us approx)

	// Return the result (a number between 0 and 1023)
	voltage = ADRESH;
	voltage = (voltage << 2) + (ADRESL >> 6);
	return voltage;
}

analogue input pot

analogue input light sensor

UART data transmission

// Example code to send data via the UART
#include <xc.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>
  
#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int); 

void main(void) 
{ 
    unsigned int colour_sensor;
    int touch_sensor = 0; 
    
    setup(); // Configure the PIC
   
    while(1) 
    { 
        colour_sensor = read_analog_channel(0);
        touch_sensor = PORTDbits.RD4;
		
        printf("TRISD SFR = %x ; touch is %d and colour reading is %d\n", TRISD ,touch_sensor, colour_sensor );
    } 
} // end of main

 
void setup(void)
{
    // Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    // Set Fosc = 8MHz, which gives Tcy = 0.5us
    OSCCON = 0b01110000;
 
    // Set up ADC (section 19 of the PIC18F4620 Data Sheet)
    // Enable AN0-7 as analog inputs
    ADCON1 = 0b00000111;
    // Left justified result, manual acquisition time,
    // AD clock source = 8 x Tosc
    ADCON2 = 0b00000001;
 
    // Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
    // RB0-5 outputs, RB6-7 inputs
    LATB = 0b00000000;
    TRISB = 0b11000000;
 
    // Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
    // RD0-3 digital outputs, RD4-7 digital inputs
    LATD = 0b00000000;
    TRISD = 0b11110000;
 
    // Set up PWM (section 15 of the PIC18F4620 Data Sheet)
    // Set PWM frequency=36kHz and duty cycle=50% on both channels
    CCP1CON = 0b00001100;   // PWM on CCP1
    CCP2CON = 0b00001100;   // PWM on CCP2
    TRISC = 0b11111001;     // CCP1, CCP2 as outputs
    T2CON = 0b00000100;     // Enable TMR2 with prescale = 1:1
    PR2 = 55;               // period = (PR2+1) * Tcy * prescale
    CCPR1L = 27;            // Ch 1 duty cycle = CCPR1L / PR2
    CCPR2L = 27;            // Ch 2 duty cycle = CCPR1L / PR2
    
    
    // Set up USART (section 18 of the PIC18F4620 Data Sheet)
    // baud_rate = Fosc/(16*(spbrg+1))
    //           = 8000000/(16*(207+1)) = 2403.846 bits/s
    OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF
        & USART_ASYNCH_MODE & USART_EIGHT_BIT
        & USART_CONT_RX & USART_BRGH_HIGH, 207);
}

//needs to be defined for printf to work. Basically this function defines how printf sends a single character to the UART
 void putch(char data) {    
     while (!TXIF)    
         continue;    
     TXREG = data;    
 }    
// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n)
{
    unsigned int voltage;
 
    ADCON0 = n << 2;
    ADCON0bits.ADON = 1;
    Delay10TCYx(3); // 15us charging time
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO); // Await result (11us approx)
 
    // Return the result (a number between 0 and 1023)
    voltage = ADRESH;
    voltage = (voltage << 2) + (ADRESL >> 6);
    return voltage;
}

Timer Interrupt

//Timer Interrupt Example - sends data via uart every 2 seconds
#include <xc.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>
  
#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int); 

unsigned long int timer_ms =0;

// Interrupt Service Routine
void interrupt high_isr (void) 
{
	//if this is a timer interrupt
	if (INTCONbits.TMR0IF)
    {  
		INTCONbits.TMR0IF = 0;// reset interrupt
        //update timer_counter
        timer_ms = timer_ms + 1;
        //reset the timer counter register
        TMR0L = 0x17;
        TMR0H = 0xFC;
	}

} 

void main(void) 
{ 
    unsigned int colour_sensor;
    int touch_sensor = 0; 
    setup();
    
    while(1) 
    { 
        //send back data every 2 seconds
        if(timer_ms > 2000)
        {
            timer_ms = 0; //reset the timer
            colour_sensor = read_analog_channel(0);
            touch_sensor = PORTDbits.RD4;
            
            printf("TRISD SFR = %x ; touch is %d and colour reading is %d\n", TRISD ,touch_sensor, colour_sensor );
        }
    } 
} // end of main
 
void setup(void)
{
    // Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    // Set Fosc = 8MHz, which gives Tcy = 0.5us
    OSCCON = 0b01110000;
 
    // Set up ADC (section 19 of the PIC18F4620 Data Sheet)
    // Enable AN0-7 as analog inputs
    ADCON1 = 0b00000111;
    // Left justified result, manual acquisition time,
    // AD clock source = 8 x Tosc
    ADCON2 = 0b00000001;
 
    // Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
    // RB0-5 outputs, RB6-7 inputs
    LATB = 0b00000000;
    TRISB = 0b11000000;
 
    // Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
    // RD0-3 digital outputs, RD4-7 digital inputs
    LATD = 0b00000000;
    TRISD = 0b11110000;
 
    // Set up PWM (section 15 of the PIC18F4620 Data Sheet)
    // Set PWM frequency=36kHz and duty cycle=50% on both channels
    CCP1CON = 0b00001100;   // PWM on CCP1
    CCP2CON = 0b00001100;   // PWM on CCP2
    TRISC = 0b11111001;     // CCP1, CCP2 as outputs
    T2CON = 0b00000100;     // Enable TMR2 with prescale = 1:1
    PR2 = 55;               // period = (PR2+1) * Tcy * prescale
    CCPR1L = 27;            // Ch 1 duty cycle = CCPR1L / PR2
    CCPR2L = 27;            // Ch 2 duty cycle = CCPR1L / PR2
	
    // Set up timer interrupt
    T0CON = T0CON & 0b11111000; // set up 1:2 prescaler so that TMR0 SFR is incremented evert 2 Tcy  i.e. 1us
    T0CONbits.T0CS = 0; //use internal instruction cycle clock
    T0CONbits.T08BIT = 0; //use 16 bit mode
    T0CONbits.PSA = 0; //turn on prescaler
    INTCONbits.TMR0IE = 1; //Enable TIMER0 interupt
    INTCON2bits.TMR0IP = 1; // Set the timer0 interrupt up as high priority
    INTCONbits.GIE = 1; //Enable global interrupts
    
    //An interrupt will be generated whenever TMR0 goes from FFFFh to 0000h.
    // Would like a timer interrup triggered every ms so will set timer to 0xffff - 1000 = 0xFC17
    TMR0L = 0x17;
    TMR0H = 0xFC;
    T0CONbits.TMR0ON = 1; //turn on timer 0
    
    
    // Set up USART (section 18 of the PIC18F4620 Data Sheet)
    // baud_rate = Fosc/(16*(spbrg+1))
    //           = 8000000/(16*(207+1)) = 2403.846 bits/s
    OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF
        & USART_ASYNCH_MODE & USART_EIGHT_BIT
        & USART_CONT_RX & USART_BRGH_HIGH, 207);
}

//needs to be defined for printf to work. Basically this function defines how printf sends a single character to the UART
 void putch(char data) {    
     while (!TXIF)    
         continue;    
     TXREG = data;    
 }     
// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n)
{
    unsigned int voltage;
 
    ADCON0 = n << 2;
    ADCON0bits.ADON = 1;
    Delay10TCYx(3); // 15us charging time
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO); // Await result (11us approx)
 
    // Return the result (a number between 0 and 1023)
    voltage = ADRESH;
    voltage = (voltage << 2) + (ADRESL >> 6);
    return voltage;
}

Basic Robot

// This is some  example code which may be useful for the robosumo competition
//
// The code is written for a robot that has one colour sensor and one touch sensor (micro switch).
// Both sensors are placed at the front of the robot.
// The robot will be in one of the following states:
//     State 1. Going Forwards
//     State 2. Moving away from the white boudary of the arena
//     State 3. Spinning
//
// ROBOT BEHAVIOUR 
// The robot will start in state 1.
// The robot will enter state 1 if the touch sensor is ever pressed.
// The robot will enter state 2 if the the colour sensor indicates it is on white and the touch sensor is not pressed.
// The robot will enter state 3 after exiting state 2.
// The robot will exit state 2 and enter state 3 after manoevering away from the white line.
// The robot will exit state 3 and enter state 1 after one second (or if the sensors were activated).

// PIN CONNECTIONS
// the colur sensor is connected to pin 2 (analog channel 0)
// the switch/touch sensor is connected to  pin 27 (RD4)
// The motors are connected to pins 19-22 (LATD0-LATD3)
//
#include <xc.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>
  
#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF

// Function prototypes
void setup(void);
unsigned int read_analog_channel(unsigned int); 

unsigned long int timer_ms =0;

// Interrupt Service Routine
void interrupt high_isr (void) 
{
	//if this is a timer interrupt
	if (INTCONbits.TMR0IF)
    {  
		INTCONbits.TMR0IF = 0;// reset interrupt
        //update timer_counter
        timer_ms = timer_ms + 1;
        //reset the timer counter register
        TMR0L = 0x17;
        TMR0H = 0xFC;
	}

} 

void main(void) 
{ 
    unsigned int colour_sensor;
    int touch_sensor = 0; 
    int state = 1;
    int prev_state = 0;
    int spin_direction = 0; //used to change the direction in which the robot spins
    int colour_threshold = 512;
    int debug = 1;
    
    setup(); // Configure the PIC
    

    while(1) 
    { 
        //---- READ SENSORS-----------------------------------------------
        colour_sensor = read_analog_channel(0);
        touch_sensor = PORTDbits.RD4;
		
        //--- DEBUGGING ------------------------------------------------
        if(debug == 1) // debugging - send data back to PC
        {   
            if(prev_state != state) 
                printf("state = %d, spin_dir = %d, touch = %d, colour=%d\n", state, spin_direction,  touch_sensor, colour_sensor);
            prev_state = state;
        }
        //---- SELECT STATE IF SENSORS ACTIVATED--------------------------
        if(touch_sensor == 1)
        {
            state = 1; //always enter this state if the touch sensor is pressed
        }
        else if(colour_sensor > colour_threshold)
        {
            state = 2; //if the switch is not pressed and the robot is on white enter state 2
        }
        
        //---- ENTER ONE OF THREE STATES-----------------------------------------
        if(state == 1) //Drive Forwards
        {
            LATD = 0b00001010; //go forwards
            timer_ms = 0; //reset the timer so that its at 0 whenever it leaves this state
        }
        else if(state == 2) // Manoever away from the white boundary of the arena
		{
            if(timer_ms < 1200) 
            {
                LATD = 0b00000101; //go backwards for 1.2 seconds
            }
            else if(timer_ms < 2000)
            {
                LATD = 0b00000110; //spin for 0.8 seconds
            }
            else
            {
                state = 3;
                timer_ms = 0; // reset the timer for entering state 3
            }    
        }
        else if(state == 3) //spin
        {
            if(spin_direction == 0)
            {
                LATD = 0b00000110; //spin for 3 seconds
            }
            else
            {
                LATD = 0b00001001; //spin for 3 seconds
            }
            if(timer_ms > 3000)
            {
                spin_direction = ~spin_direction;
                state = 1;
            }
        }
        
    } //end of while loop
} // end of main
 
void setup(void)
{
    // Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    // Set Fosc = 8MHz, which gives Tcy = 0.5us
    OSCCON = 0b01110000;
 
    // Set up ADC (section 19 of the PIC18F4620 Data Sheet)
    // Enable AN0-7 as analog inputs
    ADCON1 = 0b00000111;
    // Left justified result, manual acquisition time,
    // AD clock source = 8 x Tosc
    ADCON2 = 0b00000001;
 
    // Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
    // RB0-5 outputs, RB6-7 inputs
    LATB = 0b00000000;
    TRISB = 0b11000000;
 
    // Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
    // RD0-3 digital outputs, RD4-7 digital inputs
    LATD = 0b00000000;
    TRISD = 0b11110000;
 
    // Set up PWM (section 15 of the PIC18F4620 Data Sheet)
    // Set PWM frequency=36kHz and duty cycle=50% on both channels
    CCP1CON = 0b00001100;   // PWM on CCP1
    CCP2CON = 0b00001100;   // PWM on CCP2
    TRISC = 0b11111001;     // CCP1, CCP2 as outputs
    T2CON = 0b00000100;     // Enable TMR2 with prescale = 1:1
    PR2 = 55;               // period = (PR2+1) * Tcy * prescale
    CCPR1L = 27;            // Ch 1 duty cycle = CCPR1L / PR2
    CCPR2L = 27;            // Ch 2 duty cycle = CCPR1L / PR2
	
    // Set up timer interrupt
    T0CON = T0CON & 0b11111000; // set up 1:2 prescaler so that TMR0 SFR is incremented evert 2 Tcy  i.e. 1us
    T0CONbits.T0CS = 0; //use internal instruction cycle clock
    T0CONbits.T08BIT = 0; //use 16 bit mode
    T0CONbits.PSA = 0; //turn on prescaler
    INTCONbits.TMR0IE = 1; //Enable TIMER0 interupt
    INTCON2bits.TMR0IP = 1; // Set the timer0 interrupt up as high priority
    INTCONbits.GIE = 1; //Enable global interrupts
    
    //An interrupt will be generated whenever TMR0 goes from FFFFh to 0000h.
    // Would like a timer interrup triggered every ms so will set timer to 0xffff - 1000 = 0xFC17
    TMR0L = 0x17;
    TMR0H = 0xFC;
    T0CONbits.TMR0ON = 1; //turn on timer 0
    
    
    // Set up USART (section 18 of the PIC18F4620 Data Sheet)
    // baud_rate = Fosc/(16*(spbrg+1))
    //           = 8000000/(16*(207+1)) = 2403.846 bits/s
    OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF
        & USART_ASYNCH_MODE & USART_EIGHT_BIT
        & USART_CONT_RX & USART_BRGH_HIGH, 207);
}

//needs to be defined for printf to work. Basically this function defines how printf sends a single character to the UART
 void putch(char data) {    
     while (!TXIF)    
         continue;    
     TXREG = data;    
 }    
// Read voltage from the specified channel.
// This function takes approximately 35us.
unsigned int read_analog_channel(unsigned int n)
{
    unsigned int voltage;
 
    ADCON0 = n << 2;
    ADCON0bits.ADON = 1;
    Delay10TCYx(3); // 15us charging time
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO); // Await result (11us approx)
 
    // Return the result (a number between 0 and 1023)
    voltage = ADRESH;
    voltage = (voltage << 2) + (ADRESL >> 6);
    return voltage;
}

Distance Sensor HC-SR04 example code

// Contains function to read the HC-SR04 distance sensor/range finder
//
// Trig pin must be connected to RB0 (digital output)
// Echo pin must be connected to RD7 (digital input)

#include <xc.h>
#include <delays.h>
#include <usart.h>
#include <stdio.h>
 
#pragma config OSC=INTIO67,MCLRE=ON,WDT=OFF,LVP=OFF,BOREN=OFF
 
// Function prototypes
void setup(void);
int read_distance_sensor_cm();
 
void main(void)
{
    int distance_cm;
    setup(); // Configure the PIC
   
    while(1)
    {    
        distance_cm =read_distance_sensor_cm(); // determines distance in centimeters or -1 if outside of range
        
        if(distance_cm < 50 && distance_cm > 0 )
            LATBbits.LATB1= 1;
        else
            LATBbits.LATB1= 0;
            
    }    
}
 
void setup(void)
{
    // Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    // Set Fosc = 8MHz, which gives Tcy = 0.5us
    OSCCON = 0b01110000;
 
    // Set up Port B (section 9.2 of the PIC18F4620 Data Sheet)
    // RB0-5 outputs, RB6-7 inputs
    LATB = 0b00000000;
    TRISB = 0b11000000;
 
    // Set up Port D (section 9.4 of the PIC18F4620 Data Sheet)
    // RD0-3 digital outputs, RD4-7 digital inputs
    LATD = 0b00000000;
    TRISD = 0b11110000;
    
    
}

// Read Distance_sensor and return an integer which represents distance rounded to nearest cm.
// Return -1 if no object detected (or in the event of hardware malfunctioning)
// This function is setup to use the HC-SR04 distance sensor
// See http://users.ece.utexas.edu/~valvano/Datasheets/HCSR04b.pdf for info on how the sensor works
// Trig pin must be connected to RB0 (digital output)
// Echo pin must be connected to RD7 (digital input)
int read_distance_sensor_cm()
{
    unsigned int distance;
    
    // send a 15us pulse to the trig pin (trig pin on sensor to be connected to RB0 on pic18f)
    LATBbits.LATB0 = 1;
    Delay10TCYx(3); //25us
    LATBbits.LATB0 = 0;
   
    //Reset the timer;
    T1CON = 0b11001000;
 	TMR1H = 0;
	TMR1L = 0;   
    // start timer to check whether a pulse is ever found on echo pin - don't want to get stuck in a while loop forever
    T1CONbits.TMR1ON = 1;
    while(PORTDbits.RD7 == 0)
    {
        if(TMR1 > 20000) // exit if its taking too long to detect an echo
        {
            return(-1);
        }
    }  
    
    //Reset the timer - this time the timer is used to check the distance. 
    //The echo pin will be held high for a period of time in proportion to the distance the object is away from the sensor. 
    //See data sheet http://users.ece.utexas.edu/~valvano/Datasheets/HCSR04b.pdf for more details.
 	TMR1H = 0;
	TMR1L = 0;   
    while(PORTDbits.RD7 == 1)
    {
        if(TMR1 > 20000) // exit if its taking too long to detect the echo pin going back to zero. Something has gone wrong with the hardware and don't want to get caught in this while loop forever.
        {
            return(-1);
        }
    }  
    //calculate distance in cm and return this result. Each timer increment takes 4/8000000 seconds and sound travels at 38000 cm per second. Divide by two to get distance to the object. 
    // Distance = (num timer increments) * 4/8000000*38000/2 cm = (num timer increments)*0.0095
    distance = (int) (TMR1*0.0095);
    return( distance);
}

Further Reading

3 Responses to PIC18F4620

  1. James says:

    Why can’t I find any data about the PIC18F4260 anywhere but here? I have come across a bunch of old thermostats (unused and used) that use this chip but I can’t find any data on this chip, even on MicroChip’s webpage.

    • batchloaf says:

      Hi James,

      My guess is that there are two main reasons:

      1. Firstly, a lot of the relevant content you’ll find on the web is for the closely related PIC18F4520, which is very similar to the PIC18F4620 but came out before it. Basically, the PIC18F4520 came out first and became very popular – tons of people were using it for all sorts of things. A while later, Microchip released the PIC18F4620 which is basically an upgrade. With one or two possible small exceptions, you can use a 4620 anywhere you can use a 4520, but it has more memory and probably some other improvements I can’t remember. So, you’ll probably find lots of stuff about the PIC18F4520 on the web which will work perfectly well with the PIC18F4620. Try googling “18F4520” and see if you find more stuff.
      2. These chips still work just as well as they used to, but to some extent they have been superseded by other things. For PIC development, I moved on to the 16-bit dsPIC30F4011. For low-cost development, such as when I needed a microcontroller and programmer for everyone in my class, I switched to the MSP430 because the LaunchPad programmer was a lot cheaper than the PICkit2. Once Arduino Nano knock-offs got really cheap ($2 ish), I started sticking those into everything that I would once have put a PIC18F4620 into. I assume a lot of other people have moved on from the 4520/4620 for the same reason. Hence, there’s probably a lot less new material about them appearing online now.

      I’m kinda sorry to be waving goodbye to the PICs – they were my first love – but they pretty much priced themselves out of whatever market I’m in. The last PIC I’m using regularly is the dsPIC4011, but I’m not sure for how long 😦

      For me, the PIC18F4520/4620 is a design classic. So many fond memories!

      Ted

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s