1 | /*
|
2 | * C Implementation: main
|
3 | *
|
4 | * Description:
|
5 | *
|
6 | *
|
7 | * Author: Hagen Meyer <hagen@hcmeyer.de>, (C) 2009
|
8 | *
|
9 | * Copyright: See COPYING file that comes with this distribution
|
10 | *
|
11 | */
|
12 |
|
13 | /** \mainpage
|
14 | * Nothing here, yet…
|
15 | */
|
16 |
|
17 | /** \file
|
18 | * \brief The main file
|
19 | */
|
20 |
|
21 | #define DEBUG 0
|
22 |
|
23 | #include <stdlib.h>
|
24 | #include <avr/io.h>
|
25 | #include <avr/interrupt.h>
|
26 | #include <util/delay.h>
|
27 |
|
28 | /*##########################################################################
|
29 | CONSTANT DEFINITIONS
|
30 | ###########################################################################*/
|
31 |
|
32 | /// \brief Register for the motor PWM
|
33 | #define MOTOR_SPEED OCR0B
|
34 |
|
35 | #define SPEED_NORMAL 65
|
36 | #define SPEED_FAST 230
|
37 | #define STOP_PROBABILITY 5
|
38 |
|
39 | /// \name LED hardware connections
|
40 | //@{
|
41 | #define PORT_LED01 PORTA
|
42 | #define PORT_LED23 PORTD
|
43 | #define PIN_LED0 1
|
44 | #define PIN_LED1 0
|
45 | #define PIN_LED2 2
|
46 | #define PIN_LED3 3
|
47 | //@}
|
48 |
|
49 | /// \name Remote-Control hardware connections
|
50 | //@{
|
51 | #define REMOTE_FAST _BV(PD0) // RxD
|
52 | #define REMOTE_SLOW _BV(PD1) // TxD
|
53 | #define REMOTE_STOP (_BV(PD0)|_BV(PD1)) // both
|
54 | //@}
|
55 |
|
56 | /// \name LED commands
|
57 | //@{
|
58 | #define OFF 0
|
59 | #define ON 1
|
60 | #define TOGGLE 2
|
61 | //@}
|
62 |
|
63 | #define LED_ALL 4
|
64 |
|
65 | /** \name DIP-switch settings
|
66 | * \brief The different modes selectable with the DIP switches
|
67 | */
|
68 | //@{
|
69 | #define GAME_MODE_SLOW 0 << 0 ///< DIP1..2 = 00 (booooring)
|
70 | #define GAME_MODE_FAST 1 << 0 ///< DIP1..2 = 10 (not soo boring)
|
71 | #define GAME_MODE_RANDOM 2 << 0 ///< DIP1..2 = 01 (magic :) )
|
72 | #define GAME_MODE_RANDOM_STOP 3 << 0 ///< DIP1..2 = 11 (more magic :) )
|
73 | #define LED_MODE_OFF 0 << 2 ///< DIP3..4 = 00
|
74 | #define LED_MODE_ON 1 << 2 ///< DIP3..4 = 10
|
75 | #define LED_MODE_RAND 2 << 2 ///< DIP3..4 = 01
|
76 | #define REMOTE_MODE_25 0 << 4 ///< DIP5..6 = 00
|
77 | #define REMOTE_MODE_50 1 << 4 ///< DIP5..6 = 10
|
78 | #define REMOTE_MODE_75 2 << 4 ///< DIP5..6 = 01
|
79 | #define REMOTE_MODE_100 3 << 4 ///< DIP5..6 = 11
|
80 | //@}
|
81 |
|
82 | /*##########################################################################
|
83 | MACROS
|
84 | ###########################################################################*/
|
85 |
|
86 | /// \brief reads the Game mode from the DIP-switches
|
87 | #define getGameMode() ((~PINB) & 3)
|
88 | /// \brief reads the LED mode from the DIP-switches
|
89 | #define getLEDMode() ((~PINB) & (3<<2))
|
90 | /// \brief reads the remote-control mode from the DIP-switches
|
91 | #define getRemoteMode() ((~PINB) & (3<<4))
|
92 | /// \brief reads the buttons of the remote control
|
93 | #define getRemoteButtons() ((~PIND) & (_BV(PD0)|_BV(PD1)))
|
94 | /// \brief reads the position of the ON/OFF switch (for the motor)
|
95 | #define isOn() !(PIND & _BV(PD4))
|
96 | /// \brief starts Timer 1 with prescaler 1024 (~1ms/step)
|
97 | #define runTimer() TCCR1B = _BV(CS12) | _BV(CS10)
|
98 | /// \brief resets Timer 1
|
99 | #define resetTimer() TCNT1 = 0
|
100 | /// \brief stops Timer 1
|
101 | #define stopTimer() TCCR1B = 0
|
102 | /// \brief set the Timer-value
|
103 | #define setTimer(val) TCNT1 = (val)
|
104 | /// \brief gets the value of Timer 1 (elapsed time in ~ms)
|
105 | #define time() TCNT1
|
106 |
|
107 | /*##########################################################################
|
108 | PROTOTYPES
|
109 | ###########################################################################*/
|
110 |
|
111 | int main (void);
|
112 | void switchLED(uint8_t led, uint8_t state);
|
113 | void LEDMagic(void);
|
114 | void GameMagic(void);
|
115 |
|
116 | /*##########################################################################
|
117 | GLOBAL VARIABLES
|
118 | ###########################################################################*/
|
119 |
|
120 | uint8_t random_nr;
|
121 | uint8_t led_mode;
|
122 | uint8_t remote_prev; // previous state of the remote
|
123 | uint8_t remote_accepted; // remote commands which are accepted (selectable probability)
|
124 | uint8_t speed;
|
125 |
|
126 | /*##########################################################################
|
127 | SUBROUTINES
|
128 | ###########################################################################*/
|
129 |
|
130 | /** \brief Routine to switch the LEDS
|
131 | * \param led Which LED to switch (0 to 3, or 4 for all)
|
132 | * \param state What to do (see \ref LED commands)
|
133 | *
|
134 | */
|
135 | void switchLED(uint8_t led, uint8_t state){
|
136 | uint8_t *port;
|
137 | uint8_t operand;
|
138 | switch(led){
|
139 | case 0: port = (uint8_t*)&PORT_LED01; operand = _BV(PIN_LED0); break;
|
140 | case 1: port = (uint8_t*)&PORT_LED01; operand = _BV(PIN_LED1); break;
|
141 | case 2: port = (uint8_t*)&PORT_LED23; operand = _BV(PIN_LED2); break;
|
142 | case 3: port = (uint8_t*)&PORT_LED23; operand = _BV(PIN_LED3); break;
|
143 | case 4: switch(state){
|
144 | case ON: PORT_LED01 |= _BV(PIN_LED0) | _BV(PIN_LED1);
|
145 | PORT_LED23 |= _BV(PIN_LED2) | _BV(PIN_LED3);
|
146 | break;
|
147 | case OFF: PORT_LED01 &= ~(_BV(PIN_LED0) | _BV(PIN_LED1));
|
148 | PORT_LED23 &= ~(_BV(PIN_LED2) | _BV(PIN_LED3));
|
149 | break;
|
150 | case TOGGLE: PORT_LED01 ^= _BV(PIN_LED0) | _BV(PIN_LED1);
|
151 | PORT_LED23 ^= _BV(PIN_LED2) | _BV(PIN_LED3);
|
152 | break;
|
153 | }
|
154 | return;
|
155 | default: return;
|
156 | }
|
157 | switch(state){
|
158 | case ON: *port |= operand; break;
|
159 | case OFF: *port &= ~operand; break;
|
160 | case TOGGLE: *port ^= operand; break;
|
161 | }
|
162 | }
|
163 |
|
164 | /** \brief Function for the LED magic driven by the DIP-switches for LED mode
|
165 | */
|
166 | void LEDMagic() {
|
167 | uint8_t tmp;
|
168 | ///////
|
169 | // LED magic
|
170 | ///////
|
171 | if(led_mode == 0) { // random mode
|
172 | if(time() % 256 == 0) switchLED(random_nr & 3,TOGGLE);
|
173 | } else if(led_mode == 1) { // circle 1
|
174 | tmp = time()/128;
|
175 | switchLED((tmp-1)&3,ON);
|
176 | switchLED(tmp&3,OFF);
|
177 | } else if(led_mode == 2) { // circle 2
|
178 | tmp = ~(time()/128);
|
179 | switchLED((tmp-1)&3,ON);
|
180 | switchLED(tmp&3,OFF);
|
181 | } else if(led_mode == 3) { // toggle
|
182 | if((time()/512)&1) switchLED(LED_ALL,TOGGLE);
|
183 | }
|
184 | ///////
|
185 | // switch LED modes
|
186 | ///////
|
187 | if(getLEDMode() == LED_MODE_ON) {
|
188 | switchLED(LED_ALL,ON);
|
189 | led_mode = 0xff;
|
190 | } else if(getLEDMode() == LED_MODE_OFF) {
|
191 | switchLED(LED_ALL,OFF);
|
192 | led_mode = 0xff;
|
193 | } else if((getLEDMode() == LED_MODE_RAND) && ((time()/1024) % 10 == 0)) { // random LED modes
|
194 | led_mode = random_nr & 3;
|
195 | if(led_mode == 3) {
|
196 | switchLED(LED_ALL,OFF);
|
197 | switchLED(0,ON);
|
198 | switchLED(2,ON);
|
199 | }
|
200 | }
|
201 | }
|
202 |
|
203 | /** \brief Function which drives the motor. Controlled by the DIP-switches for Game mode
|
204 | */
|
205 | void GameMagic() {
|
206 | ///////
|
207 | // Remote control
|
208 | ///////
|
209 | uint8_t remote_curr = getRemoteButtons();
|
210 | if(remote_curr != remote_prev) {
|
211 | if((remote_curr == 0) || (getRemoteMode() == REMOTE_MODE_100)) {
|
212 | remote_accepted = remote_curr;
|
213 | } else if((getRemoteMode() == REMOTE_MODE_25) && ((random_nr & 3) == 0)) {
|
214 | remote_accepted = remote_curr;
|
215 | } else if((getRemoteMode() == REMOTE_MODE_50) && ((random_nr & 3) < 2)) {
|
216 | remote_accepted = remote_curr;
|
217 | } else if((getRemoteMode() == REMOTE_MODE_75) && ((random_nr & 3) < 3)) {
|
218 | remote_accepted = remote_curr;
|
219 | }
|
220 | remote_prev = remote_curr;
|
221 | }
|
222 | ///////
|
223 | // Game magic
|
224 | ///////
|
225 | if(getGameMode() == GAME_MODE_SLOW) { // boooring
|
226 | speed = SPEED_NORMAL;
|
227 | } else if(getGameMode() == GAME_MODE_FAST) { // not so boring
|
228 | speed = SPEED_FAST;
|
229 | } else { // magic :)
|
230 | if(time() % 256 == 0) {
|
231 | if ((random_nr >= SPEED_NORMAL) && (random_nr <= SPEED_FAST)) {
|
232 | speed = random_nr;
|
233 | } else if ((random_nr < SPEED_NORMAL) && (random_nr >= SPEED_NORMAL - 20)) { // higher probability for the lowest speed
|
234 | speed = SPEED_NORMAL;
|
235 | } else if ((random_nr > SPEED_FAST) && (random_nr <= SPEED_FAST + 10)) { // higher probability for the highest speed
|
236 | speed = SPEED_FAST;
|
237 | } else if (getGameMode() == GAME_MODE_RANDOM_STOP && random_nr < STOP_PROBABILITY) {
|
238 | speed = 0;
|
239 | }
|
240 | }
|
241 | }
|
242 | if(remote_accepted == REMOTE_FAST) {
|
243 | MOTOR_SPEED = SPEED_FAST;
|
244 | } else if(remote_accepted == REMOTE_SLOW) {
|
245 | MOTOR_SPEED = SPEED_NORMAL;
|
246 | } else if(remote_accepted == REMOTE_STOP) {
|
247 | MOTOR_SPEED = 0;
|
248 | } else {
|
249 | MOTOR_SPEED = speed;
|
250 | }
|
251 | }
|
252 |
|
253 | /*##########################################################################
|
254 | MAIN ROUTINE
|
255 | ###########################################################################*/
|
256 |
|
257 | /** \brief The main function */
|
258 | int main (void) {
|
259 | /*##########################################################################
|
260 | INITIALIZATION
|
261 | ###########################################################################*/
|
262 | ACSR = _BV(ACD); // disable analog comparator
|
263 |
|
264 | // LED0 and 1 as output
|
265 | DDRA = _BV(PA0) | _BV(PA1);
|
266 |
|
267 | // DIP-switches (PB0..5) as input w/ pullup
|
268 | PORTB = (uint8_t)(~(3<<6));
|
269 |
|
270 | // LED2 and 3 as output, Motor-PWM as output, ON/OFF switch as input w/ pullup, Remote-Switches as input w/ pullup
|
271 | DDRD = _BV(PD2) | _BV(PD3) | _BV(PD5);
|
272 | PORTD = _BV(PD0) | _BV(PD1) | _BV(PD4);
|
273 |
|
274 | MOTOR_SPEED = 0;
|
275 | // Non-Inverting 8 bit phase correct PWM (MAX=0xFF) on PD5, no prescaler
|
276 | TCCR0A = _BV(COM0B1) | _BV(WGM00);
|
277 | TCCR0B = _BV(CS00);
|
278 |
|
279 | extern unsigned short __heap_start;
|
280 | unsigned int seed = *((unsigned int *)__heap_start);
|
281 | srand(seed); // seed random number generator with uninitialized sram value
|
282 | /*##########################################################################
|
283 | MAIN LOOP
|
284 | ###########################################################################*/
|
285 | led_mode = 0xff;
|
286 | remote_prev = 0;
|
287 | for(;;) {
|
288 | random_nr = (uint8_t)rand(); // number from 0 to 0xFF
|
289 | if(isOn()) {
|
290 | runTimer();
|
291 | if(time() < 500) { // start countdount
|
292 | if(getLEDMode() != LED_MODE_OFF) switchLED(0,ON);
|
293 | speed = SPEED_NORMAL;
|
294 | MOTOR_SPEED = speed;
|
295 | } else if(time() < 1000) {
|
296 | if(getLEDMode() != LED_MODE_OFF) switchLED(1,ON);
|
297 | } else if(time() < 1500) {
|
298 | if(getLEDMode() != LED_MODE_OFF) switchLED(2,ON);
|
299 | } else if(time() < 2000) {
|
300 | if(getLEDMode() != LED_MODE_OFF) switchLED(3,ON);
|
301 | } else if(time() > 65000) { // set timer back to avoid a new countdown
|
302 | setTimer(3000);
|
303 | } else if(time() >= 3000) { // start the magic ;)
|
304 | LEDMagic();
|
305 | GameMagic();
|
306 | }
|
307 | }
|
308 | else { // switch off everything
|
309 | MOTOR_SPEED = 0;
|
310 | switchLED(LED_ALL,OFF);
|
311 | stopTimer();
|
312 | resetTimer();
|
313 | }
|
314 | }
|
315 | }
|