////////////////////////////////////////////////////////////////////////////
// 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;
}
}
}
Copyright © 2002-2006 SourceBoost Technologies