PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ir_biphase_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() {
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 /* no interrupt for Timer2, must be configured so that one bit time does
57 not exceed the Timer2 period.
58 */
59 void configTimer2(void) {
60  T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
61  | T2_32BIT_MODE_OFF
62  | T2_SOURCE_INT
63  | T2_PS_1_64 ; //at 40 MHz, approx 420 ms max, 1 tick = 1.6 us
64  PR2 = 0xFFFF; //must be long enough so that one bit time does not overflow this
65  TMR2 = 0; //clear timer2 value
66  _T2IF = 0; //clear interrupt flag
67  T2CONbits.TON = 1; //turn on the timer
68 }
69 
70 #define TWOTHIRDS_PERIOD_US 1100 //two thirds expected bit period, in microseconds
71 #define COMMAND_LENGTH 13 //number of bits expected in IR command
72 #define IR_INPUT _RB7 //using RB9 for IR input
73 
74 volatile uint16_t u16_lastCapture, u16_thisCapture,u16_delta, u16_twoThirdsPeriodTicks;
75 volatile uint8_t u8_bitCount,u8_bitCountTotal,u8_currentByte;
76 //some one-bit flags
77 typedef struct tagFLAGBITS {
78 unsigned u1_bitEdge:
79  1;
80 unsigned u1_bitValue:
81  1;
82 } FLAGBITS;
83 volatile FLAGBITS flags;
84 
85 typedef enum {
86  STATE_START_PULSE_FALL = 0,
87  STATE_START_PULSE_RISE,
88  STATE_BIT_CAPTURE,
89  STATE_LAST_EDGE,
90 } ICSTATE;
91 
92 ICSTATE e_isrICState;
93 
94 void _ISRFAST _IC1Interrupt() {
95  _IC1IF = 0;
96  u16_thisCapture = IC1BUF ; //always read buffer to prevent overflow
97  u16_delta = computeDeltaTicks(u16_lastCapture,u16_thisCapture,PR2);
98  u16_lastCapture = u16_thisCapture;
99  switch (e_isrICState) {
100  case STATE_START_PULSE_FALL:
101  e_isrICState = STATE_START_PULSE_RISE;
102  break;
103  case STATE_START_PULSE_RISE:
104  if (u16_delta > u16_twoThirdsPeriodTicks) {
105  //error, unexpected long pulse, reset back to start state
106  e_isrICState = STATE_START_PULSE_FALL;
107  } else {
108  //received start pulse, start accumulating bits
109  flags.u1_bitEdge = 1; //next edge contains a bit
110  u8_bitCount = 0;
111  u8_currentByte = 0;
112  flags.u1_bitValue = 1; //first bit is always a '1'
113  u8_bitCountTotal = 0;
114  e_isrICState = STATE_BIT_CAPTURE;
115  }
116  break;
117  case STATE_BIT_CAPTURE:
118  if ((u16_delta > u16_twoThirdsPeriodTicks) || flags.u1_bitEdge) {
119  //record this bit
120  if ((u16_delta > u16_twoThirdsPeriodTicks)) {
121  //bit value has changed if wide pulse
122  flags.u1_bitValue = !flags.u1_bitValue;
123  }
124  if (u8_bitCount != 0)u8_currentByte = u8_currentByte << 1;;
125  if (flags.u1_bitValue) u8_currentByte = u8_currentByte | 0x01;
126  u8_bitCount++;
127  u8_bitCountTotal++;
128  flags.u1_bitEdge = 1; //this was a bit edge
129  if (u8_bitCount == 7) { //received start, toggle, address
130  irFifoWrite(u8_currentByte);
131  u8_currentByte = 0;
132  u8_bitCount = 0;
133  }
134  }
135  flags.u1_bitEdge = !flags.u1_bitEdge; //next edge is opposite
136  if (u8_bitCountTotal == COMMAND_LENGTH) {
137  if (u8_bitCount != 0) irFifoWrite(u8_currentByte); //save last byte
138  if (IR_INPUT) e_isrICState = STATE_START_PULSE_FALL;
139  else e_isrICState = STATE_LAST_EDGE; //one more edge to come
140  }
141  break;
142  case STATE_LAST_EDGE:
143  e_isrICState = STATE_START_PULSE_FALL;
144  break;
145 
146  default:
147  e_isrICState = STATE_START_PULSE_FALL;
148  }
149 }
150 
151 
152 //configure input capture.
153 void configInputCapture1(void) {
154  CONFIG_RB7_AS_DIG_INPUT(); //use RB7 for IR Input (must be 5 V tolerant)
155 #if (defined(__dsPIC33E__) || defined(__PIC24E__))
156  CONFIG_IC1_TO_RP(39); //map IC1 to RP39/R7
157 #else
158  CONFIG_IC1_TO_RP(7); //map IC1 to RP7/R7
159 #endif
160  e_isrICState = STATE_START_PULSE_FALL;
161  u16_irFifoHead = 0;
162  u16_irFifoTail = 0;
163  u16_twoThirdsPeriodTicks = usToU16Ticks(TWOTHIRDS_PERIOD_US, getTimerPrescale(T2CONbits));
164 #if (defined(__dsPIC33E__) || defined(__PIC24E__))
165  IC1CON1 = IC_TIMER2_SRC | //Timer2 source
166  IC_INT_1CAPTURE | //Interrupt every capture
167  IC_EVERY_EDGE; //Capture every edge
168  IC1CON2 = 0x000C; //sync to timer2
169 #else
170  IC1CON = IC_TIMER2_SRC | //Timer2 source
171  IC_INT_1CAPTURE | //Interrupt every capture
172  IC_EVERY_EDGE; //Interrupt every edge
173 #endif
174  _IC1IF = 0;
175  _IC1IP = 1;
176  _IC1IE = 1; //enable
177 }
178 
179 int main (void) {
180  uint8_t u8_x, u8_y;
181  configBasic(HELLO_MSG);
182  configTimer2();
183  configInputCapture1();
184 
185  while (1) {
186  u8_x = irFifoRead();
187  u8_y = irFifoRead();
188  if (u8_x & 0x20) outString("Toggle = 1, ");
189  else outString("Toggle = 0, ");
190  outString("Addr: ");
191  outUint8(u8_x & 0x1F);
192  outString(",Cmd: ");
193  outUint8(u8_y);
194  outString("\n");
195  }
196 }