Hallo miteinander, ich bin ein absoluter Anfänger, was die Mikrocontroller angeht. Ich habe einen AtMega162 bei dem mit 8 Pins frei zur Verfügung stehen, die PA0 bis PA7. Mein Problem: Wie kriege ich das hin, dass ich beim Zustandswechsel, zum Beispiel am PA0 (von low auf high und dann von high auf low) eine Botschaft über UART1 rauschicken kann? Vielen Dank im Voraus. Grüsse Hemi
PORTA als Eingang konfigurieren UART1 als Sender konfigurieren Endlosschleife: PINA abfragen auf Zustandswechselabfragen in die gewünschte Form umwandlen und per UART1 verschicken. Wie das Abfragen konkret einzurichten ist, hängt einmal davon ab, wie schnell sich die Werte an PORTA ändern. Hast du da eine Vorstellung wie schnell/langsam das passiert? Und zum zweiten wie sicher der Zustandswechsel ist, d.h. ob Prelleffekte vorkommen und eine Entprellung nötig ist. Bei Tastern sollte man immer mit Prellen rechnen. Wenn saubere Digitalsignale anliegen, eher nicht. Das Senden hängt vom Datenaufkommen ab. Wenn zeitweise viel zu senden ist, lohnt es sich das Senden mit Interrupts und Puffern zu machen. Im Extremfall trennt man in eine Messzeit und eine Sendezeit und benutzt soviel Puffer wie das RAM hergibt. Dann hat man quasi einen Logikanalysator. Tja und das haben schon andere entwickelt - schau in die Codesammlung.
Also das ist so eine Art Schalter. Erklärung: Das Gerät ist dazu da um etwas ein- und auszuschalten, in dem es eine Botschaft schickt. Das Gerät hat eine eigene Stromversorgung. Wenn man die Zündung anmacht, liegt am PA0 eine Spannung von +12V an. Wenn es passiert ist, muss eine Botschaft rausgeschickt werden. Wenn die Zündung wieder ausgemacht wird, liegen am PA0 0V an. Wenn es passiert, wird eine andere Botschaft rausgeschickt. Mehr macht das Ding nicht. Kann man das evtl. in einem Interrupt realisieren, weil das Hauptprogramm schon ziemlich viel macht. Danke & Grüsse Hemi
Ich hoffe die +12V liegen nicht direkt an PA0 an, denn dann haben die armen Schutzdioden viel zu tun, um die zu hohe Spannung vom µC fernzuhalten. Es hat Vorteile, einen Hauptteil in einem Interrupt (oder Timer) zu programmieren. Du erhälst eine Nebenläufigkeit zum Hauptcode. Vom Platz her sprst du aber eher nichts. Und das langwierige Senden innerhalb des Interrupts wird als schlechter Stil betrachtet. Ändern von vorhandenem Interruptcode kann dazu führen, dass der Rest des Programmes soweit blockiert wird, dass Funktionsfehler auftreten. Eine Älternative insbesondere ohne Quellcode bzw. ohne Eingriff in denselben wäre, mit einem zweiten (schwachbrüstigen und preiswerten) µC an der 12V Leitung zu spionieren und den eigentlichen AVR komplett in Ruhe zu lassen. Wie man die Botschaft dann auf die Sendeleitung gibt, hängt vom Rest des Gerätes ab.
Doch, die +12V liegen direkt am PA0 an. Wie kann ich das besser lösen? Hier habe ich gestern noch was zusammgengehackt:
1 | DDRA &= ~( 1 << PA0 ); // PIN PA0 als Eingang definieren |
2 | PORTA |= ( 1 << PA0 ); // PullUp Widerstand aktivieren. |
3 | |
4 | // Prüfen ob PA0 high ist, wenn ja, MK4 hochfahren:
|
5 | |
6 | if ( PINA & (1<<PINA0) ) |
7 | {
|
8 | uart1_sendibus_EEP (mk4_startup_msg); |
9 | }
|
10 | |
11 | // Prüfen ob PA0 low ist, wenn ja, MK4 runterfahren:
|
12 | |
13 | if ( !(PINA & (1<<PINA0)) ) |
14 | {
|
15 | uart1_sendibus_EEP (mk4_shutdown_msg); |
16 | }
|
Grüsse Hemi
Ah, es geht um die BMW/MK4/Alextronic Geschichte. Ich hatte schon Bedenken, als du was von externem Gerät, Fernsteuern und Zündung geschrieben hast. Die 12V würde ich mindestens mit einem Spannungsteiler runtersetzen auf die Betriebsspannung des AVR. Und da das Ganze an einem KFZ installiert wird, muss man damit rechnen, dass 12V ein nomineller Wert ist. Die tatsächliche Spannung kann beträchtlich davon abweichen. Eine Strombegrenzung (Sicherung) ist auch eine Überlegung wert. Ideen zur Pegelanpassung gibt es bei Alextronic: http://www.alextronic.de/bmw/projects_bmw_info_ibus.html#_2 Alles zusammen betrachtet, würde ich eine galvanische Trennung bevorzugen und das über einen Optokoppler (Vorwiderstand nicht vergessen!) lösen. Wenn das zu lahm ist, dann einen professionellen Pegelwandler IC benutzen (Melexis TH8080 LIN-Transceiver laut Alextronic). Das Codestück sieht vernünftig aus. Den internen Pullup würde ich weglassen. Was soll der hochziehen, da sehe ich im Moment nichts. Und ich würde einer statischen oder globalen Variablen festhalten, ob die mk4_startup_msg bzw. mk4_shutdown_msg bereits gesendet wurden. Oder stört das den Empfänger nicht, wenn diese Nachricht öfters kommt?
Ja, genau, es handelt sich um ein MK4-Projekt. Die Hardware ist ein AtMega162 mit zwei TH3122 LIN Transceiver. Also bustechnisch ist alles okay und da brauche ich nichts mehr. Auf der Platine habe ich noch 8 Ein- / Ausgänge, die ich beliebig verwenden kann und einen daon wollte ich zum Hoch- und Runterfahren verwenden. Was Elektronik und Mikrocontroller angeht, bin ich ein Anfänger. Kann nur C/C++ und tralala. Aber nichts mit der Hardware. Die Variable werde ich natürlich auch verwenden, es stört zwar nicht, wenn die Botschaft mehrmals kommt, aber es muss nicht sein. Hier leicht modifizierter Code:
1 | int main ( void ) |
2 | {
|
3 | |
4 | bool switched_on = false; |
5 | |
6 | uart0_init (9600); |
7 | uart1_init (9600); |
8 | |
9 | // Setzen der Einstellungen am Port 0:
|
10 | |
11 | DDRA &= ~( 1 << PA0 ); // PIN PA0 als Eingang definieren |
12 | |
13 | // Prüfen ob PA0 high ist, wenn ja, MK4 hochfahren:
|
14 | |
15 | |
16 | while (1) |
17 | {
|
18 | if ( (PINA & (1<<PINA0)) & (switched_on == false) ) |
19 | {
|
20 | uart1_sendibus_EEP (mk4_startup_msg); |
21 | switched_on = true; |
22 | }
|
23 | |
24 | // Prüfen ob PA0 low ist, wenn ja, MK4 runterfahren:
|
25 | |
26 | if ( (!(PINA & (1<<PINA0))) & (switched_on == true) ) |
27 | {
|
28 | uart1_sendibus_EEP (mk4_shutdown_msg); |
29 | switched_on = false; |
30 | }
|
31 | }
|
32 | return 0; |
33 | }
|
Das mit Spannungsteiler sind gut aus, so werde ich es machen. Kannst Du mir sagen, auf wieviel Volt ich runter muss? Sind es diese 2,7V bis 5,5V? Grüsse Hemi
Im Datenblatt vom ATmega162 steht ab wo bis wohin LOW und HIGH garantiert erkannt werden. Der Spannungsteiler muss so dimensioniert werden, dass die HIGH/LOW Bereiche darin abgebildet werden. AVR (typ.) Vin HIGH [V] 0,7*Vcc ... Vcc+0,5 Vin LOW [V] -0,5 ... 0,3*Vcc IBUS 1 U high [V] 7 V ... Ubatt 2 U low [V] 0 V ... 2 V Angenommen der AVR läuft mit Vcc 5V, dann sind die Untergrenze Vin HIGH 3,5V und die Obergrenze Vin LOW 1,5V. Sieht nach einer einfachen Halbierung der IBUS-Spannung mit zwei gleichen Widerständen aus. Das Problem ist die maximale Eingangsspannung Ubatt. Da muss stärker reduziert werden (12V => max. 5,5V => Faktor X). Dadurch verschiebt sich aber 7V/X unter die 0,7*Vcc Bedingung von Vin HIGH. Das kann erkannt werden, wenn der AVR etwas toleranter ist oder wenn auf dem IBUS ein High-Pegel >7V (7,7V) liegt. Jetzt könnte es sein, dass du daran denkst nicht mit einem IBUS Signal auf PA0 zu gehen sondern z.B. mit einem analogen "Zündung ein" Signal vom Zündschloss. Dann mach dir unbedingt Gedanken um die Strombegrenzung, Bedenke den Fall Ubatt >>12V und es sind Störspitzen auf der Leitung und überlege, ob ein Optokoppler nicht die bessere Lösung wäre.
Die IBus Transceiver hängen direkt an den UARTs, die haben gar nichts mit den PA0-7 zu tun. Die Botschaften werden ja über einen der beiden TH3122 Transceiver verschickt und empfangen. Das, was ich will, ist einfach nur den Zustandswechsel mitzukriegen, wenn die Zündung an ist. Also genau das, was Du im letzten Abschnitt beschrieben hast. Der Optokoppler scheint wohl die bessere Alternative zu sein. Grüsse Hemi
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.