// this function receives a single serial byte from the PC
// the function main must first detect the start bit, then
// call receive_serial_byte()
#define PIN_SER_IN PORTA.F2 // which pin for serial input (PORTA.F2)
#define SER_BAUD 51 // TMR1 (1Mhz/19200 baud) = 52
unsigned char rdata; // holds the serial byte that was received
//---------------------------------------------------------
void receive_serial_byte(void)
{
// this manually receives a serial byte in any PIC pin.
// NOTE! serial is inverted to connect direct to PC serial port.
// baud timing is done by using TMR1L and removing
// timer error after each baud. Starts with 1.5 baud delay,
// so each bit is sampled in middle of baud.
unsigned char i;
i=8; // 8 data bits to receive
TMR1L = (256 - SER_BAUD - 19); // load TMR1 value for ~1.5 baud
while(TMR1L.F7); // wait for baud
while(i) // receive 8 serial bits, LSB first
{
rdata = (rdata >> 1); // rotate right to store each bit
if(PIN_SER_IN) rdata.F7 = 0; // invert and save data bit
else rdata.F7 = 1;
i--;
TMR1L -= SER_BAUD; // load corrected baud value
while(TMR1L.F7); // wait for baud
}
TMR1L -= SER_BAUD; // wait for stop bit, ensure serial port is free
while(TMR1L.F7);
}
//---------------------------------------------------------
//---------------------------------------------------------
void main()
{
// main loop here; check buttons, send serial text
while(1)
{
while(!PIN_SER_IN); // wait here for serial byte start bit
receive_serial_byte(); // then get the byte in rdata
}
}
//---------------------------------------------------------
/**********************************************************
SharpGP2_Serial.c RomanBlack.com - orig 19th July 2009.
PIC 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 a LED on
PIC pin RA0.
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_LED LATA.F0 // pin for LED
#define PIN_SER_OUT LATA.F3 // 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 cm10; // for distance display
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 = 0b00000010; // 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
PIN_LED = 0; // set LED off
bres += 65536; // add 65536uS to bres value
if(bres >= 2000000) // if reached 2 seconds!
{
bres -= 2000000; // subtract 2 seconds, keep error
PIN_LED = 1; // flash the 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
// load ADC value in 16bit math var
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
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('G'); // send ascii text
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.
unsigned char i;
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);
}
//---------------------------------------------------------