Код: Выделить всё
//////////////////////////////////////////////////////////////////////
// File: bit.h
//
// Description: Bit manipulation macros
//
// These macros preserve the current value of the 'PORT' or register.
//
// WRITEPORT is the same as writing to a port
// but preserves the keepmask bits.
//
//////////////////////////////////////////////////////////////////////
// See below for detailed description of WRITEPORT(port,newval,keepMask)
#define WRITEPORT(port,newval,keepMask) \
(port) = ((newval) & (~keepMask)) | ((port) & (keepMask));
#define setBit(var, bitnum) (var)|=(1<<(bitnum))
#define resBit(var, bitnum) (var)&=~(1<<(bitnum))
#define clearBit(var, bitnum) (var)&=~(1<<(bitnum))
#define testBit(var, bitnum) (var)&(1<<(bitnum))
///////////////////////////////////////////////////////////////////////
//
// Macro: WRITEPORT(port,newval,keepMask)
//
// Description: A macro to write only to specific bits of a port.
//
// Author: John Main.
//
// The PORT is read, keepMask bits are preserved when the
// data value is output to the port.
//
// Note this macro reads the specified port
//
// Beware of port loading (too much current) e.g. if drive an LED with
// larger current then the input high voltage will not be met
// (see data sheet graphs of Voh vs Io) so reading back a zero.
// If this is a problem the use a variable to hold the port state
// and only read/update this, the putput to port.
//
// Breakdown of action of macro WRITEPORT.
//
// 1. Read the port and only keep the desired 'keepMask' bits.
//
// e.g. if the current value of the port is 0x6b
// and the mask is 0x0c (keep bits b3..2) from the port read.
//
// ((port) & (keepMask)) results in 0x6b & 0x0c
// 0110-1011 port
// 0000-1100 keepMask
// 000001000 Result 1
//
// 2. Create the output value and send only to the used bits
// i.e. to the non 'keepMask' bits of the port.
// e.g. if newval is 0xa7 (1010-0111)
//
// ((newval) & (~keepMask))
// 1010-0111 newval
// 1111-0011 ~keepMask
// 1010-0011 Result 2
//
// 3. 'OR' these together to get the final result.
// 0000-1000 Result 1
// 1010-0011 Result 2
// 1010-1011 Ored Result 3
//
//////////////////////////////////////////////////////////////////////
Код: Выделить всё
//////////////////////////////////////////////////////////////////////
//
// File: 16F88_Ultrasonic_ranger.c
//
// Author: J F Main.
//
// Description:
//
// Range finding by generation and reception of
// ultrasonic audio at 40kHz.
//
// Compiler : mikroC, mikroElektronika C compiler
// for Microchip PIC microcontrollers
// Version: 5.0.0.3
//
// Note Testing:
//
// Tested on 16F88
//
// Requirements:
//
// 40kHz Ultrasonic amplifier (transistor amp).
//
// 40kHz ultrasonic transducer - for different transducers
// e.g. for a 32kHz transducer change the software appropriately.
//
// Target : 16F88
//
// Notes :
//
// For the CCP module (16F88):
// Which pin is used is controlled by bit 12 of the configuration
// word (either RB0 or RB3). Use the compiler settings to set the
// configuration word i.e. you can not set this from within the
// source code
//
// This software uses RB0 as input to the CCP module.
//
// RB0 : ultrasonic in (via amplifier, peak hold, level detect).
// RB3 : ultrasonic out (40kHz pulses)
//
// Version:
// 1.02 22/Feb/06 - moved segment drives to free TX pin for debug
// SEG1 was on RB2 now on RB5
// SEG2 was on RB5 now on RB2
// 1.01 15/Feb/06 - Changed to compiler 5.0.0.3
// More efficient so had to re-code gen_ultra for correct frequency.
// 1.00 14/Feb/06 - Initial release.
//
// Copyright : Copyright © John Main 2006
// http://www.best-microcontroller-projects.com
// Free for non commercial use as long as this entire copyright notice
// is included in source code and any other documentation.
//
//////////////////////////////////////////////////////////////////////
#include "bit.h"
//////////////////////////////////////////////////////////////////////
// macros
//////////////////////////////////////////////////////////////////////
// globals for interrupt.
//
unsigned int T1_O = 0; // timer1 overflow updated in interrupt routine.
unsigned short gCapInt = 0; // captured something in interrupt routine.
unsigned short gfCapOn = 1; // control capture only capture 1st value.
unsigned int t_capL = 0; // timer 1 low.
unsigned int t_capH = 0; // timer 1 high.
unsigned int t_capO = 0; // timer 1 overflow.
unsigned int gCapVal = 0; // captured this.
//////////////////////////////////////////////////////////////////////
void init(void) {
OSCCON = 0x60; // b6..4 = 110 = 4MHz
// set CCP to capture mode every rising edge.
CCP1CON = 0x05;
ANSEL = 0; // all ADC pins to digital I/O
// Timer 1 on
T1CON = (1<<TMR1ON);
}
//////////////////////////////////////////////////////////////////////
void init_ports(void) {
PORTA = 0;
TRISA = 0; // 0=o/p - sets analogue pins to digital output.
PORTB = 0;
TRISB = 0x01; // 0=o/p Receive on RB0.
}
//////////////////////////////////////////////////////////////////////
void enable_interrupts(void) {
// Timer 1
PIR1 &= ~(1<<TMR1IF); // Zero T1 overflow register value.
// Capture
PIR1 &= ~(1<<CCP1IF); // Zero Capture flag
// Interrupt enable.
PIE1 = (1<<CCP1IE);
// Global interrupt enable.
INTCON = (1<<GIE) | (1<<PEIE); // enable global & peripheral
}
//////////////////////////////////////////////////////////////////////
void disable_interrupts(void) {
INTCON &= ~(1<<GIE); // disable global & peripheral
}
//////////////////////////////////////////////////////////////////////
// RA% can only be input on 16F88
// ret table is for straight through
// PORT 0 1 2 3 4 5 6 7 to a b c d e f g dp
// So map to new outputs:
// 0 a, 1 b, 2 c, 3 d, 4 e, 6 f, 7 g - loosing dp
// i.e. keep 1st 5 and move bits 5,6 to 6,7
int2seg(unsigned short digit) {
unsigned short r;
unsigned short ret[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66,
0x6D, 0x7D, 0x07, 0x7F, 0x6F };
if (digit<0 || digit>9) {
r = 0x7f;
} else {
r =( ret[digit] & 0x1f ) | \
( (ret[digit] & 0x60)<< 1);
}
return r;
}
//////////////////////////////////////////////////////////////////////
void seg_display_int(unsigned int val) {
char op[7];
IntToStr(val,op);
// 6 digits op by above.
// e.g. for num 1234
// pos 5 4 3 2 1 0
// num x x 1 2 3 4 \0
// index from left ! 0 1 2 3 4 5
// Display the lower 4 digits.
PORTA=int2seg(op[2]-'0');
setBit(PORTB,5);
delay_ms(4);
resBit(PORTB,5);
PORTA=int2seg(op[3]-'0');
setBit(PORTB,2);
delay_ms(4);
resBit(PORTB,2);
PORTA=int2seg(op[4]-'0');
setBit(PORTB,6);
delay_ms(4);
resBit(PORTB,6);
PORTA=int2seg(op[5]-'0');
setBit(PORTB,7);
delay_ms(4);
resBit(PORTB,7);
PORTB &= ~0xe4; // turn off all resBit should do this
PORTB=0;
PORTA=0x00;
}
//////////////////////////////////////////////////////////////////////
// generate 4 pulses of ultrasonic @ 32kHz (8 periods of 32kHz).
// Use the simulator to set correct period.
// single ended drive
void gen_ultra(void) {
setBit(PORTB,3);
delay_us(12);
resBit(PORTB,3);
delay_us(11);
setBit(PORTB,3);
delay_us(12);
resBit(PORTB,3);
delay_us(11);
setBit(PORTB,3);
delay_us(12);
resBit(PORTB,3);
delay_us(11);
setBit(PORTB,3);
delay_us(12);
resBit(PORTB,3);
delay_us(11);
}
//////////////////////////////////////////////////////////////////////
void main() {
unsigned int i,val,s1,s2,tH,tL,tO;
char op[12];
unsigned long calc=0;
init_ports();
init();
gCapInt=0; // Reset capture indicator.
gen_ultra();
while(1) {
gfCapOn = 1; // allow one capture value
tO = T1_O; // Get the current timer value.
tH = TMR1H;
tL = TMR1L;
t_capL = 0; t_capH = 0; t_capO = 0; // initialise capture
gen_ultra();
enable_interrupts();
seg_display_int(val);
disable_interrupts(); // had 20 ish ms of time so stop
if (! gCapInt) { // no echo from soft output ? try loud
enable_interrupts();
seg_display_int(val);
seg_display_int(val);
disable_interrupts(); // had 20 ish ms of time so stop
}
// Did we get any echo from soft or loud ?
if (gCapInt) { // captured anything ?
gCapInt=0; // reset for next time
// 4MHz clock so timer 1 returns us
// gCapVal * 1,000,000 = seconds.
// speed of sound in air at 20degC = 340m/s
// (gCapVal*1000000*340)/(2*100) = distance in cm
s1=(t_capH-tH);
s2=(t_capL-tL);
calc = ((s1)<<8)+s2;
calc *= 34;
calc /= 2000; // output in cm
val = (int)calc;
}
} // while(1)
}
////////////////////////////////////////////////////////////////////////
void interrupt(void) {
// Free run Timer 1 get the overflow to extend counter here.
if (PIR1 & (1<<TMR1IF) ) { // T1 overflowed ?
PIR1 &= ~(1<<TMR1IF); // clear timer1 overflow bit.
T1_O++;
}
// Capture
if (PIR1 & (1<<CCP1IF)) {
PIR1 &= ~(1<<CCP1IF); // Zero Capture flag.
if (gfCapOn) { // allow only 1 capture
gfCapOn = 0;
t_capL = CCPR1L;
t_capH = CCPR1H;
t_capO = T1_O;
gCapInt = 1; // signal that a capture occured.
}
}
// Interrupts are only enabled at a specific point from program.
// They are not re-enabled here
// Note GIE set by RETFIE instruction
}