Hallo zusammen :) Entweder ist mein Ziel nur über einen Trick erreichbar, oder ich sehe den Wald vor lauter Bäumen nicht ;) Ich möchte an einem Atmega32 die Eingänge PA0 bis PA7 und PC0 bis PC6 als digitale Eingänge für einen Joystick mit mehreren Buttons nutzen. Bei den Eingängen PC0 bis PC6 ist das ja auch kein Problem. Aber bei PA0 bis PA7 (ADC0 bis ADC7) berechne ich derzeit immer die anliegende Spannung und wenn das Ergebnis größer 3V ist, dann ist der Eingang high. Das ist generell auch erst einmal so gewollt, da sich an diesen Eingängen 8 Feuerknöpfe befinden und ich so über die Spannung erkennen kann, ob ich zwischen 3V und 4V liege für Schnellfeuer oder über 4V für normales Feuer. Das hilft einem bei Spielen wie R-Type enorm weiter ;) Das kostet aber enorm rechenzeit und wenn es (wie in meinem Fall) Zeitkritisch wird, dann bekommt man ein Problem. Ich finde im Internet jedoch keine Anleitung, wie ich die ADCs deaktivieren kann. Eventuell suche ich auch einfach falsch. Und ohne diese zu deaktivieren ist die einzige Lösung, die mir einfällt, das höchste Bit auszulesen und wenn das gesetzt ist, dann ist das Signal high. Gibt es da noch einen eleganteren Weg? Danke vorab für eure Ideen :)
PORTA lässt sich doch ganz genau wie die anderen als digitaler I/O verwenden wie die anderen Ports? Oder verstehe ich dein Problem nicht?
Hallo, das sollte eigentlich nicht so sein, dann mußt du die ADCs ja aktiviert haben. Hast du jetzt vor, den eingang als reinen digitalen zu benutzen ? Oder soll er abwechselnd als AD und digitaler dienen ? Du kannst den ADC zur laufzeit auch wider ausmachen, dazu mußt du nur das register setzen. ist das register ADCSRA wichtig dort mußt du das ADEN flag löschen, dann sind die adc aus.
> Du kannst den ADC zur laufzeit auch wider ausmachen Stimmt, ist jedoch nichtmal nötig. Alle Eingänge (auch die analogen) kann man bei AVR's jederzeit über die PIN Register abfragen, selbst wenn dort gerade Sonderfunktionen aktiviert sind.
Bei den alten ATmega32 lassen sich die Digitaleingänge noch nicht abschalten, d.h. sie sind immer parallel zu den Analogeingängen aktiv. Erst beim ATmega324 lassen sie sich abschalten.
Solange man die aber nicht explizit abschaltet, sind die Digitaleingänge aktiv. Digital high/low lässt sich daher immer über die PINn - Register abfragen. Oliver
@crazyhorse: Genau das dachte ich auch erst. Aber aus irgend einem Grund hat das nicht funktioniert. Auch wenn ich die internen Pull-Up-Resistors aktiviert habe, haben die Eingänge gemacht was sie wollten. @sharpals: Ich hatte sie im ursprünglichen Skript nicht explizit aktivert oder deaktiviert. Da ich zum ersten mal mit dem Atmega32 und diesen ADC-Eingängen arbeite dachte ich nun, dass die immer irgendwie als ADC genutzt werden müssen nachdem es ohne nicht funktioniert hat. Deshalb habe ich mir also einen Codeschnipsel aus dem Internet besorgt und diesen an meine Bedürfnisse angepasst und so lange damit rumgespielt bis ich diesen verstanden hatte. Ich mache später mal einen Rückbau des Codes und poste dann hier den Code wie er vor der Umstellung auf ADC war. Evtl. sieht ja einer den Fehler :) Danke für eure Zeit :)
Danke für eure Zeit @stefanus, @peda und @oliverso :)
Nein keine angst , du bist nicht verpflichtet, sie als ADC zu nutzen. Behandle sie als ganz normale eingänge und beseitige den codeteil und alles wird gut.
Frank N. schrieb: > Das kostet aber enorm rechenzeit und wenn es (wie in meinem Fall) > Zeitkritisch wird, dann bekommt man ein Problem. Ui ui ui, du kannst deinen Joystick schneller bedienen als ein AVR ein paar Messung macht und auswertet?!?
@corrtexx: gg Das nicht, aber der SNES und der MegaDrive geben ein sehr straffes Timing mit sehr knappen Reaktionszeiten vor ;) Ich hatte mittlerweile angefangen mit Interrupts zu arbeiten und entsprechend auf die Signale von den Konsolen zu reagieren. Aber auch da hatte ich das Problem, dass die Berechnungsdauer länger ist als die maximal zugelassene Reaktionszeit von den Konsolen. Darum versuche ich da zeit zu sparen um die Codestruktur nicht noch weiter verschachteln zu müssen ;)
Hallo Das SNES verwendet AFAIK eine Shift-Register im Controller. Das kannst du mit SPI im slave mode simulieren. Das macht die Sache viel entspannter. Du kannst das nächste Byte schreiben während die Hardware gerade das aktuelle ausgibt. da1l6
> Entweder ist mein Ziel nur über einen Trick erreichbar, oder ich > sehe den Wald vor lauter Bäumen nicht ;) Manchmal sieht man Vögel, die Mühsam eine lange Treppe herunter hoppeln. Und wenn sie dann unten angekommen sind, fliegen sie davon. Muss man nicht verstehen.
Frank N. schrieb: > Ich hatte mittlerweile angefangen mit Interrupts zu arbeiten und > entsprechend auf die Signale von den Konsolen zu reagieren. Aber auch da > hatte ich das Problem, dass die Berechnungsdauer länger ist als die > maximal zugelassene Reaktionszeit von den Konsolen. dann wird deine Software wohl noch sehr suboptimal sein. Das sollte so ein Amtel bequem im Millisekundenbereich schaffen.
Frank N. schrieb: > Das kostet aber enorm rechenzeit und wenn es (wie in meinem Fall) > Zeitkritisch wird, dann bekommt man ein Problem. Dann machst Du was falsch. Nimm den ADC-Interrupt, lasse ihn das Ergebnis in ein Array schreiben und den MUX weiter schalten. Und für die Auswertung vergleichst Du einfach den Wert im Array mit der Schwelle (8Bit sollten reichen). Und natürlich rechnet man die ADC-Werte nicht in float Volts um, sondern läßt zur Compilezeit per #define die Volts in ADC-Schritte umrechnen.
1 | #define ADC_STEPS(volt) (uint8_t)(volt / 5.0 * 255)
|
Dann dauert ein Vergleich <1µs und das ist nicht enorm.
Ist es mir gestattet eine dumme Frage zu stellen? Peter D. schrieb: > Und natürlich rechnet man die ADC-Werte nicht in float Volts um, sondern > läßt zur Compilezeit per #define die Volts in ADC-Schritte > umrechnen. > #define ADC_STEPS(volt) (uint8_t)(volt / 5.0 * 255) Durch den Define kopiert der Präprozessor den Code ja einfach nur, aber ausgeführt wird er doch zur Laufzeit. Sprich es findet eine Multiplikation und eine Division mit float Werten statt. Einzig der Wertevergleich ist dann auf Integerbasis und sollte schneller gehen. Das Rechnen mit float Werten spart man sich dadurch ja nicht. Oder meintest Du, dass damit das Rechnen mit float Werten in den Interrupt verlagert wird und in der Hauptschleife nur mit Integer Werten gerechnet/verglichen werden muß?
Clemens W. schrieb: > Durch den Define kopiert der Präprozessor den Code ja einfach nur, aber > ausgeführt wird er doch zur Laufzeit. Der Compiler ist faul. Wenn er einen konstanten Ausdruck sieht, rechnet er ihn sofort aus und fügt das Ergebnis ein, statt dafür noch umständlich Laufzeitcode zu erzeugen. Das Define dient nur der besseren Lesbarkeit für Dich. Schau einfach mal ins Assemblerlisting (*.lss).
Danke für Deine schnelle Antwort! Daran das der Ausdruck teilweise zur Kompilierzeit ausgewertet wird, hab ich nicht gedacht. Aber hab dann nochmal kurz darüber nachgedacht und bin darauf gekommen, dass der Vorteil auch in den kompletten späteren Zugriffen auf das Array und im Speicherverbrauch des Arrays selber liegen.
wird eigentlich der echte spannungsbereich gebraucht ? Wenn nicht reicht es doch aus den schwellwert , oder was sonst auf der basis von dem ADC zu ermitteln .. wenn also 4V gefordert werden, dann wäre es doch der wert 204 klassischer dreisatz : const wert = byte(geforderte_spannung / V_ref * 255) ; in diesem falle braucht die CPU garnichts ausrechnen;
:
Bearbeitet durch User
Hallo zusammen :) Es tut mir Leid, dass es nun doch etwas länger gedauert hat, bis ich hier antworte. Ich habe keine Ahnung, was ich bei meinem ersten Versuch falsch gemacht hatte, da es nun auf Anhieb tadellos lief ... Hier mein Code und vielen Dank für eure Meinungen und eure Hilfe :)
1 | /*
|
2 | * 15ButtonDigitalControllerTest.c
|
3 | *
|
4 | * This is a small program to test the controller with the specific test-dongle
|
5 | *
|
6 | * PB0 OUT LED 1
|
7 | * PB1 OUT LED 2
|
8 | * PB2 OUT LED 3
|
9 | * PB3 OUT LED 4
|
10 | *
|
11 | * PA0 IN BTN1
|
12 | * PA1 IN BTN2
|
13 | * PA2 IN BTN3
|
14 | * PA3 IN BTN4
|
15 | * PA4 IN BTN5
|
16 | * PA5 IN BTN6
|
17 | * PA6 IN BTN7
|
18 | * PA7 IN BTN8
|
19 | * PC0 IN BTN9
|
20 | * PC1 IN BTN10
|
21 | * PC2 IN BTN11
|
22 | * PC3 IN UP
|
23 | * PC4 IN DOWN
|
24 | * PC5 IN LEFT
|
25 | * PC6 IN RIGHT
|
26 | *
|
27 | * Created: 26.04.2017
|
28 | * Last modified: 26.04.2017
|
29 | * Author : Frank
|
30 | */
|
31 | |
32 | #define F_CPU 1000000UL // CPU-Frequency 1MHz
|
33 | |
34 | #include <avr/io.h> // Headerfile for Input & Output |
35 | #include <util/delay.h> // Headerfile for delays |
36 | |
37 | int main(void) |
38 | {
|
39 | // Deactivate JTAG-debugging
|
40 | MCUCSR=(1<<JTD); |
41 | MCUCSR=(1<<JTD); |
42 | |
43 | // Define LED-outputs for the test-dongle
|
44 | DDRB = 0xff; // Set as output |
45 | |
46 | // Define inputs for 15 button controller
|
47 | DDRA = 0x00; // Set as input |
48 | DDRC = 0x00; // Set as input |
49 | PORTA = 0xff; // Activate PULL-UP-RESISTORS |
50 | PORTC = 0xff; // Activate PULL-UP-RESISTORS |
51 | |
52 | // Test the LEDs on Port B for 500ms
|
53 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
54 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
55 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
56 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
57 | _delay_ms(500); // Wait 0,5s |
58 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
59 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
60 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
61 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
62 | |
63 | while (1) |
64 | {
|
65 | if(!(PINA & (1<<PORTA0))) { |
66 | // PORTA0 ACTIVE - BTN1
|
67 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
68 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
69 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
70 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
71 | } else if(!(PINA & (1<<PORTA1))) { |
72 | // PORTA1 ACTIVE - BTN2
|
73 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
74 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
75 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
76 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
77 | } else if(!(PINA & (1<<PORTA2))) { |
78 | // PORTA2 ACTIVE - BTN3
|
79 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
80 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
81 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
82 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
83 | } else if(!(PINA & (1<<PORTA3))) { |
84 | // PORTA3 ACTIVE - BTN4
|
85 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
86 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
87 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
88 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
89 | } else if(!(PINA & (1<<PORTA4))) { |
90 | // PORTA4 ACTIVE - BTN5
|
91 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
92 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
93 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
94 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
95 | } else if(!(PINA & (1<<PORTA5))) { |
96 | // PORTA5 ACTIVE - BTN6
|
97 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
98 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
99 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
100 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
101 | } else if(!(PINA & (1<<PORTA6))) { |
102 | // PORTA6 ACTIVE - BTN7
|
103 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
104 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
105 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
106 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
107 | } else if(!(PINA & (1<<PORTA7))) { |
108 | // PORTA7 ACTIVE - BTN8
|
109 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
110 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
111 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
112 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
113 | } else if(!(PINC & (1<<PORTC0))) { |
114 | // PORTC0 ACTIVE - BTN9
|
115 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
116 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
117 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
118 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
119 | } else if(!(PINC & (1<<PORTC1))) { |
120 | // PORTC1 ACTIVE - BTN10
|
121 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
122 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
123 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
124 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
125 | } else if(!(PINC & (1<<PORTC2))) { |
126 | // PORTC2 ACTIVE - BTN11
|
127 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
128 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
129 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
130 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
131 | } else if(!(PINC & (1<<PORTC3))) { |
132 | // PORTC3 ACTIVE - UP
|
133 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
134 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
135 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
136 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
137 | } else if(!(PINC & (1<<PORTC4))) { |
138 | // PORTC4 ACTIVE - DOWN
|
139 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
140 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
141 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
142 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
143 | } else if(!(PINC & (1<<PORTC5))) { |
144 | // PORTC5 ACTIVE - LEFT
|
145 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
146 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
147 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
148 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
149 | } else if(!(PINC & (1<<PORTC6))) { |
150 | // PORTC6 ACTIVE - RIGHT
|
151 | PORTB |= (1<<PORTB0); // Set PORTB0 ON |
152 | PORTB |= (1<<PORTB1); // Set PORTB1 ON |
153 | PORTB |= (1<<PORTB2); // Set PORTB2 ON |
154 | PORTB |= (1<<PORTB3); // Set PORTB3 ON |
155 | } else { |
156 | PORTB &= ~(1<<PORTB0); // Set PORTB0 OFF |
157 | PORTB &= ~(1<<PORTB1); // Set PORTB1 OFF |
158 | PORTB &= ~(1<<PORTB2); // Set PORTB2 OFF |
159 | PORTB &= ~(1<<PORTB3); // Set PORTB3 OFF |
160 | }
|
161 | |
162 | _delay_ms(5); // Wait 5ms |
163 | }
|
164 | }
|
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.