Hi, ich bin habe mir momentan ein kleines Projekt zugemutet aber da ich nicht so viel Erfahrung habe in Atmega8 programmieren hab ich gehofft ihr könntet mir etwas helfen. Also meine Idee ist es einen Multiplexer zu programmieren (Platine ist schon fertig). Dieser Multiplexer hat 20 Digitale Eingänge (PD0...PD7,PB0...PB6, PC0..PC5) die eingelesen werden müssen und in einem Array gespeichert. Nun soll meine SPS eine Anfrage über PB6 schicken( auf steigende Flanke schauen) dann soll der Atmega 100ms warten. Anschließende soll nach einer festgelegten Reihenfolge die Zustände der 20 Digitalen Eingänge über den Ausgang PB7 in einem 50ms Takt ausgegeben werden. Ist so eine Art Morse. Es geht mir nur um die Atmega Programmierung. Ich weiß garnicht wie ich da Anfangen könnte. Es würde mich sehr freuen wenn einer von euch genug Zeit und Lust hat mir dabei zu helfen.
:
Verschoben durch Admin
Ah, so eine Art Bake? Der PB6 kann nicht als digitaler Eingang benutzt werden, wenn er schon mit der SPS kommuniziert. Das Array braucht es auch nicht, die Abfrage der Eingänge macht man während man sie sendet. Wenn PB6 als open collector arbeitet, dann kann das funktionieren. Die SPS gibt quasi die Kommunikation frei. Die Aufgabe ist super simpel: - Warte auf PB6 high - Setze Timer(n) auf 100 ms - Warte auf Timer(n) abgelafuen, wenn PB6 low dann zum Start - Schleife über alle Inputs :: frage Input ab und sende byte
Peter Q. schrieb: > Ich weiß garnicht wie ich da Anfangen könnte. Indem du die Aufgabe in Teilschritte zerlegst (hast du weitgehend als Prosa bereits hingeschrieben) und daraus einen Programmablauf planst. Die nötigen Grundlagen musst du dir natürlich schon erstmal (spielerisch) vorher aneignen, also: . wie lese ich Pins ein . wie erkenne ich die Änderung eines Pins . wie gebe ich ein Bit aus . wie warte ich eine bestimmte Zeit Das alles geht noc völlig linear für den Anfang, ohne Intrrupts, ohne Timer. Das ist natürlich nicht sehr elegant dann, aber es löst die gestellte Aufgabe und braucht am wenigsten Knowhow deinerseits. Optimieren kannst du danach: . Schaltflanke per Interrupt erkennen (geht beim ATmega8 nur über Timerinterrupt, wenn du einen ATmega88 nimmst, könntest du auch einen Pinchange-Interrupt benutzen) . Ausgabe über Timerinterrupt steuern . Rest der Zeit schlafen gehen
:
Bearbeitet durch Moderator
Thomas W. schrieb: > Das Array braucht es auch nicht, die Abfrage der Eingänge macht man > während man sie sendet. Dann hast du aber keinen Momentanzustand (*), sondern würdest sich ggf. ändernde Werte ausgeben. (*) Hast du natürlich streng genommen sowieso nicht, weil sich nicht alle drei Ports gleichzeitig abfragen lassen, aber zumindest sehr schnell hintereinander.
okay also der eingang PB6 wird von 24V über einen Optokoppler geschaltet, das ich auf die gewünschte eingangspannung komme. Wie arbeite ich denn mit einem Interrupt? Pins einlesen und ausgänge schalten bekomm ich auch noch hin aber die Schleife bei einem Interrupt starten usw. raff ich noch nicht so :D Kann jemand zufällig so eine kleine Code Anleitung schicken :D
Peter Q. schrieb: > Kann jemand zufällig so eine kleine Code Anleitung schicken :D http://www.mikrocontroller.net/articles/Interrupt
Dann fang' doch erstmal ohne Interrupts an. Das bisschen lässt sich komplett linear erschlagen.
So ich hab jetzt mal was im Text editor geschrieben, wie ich mir das vorstelle, also jetzt darf gelacht werden :D
1 | #include <avr/io.h> |
2 | #define F_CPU 1200000UL // 1,2 MHz
|
3 | #include <util/delay.h> |
4 | |
5 | |
6 | // Digitale Eingänge : |PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7 | PB0,PB1,PB2,PB3,PB4,PB5 | PC0,PC1,PC2,PC3,PC4,PC5
|
7 | // Data-IN: |PB6
|
8 | // Data-OUT: |PB7
|
9 | |
10 | uint8_t flanke; |
11 | uint8_t alteflanke; |
12 | |
13 | int main(void){ |
14 | DDRB |= _BV(PB7); // PB7 ist jetzt Ausgang |
15 | DDRD &= ~(1 << PD0), ~(1 << PD1),~(1 << PD2),~(1 << PD3),~(1 << PD4),~(1 << PD5),~(1 << PD6),~(1 << PD7); |
16 | DDRB &= ~(1 << PB0), ~(1 << PB1),~(1 << PB2),~(1 << PB3),~(1 << PB4),~(1 << PB5),~(1 << PB6); |
17 | DDRC &= ~(1 << PC0), ~(1 << PC1),~(1 << PC2),~(1 << PC3),~(1 << PC4),~(1 << PC5); |
18 | |
19 | |
20 | |
21 | |
22 | _flanke = PINB; // zu testende Variable |
23 | while(1){ |
24 | if ( ( flanke & (1<<PB6) ) != 0 ) |
25 | && ( alteflanke & (1<<PB6) ) == 0 ) ) |
26 | {
|
27 | _delay_ms(100); |
28 | PINB7 = inp (PIND0); // Schreibe Zustand an PD0 in PB7 |
29 | _delay_ms(50); |
30 | PINB7 = inp (PIND1); |
31 | _delay_ms(50); |
32 | PINB7 = inp (PIND2); |
33 | _delay_ms(50); |
34 | PINB7 = inp (PIND3); |
35 | _delay_ms(50); |
36 | PINB7 = inp (PIND4); |
37 | _delay_ms(50); |
38 | PINB7 = inp (PIND5); |
39 | _delay_ms(50); |
40 | PINB7 = inp (PIND6); |
41 | _delay_ms(50); |
42 | PINB7 = inp (PIND7); |
43 | _delay_ms(50); |
44 | PINB7 = inp (PINB0); |
45 | _delay_ms(50); |
46 | PINB7 = inp (PINB1); |
47 | _delay_ms(50); |
48 | PINB7 = inp (PINB2); |
49 | _delay_ms(50); |
50 | PINB7 = inp (PINB3); |
51 | _delay_ms(50); |
52 | PINB7 = inp (PINB4); |
53 | .
|
54 | .
|
55 | .
|
56 | .
|
57 | usw.. |
58 | }
|
59 | |
60 | }
|
61 | }
|
:
Bearbeitet durch Moderator
Peter Q. schrieb: > DDRD &= ~(1 << PD0), ~(1 << PD1),~(1 << PD2),~(1 << PD3),~(1 << PD4),~(1 > << PD5),~(1 << PD6),~(1 << PD7); Nun, die Übung mit dem Komma-Operator solltest du dir nochmal ansehen. Der hat eine ganz andere Bewandnis als das, was du hier willst. Aber: die DDRx-Register sind nach einem Reset ohnehin 0, noch „nuller“ geht's nicht. Lass sie also einfach in Ruhe. Korekt wäre übrigens:
1 | DDRB &= ~((1 << PB0) | (1 << PB1) | … | (1 << PB6)); |
> _flanke = PINB; // zu testende Variable Lass mal den Unterstrich weg. > while(1){ > if ( ( flanke & (1<<PB6) ) != 0 ) > && ( alteflanke & (1<<PB6) ) == 0 ) ) Vergiss nicht, „alteflanke“ vor dem Ende der while-Schleife mit dem aktuell getesteten Wert zu setzen. > PINB7 = inp (PIND0); // Schreibe Zustand an PD0 in PB7 inp() ist nirgends definiert. Ansonsten ist das aber als allereinfachste Implementierung OK.
:
Bearbeitet durch Moderator
Moin in die Runde.
1 | PINB7 = inp (PIND0); |
liefert unabhängig davon, ob #define inp(x) (1<<(x)) ist, eine Fehlermeldung, da PINB7 eine Konstante =7 ist. Was soll in deinen Augen PINB7 = <expr> bewirken ?
ja das "inp" war ein kopierfehler :D müsste das jetzt so grob implementierbar sein? #include <avr/io.h> #define F_CPU 1200000UL // 1,2 MHz #include <util/delay.h> // Digitale Eingänge : |PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7 | PB0,PB1,PB2,PB3,PB4,PB5 | PC0,PC1,PC2,PC3,PC4,PC5 // Data-IN: |PB6 // Data-OUT: |PB7 uint8_t flanke; uint8_t alteflanke; int main(void){ DDRB |= _BV(PB7); // PB4 ist jetzt Ausgang flanke = PINB; // zu testende Variable while(1){ if ( ( flanke & (1<<PB6) ) != 0 ) && ( alteflanke & (1<<PB6) ) == 0 ) ) { _delay_ms(100); PINB7 =(PIND0); // Schreibe Zustand an PD0 in PB7 _delay_ms(50); PINB7 =(PIND1); _delay_ms(50); PINB7 =(PIND2); _delay_ms(50); PINB7 = (PIND3); _delay_ms(50); PINB7 = (PIND4); _delay_ms(50); PINB7 = (PIND5); _delay_ms(50); PINB7 = (PIND6); _delay_ms(50); PINB7 =(PIND7); _delay_ms(50); PINB7 =(PINB0); _delay_ms(50); PINB7 = PINB1); _delay_ms(50); PINB7 =(PINB2); _delay_ms(50); PINB7 = (PINB3); _delay_ms(50); PINB7 = (PINB4); . . . . usw.. alteflanke = flanke; }} }
Karl M. schrieb: > eine Fehlermeldung, da PINB7 eine Konstante =7 ist. Stimmt, den Teil hatte ich mir nicht angesehen. Vorschlag:
1 | void pinb7(uint8_t val) |
2 | {
|
3 | if (val) |
4 | PORTB |= _BV(7); |
5 | else
|
6 | PORTB &= ~ _BV(7); |
7 | }
|
Bitmanipulation
Bitte gewöhn' dir mal an, [ c ] ... [ /c ] um deinen Code zu schreiben (ohne die Leerzeichen in den Klammern).
Per default sind im AVR-GCC keine Bitvariablen definiert. Dazu kann man aber meine "sbit.h" benutzen.
1 | #include "sbit.h" |
2 | // ...
|
3 | PORT_B7 = PIN_D0; |
4 | _delay_ms(50); |
5 | PORT_B7 = PIN_D1; |
6 | _delay_ms(50); |
7 | // usw.
|
Dann müsste es ja so gehen oder? Wenn ich jetzt das Programm mit dem Programmer auf den Atmega8 brennen möchte, woraum muss ich da achten damit der seinen internen Ozilator benutzt? #include <avr/io.h> #define F_CPU 1200000UL // 1,2 MHz #include <util/delay.h> // Digitale Eingänge : |PD0,PD1,PD2,PD3,PD4,PD5,PD6,PD7 | PB0,PB1,PB2,PB3,PB4,PB5 | PC0,PC1,PC2,PC3,PC4,PC5 // Data-IN: |PB6 // Data-OUT: |PB7 uint8_t flanke; uint8_t alteflanke; void pinb7(uint8_t val) { if (val) PORTB |= _BV(7); else PORTB &= ~ _BV(7); } int main(void){ DDRB |= _BV(PB7); // PB4 ist jetzt Ausgang pinb7(uint8_t val); flanke = PINB; // zu testende Variable while(1){ if ((flanke &(1<<PB6))!= 0) && (alteflanke &(1<<PB6))==0)) { _delay_ms(100); PINB7 =(PIND0); // Schreibe Zustand an PD0 in PB7 _delay_ms(50); PINB7 =(PIND1); _delay_ms(50); PINB7 =(PIND2); _delay_ms(50); PINB7 = (PIND3); _delay_ms(50); PINB7 = (PIND4); _delay_ms(50); PINB7 = (PIND5); _delay_ms(50); PINB7 = (PIND6); _delay_ms(50); PINB7 =(PIND7); _delay_ms(50); PINB7 =(PINB0); _delay_ms(50); PINB7 = PINB1); _delay_ms(50); PINB7 =(PINB2); _delay_ms(50); PINB7 = (PINB3); _delay_ms(50); PINB7 = (PINB4); . . . . usw.. alteflanke = flanke; }} }
Hallo Peter Q. schrieb: > Dann müsste es ja so gehen oder? > Wenn ich jetzt das Programm mit dem Programmer auf den Atmega8 brennen > möchte, woraum muss ich da achten damit der seinen internen Ozilator > benutzt? Nicht glauben, sondern wissen ist angesagt. Also über testen und abändern kann man vielleicht verstehen, was Jörg Wunsch und Peter Dannegger die mitteilen möchten. Du denkst an PINB7 kann man Informationen ausgaben und das ist falsch. Schau dir bitte auch die Procedure
1 | pinb7(uint8_t val); |
, dies ist eine besondere Funktion. Die Nahmeswahl ist nicht die Beste, da Du so den Unterschied zu PINB7 nicht siehst!
1 | writeBit_to_B7(uint8_t); |
Am effizientesten wird Dir, nach eine weile, 1-2 Jahre, lernen die Macrosammlung sbit.h von Peter Dannegger vorkommen.
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.