aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKing Kévin <kingkevin@cuvoodoo.info>2014-07-27 20:11:40 -0700
committerKing Kévin <kingkevin@cuvoodoo.info>2014-07-27 20:11:40 -0700
commitd6cefb130823ab130f7e07dd0f80927509e06691 (patch)
treee3a8f91bfb205c2f754406c6def8a21697960c35
parent43257b8acee3414abe766a7b1225f1a24cfeea0b (diff)
use timers to measure pulse and bits. megacode detecting added
-rw-r--r--pic/MDR/MDR.c134
1 files changed, 120 insertions, 14 deletions
diff --git a/pic/MDR/MDR.c b/pic/MDR/MDR.c
index ef46cea..9c42e4d 100644
--- a/pic/MDR/MDR.c
+++ b/pic/MDR/MDR.c
@@ -47,6 +47,8 @@
/* variables */
static uint8_t switches; /* save the last switch state */
+#define START 208 /* starting timer 0 value to wait up to 12ms in start_timer*/
+static uint8_t code[3]; /* the received code (24 bits) */
/* configuration bits */
uint16_t __at(_CONFIG1) __CONFIG1 = _FCMEN_ON & /* enable fail-safe clock monitor */
@@ -59,9 +61,17 @@ uint16_t __at(_CONFIG1) __CONFIG1 = _FCMEN_ON & /* enable fail-safe clock monito
_PWRTE_ON & /* use power-up timer */
_WDTE_OFF & /* disable watchdog */
_FOSC_XT; /* use external resonator */
+uint16_t __at(_CONFIG2) __CONFIG2 = _LVP_ON & /* enable low voltage programming */
+ /* DEBUG is not present in library, but I don't use it */
+ _BORV_LO & /* low borwn out voltage */
+ _STVREN_ON & /* enable reset on stack overflow */
+ _PLLEN_OFF & /* don't use 4X PLL, for longer timer */
+ _WRT_OFF; /* no flash write protect */
+
/* initialize micro-conroller */
void init (void) {
+ /* configure IO */
ANSELA = 0; /* all pins are digital */
ANSELB = 0; /* all pins are digital */
TRISA |= RADIO; /* radio signal is an input */
@@ -70,25 +80,67 @@ void init (void) {
TRISB &= ~(LED|MEMORY_CLK|MEMORY_DATA); /* LED is I2C memory are outputs */
led_off(); /* starting state */
+ /* configure switches input */
IOCIE = 1; /* enable interrupt on individual GPIO (typo in the lib) */
+ IOCIF = 0; /* clear GPIO interrupt */
IOCBP |= (SWITCH1|SWITCH2); /* enable interrupt when switch is released */
IOCBN |= (SWITCH1|SWITCH2); /* enable interrupt when switch is pressed */
switches = PORTB; /* save current switch state */
-/*
- T1CON = _T1CKPS1 | _T1CKPS0; // set prescaler to 8
- // 0 is set per default, but just be sure
- TMR1ON = 0; // stop timer 1
- TMR1GE = 0; // enable timer 1
- TMR1CS = 0; // use internal clock / 4 (=1MHz)
- TMR1IF = 0; // clear interrupt
- PIE1 = 1; // enable timer 1 interrupt
- PEIE = 1; // enable timer interrupt
-*/
+ /* use timer 0 to measure bitframes timing */
+ TMR0CS = 1; /* disable timer 0 (T0CKI/RA4 is connected to ground) */
+ TMR0SE = 0; /* increment timer0 on low to high edge ((T0CKI/RA4 is connected to ground) */
+ PSA = 0; /* use presacler for timer 0 */
+ PS0 = 1; /* use prescaler of 256 */
+ PS1 = 1; /* use prescaler of 256 */
+ PS2 = 1; /* use prescaler of 256 */
+ TMR0IE = 1; /* enable timer 0 interrupt */
+ TMR0IF = 0; /* clear timer 0 interrupt */
+
+ /* use timer 2 to measure pulse durations (max 16.384ms) */
+ TMR2ON = 1; /* stop timer 2 */
+ T2CKPS0 = 1; /* use prescaler of 64 */
+ T2CKPS1 = 1; /* use prescaler of 64 */
+ T2OUTPS0 = 0; /* use postscale of 1 */
+ T2OUTPS1 = 0; /* use postscale of 1 */
+ T2OUTPS2 = 0; /* use postscale of 1 */
+ T2OUTPS3 = 0; /* use postscale of 1 */
+ PR2 = 0xff; /* set interrupt on overflow */
+ TMR2IE = 1; /* enable timer 2 interrupt */
+ TMR2IF = 0; /* clear timer 2 interrupt */
+ PEIE = 1; /* enable peripheral interrupt (for timer 2) */
GIE = 1; /* golablly enable interrupts */
}
+/* start timer to measure bitframe
+ * returns the time (in 0.256ms steps) since the last start
+ * stops after 12ms (then it returns 0)
+ */
+uint8_t start_bit_timer(void)
+{
+ /* uses timer 0
+ * speed is Fosc/4 with a prescaler of 256
+ * each tick should be 1.0/((4000000/4)/256) = 0.0002560163850486431 seconds
+ * since there should be one pulse every 6ms, only wait up to 12ms
+ */
+ uint8_t time = TMR0-START; /* remember the time passed */
+ TMR0 = START; /* reset timer */
+ TMR0CS = 0; /* enable timer 0 */
+ return time;
+}
+
+/* start timer to measure pulse length
+ * read the time from TMR2
+ * step is 0.064ms
+ * stops at 0xff (16.384ms)
+ */
+void start_pulse_timer()
+{
+ TMR2 = 0; /* reset timer counter */
+ TMR2ON = 1; /* start timer 2 */
+}
+
/* funcion called on interrupts */
/* interrupt 0 is only one on PIC16 */
static void interrupt(void) __interrupt 0
@@ -98,9 +150,9 @@ static void interrupt(void) __interrupt 0
switches ^= PORTB; /* figure out which switch changed */
if (switches&SWITCH1) { /* switch 1 changed */
if (PORTB&SWITCH1) { /* switch 1 released */
- led_off();
+ led_off(); /* reset LED */
} else { /* switch 1 pressed */
- led_on();
+ led_on(); /* test LED */
}
}
if (switches&SWITCH2) { /* switch 2 changed */
@@ -110,14 +162,68 @@ static void interrupt(void) __interrupt 0
}
IOCIF = 0; /* clear GPIO interrupt */
}
+ if (TMR0IF) { /* timer 0 overflow. no bit within required time */
+ TMR0CS = 1; /* stop timer 1 */
+ TMR0 = START; /* reset timer */
+ TMR0IF = 0; /* clear timer 0 interrupt */
+ }
+ if (TMR2IF) { /* timer 2 overflow. long pulse */
+ TMR2ON = 0; /* stop timer 2 */
+ TMR2 = 0xff; /* set timer 2 count to maximum */
+ TMR2IF = 0; /* clear timer 2 interrupt */
+ }
}
void main (void)
{
+ uint8_t rx = 0; /* are we receiving a pulse */
+ uint8_t bit = 0; /* the current received bit */
+ uint8_t time = 0; /* time since previous bitframe start, in 0.256ms steps */
+
init(); /* configure micro-controller */
- led_on();
+
while (1) { /* a microcontroller runs forever */
-// sleep(); /* sleep to save power */
+ /* I can't go to sleep to safe power
+ * the RADIO is connected to RA0, but port A does not support interrupt on change
+ * the timers are off in sleep, except for timer 1 when externally driven, but this is not our case
+ * the watchdog can only wake up every 1ms, but that is not fast enough and a pulse could be missed
+ */
+ if (rx==0 && (PORTA&RADIO)) { /* pulse detected */
+ rx = 1; /* mark receiving start to wait until pulse is finished */
+ start_pulse_timer();
+ } else if (rx!=0 && !(PORTA&RADIO)) { /* end of pulse */
+ rx = 0;
+ if (TMR2>=14) { /* only observe pulses >0.9ms */
+ /* pulse should be 1ms, but 1.2ms are used in the field
+
+ * the first transmission can sometimes be detected a 10ms, even with a 1ms pulse
+ * this is why the fallinf edge is used
+ */
+ if (bit>0) { /* following pulses */
+ time += start_bit_timer(); /* get time and start measure time for next pulse */
+ if (time>=27 && time<=35) { /* pulse between 7 and 9 ms after previous bitframe start is a 0 */
+ time = 8; /* pulse is 2ms after bitframe start */
+ code[bit/8] &= ~(1<<(7-(bit%8))); /* store first bit=0 */
+ bit++; /* wait for next bit */
+ } else if (time>=40 && time<=47) { /* pulse between 10 and 12 ms after previous bitframe start is a 0 */
+ time = 20; /* the sync pulse is 5ms after bitframe start */
+ code[bit/8] |= 1<<(7-(bit%8)); /* store first bit=1 */
+ bit++; /* wait for next bit */
+ } else { /* unexpected pulse. code is broken */
+ bit = 0; /* restart from beginning for new code */
+ }
+ if (bit==24) { /* received all 24 bits */
+ led_on();
+ }
+ }
+ if (bit==0) { /* sync pulse (can be the current one it it is not a continuation */
+ start_bit_timer(); /* measure time until next bit */
+ time = 20; /* the sync pulse is 5ms after bitframe start */
+ code[bit/8] |= 1<<(7-(bit%8)); /* store first bit=1 */
+ bit++; /* wait for next bit */
+ }
+ }
+ }
}
}