summaryrefslogtreecommitdiffstats
path: root/source/AVR_Studio/Soccer/hal/board.c
blob: 458ed0350e651159b54c3473d20657dfd6c92dd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include "board.h"

static int beepFreq = 0;

Board::Board() {
	// Pin 1-6 sind ausgänge, 0 und 7 eingänge
	DDRA = (1 << PA1) | (1 << PA2) | (1 << PA3) | (1 << PA4) | (1 << PA5) | (1 << PA6);
	PORTA = 0; // Alle Low, kein Pollup

	// Alle Ausgänge
	DDRB = (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB3) | (1 << PB4) | (1 << PB5) | (1 << PB6)  | (1 << PB7);
	PORTB = (1 << PB1); // Alle Low bis PB1 , kein Pollup

	// Alle Ausgänge bis auf PC4/PC5 (Maussensor SDA)
	DDRC = (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC6)  | (1 << PC7);
	PORTC = 0; // Alle Low, kein Pollup

	// Alle Ausgänge bis auf PD0+1(I2C) + 2+3(RS232)
	DDRD = (1 << PD2) | (1 << PD3) | (1 << PD4) | (1 << PD5) | (1 << PD6)  | (1 << PD7);
	PORTD = (1 << PD0) | (1 << PD1); // Pollup-Widerstand an PD0+1 aktivieren

	// PE5 ist eingang
	DDRE = (1 << PE0) | (1 << PE1) | (1 << PE2) | (1 << PE3) | (1 << PE4) | (1 << PE6)  | (1 << PE7);
	PORTE = 0; // Alle Low, kein Pollup

	// Alle Eingänge mit Pollup
	DDRF = 0;
	PORTF = (1 << PF0) | (1 << PF1) | (1 << PF2) | (1 << PF3) | (1 << PF4) | (1 << PF5) | (1 << PF6)  | (1 << PF7);

	// Alle Ausgänge, PG0 und PG1 high
	DDRG = (1 << PG0) | (1 << PG1) | (1 << PG2) | (1 << PG3) | (1 << PG4); 
	PORTG = (1 << PG0) | (1 << PG1);	

	// aktiviere Kanal A+B auf PWM1 mit 8Bit
	TCCR1A = (1<< COM1A1) | (1<< COM1B1) | (1<< WGM10);
	TCCR1B = (1<<ICNC1) | (1<<CS12) | (1<<CS10); // set clock/prescaler 1/1024 -> enable counter

	// aktiviere Kanal A+B auf PWM3 mit 8Bit
	TCCR3A = (1<< COM3A1) | (1<< COM3B1) | (1<< WGM10);
	TCCR3B =  (1<<ICNC3) | (1<<CS32) | (1<<CS30); // set clock/prescaler 1/1024 -> enable counter

	// Schalte Motoren auf 0
	motor(0,0);
	motor(1,0);
	motor(2,0);
	motor(3,0);

	// Kicker-richtung einstellen
	PORTE &= ~(1 << PE6); // Pin2 low
	PORTA |= (1 << PA2); // Pin1 high

	// Uart-Interface einschalten
	uart1_init( 10); // 9600 BAUD bei 16MHz Atmel

	// aktiviere interrupt
	sei();
}

Board::~Board() {

}

// Gibt einen Analogen Wert zurück
int Board::GetADC(uint8_t channel) {
	uint8_t i;
	uint16_t result = 0;
	
	// Den ADC aktivieren und Teilungsfaktor auf 64 stellen
	ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);

	// Kanal des Multiplexers waehlen
	ADMUX = channel;
	// Interne Referenzspannung verwenden (also 2,56 V)
	ADMUX |= (1<<REFS1) | (1<<REFS0);
	
	// Den ADC initialisieren und einen sog. Dummyreadout machen
	ADCSRA |= (1<<ADSC);
	while(ADCSRA & (1<<ADSC));
	
	// Jetzt 3x die analoge Spannung and Kanal channel auslesen
	// und dann Durchschnittswert ausrechnen.
	for(i=0; i<3; i++) {
		// Eine Wandlung
		ADCSRA |= (1<<ADSC);
		// Auf Ergebnis warten...
		while(ADCSRA & (1<<ADSC));
		
		result += ADCW;
	}
	
	// ADC wieder deaktivieren
	ADCSRA &= ~(1<<ADEN);
	
	result /= 3;
	
	return result;
}

// Gibt den Wert vom Abstandsensor zurück
int Board::GetAbstand(int i) {
	int result = -1;
	if((i < 0) || (i > 3)) return result; // Ungültige Nummern rausfiltern

	// Sende zunächst einen Impuls aus
	ABSTAND_DDR |= (1 << i); // Konfiguriere Pin als Ausgang
	ABSTAND_PORT |= (1 << i); // Und setze ihn auf High
	usleep(10); // Warte jetzt 10us
	ABSTAND_PORT &= ~(1 << i); // Und setze den Pin wieder auf Low
	ABSTAND_DDR &= ~(1 << i); // Konfiguriere Pin als Eingang

	// Jetzt warten wir auf die Antwort vom Sensor
	while(!(ABSTAND_PIN & i)) {} // während er low ist nichts machen
	while(ABSTAND_PIN & i) { // Und während er high ist
		result++; //schleifendurchläufe zähenlen (unsauber, ich weiß)
		asm volatile("nop"); // ein ganz bisschen warten
	}  

	// Die Zahl der Schleifendurchläufe geben wir dann zurück
	return result;
}

void Board::beep(int freq) {
	beepFreq = freq;
}

void Board::ledOff() {
	PORTB |= (1 << PB1); // set bit
}

void Board::ledOn() {
	PORTB &= ~(1 << PB1); // clear bit
}

void Board::led(bool status) {
	if(status) ledOn();
	else ledOff();
}


void Board::motor(int i, int speed)
{
	if((i < 0) || (i > 3)) return;
	const int OFFSET = 40; // Motor does not work with very low ratio
	const int PWM_MAX = 255;
	int pwm = 0; // PWM-Speed

	if(speed != 0) pwm = abs(speed)+OFFSET;
	if(pwm > PWM_MAX) pwm = PWM_MAX;

	if(i == 0) {
		MOTOR0_PWM = pwm;
		if(speed > 0)
		{
			MOTOR0_PORT |= MOTOR0_A;//In 1 ein
			MOTOR0_PORT &= ~MOTOR0_B;//In 2 aus
		}
		else if(speed < 0)
		{
			MOTOR0_PORT |= MOTOR0_B;//In 2 ein
			MOTOR0_PORT &= ~MOTOR0_A;//In 1 aus
		}
		else
		{
			MOTOR0_PORT |= MOTOR0_B;//In 2 ein
			MOTOR0_PORT |= MOTOR0_A;//In 1 ein
		}
	}
	else if(i == 1) {
		MOTOR1_PWM = pwm;
		if(speed > 0)
		{
			MOTOR1_PORT |= MOTOR1_A;//In 1 ein
			MOTOR1_PORT &= ~MOTOR1_B;//In 2 aus
		}
		else if(speed < 0)
		{
			MOTOR1_PORT |= MOTOR1_B;//In 2 ein
			MOTOR1_PORT &= ~MOTOR1_A;//In 1 aus
		}
		else
		{
			MOTOR1_PORT |= MOTOR1_B;//In 2 ein
			MOTOR1_PORT |= MOTOR1_A;//In 1 ein
		}
	}
	else if(i == 2)
	{
		MOTOR2_PWM = pwm;
		if(speed > 0)
		{
			MOTOR2_PORT |= MOTOR2_A;//In 1 ein
			MOTOR2_PORT &= ~MOTOR2_B;//In 2 aus
		}
		else if(speed < 0)
		{
			MOTOR2_PORT |= MOTOR2_B;//In 2 ein
			MOTOR2_PORT &= ~MOTOR2_A;//In 1 aus
		}
		else
		{
			MOTOR2_PORT |= MOTOR2_B;//In 2 ein
			MOTOR2_PORT |= MOTOR2_A;//In 1 ein
		}
	}
	else if(i == 3) // Dribbler... hier haben wir kein PWM
	{
		if(speed > 0)
		{
			DRIBBLER_PORT |= DRIBBLER_A;//In 1 ein
			DRIBBLER_PORT &= ~DRIBBLER_B;//In 2 aus
			DRIBBLER_PWMPORT |= DRIBBLER_PWM;
		}
		else if(speed < 0)
		{
			DRIBBLER_PORT |= DRIBBLER_B;//In 2 ein
			DRIBBLER_PORT &= ~DRIBBLER_A;//In 1 aus
			DRIBBLER_PWMPORT |= DRIBBLER_PWM;
		}
		else
		{
			DRIBBLER_PORT |= DRIBBLER_B;//In 2 ein
			DRIBBLER_PORT |= DRIBBLER_A;//In 1 ein
			DRIBBLER_PWMPORT &= ~DRIBBLER_PWM;
		}
	}
}

void Board::kicker() {
	KICKER_AN
	usleep(KICKER_USLEEP);
	KICKER_AUS
}

//PWM routine für den Beeper
ISR (TIMER0_OVF_vect)
{
	static int counter = 255;

	if(counter > beepFreq/2) PORTG |= (1<<BEEPER_PIN);
	else PORTG &= ~(1<<BEEPER_PIN);

	if (counter==0) counter = 255;
	else counter--;
}