Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (9.74 KB)

1 7 bcoltin
/*
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