/******************************************************************
* *
* Project: Raj Voltmeter *
* Source: Raj_Voltmeter.c *
* Author: Mike McLaren, K8LH *
* Date: 03-Aug-12 *
* Revised: 03-Aug-12 *
* *
* 16F688 + HD44780 2x16 LCD Voltmeter Experiment based on a *
* project from Rajendra Bhatt's 'Embedded-Lab.com' blog. *
* *
* *
* IDE: MPLAB 8.84 (tabs = 4) *
* Lang: Sourceboost BoostC v7.05, Lite/Free version *
* *
******************************************************************/
#include <system.h>
#pragma DATA _CONFIG, _WDT_OFF & _INTOSCIO
#pragma CLOCK_FREQ 8000000 // 8-MHz INTOSC
/******************************************************************
* function prototypes *
******************************************************************/
/******************************************************************
* variables *
******************************************************************/
char *volt = "00.0 V"; //
int input; // adc voltage reading
/******************************************************************
* defines *
******************************************************************/
#define line1 0x80 // lcd ddram address for line 1
#define line2 0xC0 // lcd ddram address for line 2
#define lcd_d4 portc.0 // RC0
#define lcd_d5 portc.1 // RC1
#define lcd_d6 portc.2 // RC2
#define lcd_d7 portc.3 // RC3
#define lcd_rs portc.4 // RC4
#define lcd_e portc.5 // RC5
/******************************************************************
* low level drivers & functions *
******************************************************************/
void PutNyb(char work) // write nibble
{ lcd_d4 = work.4; //
lcd_d5 = work.5; //
lcd_d6 = work.6; //
lcd_d7 = work.7; //
lcd_e = 1; lcd_e = 0; // strobe 'E' pin
delay_us(160); //
} //
void PutLCD(char work) // write byte (two nibbles)
{ PutNyb(work); // write hi nibble
asm swapf _work,F // swap nibbles
PutNyb(work); // write lo nibble
} //
void PutCMD(char pdata) // lcd command (RS=0)
{ lcd_rs = 0; PutLCD(pdata); //
} //
void PutDAT(char pdata) // lcd data (RS=1)
{ lcd_rs = 1; PutLCD(pdata); //
} //
void PutDAT(char* pdata) // lcd data (RS=1) strings
{ char temp; char ndx = 0; //
while(temp = pdata[ndx]) //
PutDAT(temp); //
} //
/* *
* HD44780 "initialize by instruction" procedure for 4-bit mode *
* */
void lcdinit() //
{ delay_ms(100); //
lcd_rs = 0; // RS=0 (command)
PutNyb(0x30); delay_ms(4); // step 1 (required 4-ms delay)
PutNyb(0x30); // step 2 (built-in 160-us delay)
PutNyb(0x30); // step 3 (built-in 160-us delay)
PutNyb(0x20); // step 4 (built-in 160-us delay)
/* *
* now in 4-bit interface mode and can write full 8-bit bytes *
* */
PutCMD(0x28); // 4-bit, 2-lines, 5x7 font
PutCMD(0x0C); // display on, currsor & blink off
PutCMD(0x06); // cursor inc, shift off
PutCMD(0x01); // clear display
delay_ms(2); // required delay
} //
int getadc(char channel) //
{ int result; //
adcon0.CHS0 = channel.0; //
adcon0.CHS1 = channel.1; //
adcon0.CHS2 = channel.2; //
adcon0.ADON = 1; // turn ADC on
delay_us(20); //
adcon0.GO_DONE = 1; //
while(adcon0.GO_DONE); //
adcon0.ADON = 0; // turn ADC off
result = adresh << 8; //
result |= adresl; //
return result; // 0..1023
}
/******************************************************************
* main init *
******************************************************************/
void main() //
{
ansel = 0b00000100; // RA2/AN2 analog, others digital
adcon0 = 0b10000000; // right justified adc result
adcon1 = 0b01010000; // Fosc/16 conversion clock
cmcon0 = 0x07; // disable comparators
osccon = 0b01110000; // INTOSC = 8-MHz
while(osccon.HTS == 0); // wait until osc stable
trisa = 0b00001100; // RA2(AN2) & RA3(MCLR) inputs
trisc = 0b00000000; // portc all outputs
lcdinit(); // init LCD in 4-bit interface mode
PutDAT("DVM Project"); //
/******************************************************************
* main loop *
******************************************************************/
do //
{ input = getadc(2); // get adc reading, 0..1023
input *= 2; // scale to volts * 100
input += 5; // rounding (to 1/10th volt)
/* *
* format the output and display on LCD *
* */
volt[0] = (input/1000) | '0'; // 'tens' digit
volt[1] = (input/100)%10 | '0'; // 'ones' digit
volt[3] = (input/10)%10 | '0'; // 'tenths' digit
PutCMD(line2+5); // line 2 tab 6
PutDAT(volt); // update LCD
delay_ms(500); // 500 msec update intervals
} while(1); // loop forever
} //