summaryrefslogtreecommitdiffstats
path: root/test/picc/test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/picc/test.c')
-rw-r--r--test/picc/test.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/test/picc/test.c b/test/picc/test.c
new file mode 100644
index 0000000..5fc2e81
--- /dev/null
+++ b/test/picc/test.c
@@ -0,0 +1,348 @@
+/*
+ * 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;
+ }
+ }
+}
+