source: microcontroller/src-atmel/scannergame/lab-irkit2.c

Last change on this file was 4271, checked in by siro, 5 years ago

modified pulselength calculation, modified codeLength buffer

File size: 8.2 KB
Line 
1//      lab-irkit2.c
2//     
3//      Authors:      Hans-Gert Dahmen  <sexyludernatascha@gmail.com>
4//      modified by:  Patrick Rudolph   <siro@das-labor.org>
5//
6//      This program is free software; you can redistribute it and/or modify
7//      it under the terms of the GNU General Public License as published by
8//      the Free Software Foundation; either version 2 of the License, or
9//      (at your option) any later version.
10//     
11//      This program is distributed in the hope that it will be useful,
12//      but WITHOUT ANY WARRANTY; without even the implied warranty of
13//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14//      GNU General Public License for more details.
15//     
16//      You should have received a copy of the GNU General Public License
17//      along with this program; if not, write to the Free Software
18//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19//      MA 02110-1301, USA.
20
21
22/*
23 * IR codes are stored in an array of on/off pulse lengths.
24 * As transmissions must always start with a one and consist
25 * of alternating ones and zeroes, every even index in the
26 * array will be a one-pulse and every odd array index
27 * will be a zero-pulse.
28 */
29
30#include "lab-irkit2.h"
31#include <avr/interrupt.h>
32
33//set to 1 to debug
34#define IR_DEBUG 1
35
36//infrared current code array
37uint16_t *volatile ir_curCode;
38//length of current code
39volatile uint16_t ir_curCodeLen=0;
40//index into current code
41volatile uint16_t ir_curCodeIdx=0;
42//ir tick counter
43volatile uint8_t ir_pulse_length=0;
44//store which pin will be set next high/low
45volatile uint8_t ir_port_buffer=0;
46
47//store the code here
48uint8_t code[IR_MAX_SRAM];
49
50//setup timer1 for frequency generation
51//our frequency is stored in freq
52//timer1 will be in CTC mode and toggle outputs on compare match,
53//the timer base frequency will be the full ioclk
54//this function seta the ir_pulse_length variable
55//ir_pulse_length is et to configure TIMER0
56//to match the code specific bit pulse length
57//pulselength must be > 0
58//0 means an error has occured
59uint8_t ir_freqInit(uint16_t freq, uint16_t pulselength)
60{
61        //disable frequency output
62        FREQGEN_OFF();
63       
64        //timer1 TOP = freq, we're setting IRPORT high on OCR1B match, low on OCR1A match, PWM :)
65          OCR1A = freq; //store freq in OCR1A
66          OCR1B =(uint16_t)((float)freq - (((float)freq) *((float)IR_pulse_width))); //store pulse length in OCR1B
67
68        //toggle OC1A on match  - not needet here only doku
69        //TCCR1A = _BV(COM1A0);
70       
71        //enable Timer1 OC1A,OC1B match interrupt, for pulsing the IR LEDs
72        TIMSK|=_BV(OCIE1A)|_BV(OCIE1B); 
73
74        //enable TIMER0 Overflow interrupt
75        TIMSK|= _BV(TOIE0);
76
77        //check if pulse_length is in range
78        if((pulselength < F_CPU/0x4000) && (pulselength > 0)) 
79        {
80          ir_pulse_length=0xFF-((uint8_t)((F_CPU/64E6) *(pulselength)+1)); //calculate advanced prescaler
81        }
82        else
83        {
84                return 0; //error return 0
85        }
86        return 1; //no error return 1
87}
88
89//toggle output pins and send code
90ISR(TIMER1_COMPA_vect)
91{
92  //disable all pins on IRPORT that are set to output
93  IRPORT&=~IRUSEDPORTS;
94  //softhack: enable Timer0_ovf_int
95  TIMSK|= _BV(TOIE0);
96}
97
98//toggle output pins and send code
99ISR(TIMER1_COMPB_vect)
100{
101        //enable all pins on IRPORT that are set to output
102        //make sure its only the one we want to use
103        IRPORT|=(ir_port_buffer&IRUSEDPORTS);
104
105        //softhack: disable Timer0_ovf_int
106        TIMSK&= ~_BV(TOIE0);
107}
108
109//modulate the pulses generated by TIMER1
110ISR(TIMER0_OVF_vect)
111{
112        //update index counter
113        ir_curCodeIdx++;
114
115        //check if the code has been send
116        if(ir_curCodeIdx >= ir_curCodeLen)
117        {
118                ir_disable();  //disable everything
119        }
120        else
121        {
122                //load the new value into the port_buffer
123                ir_port_buffer = code[ir_curCodeIdx];
124                #if IR_DEBUG == 1
125                 if((ir_port_buffer & 1)>0)
126                   PORTC|=4;
127                 else
128                   PORTC&=~4;
129                #endif
130                //restore the counter buffer
131                TCNT0=ir_pulse_length;
132        }
133}
134
135
136//disable code output
137void ir_disable(void)
138{
139        FREQGEN_OFF();
140        //disable ir code generator
141        ir_curCodeLen = 0;
142        ir_curCodeIdx = 0;
143        TCCR0=0; //turn off Timer0
144        TIMSK&=~ _BV(TOIE0);  //disable TIMER0 Overflow interrupt
145        IRPORT&=~IRUSEDPORTS;  //set low level on used ports, just for sure
146        asm("nop\t\n");
147        asm("nop\t\n");
148       
149}
150
151//this function converts a bit-encoded code into
152//the internal format used by the ir sending function
153//
154//channel = 0..7
155//headerCode <binary encoded> bit 1 will sent light pulses for setpulselength(value)
156//headerLen = 1..32
157//
158//return headerLen
159uint8_t ir_genHeader(uint8_t channel, uint32_t headerCode, uint8_t headerLen)
160{
161        //more checks
162        if((channel > 7) || (headerLen == 0) ||  (headerLen > 32) )  //TODO calculate memory usage
163                return 0;
164
165        uint8_t i=0;
166        i = headerLen;
167        while(i--)
168        {
169                if(headerCode & 1)
170                {
171                        //encode a one
172                         code[i] |= (1<<channel);
173                }
174                else
175                {
176                        //encode a zero
177                        code[i] &= ~(1<<channel);
178                }
179        headerCode >>= 1;
180        }
181        return headerLen;
182}
183
184//this function converts a bit-encoded code into
185//the internal format used by the ir sending function
186//it takes an array where to place the code (must be large enough),
187//the bitcode is assumed to be in MSB first format
188//
189//the function will return the length of the generated
190//code
191//channel = 0..7
192//oneCode <binary encoded> bit 1 will sent light pulses for setpulselength(value)
193//zeroCode <binary encoded> bit 1 will sent light pulses for setpulselength(value)
194//zeroCode_length=1..8
195//oneCode_length=1..8
196//codeLen = 1..32
197//bitCode <binary encoded> bit 1 will be replaced by oneCode, bit 0 will be replaced by zeroCode
198//bitCode must be > 0
199//0 means an error has occured
200uint16_t ir_genCode(uint8_t headerlength, uint8_t channel, uint8_t oneCode, uint8_t oneCode_length, uint8_t zeroCode,uint8_t zeroCode_length, uint32_t bitCode, uint8_t codeLen)
201{
202        //check if everything is errorfree
203        if((oneCode == 0) || (oneCode == zeroCode) || (zeroCode == 0) || (bitCode == 0) || (codeLen == 0)||(oneCode_length == 0)||(zeroCode_length == 0))
204                return 0;
205
206        //more checks
207        if((channel > 7) || (oneCode_length > 8) || ( zeroCode_length > 8)|| (codeLen > 32) )  //TODO calculate memory usage
208                return 0;
209
210       
211
212        uint8_t i=codeLen,j=0;
213        uint16_t k=headerlength;
214
215        //convert bitcode
216        while(i--)
217        {
218       
219        if(bitCode & 1)
220                {       //encode a one
221                        //encode all bits
222                        for(j=0;j<oneCode_length;j++)
223                        {
224                               
225                                if((oneCode & (1<<j))!=0)
226                                {
227                                        code[k+(oneCode_length-j)] |= (1<<channel);
228                                }
229                                else
230                                {
231                                        code[k+(oneCode_length-j)] &= ~(1<<channel);
232                                }
233                        }
234                k+=oneCode_length;
235                }
236                else
237                {       //encode a zero
238                        //encode all bits
239                        for(j=0;j<zeroCode_length;j++)
240                        {
241                               
242                                if((zeroCode & (1<<j))!=0)
243                                {
244                                  code[k+(zeroCode_length-j)] |= (1<<channel);
245                                }
246                                else
247                                {
248                                        code[k+(zeroCode_length-j)] &= ~(1<<channel);
249                                }
250                        }
251                k+=zeroCode_length;
252                }
253                //shift in next code bit
254                bitCode >>= 1;
255        }
256
257        //return real code length
258        return k;
259}
260
261
262
263//send an ir code, please never use a code length of zero
264void ir_sendCode(uint16_t codeLen)
265{
266  //we have to send 0 bytes ?
267        if(codeLen == 0)
268          return; //OK done :)
269
270        //turn off code sending completely while modifying the code
271        //turn of Timer1
272        FREQGEN_OFF();
273
274        //the last code to send may never be a zero
275        //-> it would not make any sense
276        //-> the frequency generation would give a carrier for one timer
277        //   overflow after the last bit has been sent
278        //this makes even numbers the next smaller uneven ones
279        //ir_curCodeLen = (codeLen-1) | 0x01;
280        ir_curCodeLen = codeLen-1;
281
282        //reset timer count to be in sync
283        TCNT0=ir_pulse_length;
284
285        //enable code sending by setting the index to zero
286        ir_curCodeIdx = 0;
287        ir_port_buffer =0;
288
289        //enable frequency generation
290        FREQGEN_ON();
291
292        //enable code generator
293        TCCR0=_BV(CS01)|_BV(CS00); //enable Timer0, prescaler 1:64
294       
295        //enable TIMER0 Overflow interrupt
296        TIMSK|= _BV(TOIE0);
297}
298
299
300//returns 1 if transmission is pending
301//else 0
302uint8_t transmission_pending(void)
303{
304  if(((TCCR1B & _BV(CS10))> 0 )&& (ir_curCodeLen > 0))
305    return 1;
306 
307  return 0;
308}
309
310//all-in-one initialization
311//returns 0 on error
312uint8_t ir_init(uint16_t freq, uint16_t pulselength)
313{
314        //disable ir code generator
315        ir_disable();
316
317        //ir LED output - NPN tansistor needs low output or LED will die - overcurrent driven
318        IRDDR|=IRUSEDPORTS; //set used ports to output
319        IRPORT&=~IRUSEDPORTS;  //set low level on used ports
320
321        //enable frequency generator, constant frequency
322        //move this to main()
323        return ir_freqInit(freq,pulselength);
324}
Note: See TracBrowser for help on using the repository browser.