//*********************************************************
/* Junebug_Serial4.c RomanBlack.com 19th July 2009.
Junebug 18F1320, uses my "zero error 1 second timer"
system to generate a 2 second interval, then every
2 seconds it reads an analog voltage from a
Sharp GP2 distance sensor and converts it to decimal
distance, then sends that data as a text string to PC
via bitbanged serial out. It also flashes Junebug LED1
everytime it takes a distance sample.
Code for MikroC, config handled by MikroC compiler;
_INTI02_OSC_1H
_WDT_OFF_2H
-MCLRE_ON_3H
_LVP_OFF_4L
_PWRT_ON_2L
*/
//*********************************************************
// functions declared
void calc_distance(void);
void send_serial_message(void);
void send_serial_byte(unsigned char);
#define PIN_SER_OUT LATA.F3 // which pin for serial out (PORTA.F3)
#define SER_BAUD 51 // TMR3 (1Mhz/19200 baud) = 52
// tested; works from 49 to 53, using 51
unsigned char i; // used for looping
unsigned char cm10; //
unsigned char cm; //
unsigned int math; // used for voltage calculations
unsigned long bres; // for bresenham 2-second timer system
//---------------------------------------------------------
void main()
{
// setup the PIC 18F1320
OSCCON = 0x72; // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10000010; // RA7 high imp, RA3 is serial out,
// RA1 is ADC input measuring VR1
PORTB = 0;
INTCON2 = 0; // PORTB pullups ON
TRISB = 0b00000000; // PORTB not used
ADCON0 = 0b00000101; // ADC ON, RA1 is ADC input
ADCON1 = 0b01111101; // AN1 is ADC input
ADCON2 = 0b10100010; // right justify, 8Tad, 32Tosc
T1CON = 0b00010001; // TMR1 is ON, 1:2 prescale, =1MHz
T3CON = 0b00010001; // TMR3 is ON, 1:2 prescale, =1MHz
// main loop here;
while(1)
{
// wait for 2 seconds, uses TMR1 free running at 1Mhz
while(!PIR1.TMR1IF); // wait for TMR1 overflow
PIR1.TMR1IF = 0; // clear overflow flag
LATA = 0; // all LEDs off
bres += 65536; // add 65536uS to bres value
if(bres >= 2000000) // if reached 2 seconds!
{
bres -= 2000000; // subtract 2 seconds, keep error
// flash Junebug LED1, RA0=1 RA6=0 RA7=hiimpedance
LATA.F0 = 1; // LED on
// read the ADC voltage RA1 (Sharp GP2 sensor)
ADCON0.F1 = 1; // set GO bit, start doing ADC
while(ADCON0.F1); // wait until ADC done
calc_distance(); // convert ADC value to distance
send_serial_message(); // send message back to PC!
}
}
}
//---------------------------------------------------------
void calc_distance(void)
{
// from the Sharp datasheet the analog voltage is
// the inverse of distance, so distance can be calculated
// d = (1 / volts) then just scaled to suit the sensor
[B]// load ADC value in 16bit math var[/B]
math = ADRESH;
math = (math * 256);
math += ADRESL;
// now invert it; (1 / volts) use (6050 / volts) for scaling
math = (6050 / math);
if(math >= 2) math -=2; // fix linear error (-2)
if(math > 99) math = 99; // max limit at 99cm
// convert from 0-99 to 2 decimal digits, 0-99cm
cm10=0;
while(math >= 10)
{
cm10++;
math -= 10;
}
cm = math;
}
//---------------------------------------------------------
void send_serial_message(void)
{
// send message and number to serial port
send_serial_byte('J'); // send ascii text
send_serial_byte('u');
send_serial_byte('n');
send_serial_byte('e');
send_serial_byte('b');
send_serial_byte('u');
send_serial_byte('g');
send_serial_byte(' ');
send_serial_byte('G');
send_serial_byte('P');
send_serial_byte('2');
send_serial_byte('=');
send_serial_byte('0'+ cm10); // send number as ascii text 0-9
send_serial_byte('0'+ cm); // send number as ascii text 0-9
send_serial_byte('c');
send_serial_byte('m');
send_serial_byte(13); // send carriage return/linefeed pair
send_serial_byte(10); // to start a new text line
}
//---------------------------------------------------------
void send_serial_byte(unsigned char data)
{
// this manually sends a serial byte out any PIC pin.
// NOTE! serial is inverted to connect direct to PC serial port.
// baud timing is done by using TMR3L and removing
// timer error after each baud.
i=8; // 8 data bits to send
PIN_SER_OUT = 1; // make start bit
TMR3L = (256 - SER_BAUD); // load TMR3 value for first baud;
while(TMR3L.F7); // wait for baud
while(i) // send 8 serial bits, LSB first
{
if(data.F0) PIN_SER_OUT = 0; // invert and send data bit
else PIN_SER_OUT = 1;
data = (data >> 1); // rotate right to get next bit
i--;
TMR3L -= SER_BAUD; // load corrected baud value
while(TMR3L.F7); // wait for baud
}
PIN_SER_OUT = 0; // make stop bit
TMR3L -= SER_BAUD; // wait a couple of baud for safety
while(TMR3L.F7);
TMR3L -= SER_BAUD;
while(TMR3L.F7);
}