root / trunk / code / projects / libdragonfly / lights.c @ 776
History | View | Annotate | Download (11.1 KB)
1 | 241 | bcoltin | /**
|
---|---|---|---|
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 | 8 | bcoltin | /*
|
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 |