You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/test/picc/test.c

349 lines
8.0 KiB

/*
* level - electronic level using the ADXL202
*
* This program consists of an interrupt routine that measures the pulse
* width from the ADXL202 and a main routine that updates the dot matrix
* display on the DISPLAY board.
*
* Timer1 and the two Capture/Compare registers are used to measure the
* pulse width.
*
* Use PICCLITE to compile this program for the PIC16F877.
*
* Status: Sept 25, 2003
* Working. The code is pretty brute force and the resolution isn't
* what I expected. Need to review calculations for angle vs. accel
* (gravity). I determined the zero offsets empirically and hard coded
* them. For coding simplicity I am discarding any measurements where
* the counter overflows during the measurement.
*
* Improvements should include: a method to zero the offsets at
* runtime and increased gain (which probably means going to 16 bit
* values). Also consider filtering the measured values to gain stability.
* Add code to handle counter overflow.
*/
#include <pic.h>
#include "test.h"
/*
* bit macros suggested by the PICCLITE manual
*/
#define BITSET(var, bitno) ((var) |= 1 << (bitno))
#define BITCLR(var, bitno) ((var) &= ~(1 << (bitno)))
/*
* pulse with variables
*
* These are set up the measurePW() ISR and read by the main loop
*/
unsigned char PeriodStartX;
unsigned char PeriodEndX;
unsigned char PulseEndX;
unsigned char PulseEndTempX;
unsigned char PWSyncX;
unsigned char PeriodStartY;
unsigned char PeriodEndY;
unsigned char PulseEndY;
unsigned char PulseEndTempY;
unsigned char PWSyncY;
/*
* interrupt service routine to measure pulse width
*
* This routine uses the capture facility of the 16F877 to measure the
* period and the pulse width of a signal. This routine has two states
* the first looks for the rising edge of the signal which indicates the
* end of one period and the beginning of the next. The second state
* looks for the falling edge of the signal to determine the pulse
* width.
*
* Only the high 8 bits of the captured time are record. At 20MHz this
* yields a time resolution of approximately 51us.
*
* RC0 and RC1 indicate ISR over-run (in other words the main loop did
* not handle the measured values quickly enough).
*/
void interrupt
measurePW(void)
{
/* determined which capture register requires service */
if (CCP1IF == 1)
{
/* CCP1 */
if ((CCP1CON & 0b00000111) == 0b00000101)
{
/* rising edge-
* record last rise time (period_end -> period_start)
* record last falling time (pulse_end_temp -> pulse_end)
* record this rise time (capture -> period_end)
* set synchronization flag
* change mode to look for falling edge
*/
PeriodStartX = PeriodEndX;
PulseEndX = PulseEndTempX;
PeriodEndX = CCPR1H;
PWSyncX++;
CCP1CON = 0b00000100;
/* Indicated an ISR over-run if the sync flag was
* not cleared by the main loop
*/
if (PWSyncX > 1)
{
RC0 = 0;
}
}
else /* assume falling edge */
{
/* falling-
* save this falling time for later
* change mode to look for rising edge
*/
PulseEndTempX = CCPR1H;
CCP1CON = 0b00000101;
}
/*
* clear interrupt flags and return
*/
CCP1IF = 0;
}
else
{
/* CCP2 */
if ((CCP2CON & 0b00000111) == 0b00000101)
{
/* rising edge-
* record last rise time (period_end -> period_start)
* record last falling time (pulse_end_temp -> pulse_end)
* record this rise time (capture -> period_end)
* set synchronization flag
* change mode to look for falling edge
*/
PeriodStartY = PeriodEndY;
PulseEndY = PulseEndTempY;
PeriodEndY = CCPR2H;
PWSyncY++;
CCP2CON = 0b00000100;
/* Indicated an ISR over-run if the sync flag was
* not cleared by the main loop
*/
if (PWSyncY > 1)
{
RC3 = 0;
}
}
else /* assume falling edge */
{
/* falling-
* save this falling time for later
* change mode to look for rising edge
*/
PulseEndTempY = CCPR2H;
CCP2CON = 0b00000101;
}
/*
* clear interrupt flags and return
*/
CCP2IF = 0;
}
}
/*
* measure tilt and update dot matrix display
*
* This program uses the times recorded by the measurePW() ISR to
* calculate pulse width. The pulse width is then translated into a tilt
* measurement and finally displayed on the dot matrix display.
*/
void
main(void)
{
unsigned char periodX = 0;
unsigned char pulseX = 0;
unsigned char periodY = 0;
unsigned char pulseY = 0;
int tiltX;
int tiltY;
/*
* Setup I/O ports
* RC0 and RC3 outputs, the rest are inputs.
* RA5 output (power to ADXL202)
* Set port C outputs high to turn off the LEDs
*/
TRISC = 0b11110110;
RA5 = 1;
PORTC = 0xff;
/*
* Setup the I/O ports that control the dot matrix display
*/
TRISA = 0b11000000;
TRISB = 0b11100000;
TRISD = 0b10000000;
ADCON1 = 0x06; /* disable ADC so that port A is digital I/O */
PORTD = 0; /* turn off all rows */
PORTB = 0xff; /* turn off all columns */
PORTA = 0xff; /* turn off all columns */
/* configure timer1
* 1:1 prescale
* Internal clock (Fosc/4)
* Enabled
*/
T1CON = 0b00000001;
/*
* configure capture registers
* capture on rising edge
*/
CCP1CON = 0b00000101;
CCP2CON = 0b00000101;
/*
* clear sync flag
*/
PWSyncX = 0;
PWSyncY = 0;
/*
* enable interrupts
*/
PEIE = 1;
CCP1IE = 1;
CCP2IE = 1;
ei();
/*
* main loop
*/
for (;;)
{
/*
* kick watchdog
*/
CLRWDT();
if (PWSyncX > 0)
{
/*
* Test for easy calculations
* i.e., no counter roll over during the measurment
*/
if (PeriodEndX > PeriodStartX)
{
if (PulseEndX > PeriodStartX)
{
/*
* no roll over, so proceed
*/
periodX = PeriodEndX - PeriodStartX;
pulseX = PulseEndX - PeriodStartX;
periodX = (periodX / 2) + 9; /* offset = 9 */
tiltX = (periodX) - pulseX;
/*
* turn off all rows and then figure out which row to turn
* on based on the tilt
*/
PORTD = 0;
if (tiltX < -5)
{
RD6 = 1;
}
else if (tiltX < -4)
{
RD5 = 1;
}
else if (tiltX < -2)
{
RD4 = 1;
}
else if (tiltX > 5)
{
RD0 = 1;
}
else if (tiltX > 4)
{
RD1 = 1;
}
else if (tiltX > 2)
{
RD2 = 1;
}
else
{
RD3 = 1;
}
}
}
PWSyncX = 0;
}
if (PWSyncY > 0)
{
/*
* Test for easy calculations
* i.e., no counter roll over during the measurment
*/
if (PeriodEndY > PeriodStartY)
{
if (PulseEndY > PeriodStartY)
{
/*
* no roll over, so proceed
*/
periodY = PeriodEndY - PeriodStartY;
pulseY = PulseEndY - PeriodStartY;
periodY = (periodY / 2) - 1; /* offset = -1 */
tiltY = (periodY) - pulseY;
/*
* turn off all columns then figure out which column
* to turn on based on the tilt
*/
PORTA = PORTA | 0b00111111;
PORTB = PORTB | 0b00011111;
if (tiltY < -5)
{
RB1 = 0;
}
else if (tiltY < -4)
{
RB0 = 0;
}
else if (tiltY < -2)
{
RA4 = 0;
}
else if (tiltY > 5)
{
RA0 = 0;
}
else if (tiltY > 4)
{
RA1 = 0;
}
else if (tiltY > 2)
{
RA2 = 0;
}
else
{
RA3 = 0;
}
}
}
PWSyncY = 0;
}
}
}