root / trunk / code / lib / src / libdragonfly / lights.c @ 277
History | View | Annotate | Download (10.5 KB)
1 | 276 | emarinel | /**
|
---|---|---|---|
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 | 277 | emarinel | Revamped orb code so it works. Need to check interaction with rtc, and tweak some colors.
|
46 | 276 | emarinel | |
47 | 2.1.07 - James
|
||
48 | 277 | emarinel | Modified sort_buffer() to prune for repeats. PWM now uses orb_buf_size for the number of orb values in
|
49 | orb_time_arr[].
|
||
50 | Changed sorting algorithm used in sort_buffer() to selection sort (faster). And it works now.
|
||
51 | 276 | emarinel | |
52 | 1.25.07 - KWoo
|
||
53 | 277 | emarinel | Deleted old FF+ code to make it cleaner. Commented code. This all works. Note however that if you ever plan to
|
54 | use the software PWM (which is this) you will need to change the implementation of orb_enable() and orb_disable()
|
||
55 | to not shutdown the PWM.
|
||
56 | 276 | emarinel | */
|
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 | 277 | emarinel | #define ORB_COUNT 8 //please dont change this, or bad things might happen |
83 | 276 | emarinel | |
84 | // an orb node
|
||
85 | struct ORB_NODE {
|
||
86 | 277 | emarinel | uint8_t num; |
87 | uint16_t angle; |
||
88 | 276 | emarinel | }; |
89 | |||
90 | //the change in an orb
|
||
91 | struct ORB_CHANGE {
|
||
92 | 277 | emarinel | uint16_t port_val; |
93 | uint16_t split_time_period; |
||
94 | 276 | emarinel | }; |
95 | |||
96 | // the status of an orb
|
||
97 | struct ORB_STATUS_STRUCT {
|
||
98 | 277 | emarinel | 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 | 276 | emarinel | } ORB_STATUS; |
105 | |||
106 | void orb_sort(void); |
||
107 | void orb_setup_pulse(void); |
||
108 | |||
109 | SIGNAL (SIG_OUTPUT_COMPARE3C){ |
||
110 | 277 | emarinel | //pull the correct ones down
|
111 | ORBPORT &= (~ORBMASK)|(ORB_STATUS.changes[ORB_STATUS.current_orb].port_val); |
||
112 | 276 | emarinel | |
113 | 277 | emarinel | ++ORB_STATUS.current_orb; //now look at next orb transition
|
114 | 276 | emarinel | |
115 | 277 | emarinel | if (ORB_STATUS.current_orb < ORB_STATUS.change_count) { //if it isnt the end... |
116 | //setup timer for next pull down
|
||
117 | OCR3C = TCNT3+ORB_STATUS.changes[ORB_STATUS.current_orb].split_time_period; |
||
118 | } else { //we are done with these pulses |
||
119 | orb_setup_pulse(); |
||
120 | } |
||
121 | 276 | emarinel | } |
122 | |||
123 | //sets a channel to a value
|
||
124 | void orb_set_angle(int orb, int angle) { |
||
125 | 277 | emarinel | uint8_t mysreg; |
126 | 276 | emarinel | |
127 | 277 | emarinel | orb=orb&0x07; //only have 8 |
128 | angle=angle&0xff; //only accept 0-255 |
||
129 | angle=255-angle; //inverse intensity |
||
130 | angle=angle<<2; //scale up so that we dont run it too often |
||
131 | angle+=3; //0 values dont really work |
||
132 | |||
133 | if (ORB_STATUS.orb_angles[orb] != angle) { //if the angle has changed |
||
134 | mysreg=SREG; |
||
135 | cli(); //disable interrupts
|
||
136 | ORB_STATUS.orb_angles[orb] = angle; //update angle
|
||
137 | ORB_STATUS.new_angles = 1;
|
||
138 | SREG=mysreg; //put interrupt status back
|
||
139 | } |
||
140 | 276 | emarinel | } |
141 | |||
142 | void orb_sort(void) { |
||
143 | 277 | emarinel | int done = 0, i; |
144 | 276 | emarinel | |
145 | 277 | emarinel | while (! done) {
|
146 | done = 1;
|
||
147 | 276 | emarinel | |
148 | 277 | emarinel | for (i = 0; i < ORB_COUNT - 1; ++i) { //loop through all |
149 | //if they are out of order, swap them
|
||
150 | if (ORB_STATUS.orbs[i].angle > ORB_STATUS.orbs[i+1].angle) { |
||
151 | ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
|
||
152 | ORB_STATUS.orbs[i+1].angle ^= ORB_STATUS.orbs[i].angle;
|
||
153 | ORB_STATUS.orbs[i].angle ^= ORB_STATUS.orbs[i+1].angle;
|
||
154 | 276 | emarinel | |
155 | 277 | emarinel | ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
|
156 | ORB_STATUS.orbs[i+1].num ^= ORB_STATUS.orbs[i].num;
|
||
157 | ORB_STATUS.orbs[i].num ^= ORB_STATUS.orbs[i+1].num;
|
||
158 | 276 | emarinel | |
159 | 277 | emarinel | done = 0;
|
160 | 276 | emarinel | } |
161 | 277 | emarinel | } |
162 | } |
||
163 | 276 | emarinel | } |
164 | |||
165 | //calculate the split times
|
||
166 | void orb_setup_pulse(void) { |
||
167 | 277 | emarinel | int i;
|
168 | uint16_t my_port; |
||
169 | uint16_t sum = 0;
|
||
170 | uint16_t split_time; |
||
171 | 276 | emarinel | |
172 | 277 | emarinel | my_port = 0xff; //all on |
173 | 276 | emarinel | |
174 | 277 | emarinel | if (ORB_STATUS.new_angles) {
|
175 | ORB_STATUS.change_count = 0;
|
||
176 | 276 | emarinel | |
177 | 277 | emarinel | for (i = 0; i < ORB_COUNT; ++i) { //get the new values |
178 | ORB_STATUS.orbs[i].angle = ORB_STATUS.orb_angles[ORB_STATUS.orbs[i].num]; |
||
179 | } |
||
180 | 276 | emarinel | |
181 | 277 | emarinel | orb_sort(); //sort them
|
182 | ORB_STATUS.new_angles = 0;
|
||
183 | 276 | emarinel | |
184 | 277 | emarinel | for (i = 0; i < ORB_COUNT; ++i) { //calculate split times |
185 | split_time = ORB_STATUS.orbs[i].angle - sum; |
||
186 | my_port &= ~_BV(ORB_STATUS.orbs[i].num); |
||
187 | 276 | emarinel | |
188 | 277 | emarinel | for (; i < ORB_COUNT - 1 && ORB_STATUS.orbs[i].angle == ORB_STATUS.orbs[i+1].angle; ++i) { |
189 | my_port &= ~_BV(ORB_STATUS.orbs[i+1].num); //look for doups |
||
190 | 276 | emarinel | } |
191 | |||
192 | 277 | emarinel | ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; //which pins are low
|
193 | ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = split_time; |
||
194 | 276 | emarinel | |
195 | ++ORB_STATUS.change_count; |
||
196 | |||
197 | 277 | emarinel | sum += split_time; |
198 | } |
||
199 | 276 | emarinel | |
200 | 277 | emarinel | ORB_STATUS.changes[ORB_STATUS.change_count].port_val = my_port; |
201 | ORB_STATUS.changes[ORB_STATUS.change_count].split_time_period = ORB_RESET - sum; //get a constant period
|
||
202 | 276 | emarinel | |
203 | 277 | emarinel | ++ORB_STATUS.change_count; |
204 | } |
||
205 | 276 | emarinel | |
206 | 277 | emarinel | ORB_STATUS.current_orb = 0;
|
207 | 276 | emarinel | |
208 | 277 | emarinel | ORBPORT |= ORBMASK; //start with all high
|
209 | OCR3C = TCNT3 + ORB_STATUS.changes[0].split_time_period; //wait for first split |
||
210 | 276 | emarinel | } |
211 | |||
212 | /**
|
||
213 | * @defgroup orbs Orbs
|
||
214 | * @brief Functions for controlling the color of the orbs.
|
||
215 | *
|
||
216 | * Functions for controlling the color and lighting of the orbs.
|
||
217 | *
|
||
218 | * @{
|
||
219 | **/
|
||
220 | |||
221 | /**
|
||
222 | * Initializes the PWM for Orb control. This must be called before
|
||
223 | * the orbs are used for them to function.
|
||
224 | **/
|
||
225 | void orb_init()
|
||
226 | { |
||
227 | 277 | emarinel | int i;
|
228 | uint8_t mysreg; |
||
229 | 276 | emarinel | |
230 | 277 | emarinel | ORBDDR |= ORBMASK; //all outputs
|
231 | 276 | emarinel | |
232 | 277 | emarinel | mysreg=SREG; |
233 | cli(); //turn off interrupts for now
|
||
234 | 276 | emarinel | |
235 | 277 | emarinel | //init everything
|
236 | 276 | emarinel | |
237 | 277 | emarinel | for (i = 0; i < ORB_COUNT; ++i) { |
238 | ORB_STATUS.orbs[i].num = i; |
||
239 | ORB_STATUS.orbs[i].angle = 1023; //127 is a pretty stupid start angle, but oh well |
||
240 | ORB_STATUS.orb_angles[i] = 1023;
|
||
241 | } |
||
242 | 276 | emarinel | |
243 | 277 | emarinel | ORB_STATUS.new_angles = 1;
|
244 | ORB_STATUS.change_count = 0;
|
||
245 | 276 | emarinel | |
246 | 277 | emarinel | //init timer3
|
247 | TCCR3A = 0;
|
||
248 | TCCR3B = _BV(CS31); //prescale = 8
|
||
249 | TCCR3C = 0;
|
||
250 | ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
|
||
251 | OCR3C = TCNT3+ORB_RESET; |
||
252 | 276 | emarinel | |
253 | 277 | emarinel | SREG=mysreg; |
254 | 276 | emarinel | } |
255 | |||
256 | /**
|
||
257 | * Set both orbs to the color specified. orb_init must
|
||
258 | * be called before this function may be used.
|
||
259 | *
|
||
260 | * @param red_led the red component of the color
|
||
261 | * @param green_led the green component of the color
|
||
262 | * @param blue_led the blue component of the color
|
||
263 | *
|
||
264 | * @see orb_init
|
||
265 | **/
|
||
266 | void orb_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) { |
||
267 | 277 | emarinel | orb1_set(red_led,green_led,blue_led); |
268 | orb2_set(red_led,green_led,blue_led); |
||
269 | 276 | emarinel | } |
270 | |||
271 | /**
|
||
272 | * Set orb1 to the color specified. orb_init must
|
||
273 | * be called before this function may be used.
|
||
274 | *
|
||
275 | * @param red_led the red component of the color
|
||
276 | * @param green_led the green component of the color
|
||
277 | * @param blue_led the blue component of the color
|
||
278 | *
|
||
279 | * @see orb_init
|
||
280 | **/
|
||
281 | void orb1_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) { |
||
282 | 277 | emarinel | orb_set_angle(0,red_led);
|
283 | orb_set_angle(1,green_led);
|
||
284 | orb_set_angle(2,blue_led);
|
||
285 | 276 | emarinel | } |
286 | |||
287 | /**
|
||
288 | * Set orb2 to the color specified. orb_init must
|
||
289 | * be called before this function may be used.
|
||
290 | *
|
||
291 | * @param red_led the red component of the color
|
||
292 | * @param green_led the green component of the color
|
||
293 | * @param blue_led the blue component of the color
|
||
294 | *
|
||
295 | * @see orb_init
|
||
296 | **/
|
||
297 | void orb2_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) { |
||
298 | 277 | emarinel | orb_set_angle(4,red_led);
|
299 | orb_set_angle(5,green_led);
|
||
300 | orb_set_angle(6,blue_led);
|
||
301 | 276 | emarinel | } |
302 | |||
303 | /**
|
||
304 | * Set both orbs to the specified color. This function
|
||
305 | * is intended to be used with the predefined
|
||
306 | * colors. orb_init must be called before this
|
||
307 | * function may be used.
|
||
308 | *
|
||
309 | * @param col the color to set the orbs to
|
||
310 | *
|
||
311 | * @see orb_init
|
||
312 | **/
|
||
313 | void orb_set_color(int col) |
||
314 | { |
||
315 | 277 | emarinel | int red, green, blue;
|
316 | 276 | emarinel | |
317 | 277 | emarinel | red = ((col & 0xE0) >> 5) * 36; |
318 | green = ((col & 0x1C) >> 2) * 36; |
||
319 | blue = (col & 0x03) * 85; |
||
320 | 276 | emarinel | |
321 | 277 | emarinel | orb_set(red, green, blue); |
322 | 276 | emarinel | } |
323 | |||
324 | /**
|
||
325 | * Set orb1 to the specified color. This function
|
||
326 | * is intended to be used with the predefined
|
||
327 | * colors. orb_init must be called before this
|
||
328 | * function may be used.
|
||
329 | *
|
||
330 | * @param col the color to set the orbs to
|
||
331 | *
|
||
332 | * @see orb_init
|
||
333 | **/
|
||
334 | void orb1_set_color(int col) |
||
335 | { |
||
336 | 277 | emarinel | int red, green, blue;
|
337 | 276 | emarinel | |
338 | 277 | emarinel | red = ((col & 0xE0) >> 5) * 36; |
339 | green = ((col & 0x1C) >> 2) * 36; |
||
340 | blue = (col & 0x03) * 85; |
||
341 | 276 | emarinel | |
342 | 277 | emarinel | orb1_set(red, green, blue); |
343 | 276 | emarinel | } |
344 | |||
345 | /**
|
||
346 | * Set orb2 to the specified color. This function
|
||
347 | * is intended to be used with the predefined
|
||
348 | * colors. orb_init must be called before this
|
||
349 | * function may be used.
|
||
350 | *
|
||
351 | * @param col the color to set the orbs to
|
||
352 | *
|
||
353 | * @see orb_init
|
||
354 | **/
|
||
355 | void orb2_set_color(int col) |
||
356 | { |
||
357 | 277 | emarinel | int red, green, blue;
|
358 | 276 | emarinel | |
359 | 277 | emarinel | red = ((col & 0xE0) >> 5) * 36; |
360 | green = ((col & 0x1C) >> 2) * 36; |
||
361 | blue = (col & 0x03) * 85; |
||
362 | 276 | emarinel | |
363 | 277 | emarinel | orb2_set(red, green, blue); |
364 | 276 | emarinel | } |
365 | |||
366 | //DOES THIS WORK?
|
||
367 | // Disables the timer1 interrupt, disabling the Orb's color fading capabilities
|
||
368 | // You can still turn the red, green, and blue leds on and off with set_orb_dio
|
||
369 | /* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
|
||
370 | /**
|
||
371 | * Disables the orb color fading capabilities
|
||
372 | * by disabling the timer1 interrupt.
|
||
373 | *
|
||
374 | * @see orb_init
|
||
375 | **/
|
||
376 | void orb_disable()
|
||
377 | { |
||
378 | 277 | emarinel | TCCR3B &= 0; //Turn off everything |
379 | ORB_PORT |= _BV(ORB1_RED); |
||
380 | ORB_PORT |= _BV(ORB1_GREEN); |
||
381 | ORB_PORT |= _BV(ORB1_BLUE); |
||
382 | ORB_PORT |= _BV(ORB2_RED); |
||
383 | ORB_PORT |= _BV(ORB2_GREEN); |
||
384 | ORB_PORT |= _BV(ORB2_BLUE); |
||
385 | 276 | emarinel | } |
386 | |||
387 | //DOES THIS WORK?
|
||
388 | // Enables the timer1 interrupt, enabling the Orb's color fading capabilities
|
||
389 | /**
|
||
390 | * Enables the orb's color fading capabilities.
|
||
391 | *
|
||
392 | * @see orb_init
|
||
393 | **/
|
||
394 | void orb_enable()
|
||
395 | { |
||
396 | 277 | emarinel | // TCCR0 |= _BV(COM01) | _BV(COM00) | _BV(WGM00) | _BV(CS01); //Toggle OC Pin on match, FAST PWM Mode, clock/8
|
397 | TCCR3B =_BV(CS31); |
||
398 | 276 | emarinel | } |
399 | |||
400 | /** @} **/ //end group |