Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / lib / src / libdragonfly / lights.c @ 766

History | View | Annotate | Download (11.1 KB)

1
/**
2
 * Copyright (c) 2007 Colony Project
3
 * 
4
 * Permission is hereby granted, free of charge, to any person
5
 * obtaining a copy of this software and associated documentation
6
 * files (the "Software"), to deal in the Software without
7
 * restriction, including without limitation the rights to use,
8
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9
 * copies of the Software, and to permit persons to whom the
10
 * Software is furnished to do so, subject to the following
11
 * conditions:
12
 * 
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 **/
25

    
26

    
27
/**
28
 * @file ligths.c
29
 * @brief Orbs
30
 *
31
 * Implemenation for the orbs (tri-colored LEDs)
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 * @bug Colors are incorrect, seems to not work with wireless library
35
 **/
36

    
37
/*
38
lights.c
39
Controls orb1 and orb2. Also contains the framework for a software PWM that may be used for servos in the future.
40

41
author: CMU Robotics Club, Colony Project
42

43
Change Log:
44
2.4.07 - Aaron
45
        Revamped orb code so it works.  Need to check interaction with rtc, and tweak some colors.
46

47
2.1.07 - James
48
        Modified sort_buffer() to prune for repeats.  PWM now uses orb_buf_size for the number of orb values in orb_time_arr[].
49
                Changed sorting algorithm used in sort_buffer() to selection sort (faster). And it works now.
50

51
1.25.07 - KWoo
52
        Deleted old FF+ code to make it cleaner. Commented code. This all works. Note however that if you ever plan to use the
53
                software PWM (which is this) you will need to change the implementation of orb_enable() and orb_disable() to not
54
                shutdown the PWM.
55

56
*/
57

    
58
#include "lights.h"
59
#include "dragonfly_lib.h"
60
#include <avr/interrupt.h>
61

    
62
#define ORB_RESET 1025
63
#define ORBPORT PORTC
64
#define ORBDDR DDRC
65
#define ORBMASK 0x77
66

    
67
/***** Port and Pin Definitions ****/
68

    
69
//Orb Ports and Registers
70
#define ORB_PORT        PORTC
71
#define ORB_DDR         DDRC
72

    
73
//Orb Pins
74
#define ORB1_RED        0x00
75
#define ORB1_GREEN      0x01
76
#define ORB1_BLUE       0x02
77
#define ORB2_RED        0x04
78
#define ORB2_GREEN      0x05
79
#define ORB2_BLUE       0x06
80

    
81

    
82
#define ORB_COUNT 8        //please dont change this, or bad things might happen
83

    
84
// an orb node
85
struct ORB_NODE {
86
   uint8_t num;
87
   uint16_t angle;
88
};
89

    
90
//the change in an orb
91
struct ORB_CHANGE {
92
   uint16_t port_val;
93
   uint16_t split_time_period;
94
};
95

    
96
// the status of an orb
97
struct ORB_STATUS_STRUCT {
98
   struct ORB_NODE orbs[ORB_COUNT];
99
   uint16_t orb_angles[ORB_COUNT];
100
   struct ORB_CHANGE changes[ORB_COUNT+1];
101
   uint8_t change_count;
102
   uint8_t new_angles;
103
   uint8_t current_orb;
104

    
105
} ORB_STATUS;
106

    
107
void orb_sort(void);
108
void orb_setup_pulse(void);
109

    
110
SIGNAL (SIG_OUTPUT_COMPARE3C){
111

    
112
                //pull the correct ones down
113
      ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val);
114

    
115
      ++ORB_STATUS.current_orb; //now look at next orb transition
116

    
117
      if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end...
118
          
119
                        //setup timer for next pull down
120
         OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period;
121
                 
122
     }
123
      else { //we are done with these pulses
124
                orb_setup_pulse();
125
      }
126

    
127
}
128

    
129

    
130
//sets a channel to a value
131
void orb_set_angle(int orb, int angle) {
132
        uint8_t mysreg;
133
        
134
        orb=orb&0x07; //only have 8
135
        angle=angle&0xff; //only accept 0-255
136
        angle=255-angle; //inverse intensity
137
        angle=angle<<2; //scale up so that we dont run it too often
138
        angle+=3; //0 values dont really work
139
   if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed
140
          mysreg=SREG; 
141
          cli(); //disable interrupts
142
      ORB_STATUS.orb_angles[orb] = angle; //update angle
143
      ORB_STATUS.new_angles = 1;
144
          SREG=mysreg; //put interrupt status back
145
   }
146
}
147

    
148

    
149
void orb_sort(void) {
150
   int done = 0, i;
151
   
152
   while (! done) {
153
      done = 1;
154

    
155
      for (i = 0; i < ORB_COUNT - 1; ++i) {  //loop through all
156
          
157
                        //if they are out of order, swap them
158
         if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) {
159
            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
160
            ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle;
161
            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
162

    
163
            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
164
            ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num;
165
            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
166

    
167
            done = 0;
168
         }
169
      }
170
   }
171
}
172

    
173
//calculate the split times
174
void orb_setup_pulse(void) {
175
   int i;
176
   uint16_t my_port;
177
   uint16_t sum = 0;
178
   uint16_t split_time;
179

    
180
   my_port = 0xff; //all on
181

    
182
   if (ORB_STATUS.new_angles) {
183

    
184
      ORB_STATUS.change_count = 0;
185
          for (i = 0; i < ORB_COUNT; ++i) { //get the new values
186
         ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num];
187
      }
188

    
189
      orb_sort(); //sort them
190
      ORB_STATUS.new_angles = 0;
191

    
192
      for (i = 0; i < ORB_COUNT; ++i) { //calculate split times
193
         split_time = ORB_STATUS.orbs[i].angle - sum;
194
         my_port &= ~_BV(ORB_STATUS.orbs[i].num);
195
                 
196
         for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) {
197
            my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups
198
         }
199
                 
200
         ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low
201
         ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time;
202
         
203
                 ++ORB_STATUS.change_count;
204
                 
205
         sum += split_time;
206
      }
207

    
208
      ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port;
209
      ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period
210

    
211
      ++ORB_STATUS.change_count;
212

    
213
   }
214

    
215

    
216

    
217
   ORB_STATUS.current_orb = 0;
218

    
219
    ORBPORT |= ORBMASK; //start with all high
220
        OCR3C = TCNT3 + ORB_STATUS.changes[0].split_time_period; //wait for first split
221

    
222
}
223

    
224
/**
225
 * @defgroup orbs Orbs
226
 * @brief Functions for controlling the color of the orbs.
227
 * 
228
 * Functions for controlling the color and lighting of the orbs.
229
 *
230
 * @{
231
 **/
232

    
233
/**
234
 * Initializes the PWM for Orb control. This must be called before 
235
 * the orbs are used for them to function.
236
 **/
237
void orb_init() 
238
{        
239
   int i;
240
   uint8_t mysreg;
241
   
242
   ORBDDR |= ORBMASK;        //all outputs
243
   
244
        mysreg=SREG;
245
        cli(); //turn off interrupts for now
246

    
247
        //init everything
248

    
249
   for (i = 0; i < ORB_COUNT; ++i) {
250
      ORB_STATUS.orbs[i].num = i;
251
      ORB_STATUS.orbs[i].angle = 1023;        //127 is a pretty stupid start angle, but oh well
252
      ORB_STATUS.orb_angles[i] = 1023;
253
   }
254

    
255
   ORB_STATUS.new_angles = 1;
256
   ORB_STATUS.change_count = 0;
257

    
258
        //init timer3
259
        TCCR3A = 0; 
260
        TCCR3B = _BV(CS31); //prescale = 8
261
        TCCR3C = 0;
262
        ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
263
        OCR3C = TCNT3+ORB_RESET;
264

    
265
        SREG=mysreg;
266
}
267

    
268
/**
269
 * Set both orbs to the color specified. orb_init must
270
 * be called before this function may be used.
271
 *
272
 * @param red_led the red component of the color
273
 * @param green_led the green component of the color
274
 * @param blue_led the blue component of the color
275
 *
276
 * @see orb_init
277
 **/
278
void orb_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
279
        orb1_set(red_led,green_led,blue_led);
280
        orb2_set(red_led,green_led,blue_led);
281

    
282
}
283

    
284
/**
285
 * Set orb1 to the color specified. orb_init must
286
 * be called before this function may be used.
287
 *
288
 * @param red_led the red component of the color
289
 * @param green_led the green component of the color
290
 * @param blue_led the blue component of the color
291
 *
292
 * @see orb_init
293
 **/
294
void orb1_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
295
        orb_set_angle(0,red_led);
296
        orb_set_angle(1,green_led);
297
        orb_set_angle(2,blue_led);
298
}
299

    
300
/**
301
 * Set orb2 to the color specified. orb_init must
302
 * be called before this function may be used.
303
 *
304
 * @param red_led the red component of the color
305
 * @param green_led the green component of the color
306
 * @param blue_led the blue component of the color
307
 *
308
 * @see orb_init
309
 **/
310
void orb2_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {        
311
        orb_set_angle(4,red_led);
312
        orb_set_angle(5,green_led);
313
        orb_set_angle(6,blue_led);
314
}
315

    
316
/**
317
 * Set both orbs to the specified color. This function
318
 * is intended to be used with the predefined
319
 * colors. orb_init must be called before this
320
 * function may be used.
321
 *
322
 * @param col the color to set the orbs to
323
 *
324
 * @see orb_init
325
 **/
326
void orb_set_color(int col)
327
{
328
 int red, green, blue;
329

    
330
 red = ((col & 0xE0) >> 5) * 36;
331
 green = ((col & 0x1C) >> 2) * 36;
332
 blue = (col & 0x03) * 85;
333

    
334
 orb_set(red, green, blue);
335
}
336

    
337
/**
338
 * Set orb1 to the specified color. This function
339
 * is intended to be used with the predefined
340
 * colors. orb_init must be called before this
341
 * function may be used.
342
 *
343
 * @param col the color to set the orbs to
344
 *
345
 * @see orb_init
346
 **/
347
void orb1_set_color(int col)
348
{
349
 int red, green, blue;
350

    
351
 red = ((col & 0xE0) >> 5) * 36;
352
 green = ((col & 0x1C) >> 2) * 36;
353
 blue = (col & 0x03) * 85;
354

    
355
 orb1_set(red, green, blue);
356
}
357

    
358
/**
359
 * Set orb2 to the specified color. This function
360
 * is intended to be used with the predefined
361
 * colors. orb_init must be called before this
362
 * function may be used.
363
 *
364
 * @param col the color to set the orbs to
365
 *
366
 * @see orb_init
367
 **/
368
void orb2_set_color(int col)
369
{
370
 int red, green, blue;
371

    
372
 red = ((col & 0xE0) >> 5) * 36;
373
 green = ((col & 0x1C) >> 2) * 36;
374
 blue = (col & 0x03) * 85;
375

    
376
 orb2_set(red, green, blue);
377
}
378

    
379
//DOES THIS WORK?
380
// Disables the timer1 interrupt, disabling the Orb's color fading capabilities
381
// You can still turn the red, green, and blue leds on and off with set_orb_dio
382
/* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
383
/**
384
 * Disables the orb color fading capabilities
385
 * by disabling the timer1 interrupt.
386
 *
387
 * @see orb_init
388
 **/
389
void orb_disable()
390
{
391
        TCCR3B &= 0;          //Turn off everything
392
        ORB_PORT |= _BV(ORB1_RED);
393
        ORB_PORT |= _BV(ORB1_GREEN);
394
        ORB_PORT |= _BV(ORB1_BLUE);
395
        ORB_PORT |= _BV(ORB2_RED);
396
        ORB_PORT |= _BV(ORB2_GREEN);
397
        ORB_PORT |= _BV(ORB2_BLUE);
398
}
399

    
400
//DOES THIS WORK?
401
// Enables the timer1 interrupt, enabling the Orb's color fading capabilities
402
/**
403
 * Enables the orb's color fading capabilities.
404
 *
405
 * @see orb_init
406
 **/
407
void orb_enable()
408
{
409
//        TCCR0 |= _BV(COM01) | _BV(COM00)  | _BV(WGM00) | _BV(CS01);        //Toggle OC Pin on match, FAST PWM Mode, clock/8
410
        TCCR3B =_BV(CS31);
411
}
412

    
413
/** @} **/ //end group
414