Project

General

Profile

Revision 877

Delete src directory.

View differences:

trunk/code/lib/src/libdragonfly/math.c
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 math.c
29
 * @brief Math Functions
30
 *
31
 * Useful math functions.
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 **/
35

  
36
#include "math.h"
37

  
38
/**
39
 * @defgroup math Math
40
 * Function(s) for performing math operations
41
 *
42
 * @{
43
 **/
44

  
45
/**
46
 * finds the absolute value of x
47
 * 
48
 * @param x the int of which we want to take its absolute value
49
 * 
50
 * @return the absolute value of x
51
 **/
52
int abs_int (int x) {
53

  
54
  if(x < 0)
55
    return -x;
56
    
57
  return x;
58
}
59

  
60
/**@}**/ //end defgroup
61

  
trunk/code/lib/src/libdragonfly/lights.c
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
/**
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
414

  
trunk/code/lib/src/libdragonfly/time.c
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 time.c
29
 * @brief Timer code
30
 *
31
 * Implementation of functions for timers.
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 **/
35

  
36
/*
37
  time.c
38
  anything that requires a delay
39
  mostly delay_ms
40

  
41
  author: Robotics Club, Colony Project
42

  
43
  Change Log:
44
  2.5.07 - Kevin
45
  Aaron fixed the orb/servo code and made them use timer3 but compare registers B and C. He hard set the prescaler
46
  to 8 so the RTC broke. Changed it so that we use a 8 prescaler which sets the compare match at 1/16th of a second.
47
  You now count how many 16ths of a second you want until you trigger your actual interrupt. Works. Changed defines
48
  for time so you can still call rtc_init with a scale but now it is defined in terms of actual time like second, quarter_second
49
  etc. Read that section in the time.h file for more information. Tested and works, though the clock drifts more than
50
  it used to
51
  1.30.07 - Kevin
52
  Modified the clock to run on timer3 on the Dragonfly. Works with decent accuracy. Using a prescaler of 256
53
  the timer counts up to a precomputer value which will trigger an interrupt and reset the timer. Multiples of
54
  256 change it by that multiple. Refer to the time.h file for all possible prescalers.
55
  The interrupt will call a specified function _rtc_func every pulse.
56
  All of it has been tested and it works.
57

  
58
*/
59
#include <avr/interrupt.h>
60
#include <util/delay.h>
61
#include <time.h>
62
#include <serial.h>
63

  
64
/* Calculate how many cycles to delay for to get 1 ms. Based on F_CPU which should be defined by the makefile */
65
#ifdef F_CPU
66
#define WAIT_CYCLES ((F_CPU / 1000) / 10)
67
#else
68
#define WAIT_CYCLES (8000 / 10)
69
#endif
70

  
71
static volatile int _rtc_val = 0;
72
static volatile int _rtc_pulse = 0;
73
static volatile int _rtc_scale = 32;	//Defaults to 1 Second per pulse
74
static void (*_rtc_f)(void) = 0;
75

  
76

  
77

  
78
/**
79
 * @defgroup time Time
80
 * @brief Time functions
81
 * 
82
 * Functions dealing with time.
83
 * 
84
 * @{
85
 **/
86

  
87
/**
88
 * Delays for the specified number of milliseconds.
89
 * It depends on F_CPU to be defined in order to calculate how many cycles
90
 * it should delay. If it is not defined, a default clock of 8MHz is assumed.
91
 * 
92
 * We use _delay_loop_2 which will run assembly instructions that should be
93
 * 4 cycles long. Optimizations must be enabled for this to be true.
94
 * That function is called to ensure around 1ms per execution. To generate
95
 * multiple ms we run a for loop of how many milliseconds are desired.
96
 *
97
 * The error should be just the skew on the oscillator as the formula to 
98
 * calculate delay cycles should always be a whole number. The is some skew
99
 * in practice though it is unavoidable. Delaying for less than 1s should make
100
 * the error negligable.
101
 *
102
 * @param ms the number of milliseconds to delay for
103
 **/
104
void delay_ms(int ms) {
105
    for (; ms > 0; ms--) {
106
        _delay_loop_2(WAIT_CYCLES);
107
    }
108
}
109

  
110

  
111
/* 	Prescales defined in time.h. SECOND will give you 1 second.
112
	More scales are defined in the time.h file.
113
	rtc_func is the address to a function that you want called every clock tick. */
114
/**
115
 * Initializes the real time clock. Prescales are defined in time.h.
116
 * For example, SECOND will give 1 second. The specified function is
117
 * called every clock tick. For the real time clock to activate,
118
 * interrupts must be enabled. (through sei() )
119
 *
120
 * @param prescale_opt the period with which the timer is triggered
121
 * @param rtc_func the function called when the timer is triggered
122
 *
123
 * @see rtc_get, rtc_reset
124
 *
125
 **/
126
void rtc_init(int prescale_opt, void (*rtc_func)(void)) {
127
	
128
  //Clear timer register for Timer 3
129
  TCNT3 = 0;
130
	
131
  /* 	This sets the Waveform Generation Module to CTC (Clear Timer on Compare) Mode (100)
132
	See page135 in Atmega128 Docs for more modes and explanations */
133
  TCCR3B |= _BV(WGM32);
134
	
135
  /* 	This sets the prescaler for the system clock (8MHz) ie: divides the clock by some number.
136
	Currently set to a prescaler of 8 because that is what the orb and servos use (they are on this timer as well)
137
	See page137 in Atemga128 Docs for all the available prescalers */
138
  TCCR3B |= _BV(CS31);
139
	
140
  /* 	Sets the two regsiters that we compare against. So the timer counts up to this number and
141
	then resets back to 0 and calls the compare match interrupt.
142
	8x10^6 / 8 = 1/16 Second. All values are based off of this number. Do not change it unless you
143
	are l337*/
144
		
145
  OCR3A = 0xF424;	
146

  
147
  /* 	Enable Output Compare A Interrupt. When OCR3A is met by the timer TCNT3 this interrupt will be
148
	triggerd. (See page140 in Atmega128 Docs for more information */
149
  ETIMSK |= _BV(OCIE3A);
150
	
151
  /*	Store the pointer to the function to be used in the interrupt */
152
  _rtc_f = rtc_func;
153
	
154
  /*	Store how many 1/16ths of a second you want to let by before triggering an interrupt */
155
  _rtc_scale = prescale_opt;
156
}
157

  
158
/**
159
 * Returns the time elapsed in seconds since the last call to
160
 * rtc_init or rtc_reset.
161
 *
162
 * @return the number of seconds since the last call to rtc_init or rtc_reset
163
 *
164
 * @see rtc_init, rtc_reset
165
 **/
166
int rtc_get(void) {
167
  return _rtc_val;
168
}
169

  
170
/**
171
 * Resets the real time clock counter to 0.
172
 *
173
 * @see rtc_init, rtc_get
174
 **/
175
void rtc_reset(void) {
176
  _rtc_val = 0;
177
}
178

  
179
/** @} **/ //end defgroup
180

  
181
/*	Called every pulse. Function in _rtc_f is called every _rtc_scale and also the counter is updated.
182
	Bascially, since the pulse is hard set at 1/16s  you want to count how many 16ths of a second have passed
183
	and when it reaches the amount of time you want, execute the code. */
184
SIGNAL(TIMER3_COMPA_vect) {
185

  
186
  if (_rtc_pulse ==  _rtc_scale) {
187
    //Increment the real time clock counter
188
    _rtc_val++;
189
		
190
    //Calls the function tied to the real time clock if defined
191
    if(_rtc_f != 0)
192
      _rtc_f();
193
		
194
    //Resets the pulse until the next scale is matched
195
    _rtc_pulse = 0;
196
  }	
197
	
198
  //Updates the amount of pulses seen since the last scale match
199
  _rtc_pulse++;
200
	
201
}
trunk/code/lib/src/libdragonfly/motor.c
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 motor.c
29
 * @brief Motors
30
 *
31
 * Implementation of functions for controlling the motors.
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 * Much of this is taken from FWR's library, author: Tom Lauwers
35
 **/
36

  
37
#include "motor.h"
38

  
39
/**
40
 * @defgroup motors Motors
41
 * @brief Functions for controlling the motors.
42
 * Functions for controlling the motors. Found in motor.h.
43
 * @{
44
 **/
45

  
46
/**
47
 * Initializes both motors so that they can be used with future
48
 * calls to motor1_set and motor2_set.
49
 *
50
 * @see motors_off, motor1_set, motor2_set
51
 **/
52
void motors_init( void ) {
53
  // Configure counter such that we use phase correct
54
  // PWM with 8-bit resolution
55
  PORTA &= 0x0F;
56
  DDRA |= 0xF0;
57
  DDRB |= 0x60;
58

  
59
  //timer 1A and 1B
60
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
61
  TCCR1B = _BV(WGM12) | _BV(CS10);
62
  //	TCCR1A = 0xA1;
63
  //	TCCR1B = 0x04;
64
  OCR1AH=0;
65
  OCR1AL=0;
66
  OCR1BH=0;
67
  OCR1BL=0;
68
}
69

  
70
/**
71
 * Sets the speed and direction of motor1.
72
 * motors_init must be called before this function can be used.
73
 *
74
 * @param direction Either FORWARD or BACKWARD to set the direction of rotation.
75
 * @param speed The speed the motor will run at, in the range 0-255.
76
 * 
77
 * @see motor2_set, motors_init
78
 **/
79
void motor1_set(int direction, int speed) {
80

  
81
  if(direction == 0) {
82
    // turn off PWM first if switching directions
83
    if((PORTA & 0x30) != 0x10) {
84
      OCR1A = 0;
85
    }	
86
    PORTA = (PORTA & 0xCF) | 0x10;
87
    //		PORTD |= 0x10;
88
    //		PORTD &= 0xBF;
89
  } else {
90
    // turn off PWM first if switching directions
91
    if((PORTA & 0x30) != 0x20) {
92
      OCR1A = 0;
93
    }
94
    PORTA = (PORTA & 0xCF) | 0x20;
95
    //		PORTD |= 0x40;
96
    //		PORTD &= 0xEF;
97
  }
98
	
99
  // Set the timer to count up to speed, an 8-bit value
100
  OCR1AL = speed;
101
}
102

  
103
/**
104
 * Sets the speed and direction of motor2.
105
 * motors_init must be called before this function can be used.
106
 *
107
 * @param direction Either FORWARD or BACKWARD to set the direction of rotation.
108
 * @param speed The speed the motor will run at, in the range 0-255.
109
 *
110
 * @see motor1_set, motors_init
111
 **/
112
void motor2_set(int direction, int speed) {
113
  if(direction == 0) {
114
    //		PORTD |= 0x20;
115
    //		PORTD &= 0x7F;
116
    // turn off PWM first if switching directions
117
    if((PORTA & 0xC0) != 0x80) {
118
      OCR1B = 0;
119
    }		
120
		
121
    PORTA = (PORTA & 0x3F) | 0x80;
122
  } else {
123
    //		PORTD |= 0x80;
124
    //		PORTD &= 0xDF;
125

  
126
    // turn off PWM first if switching directions
127
    if((PORTA & 0xC0) != 0x40) {
128
      OCR1B = 0;
129
    }		
130
		
131
    PORTA = (PORTA & 0x3F) | 0x40;
132
  }
133
  OCR1BL = speed;
134
}
135

  
136
/**
137
 * Turns off both motors.
138
 *
139
 * @see motors_init
140
 **/
141
void motors_off( void ) {
142
  OCR1AL = 0x0;
143
  OCR1BL = 0x0;
144
}
145

  
146
/**@}**///end defgroup
147

  
trunk/code/lib/src/libdragonfly/analog.c
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
 * @file analog.c
28
 * @brief Analog input and output
29
 *
30
 * Contains functions for manipulating the ADC on the Dragonfly board.
31
 * 
32
 * @author Colony Project, CMU Robotics Club
33
 * code mostly taken from fwr analog file (author: Tom Lauwers)
34
 **/
35

  
36
#include <util/delay.h>
37
#include <avr/interrupt.h>
38
#include "analog.h"
39
#include "serial.h"
40
// Internal Function Prototypes
41
void set_adc_mux(int which);
42

  
43
/**
44
 * @defgroup analog Analog
45
 * Functions for manipulation the ADC on the dragonfly board.
46
 * All definitions may be found in analog.h.
47
 *
48
 * @{
49
 **/
50

  
51
int adc_loop_running = 0;
52
int adc_current_port = 0;
53
adc_t an_val[11];
54

  
55
/**
56
 * Initializes the ADC.
57
 * Call analog_init before reading from the analog ports.
58
 *
59
 * @see analog8, analog10, analog_get8, analog_get10
60
 **/
61
void analog_init(int start_conversion) {
62
	for (int i = 0; i < 11; i++) {
63
		an_val[i].adc10 = 0;
64
		an_val[i].adc8 = 0;
65
	}
66

  
67
	// ADMUX register
68
	// Bit 7,6 - Set voltage reference to AVcc (0b01)
69
	// Bit 5 - ADLAR set to simplify moving from register
70
	// Bit 4 - X
71
	// Bit 3:0 - Sets the current channel
72
	// Initializes to read from AN1 first (AN0 is reservered for the BOM)
73
	ADMUX = 0;
74
	ADMUX |= ADMUX_OPT | _BV(MUX0);
75

  
76
	// ADC Status Register A
77
	// Bit 7 - ADEN is set (enables analog)
78
	// Bit 6 - Start conversion bit is set (must be done once for free-running mode)
79
	// Bit 5 - Enable Auto Trigger (for free running mode) NOT DOING THIS RIGHT NOW
80
	// Bit 4 - ADC interrupt flag, 0
81
	// Bit 3 - Enable ADC Interrupt (required to run free-running mode)
82
	// Bits 2-0 - Set to create a clock divisor of 128, to make ADC clock = 8,000,000/64 = 125kHz
83
	ADCSRA = 0;
84
	ADCSRA |= _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
85
	
86
	// Set external mux lines to outputs
87
	DDRG |= 0x1C;
88
	
89
	// Set up first port for conversions
90
	set_adc_mux(0x00);
91
	adc_current_port = AN1;
92

  
93
	//Start the conversion if requested
94
	if (start_conversion)
95
		analog_start_loop();
96
	else
97
		analog_stop_loop();
98
}	
99

  
100
/**
101
 * Returns the 8-bit analog conversion of which from
102
 * the lookup table. If the requested port is the BOM_PORT
103
 * you will get an automatic 0 since the BOM_PORT is not
104
 * read in the loop and not stored. If you need that port
105
 * you should use the functions in bom.c. There is an analog_get8
106
 * function which for instant lookups but should be avoided unless
107
 * you know what you're doing.
108
 *
109
 * @param which the port that you want to read
110
 *
111
 * @bug may cause a seg fault if which is a larger value
112
 * than exists in an_val table. Not sure if we should fix
113
 * this or not since it would add overhead.
114
 *
115
 * @return 8-bit analog value for the which port requested
116
 *
117
 * @see analog10, analog_get8, analog_get10
118
 **/
119
unsigned int analog8(int which) {
120
	if (which == BOM_PORT) {
121
		return 0;
122
	} else {
123
		return an_val[which - 1].adc8;
124
	}
125
}
126

  
127
/**
128
 * Returns the 10-bit analog conversion of which from
129
 * the lookup table. If the requested port is the BOM_PORT
130
 * you will get an automatic 0 since the BOM_PORT is not
131
 * read in the loop and not stored. If you need that port
132
 * you should use the functions in bom.c. There is an analog_get10
133
 * function which for instant lookups but should be avoided unless
134
 * you know what you are doing.
135
 *
136
 * @param which the port that you want to read
137
 *
138
 * @bug may cause a seg fault if which is a larger value
139
 * than exists in an_val table. Not sure if we should fix
140
 * this or not since it would add overhead.
141
 *
142
 * @return 10-bit analog value for the which port requested
143
 *
144
 * @see analog8, analog_get8, analog_get10
145
 **/
146
unsigned int analog10(int which) {
147
	if (which == BOM_PORT) {
148
		return 0;
149
	} else {
150
		return an_val[which - 1].adc10;
151
	}
152
}
153

  
154
/**
155
 * Starts the analog update loop. Will continue to run
156
 * until analog_stop_loop is called.
157
 *
158
 * @see analog_stop_loop
159
 **/
160
void analog_start_loop(void) {
161
	//Start the conversion
162
	ADCSRA |= _BV(ADSC);
163
	adc_loop_running = 0x1;
164
}
165

  
166
/**
167
 * Stops the analog update loop. If there is a current
168
 * read, it will finish up and be stored before the loop
169
 * is interrupted. No further updates will be made until
170
 * the loop is started again.
171
 *
172
 * @see analog_start_loop
173
 **/
174
void analog_stop_loop(void) {
175
	//Stop the conversion
176
	adc_loop_running = 0x0;
177
}
178
/**
179
 * Reads an 8-bit number from an analog port.
180
 * analog_init must be called before using this function.
181
 * The analog loop must also be stopped before using this
182
 * function or you will mess up the lookup table. You
183
 * must also reenabled the loop when you are done unless
184
 * you are doing more instant reads. See analog_stop_loop
185
 * and analog_start_loop for more information about the loop.
186
 * 
187
 * @param which the analog port to read from. One of
188
 * the constants AN0 - AN7.
189
 *
190
 * @return the 8-bit input to the specified port
191
 *
192
 * @see analog_init, analog_get10, analog8, analog_stop_loop,
193
 * analog_start_loop
194
 **/
195
unsigned int analog_get8(int which) {	
196
	// Let any previous conversion finish
197
	while (ADCSRA & _BV(ADSC));
198
	
199
	if(which < EXT_MUX) {
200
		ADMUX = ADMUX_OPT + which;
201
	} else {
202
		ADMUX = ADMUX_OPT + EXT_MUX;
203
		set_adc_mux(which - 8);
204
	}
205
	
206
	// Start the conversion
207
	ADCSRA |= _BV(ADSC);
208

  
209
	// Wait for the conversion to finish
210
	while (ADCSRA & _BV(ADSC));
211

  
212
	return ADCH; //since we left aligned the data, ADCH is the 8 MSB.
213
}
214

  
215
/**
216
 * Reads an 10-bit number from an analog port.
217
 * analog_init must be called before using this function.
218
 * The analog loop must also be stopped before using this
219
 * function or you will mess up the lookup table. You
220
 * must also reenabled the loop when you are done unless
221
 * you are doing more instant reads. See analog_stop_loop
222
 * and analog_start_loop for more information about the loop.
223
 * 
224
 *
225
 * @param which the analog port to read from. Typically
226
 * a constant, one of AN0 - AN7.
227
 *
228
 * @return the 10-bit number input to the specified port
229
 * 
230
 * @see analog_init, analog_get8, analog10, analog_stop_loop,
231
 * analog_start_loop
232
 **/
233
unsigned int analog_get10(int which) {
234
	int adc_h;
235
	int adc_l;
236
	
237
	// Let any previous conversion finish
238
	while (ADCSRA & _BV(ADSC));
239

  
240
	if(which < EXT_MUX) {
241
		ADMUX = ADMUX_OPT + which;
242
	} else {
243
		ADMUX = ADMUX_OPT + EXT_MUX;
244
		set_adc_mux(which - 8);
245
	}
246
	
247
	// Start the conversion
248
	ADCSRA |= _BV(ADSC);
249

  
250
	// Wait for the conversion to finish
251
	while (ADCSRA & _BV(ADSC));
252
	
253
	adc_l = ADCL;
254
	adc_h = ADCH;
255

  
256
	return ((adc_h << 2) | (adc_l >> 6));
257
}
258

  
259
/**
260
 * Returns the current position of the wheel, as an integer
261
 * in the range 0 - 255.
262
 * analog_init must be called before using this function.
263
 *
264
 * @return the orientation of the wheel, as an integer in
265
 * the range 0 - 255.
266
 *
267
 * @see analog_init
268
 **/
269
int wheel(void) {
270
	return analog8(WHEEL_PORT);
271
}
272

  
273

  
274
/**
275
 * Sets the value of the external analog mux. Values are read
276
 * 	on AN7 physical port. (AN8 - AN15 are "virtual" ports).
277
 *
278
 * @param which which analog mux port (0-7) which corresponds
279
 * 		  to AN8-AN15.
280
 *
281
 * @bug FIX THIS IN THE NEXT BOARD REVISION:
282
 *		ADDR2 ADDR1 ADDR0
283
 *		G2.G4.G3 set mux to port 0-7 via vinary selection
284
 *		math would be much cleaner if it was G4.G3.G2
285
 *
286
 * @see analog_init
287
 **/
288
void set_adc_mux(int which) {  
289
  // mask so only proper bits are possible.  
290
  PORTG = (PORTG & 0xE3) | ((which & 0x03) << 3) | (which & 0x04);
291
}
292

  
293
/**@}**/ //end defgroup
294

  
295

  
296
ISR(ADC_vect) {
297
	static volatile int adc_prev_loop_running = 0; 
298
	int adc_h = 0;
299
	int adc_l = 0;
300

  
301
	//Store the value only if this read isn't for the BOM
302
	if (ADMUX != BOM_PORT) {
303
		adc_l = ADCL;
304
		adc_h = ADCH;
305
	
306
		an_val[adc_current_port - 1].adc10 = (adc_h << 2) | (adc_l >> 6);
307
		an_val[adc_current_port - 1].adc8 = adc_h;
308
	}
309
	
310
	//Save the result only if we just turned off the loop
311
	if (!adc_loop_running && !adc_prev_loop_running)
312
		return;
313
	
314
	adc_prev_loop_running = adc_loop_running;
315
	
316
	//Skip AN7 because it is not a real port
317
	if (adc_current_port == AN6) {
318
		ADMUX = ADMUX_OPT | EXT_MUX;
319
		set_adc_mux(AN8 - 8);
320
		adc_current_port = AN8;
321
	//Wrap around
322
	} else if (adc_current_port == AN11) {
323
		adc_current_port = AN1;
324
		ADMUX = ADMUX_OPT | adc_current_port;
325
	//Normal increment
326
	} else {
327
		adc_current_port++;
328
	
329
		if(adc_current_port < EXT_MUX) {
330
			ADMUX = ADMUX_OPT | adc_current_port;
331
		} else {
332
			ADMUX = ADMUX_OPT | EXT_MUX;
333
			set_adc_mux(adc_current_port - 8);
334
		}
335
	}
336

  
337
	//Initiate next conversion only if we are running a loop
338
	if (!adc_loop_running) {
339
		return;
340
    } else {
341
    	ADCSRA |= _BV(ADSC);
342
	}
343
		
344
	return;
345
}
346

  
trunk/code/lib/src/libdragonfly/lcd.c
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 lcd.c
29
 * @brief LCD
30
 *
31
 * Implementation of functions for using the LCD.
32
 *
33
 * @author Colony Project, CMU Robotics Club
34
 **/
35
#include <avr/io.h>
36
#include <lcd.h>
37
#include <time.h>
38

  
39
//LCD defines
40
#define RST _BV(4)  // pd4 (GPIO)
41
#define SCE _BV(0)  // pb0 (~SS)
42
#define D_C _BV(5)  // pd5 (GPIO?)
43
#define SDI _BV(2)  // pb2 (MOSI)
44
#define SCK _BV(1) // pb1 (SCK)
45

  
46
#define LCDPORT PORTB
47
#define LCDDDR DDRB
48

  
49
#define LCDRESETPORT PORTD
50
#define LCDRESETDDR DDRD
51

  
52
void lcd_putbyte(unsigned char b);
53

  
54

  
55
//**************************************Old shit below!*****************
56
/*
57
  FontLookup - a lookup table for all characters
58
*/
59
static const unsigned char FontLookup [][5] =
60
  {
61
    { 0x00, 0x00, 0x00, 0x00, 0x00 },  // sp
62
    { 0x00, 0x00, 0x5f, 0x00, 0x00 },   // !
63
    { 0x00, 0x07, 0x00, 0x07, 0x00 },   // "
64
    { 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #
65
    { 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $
66
    { 0x23, 0x13, 0x08, 0x64, 0x62 },   // %
67
    { 0x36, 0x49, 0x55, 0x22, 0x50 },   // &
68
    { 0x00, 0x05, 0x03, 0x00, 0x00 },   // '
69
    { 0x00, 0x1c, 0x22, 0x41, 0x00 },   // (
70
    { 0x00, 0x41, 0x22, 0x1c, 0x00 },   // )
71
    { 0x14, 0x08, 0x3E, 0x08, 0x14 },   // *
72
    { 0x08, 0x08, 0x3E, 0x08, 0x08 },   // +
73
    { 0x00, 0x00, 0x50, 0x30, 0x00 },   // ,
74
    { 0x10, 0x10, 0x10, 0x10, 0x10 },   // -
75
    { 0x00, 0x60, 0x60, 0x00, 0x00 },   // .
76
    { 0x20, 0x10, 0x08, 0x04, 0x02 },   // /
77
    { 0x3E, 0x51, 0x49, 0x45, 0x3E },   // 0
78
    { 0x00, 0x42, 0x7F, 0x40, 0x00 },   // 1
79
    { 0x42, 0x61, 0x51, 0x49, 0x46 },   // 2
80
    { 0x21, 0x41, 0x45, 0x4B, 0x31 },   // 3
81
    { 0x18, 0x14, 0x12, 0x7F, 0x10 },   // 4
82
    { 0x27, 0x45, 0x45, 0x45, 0x39 },   // 5
83
    { 0x3C, 0x4A, 0x49, 0x49, 0x30 },   // 6
84
    { 0x01, 0x71, 0x09, 0x05, 0x03 },   // 7
85
    { 0x36, 0x49, 0x49, 0x49, 0x36 },   // 8
86
    { 0x06, 0x49, 0x49, 0x29, 0x1E },   // 9
87
    { 0x00, 0x36, 0x36, 0x00, 0x00 },   // :
88
    { 0x00, 0x56, 0x36, 0x00, 0x00 },   // ;
89
    { 0x08, 0x14, 0x22, 0x41, 0x00 },   // <
90
    { 0x14, 0x14, 0x14, 0x14, 0x14 },   // =
91
    { 0x00, 0x41, 0x22, 0x14, 0x08 },   // >
92
    { 0x02, 0x01, 0x51, 0x09, 0x06 },   // ?
93
    { 0x32, 0x49, 0x59, 0x51, 0x3E },   // @
94
    { 0x7E, 0x11, 0x11, 0x11, 0x7E },   // A
95
    { 0x7F, 0x49, 0x49, 0x49, 0x36 },   // B
96
    { 0x3E, 0x41, 0x41, 0x41, 0x22 },   // C
97
    { 0x7F, 0x41, 0x41, 0x22, 0x1C },   // D
98
    { 0x7F, 0x49, 0x49, 0x49, 0x41 },   // E
99
    { 0x7F, 0x09, 0x09, 0x09, 0x01 },   // F
100
    { 0x3E, 0x41, 0x49, 0x49, 0x7A },   // G
101
    { 0x7F, 0x08, 0x08, 0x08, 0x7F },   // H
102
    { 0x00, 0x41, 0x7F, 0x41, 0x00 },   // I
103
    { 0x20, 0x40, 0x41, 0x3F, 0x01 },   // J
104
    { 0x7F, 0x08, 0x14, 0x22, 0x41 },   // K
105
    { 0x7F, 0x40, 0x40, 0x40, 0x40 },   // L
106
    { 0x7F, 0x02, 0x0C, 0x02, 0x7F },   // M
107
    { 0x7F, 0x04, 0x08, 0x10, 0x7F },   // N
108
    { 0x3E, 0x41, 0x41, 0x41, 0x3E },   // O
109
    { 0x7F, 0x09, 0x09, 0x09, 0x06 },   // P
110
    { 0x3E, 0x41, 0x51, 0x21, 0x5E },   // Q
111
    { 0x7F, 0x09, 0x19, 0x29, 0x46 },   // R
112
    { 0x46, 0x49, 0x49, 0x49, 0x31 },   // S
113
    { 0x01, 0x01, 0x7F, 0x01, 0x01 },   // T
114
    { 0x3F, 0x40, 0x40, 0x40, 0x3F },   // U
115
    { 0x1F, 0x20, 0x40, 0x20, 0x1F },   // V
116
    { 0x3F, 0x40, 0x38, 0x40, 0x3F },   // W
117
    { 0x63, 0x14, 0x08, 0x14, 0x63 },   // X
118
    { 0x07, 0x08, 0x70, 0x08, 0x07 },   // Y
119
    { 0x61, 0x51, 0x49, 0x45, 0x43 },   // Z
120
    { 0x00, 0x7F, 0x41, 0x41, 0x00 },   // [
121
    { 0x02, 0x04, 0x08, 0x10, 0x20 },   // backslash
122
    { 0x00, 0x41, 0x41, 0x7F, 0x00 },   // ]
123
    { 0x04, 0x02, 0x01, 0x02, 0x04 },   // ^
124
    { 0x40, 0x40, 0x40, 0x40, 0x40 },   // _
125
    { 0x00, 0x01, 0x02, 0x04, 0x00 },   // '
126
    { 0x20, 0x54, 0x54, 0x54, 0x78 },   // a
127
    { 0x7F, 0x48, 0x44, 0x44, 0x38 },   // b
128
    { 0x38, 0x44, 0x44, 0x44, 0x20 },   // c
129
    { 0x38, 0x44, 0x44, 0x48, 0x7F },   // d
130
    { 0x38, 0x54, 0x54, 0x54, 0x18 },   // e
131
    { 0x08, 0x7E, 0x09, 0x01, 0x02 },   // f
132
    { 0x0C, 0x52, 0x52, 0x52, 0x3E },   // g
133
    { 0x7F, 0x08, 0x04, 0x04, 0x78 },   // h
134
    { 0x00, 0x44, 0x7D, 0x40, 0x00 },   // i
135
    { 0x20, 0x40, 0x44, 0x3D, 0x00 },   // j
136
    { 0x7F, 0x10, 0x28, 0x44, 0x00 },   // k
137
    { 0x00, 0x41, 0x7F, 0x40, 0x00 },   // l
138
    { 0x7C, 0x04, 0x18, 0x04, 0x78 },   // m
139
    { 0x7C, 0x08, 0x04, 0x04, 0x78 },   // n
140
    { 0x38, 0x44, 0x44, 0x44, 0x38 },   // o
141
    { 0x7C, 0x14, 0x14, 0x14, 0x08 },   // p
142
    { 0x08, 0x14, 0x14, 0x18, 0x7C },   // q
143
    { 0x7C, 0x08, 0x04, 0x04, 0x08 },   // r
144
    { 0x48, 0x54, 0x54, 0x54, 0x20 },   // s
145
    { 0x04, 0x3F, 0x44, 0x40, 0x20 },   // t
146
    { 0x3C, 0x40, 0x40, 0x20, 0x7C },   // u
147
    { 0x1C, 0x20, 0x40, 0x20, 0x1C },   // v
148
    { 0x3C, 0x40, 0x30, 0x40, 0x3C },   // w
149
    { 0x44, 0x28, 0x10, 0x28, 0x44 },   // x
150
    { 0x0C, 0x50, 0x50, 0x50, 0x3C },   // y
151
    { 0x44, 0x64, 0x54, 0x4C, 0x44 },    // z
152
    { 0x00, 0x08, 0x36, 0x41, 0x41 },   // {
153
    { 0x00, 0x00, 0x7F, 0x00, 0x00 },   // |
154
    { 0x41, 0x41, 0x36, 0x08, 0x00 },   // }
155
    { 0x02, 0x01, 0x01, 0x02, 0x01 },   // ~
156
    { 0x55, 0x2A, 0x55, 0x2A, 0x55 },   // del
157
  };
158

  
159

  
160
/**
161
 * @defgroup lcd LCD
162
 * @brief Functions for the LCD
163
 * Functions for writing to the LCD.
164
 * All functions may be found in lcd.h.
165
 *
166
 * @{
167
 **/
168

  
169
/**
170
 * Initializes the LCD. Must be called before any other
171
 * LCD functions.
172
 **/
173
void lcd_init(void) {
174
  LCDDDR |= (SCE | SDI | SCK);
175
  LCDRESETDDR |= (RST|D_C);
176

  
177
  LCDPORT &= ~( SCE | SDI | SCK);
178
  LCDRESETPORT &=~(D_C);
179
  
180
  SPCR |= 0x50;//0b01010000; // no SPI int, SPI en, Master, sample on rising edge, fosc/2
181
  SPSR |= 0x01;       // a continuation of the above
182

  
183
  LCDRESETPORT |= RST;
184
  delay_ms(10);
185
  LCDRESETPORT &= (~RST);
186
  delay_ms(100);
187
  LCDRESETPORT |= RST;
188
	
189
  lcd_putbyte( 0x21 );  // LCD Extended Commands.
190
  lcd_putbyte( 0xC8 );  // Set LCD Vop (Contrast).
191
  lcd_putbyte( 0x06 );  // Set Temp coefficent.
192
  lcd_putbyte( 0x13 );  // LCD bias mode 1:48.
193
  lcd_putbyte( 0x20 );  // LCD Standard Commands, Horizontal addressing mode.
194
  lcd_putbyte( 0x0C );  // LCD in normal mode.
195
	
196
  LCDRESETPORT |= D_C;		//put it in init instead of main
197
	
198
  lcd_clear_screen();
199
}
200

  
201
/**
202
 * Clears the LCD screen. lcd_init must be called first.
203
 * 
204
 * @see lcd_init
205
 **/
206
void lcd_clear_screen( void ) {
207
  int i;
208
  for (i = 0; i < 504; i++)
209
    lcd_putbyte(0x0);
210
	
211
  lcd_gotoxy(0,0);
212
}
213

  
214
/**
215
 * Prints a character on the LCD screen. lcd_init
216
 * must be called before this function may be used.
217
 *
218
 * @param c the character to print
219
 *
220
 * @see lcd_init
221
 **/
222
void lcd_putc(char c) {
223
  int i;
224
	
225
  for (i = 0; i < 5; i++)
226
    lcd_putbyte(FontLookup[c-32][i]);
227
  lcd_putbyte(0);
228
}
229

  
230
/*
231
  print an entire string to the lcd
232
*/
233
void lcd_puts(char *s) {
234
  char *t = s;
235
  while (*t != 0) {
236
    lcd_putc(*t);
237
    t++;
238
  }
239
}
240

  
241
/*
242
  go to coordinate x, y
243
  y: vertically - 1 char
244
  x: horizontally - 1 pixel
245

  
246
  multiply x by 6 if want to move 1 entire character
247

  
248
  origin (0,0) is at top left corner of lcd screen
249
*/
250

  
251
/**
252
 * Move the current cursor position to the one specified.
253
 * lcd_init must be called before this function may be used.
254
 * 
255
 * @param x The x coordinate of the new position
256
 * @param y The y coordinate of the new position
257
 *
258
 * @see lcd_init
259
 **/
260
void lcd_gotoxy(int x, int y) {
261
  LCDRESETPORT &= ~(D_C);
262
  lcd_putbyte(0x40 | (y & 0x07));
263
  lcd_putbyte(0x80 | (x & 0x7f));
264
  LCDRESETPORT |= D_C;
265
}
266

  
267
/*
268
  prints an int to the lcd
269

  
270
  code adapted from Chris Efstathiou's code (hendrix@otenet.gr)
271
*/
272

  
273
/**
274
 * Print an integer to the LCD screen.
275
 * lcd_init must be called before this function may be used.
276
 * 
277
 * @param value the integer to print
278
 *
279
 * @see lcd_init
280
 **/
281
void lcd_puti(int value ) {
282
  unsigned char lcd_data[6]={'0','0','0','0','0','0' }, position=sizeof(lcd_data), radix=10; 
283

  
284
  /* convert int to ascii  */ 
285
  if(value<0) { 
286
    lcd_putc('-'); 
287
    value=-value; 
288
  }    
289
  do { 
290
    position--; 
291
    *(lcd_data+position)=(value%radix)+'0'; 
292
    value/=radix;  
293
  } while(value); 
294

  
295
    
296
  /* start displaying the number */
297
  for(;position<=(sizeof(lcd_data)-1);position++)
298
    lcd_putc(lcd_data[position]);
299

  
300
  return;
301
}
302

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff