Picdem2PlusDemo.c

Example code for PICDEM 2 PLUS board and ICD2 for BoostC compiler (by Dan McFarland).



////////////////////////////////////////////////////////////////////////////
// PicDem2 Plus Demo, designed for BoostC
//
// Author: Dan McFarland, 3/30/2005
//
//
// Designed and developed using the BoostC compiler integrated into Microchip's
// MPLAB IDE and the ICD2 programmer/debugger for the   
// PICDEM 2 PLUS board running at a clock freq of 4MHz.
// Tested with the 18F452 and 16F877 chips.  
//
////////////////////////////////////////////////////////////////////////////
//  From Microchip's .asm demo code:
//
//  PICDEM 2 PLUS DEMO code. The following functions are included      
//  with this code:                                                    
//    1. Voltmeter                                                     
//      The center tap of R16 is connected to RA0, the                 
//      A/D converter converts this analog voltage and                 
//      the result is displayed on the LCD in a range                  
//      from 0.00V - 5.00V.                                            
//    2. Buzzer                                                        
//      The Piezo buzzer is connected to RC2 and is                    
//      driven by the CCP1 module. The period and duty                 
//      cycle are adjustable on the fly through the LCD                
//      and push-buttons.                                              
//    3. Temperature                                                   
//      A TC74 Serial Digital Thermal Sensor is used to                
//      measure ambient temperature. The PIC and TC74                  
//      communicate using the MSSP module. The TC74 is                 
//      connected to the SDA & SCL I/O pins of the PIC                 
//      and functions as a slave.                                  
//    4. Clock                                                         
//      This function is a real-time clock. When the                   
//      mode is entered, time begins at 00:00:00.                      
//
////////////////////////////////////////////////////////////////////////////
#include <system.h>
#include <icd2.h> // needed only if icd2 used for debugging

// These setting are for the PICDEM2 PLUS board!
#define LCD_ARGS  1, /* Interface type: mode 0 = 8bit, 1 = 4bit(low nibble), 2 = 4bit(upper nibble) */ \
    1,               /* Use busy signal: 1 = use busy, 0 = use time delays */                          \
    PORTD, TRISD,    /* Data port and data port tris register */                                       \
    PORTA, TRISA,    /* Control port and control port tris register */                                 \
    3,               /* Bit number of control port is connected to RS */                               \
    2,               /* Bit number of control port is connected to RW */                               \
    1                /* Bit number of control port is connected to Enable */

#include <lcd_driver.h>  // LCD template code

#ifdef _PIC16
  // _LVP_OFF disables Low Voltage Programming, enabling use of the RB3 output.
  #pragma DATA _CONFIG, _CP_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC & _LVP_OFF
#else
  #pragma DATA    _CONFIG1H, _OSCS_OFF_1H & _HS_OSC_1H
  #pragma DATA    _CONFIG2L, _BOR_ON_2L & _BORV_20_2L & _PWRT_OFF_2L
  #pragma DATA    _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H
  #pragma DATA    _CONFIG3H, _CCP2MX_ON_3H
  #pragma DATA    _CONFIG4L, _STVR_ON_4L & _LVP_OFF_4L & _DEBUG_OFF_4L
  #pragma DATA    _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
  #pragma DATA    _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
  #pragma DATA    _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
  #pragma DATA    _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
  #pragma DATA    _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
  #pragma DATA    _CONFIG7H, _EBTRB_OFF_7H
#endif

#pragma CLOCK_FREQ 4000000

volatile bit rb0@PORTB.0;     // RB0 pushbutton
volatile bit ra4@PORTA.4;     // RA4 pushbutton

// Function to return the status of the S3 switch
char exit()
{
  int rb=0;
  rb = rb0;                             // Get state of S3
  return(!rb);
}

void led_fun();                         // Prototypes
void voltmeter();
void beeper();
void temperature();
void clock();

void main()
{
  // most important line that is often forgotten 
  // - turn PortA inputs that we are using into digital mode.
  adcon1 = 00001110b; // Bit 0 is an analog input for the A/D, the 1's are digital inputs.
  lcd_setup();

  int i2;
  set_bit(trisa,4);                     // Porta, bit4 goes to the S2 pushbutton

  trisb=0;                              // Make all of portb output
  set_bit(trisb,0);                     // Portb, bit 0 goes to the S3 pushbutton AND RB0 LED, so we'll make it an input
  portb=0;                              // Clear portb to turn off all the LEDs if they happen to be on.

  lprintf("Microchip/BoostC");
  lprintf("\n  Picdem2 Plus  ");

  delay_s(2);

  // Make RB0 an input to check the switch:
  set_bit(trisb,0);                     // Make RB0 an input to check the switch:

  // Here's our demo loop, written to aproximate the algorithm used in the .asm code.
  while(1)
  {
    //------------------ VOLT MEASUREMENT  ----------------------------
    lcd_gotoxy( 0, 0 );
    lprintf("   Voltmeter    ");
    lprintf("\nRA4=Next RB0=Now");

    // Note that the switches are active-low

    while( ra4 == 0);                   // while S2 is pressed

    while( ra4 == 1)                    // while S2 is released
    {
      if (rb0==0)
      {
        voltmeter();
        lprintf("\nRA4=Next RB0=Now");
      }
    }

    //------------------ Beeper ---------------------------------------
    lcd_gotoxy( 0, 0 );
    lprintf("     Beeper     ");
    lprintf("\nRA4=Next RB0=Now");

    while( ra4 == 0);                   // while s2 is pressed

    while( ra4 == 1)                    // while S2 is released
    {
      if (rb0==0)
      {
        beeper();
        lprintf("\nRA4=Next RB0=Now");
      }
    }

    //------------------ Temperature ----------------------------------
    lcd_gotoxy( 0, 0 );
    lprintf("  Temperature   ");
    lprintf("\nRA4=Next RB0=Now");

    while( ra4 == 0);                   // while s2 is pressed

    while( ra4 == 1)                    // while S2 is released
    {
      if (rb0==0)
      {
        temperature();
        lprintf("\nRA4=Next RB0=Now");
      }
    }

    //------------------ LED Fun --------------------------------------
    lcd_gotoxy( 0, 0 );
    lprintf("    LED Fun     ");
    lprintf("\nRA4=Next RB0=Now");

    while( ra4 == 0);                   // while s2 is pressed

    while( ra4 == 1)                    // while S2 is released
    {
      if (rb0==0)
      {
        led_fun();
        lprintf("\nRA4=Next RB0=Now");
      }
    }

    //------------------ Clock ----------------------------------------
    lcd_gotoxy( 0, 0 );
    lprintf("     Clock      ");
    lprintf("\nRA4=Next RB0=Now");

    while( ra4 == 0);                   // while s2 is pressed

    while( ra4 == 1)                    // while S2 is released
    {
      if (rb0==0)
      {
        clock();
        lprintf("\nRA4=Next RB0=Now");
      }
    }
  } //  while(1)
}


//----------------------------------------------------------------------------------------
//
//  led_fun -- Demonstrate the lighting the LEDs.  Note that we have to play a little 
//             switcheroo on the RB0 line, but the input and output can be done on the same pin.
//
//----------------------------------------------------------------------------------------

void led_fun()
{
  unsigned char j;
  unsigned char k;

  lprintf("\n   RB0 = Exit   ");
  while(rb0==0);                        // while RB0, S3 is pressed.  S3 and RB0 LED share the same portb pin.
  clear_bit(trisb,0);                   // Set RB0 to output

  while(1)
  {
    for (j=0; j<16; j++)
    {
      clear_bit(trisb,0);               // Set RB0 to output

      portb=j;                          // Output LED's
      delay_ms(50);

      set_bit(trisb,0);                 // Set RB0 to input
      delay_ms(2);                      // Needs some time to turn RB0 around to an input
                                        // Without this delay, RB0 will always read a 0, regardless of the switch.
      if (exit())
      {
        while (rb0 == 0);               // We need to stay here until RB0 is released, or we'll jump right into the next menu option.
        portb=0;
        return;
      }
    } // for (j=0...

    for (j=0; j<10; j++)
    {
      clear_bit(trisb,0);               // Set RB0 to output

      for (k=0; k<4; k++)
      {
        portb = 1<<k;                   // Make a 4-bit chaser light
        delay_ms(40);
      }

      set_bit(trisb,0);                 // Set RB0 to input
      delay_ms(2);                      // Needs some time to turn RB0 around to an input
                                        // Without this delay, RB0 will always read a 0, regardless of the switch.
      if (exit())
      {
        while (rb0 == 0);               // We need to stay here until RB0 is released, or we'll jump right into the next menu option.
        portb=0;
        return;
      }
    } // for (j=0...
  } // while(1)...
}


//----------------------------------------------------------------------------------------
//
//  voltmeter -- Demonstrate the useage of the PIC A/D converter by displaying the voltage
//               produced by the on-board 5K ohm pot.
//
//----------------------------------------------------------------------------------------

void voltmeter()
{
  volatile bit Go_Done@ADCON0.2;        // Note the the 18F4520 chip puts this in bit 1.
  volatile unsigned char ad_h@ADRESH;
  volatile unsigned char ad_l@ADRESL;

  while(rb0==0);                        // while RB0, S3 is pressed.  S3 and RB0 LED share the same portb pin.

  unsigned int AD_Result;
  unsigned int shiftH;
  unsigned int shiftL;

  lprintf("\n   RB0 = Exit   ");

  trisb=1;                              // Set portb to all outputs, except RB0.
  set_bit(trisa,0);                     // Set porta, bit 0 to input;
  adcon1 = 00001110b;                   // Bit 0 is an analog input for the A/D, the 1's are digital inputs.
  adcon0 = 10000001b;                   // Turn on the A/D converter, select channel 0.

  while(1)
  {
    clear_bit(trisb,0);                 // Set RB0 to output, so we can use the LED

    Go_Done=1;                          // Start conversion
    while ( Go_Done == 1 )              // Wait for conversion to complete -- better put a timeout in here some time.

    lcd_gotoxy( 0, 0 );

    // Separate int's need to be used to keep the shifts from screwing up.
    shiftH = ad_h;
    shiftL = ad_l;

    AD_Result = (shiftH<<2) | (shiftL>>6);  // Combine the two registers to get full 10 bits.

    lprintf("A/D  :%03X      ", AD_Result );
    lprintf("\nVolts:%d", (ad_h*0xC3)/10000);  // Print the 1's digit

    lcd_gotoxy( 7,1 );                  // Prepare to display the .fractional part.
    lprintf("%04dV                ", (ad_h*0xC3)/10);  // prints all digits, including the 1's digit printed above
    lcd_gotoxy( 7,1 );
    lprintf(".");                       // A cheap way of covering up the most significant 1's digit, which is redundant.

    portb=ad_h>>4;                      // Display the upper 4 A/D bits on the LEDs

    delay_ms(50);                       // Give LEDs time to shine

    set_bit(trisb,0);                   // Set RB0 to input so we can check S3 for exit.
    delay_ms(2);                        // Needs some time to turn RB0 around to an input.

    if (exit())
    {
      portb=0;                          // Shut off all the LEDs before we exit.
      while (rb0 == 0);                 // We need to stay here until RB0 is released, or we'll jump right into the next menu option.

      lcd_gotoxy( 0, 0 );
      lprintf("   Voltmeter    ");      // Get the prompt back up for when we're out.
      lprintf("\nRA4=Next RB0=Now");
      return;
    }
  }
  adcon0=0;                             // Shut off the AD converter.
}


//----------------------------------------------------------------------------------------
//
//  Beeper -- Use the PWM module in the PIC to generate a signal on the piezo.  This is a much nicer
//            demo of the PWM than the boring one that is in the .asm code.  This one loops through 
//            various settings of the period or dutycycle as selected by S2.
//            If you happen to have a scope available, hang a probe on R11 and see that the PWM
//            does something interesting with the period.  You'll see that PR2 only adjusts 
//            the duration of the second half of the cycle.
//
//----------------------------------------------------------------------------------------
void beeper()
{
  unsigned char i2;
  unsigned char start;
  unsigned char finish;
  unsigned char increment;
  unsigned char pwm_loop_type;

  volatile bit t2ckps0@T2CON.0;
  volatile bit t2ckps1@T2CON.1;

  lcd_gotoxy( 0, 0 );
  lprintf("Prd.=128 DC=128");
  //         1234567890123456
  lprintf("\nRA4=<-> RB0=Exit");

  while(rb0==0);                        // while RB0, S3 is pressed.  S3 and RB0 LED share the same portb pin.

  pr2     = 0x80;                       // PR2 = Timer2 period register.
  ccpr1l  = 0x80;                       // CCPR1L = Capture/Compare/PWM Register1 Low Byte
  t2con   = 0;

  set_bit(t2con,2);                     // Turn on timer2

  t2ckps0=1;                            // Try changing these bits...
  t2ckps1=0;                            //   ...see what happens.

  ccp1con = 0x0F;                       // CCP1CON = Capture/Compare/PWM Control -- put CCP1 into PWM mode
  clear_bit(trisc,2);                   // Portc, pin2 is the PWM output.
  set_bit(trisb,0);                     // Set RB0 to input so we can check S3 for exit.
  pwm_loop_type = 1;                    // PERIOD;

  while(1)
  {
    if (pwm_loop_type == 1)             // ==1, PERIOD)
    {
      start     = 0xFF;
      finish    = 0x80;
    }
    else                                // ==0, DUTYCYCLE 
    {
      start     = 0x80;
      finish    = 0;
    }
    increment = -1;

    for (i2=start; i2>finish; i2 += increment)
    {
      if (ra4 == 0)                     // If S2 (ra4) is depressed, then toggle between freq period and duty cycle.
      {
        pwm_loop_type = !pwm_loop_type;
        while(ra4 == 0);                // Wait here until the switch is released.
        break;                          // Blow out of the for loop and reconfigure it for the other PWM 
      }

      if (pwm_loop_type == 1)           // PERIOD)
      {
        pr2 = i2;
        lcd_gotoxy( 5,0 );
        lprintf("%03d", i2);
      }
      else
      {
        ccpr1l = i2;
        lcd_gotoxy( 12,0 );
        lprintf("%03d", i2);
      }

      delay_ms(60);                     // Slow the loop down to just the right frequency or duty cycle sweep.

      if (exit())
      {
        while (rb0 == 0);               // We need to stay here until RB0 is released, or we'll jump right into the next menu option.
        ccp1con = 0;                    // Shut off the PWM.
        portb=0;
        set_bit(trisc,2);

        lcd_gotoxy( 0, 0 );
        lprintf("     Beeper     ");

        return;
      }

    } // for (i2=...
  } // while (1)
}

//----------------------------------------------------------------------------------------
//
//  Temperature -- This is a straight conversion from Microchip's .asm demo code, but  
//                 replacing the "ssprw" macro with a 50 ms delay.  The equivalent C code
//                 always caused a hang, so I cheated with the delay rather than figure out why.  
//                 The .asm demo program writes the result of the temperature to the EEPROM.  That
//                 is not implemented in this demo.
//
//----------------------------------------------------------------------------------------

void temperature()
{
  int j;
  unsigned char delay = 50;
  unsigned char cmd_byte;
  unsigned char read_data;

  volatile bit smp@SSPSTAT.7;           // 1 == Input sampled at the end of the data output time. 
  volatile bit cke@SSPSTAT.6;           // 1 == Data transmitted on rising edge of SCK.
  volatile bit r_w@SSPSTAT.2;           // 1 == Transmit is in progress.

  volatile bit tmr1if@PIR1.0;

  //              7     6      5     4     3   2    1   0
  //  SSPCON2:  GCEN ACKSTAT ACKDT ACKEN RCEN PEN RSEN SEN

  volatile bit sen    @SSPCON2.0;       // 1 = Initiate START condition on SDA and SCL pins. Automatically cleared by hardware.
  volatile bit rsen   @SSPCON2.1;       // 1 = Initiate Repeated START condition on SDA and SCL pins.  Automatically cleared by hardware.
  volatile bit pen    @SSPCON2.2;       // STOP Condition Enable bit. 1 = Initiate STOP condition on SDA and SCL pins. Automatically cleared by hardware
  volatile bit rcen   @SSPCON2.3;       // Receive Enable bit (Master mode only) 1 = Enables Receive mode for I2C
  volatile bit acken  @SSPCON2.4;       // Acknowledge Sequence Enable bit, 0 = Acknowledge Sequence Idle
  volatile bit ackdt  @SSPCON2.5;       // Acknowledge Data bit, 0 = Acknowledge.
  volatile bit ackstat@SSPCON2.6;       // Acknowledge Status bit (Master Transmit mode only), 0 = Acknowledge was received from slave

  lprintf("\n   RB0 = Exit   ");
  while(rb0==0);                        // while RB0, S3 is pressed.  S3 and RB0 LED share the same portb pin.

  set_bit(trisc,3);
  set_bit(trisc,4);

  #ifdef _PIC16
    sspcon = 00101000b;                 // 16F877 has the same register, it's just labelled differently.
  #else
    sspcon1 = 00101001b;                // Enable the serial port and configures the SDA and SCL pins as the serial port pins
  #endif                                // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)), clock polarity == 0.

  smp = 1;                              // Disable slew rate control in sspstat, for Standard Speed mode.
  sspadd = 5;                           // Set the slave device address
  tmr1if = 0;                           // Clear the TMR1 overflow interrupt flag bit.
  tmr1h = 0;
  tmr1l = 0;
  cmd_byte = 1;                         // A command byte == 1 means that the TC74 sensor should measure the temperature.

  while(1)
  {
    cke = 1;                            // SSPSTAT Clock edge select.  Data is transmitted on the rising edge of SCK.
    sen = 1;                            // Initiate START condition on SDA and SCL pins. Automatically cleared by hardware.

    while ( sen == 1 );                 // Wait for the hardware to drop sen.

    sspbuf = 10011010b;                 // Send TC74 ADDRESS (write)

    delay_ms(delay);

    // ssprw                            // The following two lines were converted from a macro in the .asm code, but cause a hang here.
    //                                       I replaced them with a 50 ms delay.  Testing showed that we need more than 30 ms.
    // while( sspcon2 != 0 );           // Wait for SEN to drop?
    // while ( r_w == 1 );              // Wait for R_W to drop.  R_W == 1 == Transmit is in progress

    while ( ackstat == 1 );             // Wait for ackstat to drop.    

    sspbuf = cmd_byte;                  // Issue the command to the TC74 

    delay_ms(delay);

    // ssprw                            // The following two lines were converted from a macro in the .asm code, but cause a hang here.
    //                                       I replaced them with a 50 ms delay.  Testing showed that we need more than 30 ms.
    //while( sspcon2 != 0 );                // Wait for SEN to drop?
    //while ( r_w == 1 );                   // Wait for R_W to drop.  R_W == 1 == Transmit is in progress

    while ( ackstat == 1 );             // Wait for ackstat to drop.    

    rsen = 1;                           // Repeated start.
    while ( rsen == 1 );                // Wait for rsen to drop.

    sspbuf = 10011011b;                 // Send TC74 ADDRESS (read)

    delay_ms(delay);

    // ssprw                            // The following two lines were converted from a macro in the .asm code, but cause a hang here.
    //                                     I replaced them with a 50 ms delay.  Testing showed that we need more than 30 ms.
    //while( sspcon2 != 0 );              // Wait for SEN to drop?
    //while ( r_w == 1 );                 // Wait for R_W to drop.  R_W == 1 == Transmit is in progress

    while ( ackstat == 1 );             // Wait for ackstat to drop.    

    rcen = 1;                           // Enable Receive mode
    while ( rcen == 1 );

    read_data = sspbuf;                 // Read from the TC74.  This variable is "temperature" in the .asm code.

    ackdt = 1;                          // Send NOT-ack. 
    acken = 1;                          // Send Acknowledge Sequence not idle
    while ( acken == 1 );               // Wait for acken to drop

    pen = 1;                            // Initiate STOP condition on SDA and SCL pins. Automatically cleared by hardware.
    while( pen == 1 );                  // Wait for pen to drop

    if ( cmd_byte == 0 )
    {
      lcd_gotoxy( 0, 0 );
      lprintf("Temp: %d C      ", read_data ); // Display the temperature
    }

    if ( read_data & 0x40 )             // Check the data ready bit from the TC74.  If data's ready, go tell TC74 to send the data.
      cmd_byte = 0;                     // Prepare to issue a "read temp" command.
    else
      cmd_byte = 1;                     // Prepare to issue a "measure temp" command.

    set_bit(trisb,0);                   // Set RB0 to input so we can check S3 for exit.
    delay_ms(2);                        // Needs some time to turn RB0 around to an input.

    if (exit())
    {
      while (rb0 == 0);                 // We need to stay here until RB0 is released, or we'll jump right into the next menu option.
      portb=0;

      lcd_gotoxy( 0, 0 );
      lprintf("  Temperature   ");

      return;
    }
  }
}


//----------------------------------------------------------------------------------------
//
//  Clock -- Not implemented, only stubbed out.
//
//----------------------------------------------------------------------------------------

void clock()
{
  volatile bit tmr1if@PIR1.0;

  int j;

  lprintf("\n   RB0 = Exit   ");
  while(rb0==0);                        // while RB0, S3 is pressed.  S3 and RB0 LED share the same portb pin.

  while(1)
  {
    lcd_gotoxy( 0, 0 );
    lprintf("You add clk code");

    // Clock not implemented.  This is the student's first programming assignment!

    if (exit())
    {
      while (rb0 == 0);               // We need to stay here until RB0 is released, or we'll jump right into the next menu option.
      portb=0;
      lcd_gotoxy( 0, 0 );
      lprintf("     Clock      ");
      return;
    }
  }
}



http://www.sourceboost.com/home.html

Copyright © 2002-2006 SourceBoost Technologies