PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
robot_ir_decode.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 #include "pic24_all.h"
30 
31 /** \file
32  * Decodes bi-phase bitstream from IR remote control as output by IR receiver
33  * Protocol is Phillips VCR control, 13 bit command (start bit, toggle bit, 5-bit address, 6-bit data)
34  * Timer2 divider must be set such that one bit time does not exceed the timer period.
35 */
36 
37 #define IR_FIFO_SIZE 32
38 volatile uint8_t au8_irFIFO[32];
39 volatile uint16_t u16_irFifoHead = 0;
40 volatile uint16_t u16_irFifoTail = 0;
41 
42 void irFifoWrite(uint8_t u8_x) {
43  u16_irFifoHead++;
44  if (u16_irFifoHead == IR_FIFO_SIZE) u16_irFifoHead = 0;
45  au8_irFIFO[u16_irFifoHead] = u8_x;
46 }
47 uint8_t irFifoRead(void) {
48  while (u16_irFifoHead == u16_irFifoTail) {
49  doHeartbeat();
50  }
51  u16_irFifoTail++;
52  if (u16_irFifoTail == IR_FIFO_SIZE) u16_irFifoTail = 0;
53  return au8_irFIFO[u16_irFifoTail];
54 }
55 
56 uint8_t irFifoDataRdy(void) {
57  return(u16_irFifoHead != u16_irFifoTail);
58 }
59 
60 
61 
62 #define PWM_PERIOD 20000 //in microseconds
63 
64 /* no interrupt for Timer2, must be configured so that one bit time does
65 not exceed the Timer2 period. Will use 20 ms since this will also be
66 used for servo control
67 */
68 void configTimer2(void) {
69  T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
70  | T2_32BIT_MODE_OFF
71  | T2_SOURCE_INT
72  | T2_PS_1_64 ; //at 40 MHz, approx 104 ms max, 1 tick = 1.6 us
73  PR2 = usToU16Ticks(PWM_PERIOD, getTimerPrescale(T2CONbits)) - 1;
74  TMR2 = 0; //clear timer2 value
75  _T2IF = 0; //clear interrupt flag
76  T2CONbits.TON = 1; //turn on the timer
77 }
78 
79 #define TWOTHIRDS_PERIOD_US 1100 //two thirds expected bit period, in microseconds
80 #define COMMAND_LENGTH 13 //number of bits expected in IR command
81 #define IR_INPUT _RB7 //using RB9 for IR input
82 
83 volatile uint16_t u16_lastCapture, u16_thisCapture,u16_delta, u16_twoThirdsPeriodTicks;
84 volatile uint8_t u8_bitCount,u8_bitCountTotal,u8_currentByte;
85 //some one-bit flags
86 typedef struct tagFLAGBITS {
87 unsigned u1_bitEdge:
88  1;
89 unsigned u1_bitValue:
90  1;
91 } FLAGBITS;
92 static volatile FLAGBITS flags;
93 
94 typedef enum {
95  STATE_START_PULSE_FALL = 0,
96  STATE_START_PULSE_RISE,
97  STATE_BIT_CAPTURE,
98  STATE_LAST_EDGE,
99 } ICSTATE;
100 
101 ICSTATE e_isrICState;
102 
103 void _ISRFAST _IC1Interrupt() {
104  _IC1IF = 0;
105  u16_thisCapture = IC1BUF ; //always read buffer to prevent overflow
106  u16_delta = computeDeltaTicks(u16_lastCapture,u16_thisCapture,PR2);
107  u16_lastCapture = u16_thisCapture;
108  switch (e_isrICState) {
109  case STATE_START_PULSE_FALL:
110  e_isrICState = STATE_START_PULSE_RISE;
111  break;
112  case STATE_START_PULSE_RISE:
113  if (u16_delta > u16_twoThirdsPeriodTicks) {
114  //error, unexpected long pulse, reset back to start state
115  e_isrICState = STATE_START_PULSE_FALL;
116  } else {
117  //received start pulse, start accumulating bits
118  flags.u1_bitEdge = 1; //next edge contains a bit
119  u8_bitCount = 0;
120  u8_currentByte = 0;
121  flags.u1_bitValue = 1; //first bit is always a '1'
122  u8_bitCountTotal = 0;
123  e_isrICState = STATE_BIT_CAPTURE;
124  }
125  break;
126  case STATE_BIT_CAPTURE:
127  if ((u16_delta > u16_twoThirdsPeriodTicks) || flags.u1_bitEdge) {
128  //record this bit
129  if ((u16_delta > u16_twoThirdsPeriodTicks)) {
130  //bit value has changed if wide pulse
131  flags.u1_bitValue = !flags.u1_bitValue;
132  }
133  if (u8_bitCount != 0)u8_currentByte = u8_currentByte << 1;;
134  if (flags.u1_bitValue) u8_currentByte = u8_currentByte | 0x01;
135  u8_bitCount++;
136  u8_bitCountTotal++;
137  flags.u1_bitEdge = 1; //this was a bit edge
138  if (u8_bitCount == 7) { //received start, toggle, address
139  irFifoWrite(u8_currentByte);
140  u8_currentByte = 0;
141  u8_bitCount = 0;
142  }
143  }
144  flags.u1_bitEdge = !flags.u1_bitEdge; //next edge is opposite
145  if (u8_bitCountTotal == COMMAND_LENGTH) {
146  if (u8_bitCount != 0) irFifoWrite(u8_currentByte); //save last byte
147  if (IR_INPUT) e_isrICState = STATE_START_PULSE_FALL;
148  else e_isrICState = STATE_LAST_EDGE; //one more edge to come
149  }
150  break;
151  case STATE_LAST_EDGE:
152  e_isrICState = STATE_START_PULSE_FALL;
153  break;
154 
155  default:
156  e_isrICState = STATE_START_PULSE_FALL;
157  }
158 }
159 
160 
161 //configure input capture.
162 void configInputCapture1(void) {
163  CONFIG_RB7_AS_DIG_INPUT(); //use RB7 for IR Input (must be 5 V tolerant)
164  CONFIG_IC1_TO_RP(7); //map IC1 to RP7/R7
165  e_isrICState = STATE_START_PULSE_FALL;
166  u16_irFifoHead = 0;
167  u16_irFifoTail = 0;
168  u16_twoThirdsPeriodTicks = usToU16Ticks(TWOTHIRDS_PERIOD_US, getTimerPrescale(T2CONbits));
169  IC1CON = IC_TIMER2_SRC | //Timer2 source
170  IC_INT_1CAPTURE | //Interrupt every capture
171  IC_EVERY_EDGE; //Interrupt every edge
172  _IC1IF = 0;
173  _IC1IP = 1;
174  _IC1IE = 1; //enable
175 }
176