שימו לב - גם כאן קוד כתוב ל- PIC. לוגיקת העבודה היא אותה לוגיקה.
//////////////////////////////////////////////////////////////////////////////
// SRF08 Ultrasonic rangefinder Software - Preliminary
//
// Written by Gerald Coe - November 2001
//
// (C) Copyright Devantech Ltd 2001
// Commercial use of this software is prohibited.
// Private and Educational use only is permitted
//
////////////////////////////////////////////////////////////////////////////
//
// Sonar uses one of 16 addresses -> 0xe0 - 0xfe
// Bit 0 is always zero - its the i2c rd/wr bit
//
////////////////////////////////////////////////////////////////////////////
//
// This software is written for the HITECH PICC C compiler
//
////////////////////////////////////////////////////////////////////////////
#include "pic.h"
#define version 1 // software version
#define echo RA2 // 1st stage echo line
#define led RB4 // low to light led
#define pot_ud RC0 // Pot up/dw control
#define pot_cs RC1 // Pot chip select control
#define anpower RC2 // analog power - low on
#define txpower RC5 // Tx power - low on
#define clamp RC6 // comparator clamp
#define clamp_en TRISC6 // comparator clamp enable
#define detect RC7
// initialise the eeprom with 0xea i2c address
// the default shipping address is 0xe0, our test jig
// will change the address to 0xe0
__EEPROM_DATA (0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0xff, 0xff);
// prototypes
void setup(void);
void burst(void);
void multi_range(void);
void ann_range(void);
void set_bit(unsigned char idx);
void flash_addr(void);
void convert(unsigned char cmd, unsigned char idx);
// global variables
char buffer[36];
char loop, dlyctr;
bit timeout;
unsigned char command, index;
unsigned char gain, gaincnt;
// the interrupt
void interrupt the_only_one(void)
{
static char idx=0, wr_addr=0;
char i2c_data;
if(SSPIF) { // I2C interrupt
SSPIF = 0;
if(!STAT_DA) { // low = address
wr_addr=0;
}
if(STAT_RW) { // high = read from this program
SSPBUF = buffer[idx]; // send data
if(idx<36) ++idx; // limit index to 32 bytes
CKP = 1; // release I2C clock line
}
else {
i2c_data = SSPBUF; // read incoming data
wr_addr++;
if(wr_addr==2) { // 1st byte written is internal location
idx = i2c_data; // lower 4 bits only (0-35 index)
if(idx>35) idx=35; // limit index
}
else {
if(idx==0 && wr_addr==3) { // register 0 is start ping command
command=i2c_data;
}
}
}
SSPOV = 0;
}
if(TMR1IF==1) { // timer1 is the echo timer
timeout = 1; // end of echo timing when it rolls over
TMR1ON = 0;
TMR1IF = 0;
}
}
void main(void)
{
static unsigned char seq=0;
setup(); // initialise the peripherals
flash_addr(); // flash the I2C address on LED
while(1) {
while(!command); // wait for start command
timeout = 1; // end of echo timing when new command arrives
TMR1ON = 0;
TMR1IF = 0;
switch(command) {
case 0x00: // Gain commands to limit max. gain in
case 0x01: // Range Mode
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F: gain = command;
break;
case 0x80: // inches, centimetres or uS
case 0x81:
case 0x82: multi_range(); // 2byte multi-ping data
seq = 0; // reset address change sequence
break;
case 0x83:
case 0x84:
case 0x85: ann_range(); // 2byte 1st, 1byte multi-pings
seq = 0; // reset address change sequence
break;
case 0xa0: seq = 1; // start of sequence to change address
break;
case 0xaa: if(seq==1) ++seq; // 2nd of sequence to change address
else seq = 0;
break;
case 0xa5: if(seq==2) ++seq; // 3rd of sequence to change address
else seq = 0;
break;
case 0xe0: // if seq=3 user is changing sonar I2C address
case 0xe2:
case 0xe4:
case 0xe6:
case 0xe8:
case 0xea:
case 0xec:
case 0xee:
case 0xf0:
case 0xf2:
case 0xf4:
case 0xf6:
case 0xf8:
case 0xfa:
case 0xfc:
case 0xfe: if(seq==3) {
EEPROM_WRITE(5, command);
SSPADD = command;
led = 0;
}
seq = 0;
break;
}
command = 0;
anpower = 1; // analog power off
}
}
////////////////////////////////////////////////////////////////////////////
// The burst routine generates an acurately timed 40khz burst of 8 cycles.
// Timing assumes an 8Mhz PIC (500nS instruction rate)
// I drop down to assembler here because I don't trust the compiler to
// always generate accurately timed code with different versions or
// optimisation settings
//
void burst(void) {
char x;
clamp = 0;
clamp_en = 0; // force low on clamp line
pot_cs = 1; // deselect pot
led = 0; // on
GIE = 0; // disable interrupts for timing accuracy
txpower = 0; // turn st232 on
anpower = 0; // turn analog power on
loop = 8; // number of cycles in burst
pot_ud = 1; // select pot inc mode
x = 0;
while(--x); // wait for +/- 10v to charge up.
pot_cs = 0; // enable pot
for(x=2; x<36; x++) { // and take opportunity to clear echo buffer
pot_ud = 0; // and reset pot wiper
buffer[x] = 0;
pot_ud = 1;
}
clamp_en = 1; // release clamp line
ADGO = 1; // convert light sensor
pot_cs = 1; // deselect pot
while(ADGO);
pot_ud = 0; // select pot dec mode
buffer[1] = ADRESH; // store light sensor reading
#asm
burst1: movlw 0x14 ; 1st half cycle
movwf _PORTB
nop
movlw 7 ; (7 * 3inst * 500nS) -500nS = 10uS
movwf _dlyctr ; 10uS + (5*500nS) = 12.5uS
burst2: decfsz _dlyctr,f
goto burst2
movlw 0x18 ; 2nd half cycle
movwf _PORTB
movlw 6 ; (6 * 3inst * 500nS) -500nS = 8.5uS
movwf _dlyctr ; 8.5uS + (8*500nS) = 12.5uS
burst3: decfsz _dlyctr,f
goto burst3
nop
decfsz _loop,f
goto burst1
movlw 0x10 ; set both drives low
movwf _PORTB
#endasm
GIE = 1;
txpower = 1; // turn st232 off
led = 1; // Led off
pot_cs = 0; // enable pot
}
////////////////////////////////////////////////////////////////////////////
void multi_range(void) {
unsigned char tone_cnt, period, cmd;
burst(); // send 40khz burst, reset pot wiper and clear buffer
cmd = command; // save cmd so we know how to convert result
TMR0 = 0;
TMR1H = 0;
TMR1L = 0;
timeout = 0;
tone_cnt = 3;
index = 2;
TMR1ON = 1;
TMR2 = 0;
TMR2IF = 0;
gaincnt = gain;
while(timeout==0) { // while still timing stage3
while(timeout==0 && echo==0) { // wait for high
if(TMR2IF && gaincnt) {
pot_ud = 1;
--gaincnt;
TMR2IF = 0;
pot_ud = 0;
}
}
while(timeout==0 && echo==1) { // wait for low
if(TMR2IF && gaincnt) {
pot_ud = 1;
--gaincnt;
TMR2IF = 0;
pot_ud = 0;
}
}
if(timeout==0) {
period = TMR0;
TMR0 = 0;
if(period>40 && period<60) {
if(!(--tone_cnt)) {
do {
buffer[index] = TMR1H;
buffer[index+1] = TMR1L;
}while(buffer[index] != TMR1H);
convert(cmd, index); // convert to in, cm or uS
if(index == 36) return;
index += 2;
tone_cnt = 3;
period = 0;
while(--period){ // delay about 5 inches of range
if(TMR2IF && gaincnt) {
pot_ud = 1;
--gaincnt;
TMR2IF = 0;
pot_ud = 0;
}
}
while(--period){
if(TMR2IF && gaincnt) {
pot_ud = 1;
--gaincnt;
TMR2IF = 0;
pot_ud = 0;
}
}
while(--period){
if(TMR2IF && gaincnt) {
pot_ud = 1;
--gaincnt;
TMR2IF = 0;
pot_ud = 0;
}
}
}
}
else tone_cnt=3;
}
}
}
////////////////////////////////////////////////////////////////////
void ann_range(void) {
unsigned char tone_cnt, period, index, cmd;
burst(); // send 40khz burst and clear buffer
cmd = command; // save cmd so we know how to convert result
TMR0 = 0;
TMR1H = 0;
TMR1L = 0;
timeout = 0;
tone_cnt = 3;
index = 2;
TMR1ON = 1;
while(timeout==0) { // while still timing stage3
while(timeout==0 && echo==0) { // wait for high
if(TMR2IF) {
pot_ud = 1;
TMR2IF = 0;
pot_ud = 0;
}
}
while(timeout==0 && echo==1) { // wait for low
if(TMR2IF) {
pot_ud = 1;
TMR2IF = 0;
pot_ud = 0;
}
}
if(timeout==0) {
period = TMR0;
TMR0 = 0;
if(period>40 && period<60) {
if(!(--tone_cnt)) {
set_bit(TMR1H);
if(index==2) { // only 1st echo in ann mode
do {
buffer[index] = TMR1H;
buffer[index+1] = TMR1L;
}while(buffer[index] != TMR1H);
convert(cmd, index); // convert to in, cm or uS
index += 2;
}
tone_cnt = 1; // to detect continuing echo
}
}
else tone_cnt=3;
}
}
}
void set_bit(unsigned char idx)
{
char pos;
pos = idx&7; // lower 3 bits indicate bit position
idx = (idx>>3)+4; // index into buffer
switch(pos) {
case 0: buffer[idx] |= 0x01;
break;
case 1: buffer[idx] |= 0x02;
break;
case 2: buffer[idx] |= 0x04;
break;
case 3: buffer[idx] |= 0x08;
break;
case 4: buffer[idx] |= 0x10;
break;
case 5: buffer[idx] |= 0x20;
break;
case 6: buffer[idx] |= 0x40;
break;
case 7: buffer[idx] |= 0x80;
break;
}
}
////////////////////////////////////////////////////////////////////
void convert(unsigned char cmd, unsigned char idx)
{
unsigned int x;
x = (buffer[idx]<<8) + buffer[idx+1];
switch(cmd) {
case 0x80:
case 0x83: x /= 148; // convert to inches
break;
case 0x81:
case 0x84: x /= 58; // convert to cm
}
buffer[idx] = x>>8;
buffer[idx+1] = x&0xff; // replace uS with inches, cm or uS
}
////////////////////////////////////////////////////////////////////
void setup(void)
{
// _CONFIG(0x0d42); // code protected, hs osc
__CONFIG(0x3d72); // code not protected, hs osc
ADCON1 = 0x0e; // PortA 0 is analog, rest are digital
ADCON0 = 0x41; // convert ch0
PORTC = 0xff; // nothing powered at start
TRISA = 0xff; // All inputs
TRISB = 0xc3; // 11000011 PB7,6,1,0 are inputs, rest are outputs
TRISC = 0x18; // 00011000 RC3,4 are inputs
OPTION = 0x08; // portb pullups on, prescaler to wdt
T1CON = 0x10; // timer1 prescale 1:2, but not started yet
T2CON = 0x04; // 1:4 prescale and running
// T2CON = 0x06; // 1:16 prescale and running
PR2 = 140; // set TMR2IF every 280uS at 8MHz
SSPSTAT = 0x80; // slew rate disabled
SSPCON = 0x36; // enable port in 7 bit slave mode
SSPCON2 = 0x80; // enable general call (address 0)
SSPADD = EEPROM_READ(5); // address 0xE0 - 0xFE
if(SSPADD<0xE0)
SSPADD=0xE0; // protection against corrupted eeprom
else SSPADD &= 0xfe;
buffer[0] = version; // software revision
SSPIE = 1; // enable I2C interrupts
TMR1IE = 1; // enable timer1 interrupts
TMR1IF = 0;
SSPIF = 0;
PEIE = 1; // enable peripheal interrupts
GIE = 1; // enable global interrupts
gain = 32; // maximum gain at power-up
}
////////////////////////////////////////////////////////////////////
void flash_addr(void)
{
unsigned char count;
long delay, on, off;
on = off = 30000;
count = ((SSPADD>>1)&0x0f)+1;
do {
delay = on;
on = 10000;
led = 0; // led on
while(--delay) if(command) return;
delay = off;
off = 20000;
led = 1; // led off
while(--delay) if(command) return;
}
while(--count);
}
////////////////////////////////////////////////////////////////////
אין תגובות:
הוסף רשומת תגובה