Project

General

Profile

Statistics
| Revision:

root / branches / simulator / projects / libdragonfly / lights.c @ 891

History | View | Annotate | Download (8.96 KB)

1
/**
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
        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
void orb_init() 
225
{        
226
   int i;
227
   uint8_t mysreg;
228
   
229
   ORBDDR |= ORBMASK;        //all outputs
230
   
231
        mysreg=SREG;
232
        cli(); //turn off interrupts for now
233

    
234
        //init everything
235

    
236
   for (i = 0; i < ORB_COUNT; ++i) {
237
      ORB_STATUS.orbs[i].num = i;
238
      ORB_STATUS.orbs[i].angle = 1023;        //127 is a pretty stupid start angle, but oh well
239
      ORB_STATUS.orb_angles[i] = 1023;
240
   }
241

    
242
   ORB_STATUS.new_angles = 1;
243
   ORB_STATUS.change_count = 0;
244

    
245
        //init timer3
246
        TCCR3A = 0; 
247
        TCCR3B = _BV(CS31); //prescale = 8
248
        TCCR3C = 0;
249
        ETIMSK |= _BV(OCIE3C); //turn on oc3c interrupt
250
        OCR3C = TCNT3+ORB_RESET;
251

    
252
        SREG=mysreg;
253
}
254

    
255
void orb_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
256
        orb1_set(red_led,green_led,blue_led);
257
        orb2_set(red_led,green_led,blue_led);
258

    
259
}
260

    
261
void orb1_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {
262
        orb_set_angle(0,red_led);
263
        orb_set_angle(1,green_led);
264
        orb_set_angle(2,blue_led);
265
}
266

    
267
void orb2_set(unsigned char red_led, unsigned char green_led, unsigned char blue_led) {        
268
        orb_set_angle(4,red_led);
269
        orb_set_angle(5,green_led);
270
        orb_set_angle(6,blue_led);
271
}
272

    
273
void orb_set_color(int col)
274
{
275
 int red, green, blue;
276

    
277
 red = ((col & 0xE0) >> 5) * 36;
278
 green = ((col & 0x1C) >> 2) * 36;
279
 blue = (col & 0x03) * 85;
280

    
281
 orb_set(red, green, blue);
282
}
283

    
284
void orb1_set_color(int col)
285
{
286
 int red, green, blue;
287

    
288
 red = ((col & 0xE0) >> 5) * 36;
289
 green = ((col & 0x1C) >> 2) * 36;
290
 blue = (col & 0x03) * 85;
291

    
292
 orb1_set(red, green, blue);
293
}
294

    
295
void orb2_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
 orb2_set(red, green, blue);
304
}
305

    
306
//DOES THIS WORK?
307
// Disables the timer1 interrupt, disabling the Orb's color fading capabilities
308
// You can still turn the red, green, and blue leds on and off with set_orb_dio
309
/* If we use the PWM for anything else besides the ORB, this implementation needs to be done better */
310
void orb_disable()
311
{
312
        TCCR3B &= 0;          //Turn off everything
313
        ORB_PORT |= _BV(ORB1_RED);
314
        ORB_PORT |= _BV(ORB1_GREEN);
315
        ORB_PORT |= _BV(ORB1_BLUE);
316
        ORB_PORT |= _BV(ORB2_RED);
317
        ORB_PORT |= _BV(ORB2_GREEN);
318
        ORB_PORT |= _BV(ORB2_BLUE);
319
}
320

    
321
//DOES THIS WORK?
322
// Enables the timer1 interrupt, enabling the Orb's color fading capabilities
323
void orb_enable()
324
{
325
//        TCCR0 |= _BV(COM01) | _BV(COM00)  | _BV(WGM00) | _BV(CS01);        //Toggle OC Pin on match, FAST PWM Mode, clock/8
326
        TCCR3B =_BV(CS31);
327
}
328