8/29/2009

Using the DAC on a PIC18F2*550

I tried to figure out how to use the integrated DAC. I have a 2k7 Potentiometer (unfortunately, a non-linear one) connected between Vdd and Vss, the terminal goes to AN0. AN1:AN6 drive 6 LED to form a simple bar-graph display showing the captured voltage.

#include <p18cxxx.h>
#include <delays.h>

#pragma config MCLRE = ON      //MCLR pin enabled; RE3 digital input disabled
#pragma config WDT = OFF       //HW Disabled - SW Controlled
#pragma config BOR = OFF       //Brown-out Reset disabled in hardware and software 

#pragma config FOSC = INTOSCIO_EC     //Internal oscillator, port function on RA6, EC used by USB 
#pragma config LVP = OFF              //Single-Supply ICSP disabled, free RB5
#pragma config PBADEN = OFF           //RB0 through RB4 pins are configured as digital I/O on Reset
#pragma config DEBUG = OFF            //Background debugger disabled, RB6 and RB7 configured as I/O pins

void init (void);
void main (void);

void init (void)
{
    OSCCON = 0xFF;    //internal oscillator at 8MHz
                      //1ms = 2000000 Instructions

    ADCON0 = 0x01;    //Enable ADC on Channel AN0
    ADCON1 = 0x0E;    //ADC on AN0, VDD and VSS reference
    ADCON2 = 0xA7;    //Right justified, 8TAD, FRC Clock
}

void main (void)
{

    int adc;

    init();
    TRISA = 0x00;
    LATA = 0x7E;    //1st bit used by ADC, last bit non existent

    while (1)
    {
        ADCON0bits.GO_DONE = 1;            //Start the DAC
        while (ADCON0bits.GO_DONE) {}      //Wait for the DAC to finish calculating
        adc = ADRESL + (ADRESH * 256);     //Add the two 8-bit registers into one Integer
        //LATA = (adc / 16) << 1;          //for testing, you can output the value
                                           //in binary

        if (adc  >= 876)                   //6 LED + Off = 7 states
        {LATA = 0x7E;}                     //adc >= 6/7*1023, adc >= 5/7*1023 and so on.
        else if (adc  >= 730)
        {LATA = 0x3E;}                     //Light 6 LED
        else if (adc  >= 584)
        {LATA = 0x1E;}                     //Light 5 LED
        else if (adc  >= 438)
        {LATA = 0x0E;}                     //...
        else if (adc  >= 292)
        {LATA = 0x06;}
        else if (adc  >= 146)
        {LATA = 0x02;}
        else
        {LATA = 0x00;}
          
        Delay10KTCYx(1);    //According to the datasheet, we only have to wait
                            //4 instructions after collecting data
     }
}

Test circuit:

8/26/2009

Get all possible digital inputs on a PIC18F2*50

Same thing as last post, the other way round.

Pins available for digital input:

  • PORTA: RA0 through RA6 gives 7 inputs
  • PORTB: RB0 through RB7 gives 8 inputs
  • PORTC: RB0 through RB2 and RB4 through RB7 gives 7 inputs
  • PORTE: RE3 gives one input
=> on a PIC18F2*50 you have 23 digital outputs total.

Configure options:
  • FOSC = INTOSCIO_EC //using the internal oscillator will free pins RA5 and RA6
  • LVP = OFF //you don't have to ground RB5 anymore
  • PBADEN = OFF //disable the analog inputs on RB0 through RB4
  • DEBUG = OFF //disable debug output, free RB6 and RB7
  • MCLRE = OFF //disable the master clear option, free RE3

Registers to set:
  • ADCON1 = 0x0F; //disable analog inputs on RA0 through RA3
  • UCON = 0x00; //disable the usb module, free RC4 and RC5
  • UCFG = 0x08;
RC4, RC5 & RE3 can only be used as digital inputs, not as outputs. PORTB has internal pullups which can be activated by clearing bit7 at INTCON2. This is very handy for me because I have wildly fluctuating inputs here with the breadboard and power over my pc's USB.

Get all possible digital outputs on a PIC18F2*50

Recently I've been experimenting with a PIC18F2550 microcontroller and it wasn't easy at all to get the ports running in the mode I wanted to. So at first, I looked through the datasheet to find out which ports can be used as digital output pins and how to configure them. This is what I came up with:

Available output pins:
  • PORTA: RA0 through RA6 gives 7 outputs
  • PORTB: RB0 through RA7 gives 8 outputs
  • PORTC: RC0 through RC2, RC6 & RC7 gives 5 outputs
=> on a PIC18F2*50 you have 20 digital outputs total.

Configure options:

  • FOSC = INTOSCIO_EC //using the internal oscillator will free pins RA5 and RA6
  • LVP = OFF //you don't have to ground RB5 anymore
  • PBADEN = OFF //disable the analog inputs on RB0 through RB4
  • DEBUG = OFF //disable debug output, free RB6 and RB7
    Registers to set:
    • ADCON1 = 0x0F; //disable analog inputs on RA0 through RA3

    One comment on using RB6 & RB7: You'll have to interface these pins over at least 10k resistors to be able to do ICSP programming on these pins. If you can avoid it, don't use these pins for I/O in your circuit.

    Testing code:
    #include <p18cxxx.h>
    
    #pragma config MCLRE = ON             //MCLR pin enabled; RE3 digital input disabled
    #pragma config WDT = OFF              //HW Disabled - SW Controlled
    #pragma config BOR = OFF              //Brown-out Reset disabled in hardware and software
    
    #pragma config FOSC = INTOSCIO_EC     //Internal oscillator, port function on RA6, EC used by USB
    #pragma config LVP = OFF              //Single-Supply ICSP disabled, free RB5
    #pragma config PBADEN = OFF           //RB0 through RB4 pins are configured as digital I/O on reset
    #pragma config DEBUG = OFF            //Background debugger disabled, RB6 and RB7 configured as I/O pins on reset
    
    void main ( void );
    void init ( void );
    
    void init (void)
    {
        OSCCON = 0xFF;    //8MHz internal clock
                          //1ms = 2000000 Instructions
        ADCON1 = 0x0F;    //Set multiplexed pins on PORTA to digital
        TRISA = 0x00;     //Configure RA0 through RA6 as output
        TRISB = 0x00;     //Configure PORTB as output
        TRISC = 0x00;     //Configure RC0:RC3, RC6:RC7 as output
        LATA = 0x00;      //Reset Pins
        LATB = 0x00;
        LATC = 0x00;
    }
    
    void main (void)
    {
        init();
    
        LATA = 0x7F;     //01111111
        LATB = 0x3F;     //00111111
        LATC = 0xC7;     //11000111
    
        while (1) {}
    }
    Result

    My PIC18F2550 controlling 18 low-current (!) LED independently. RC6 and RC7 were needed for ICSP.
    The maximum rated current per Pin is 20mA, Vss (Ground) can only handle 200mA. Caution: Using standard LED would fry the ports!