root / branches / encoders / code / lib / src / libdragonfly / lights.c @ 1345
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 |