Project

General

Profile

Statistics
| Revision:

root / trunk / code / lib / src / libdragonfly / lights.c @ 7

History | View | Annotate | Download (9.74 KB)

1
/*
2
lights.c
3
Controls orb1 and orb2. Also contains the framework for a software PWM that may be used for servos in the future.
4

5
author: CMU Robotics Club, Colony Project
6

7
Change Log:
8
2.4.07 - Aaron
9
        Revamped orb code so it works.  Need to check interaction with rtc, and tweak some colors.
10

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

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

20
*/
21

    
22
#include "lights.h"
23
#include "dragonfly_lib.h"
24
#include <avr/interrupt.h>
25

    
26

    
27
#define ORB_RESET 1025
28

    
29
#define ORBPORT PORTC
30

    
31
#define ORBDDR DDRC
32

    
33
#define ORBMASK 0x77
34

    
35

    
36
/***** Port and Pin Definitions ****/
37

    
38
//Orb Ports and Registers
39
#define ORB_PORT        PORTC
40
#define ORB_DDR         DDRC
41

    
42
//Orb Pins
43
#define ORB1_RED        0x00
44
#define ORB1_GREEN      0x01
45
#define ORB1_BLUE       0x02
46
#define ORB2_RED        0x04
47
#define ORB2_GREEN      0x05
48
#define ORB2_BLUE       0x06
49

    
50

    
51
#define ORB_COUNT 8        //please dont change this, or bad things might happen
52

    
53
// an orb node
54
struct ORB_NODE {
55
   uint8_t num;
56
   uint16_t angle;
57
};
58

    
59
//the change in an orb
60
struct ORB_CHANGE {
61
   uint16_t port_val;
62
   uint16_t split_time_period;
63
};
64

    
65
// the status of an orb
66
struct ORB_STATUS_STRUCT {
67
   struct ORB_NODE orbs[ORB_COUNT];
68
   uint16_t orb_angles[ORB_COUNT];
69
   struct ORB_CHANGE changes[ORB_COUNT+1];
70
   uint8_t change_count;
71
   uint8_t new_angles;
72
   uint8_t current_orb;
73

    
74
} ORB_STATUS;
75

    
76
void orb_sort(void);
77
void orb_setup_pulse(void);
78

    
79
SIGNAL (SIG_OUTPUT_COMPARE3C){
80

    
81
                //pull the correct ones down
82
      ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val);
83

    
84
      ++ORB_STATUS.current_orb; //now look at next orb transition
85

    
86
      if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end...
87
          
88
                        //setup timer for next pull down
89
         OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period;
90
                 
91
     }
92
      else { //we are done with these pulses
93
                orb_setup_pulse();
94
      }
95

    
96
}
97

    
98

    
99
//sets a channel to a value
100
void orb_set_angle(int orb, int angle) {
101
        uint8_t mysreg;
102
        
103
        orb=orb&0x07; //only have 8
104
        angle=angle&0xff; //only accept 0-255
105
        angle=255-angle; //inverse intensity
106
        angle=angle<<2; //scale up so that we dont run it too often
107
        angle+=3; //0 values dont really work
108
   if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed
109
          mysreg=SREG; 
110
          cli(); //disable interrupts
111
      ORB_STATUS.orb_angles[orb] = angle; //update angle
112
      ORB_STATUS.new_angles = 1;
113
          SREG=mysreg; //put interrupt status back
114
   }
115
}
116

    
117

    
118
void orb_sort(void) {
119
   int done = 0, i;
120
   
121
   while (! done) {
122
      done = 1;
123

    
124
      for (i = 0; i < ORB_COUNT - 1; ++i) {  //loop through all
125
          
126
                        //if they are out of order, swap them
127
         if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) {
128
            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
129
            ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle;
130
            ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
131

    
132
            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
133
            ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num;
134
            ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
135

    
136
            done = 0;
137
         }
138
      }
139
   }
140
}
141

    
142
//calculate the split times
143
void orb_setup_pulse(void) {
144
   int i;
145
   uint16_t my_port;
146
   uint16_t sum = 0;
147
   uint16_t split_time;
148

    
149
   my_port = 0xff; //all on
150

    
151
   if (ORB_STATUS.new_angles) {
152

    
153
      ORB_STATUS.change_count = 0;
154
          for (i = 0; i < ORB_COUNT; ++i) { //get the new values
155
         ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num];
156
      }
157

    
158
      orb_sort(); //sort them
159
      ORB_STATUS.new_angles = 0;
160

    
161
      for (i = 0; i < ORB_COUNT; ++i) { //calculate split times
162
         split_time = ORB_STATUS.orbs[i].angle - sum;
163
         my_port &= ~_BV(ORB_STATUS.orbs[i].num);
164
                 
165
         for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) {
166
            my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups
167
         }
168
                 
169
         ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low
170
         ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time;
171
         
172
                 ++ORB_STATUS.change_count;
173
                 
174
         sum += split_time;
175
      }
176

    
177
      ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port;
178
      ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period
179

    
180
      ++ORB_STATUS.change_count;
181

    
182
   }
183

    
184

    
185

    
186
   ORB_STATUS.current_orb = 0;
187

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

    
191
}
192

    
193
/**
194
 * @defgroup orbs Orbs
195
 * @brief Functions for controlling the color of the orbs.
196
 * 
197
 * Functions for controlling the color and lighting of the orbs.
198
 *
199
 * @{
200
 **/
201

    
202
/**
203
 * Initializes the PWM for Orb control. This must be called before 
204
 * the orbs are used for them to function.
205
 **/
206
void orb_init() 
207
{        
208
   int i;
209
   uint8_t mysreg;
210
   
211
   ORBDDR |= ORBMASK;        //all outputs
212
   
213
        mysreg=SREG;
214
        cli(); //turn off interrupts for now
215

    
216
        //init everything
217

    
218
   for (i = 0; i < ORB_COUNT; ++i) {
219
      ORB_STATUS.orbs[i].num = i;
220
      ORB_STATUS.orbs[i].angle = 1023;        //127 is a pretty stupid start angle, but oh well
221
      ORB_STATUS.orb_angles[i] = 1023;
222
   }
223

    
224
   ORB_STATUS.new_angles = 1;
225
   ORB_STATUS.change_count = 0;
226

    
227
        //init timer3
228
        TCCR3A = 0; 
229
        TCCR3B = _BV(CS31); //prescale = 8
230
        TCCR3C = 0;
231
        ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
232
        OCR3C = TCNT3+ORB_RESET;
233

    
234
        SREG=mysreg;
235
}
236

    
237
/**
238
 * Set both orbs to the color specified. orb_init must
239
 * be called before this function may be used.
240
 *
241
 * @param red_led the red component of the color
242
 * @param green_led the green component of the color
243
 * @param blue_led the blue component of the color
244
 *
245
 * @see orb_init
246
 **/
247
void orb_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
248
        orb1_set(red_led,green_led,blue_led);
249
        orb2_set(red_led,green_led,blue_led);
250

    
251
}
252

    
253
/**
254
 * Set orb1 to the color specified. orb_init must
255
 * be called before this function may be used.
256
 *
257
 * @param red_led the red component of the color
258
 * @param green_led the green component of the color
259
 * @param blue_led the blue component of the color
260
 *
261
 * @see orb_init
262
 **/
263
void orb1_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
264
        orb_set_angle(0,red_led);
265
        orb_set_angle(1,green_led);
266
        orb_set_angle(2,blue_led);
267
}
268

    
269
/**
270
 * Set orb2 to the color specified. orb_init must
271
 * be called before this function may be used.
272
 *
273
 * @param red_led the red component of the color
274
 * @param green_led the green component of the color
275
 * @param blue_led the blue component of the color
276
 *
277
 * @see orb_init
278
 **/
279
void orb2_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {        
280
        orb_set_angle(4,red_led);
281
        orb_set_angle(5,green_led);
282
        orb_set_angle(6,blue_led);
283
}
284

    
285
/**
286
 * Set both orbs to the specified color. This function
287
 * is intended to be used with the predefined
288
 * colors. orb_init must be called before this
289
 * function may be used.
290
 *
291
 * @param col the color to set the orbs to
292
 *
293
 * @see orb_init
294
 **/
295
void orb_set_color(int col)
296
{
297
 int red, green, blue;
298

    
299
 red = ((col & 0xE0) >> 5) * 36;
300
 green = ((col & 0x1C) >> 2) * 36;
301
 blue = (col & 0x03) * 85;
302

    
303
 orb_set(red, green, blue);
304
}
305

    
306
/**
307
 * Set orb1 to the specified color. This function
308
 * is intended to be used with the predefined
309
 * colors. orb_init must be called before this
310
 * function may be used.
311
 *
312
 * @param col the color to set the orbs to
313
 *
314
 * @see orb_init
315
 **/
316
void orb1_set_color(int col)
317
{
318
 int red, green, blue;
319

    
320
 red = ((col & 0xE0) >> 5) * 36;
321
 green = ((col & 0x1C) >> 2) * 36;
322
 blue = (col & 0x03) * 85;
323

    
324
 orb1_set(red, green, blue);
325
}
326

    
327
/**
328
 * Set orb2 to the specified color. This function
329
 * is intended to be used with the predefined
330
 * colors. orb_init must be called before this
331
 * function may be used.
332
 *
333
 * @param col the color to set the orbs to
334
 *
335
 * @see orb_init
336
 **/
337
void orb2_set_color(int col)
338
{
339
 int red, green, blue;
340

    
341
 red = ((col & 0xE0) >> 5) * 36;
342
 green = ((col & 0x1C) >> 2) * 36;
343
 blue = (col & 0x03) * 85;
344

    
345
 orb2_set(red, green, blue);
346
}
347

    
348
//DOES THIS WORK?
349
// Disables the timer1 interrupt, disabling the Orb's color fading capabilities
350
// You can still turn the red, green, and blue leds on and off with set_orb_dio
351
/* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
352
/**
353
 * Disables the orb color fading capabilities
354
 * by disabling the timer1 interrupt.
355
 *
356
 * @see orb_init
357
 **/
358
void orb_disable()
359
{
360
        TCCR3B &= 0;          //Turn off everything
361
        ORB_PORT |= _BV(ORB1_RED);
362
        ORB_PORT |= _BV(ORB1_GREEN);
363
        ORB_PORT |= _BV(ORB1_BLUE);
364
        ORB_PORT |= _BV(ORB2_RED);
365
        ORB_PORT |= _BV(ORB2_GREEN);
366
        ORB_PORT |= _BV(ORB2_BLUE);
367
}
368

    
369
//DOES THIS WORK?
370
// Enables the timer1 interrupt, enabling the Orb's color fading capabilities
371
/**
372
 * Enables the orb's color fading capabilities.
373
 *
374
 * @see orb_init
375
 **/
376
void orb_enable()
377
{
378
//        TCCR0 |= _BV(COM01) | _BV(COM00)  | _BV(WGM00) | _BV(CS01);        //Toggle OC Pin on match, FAST PWM Mode, clock/8
379
        TCCR3B =_BV(CS31);
380
}
381

    
382
/** @} **/ //end group
383