Hi Leute,
bin rel. neu im Bereich der µC-Programmierung und hoffe bei euch ein
bissl Unterstützung zu finden :)
Muss für meinen Opa die Steuerelektronik für seinen Treppenlift
reparieren und habe daher leider nicht die Zeit alles (netz, Literatur)
zu durchstöbern und mir selbst anzueignen. kommt aber alles noch... :)
Habe folgendes Problem:
Möchte am PORTB die Bits 0-3 abfragen und je nachdem wie sie geschaltet
sind in PORTA die Bits 0-3 schalten.
Arbeite mit dem ATMEGA16 und benutze das AVR ISP mkII als
Programmierschnittstelle.
Habe unten meinen Code gepostet. Da seht ihr bestimmt direkt den Mist
den ich verzapft hab ;)
Vielen Dank schonmal im Vorraus.
#include <avr/io.h>
#include <stdint.h>
int main (void) {
DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (1 << DDA3);
// PortA auf Ausgang
DDRB = (0 << DDB0) | (0 << DDB1) | (0 << DDB2) | (0 << DDB3);
// PortB auf Eingang
while (1) {
// solange PINB0 und PINB1 == HIGH sollen PINA0, PINA1 und PINA3 HIGH
sein
while (PINB & (1<<PINB0 & 1<<PINB1)) {
PORTA |= (1<<PORTA0 & (1<<PORTA1 & 1<<PORTA3);
};
while ( PINB & (1<<PINB0 & 1<<PINB3) ) {
PORTA |= (0<<PORTA0 & 0<<PORTA3);
};
while ( PINB & (1<<PINB2 & 1<<PINB3) ) {
PORTA |= (1<<PORTA0 & (1<<PORTA2 & 1<<PORTA3);
};
};
return 0;
}
Andyloco wrote:
> // solange PINB0 und PINB1 == HIGH sollen PINA0, PINA1 und PINA3 HIGH> sein> while (PINB & (1<<PINB0 & 1<<PINB1)) {> PORTA |= (1<<PORTA0 & (1<<PORTA1 & 1<<PORTA3);> };
Laut Kommentar ist die Logikabfrage so zu machen
while (PINB & ((1<<PINB0) | (1<<PINB1))) {
PORTA |= ((1<<PORTA0) | ((1<<PORTA1) | (1<<PORTA3));
};
Die anderen Bedingungen habe ich nicht geprüft, weil keine Kommentare da
sind und ich nicht weiss, was du machen willst.
Du weißt aber schon, daß ein while (a) {x} x erst verläßt, wenn a unwahr
ist?
Damit dürften Deine anderen 'whiles' erst abgearbeitet werden, wenn das
vorherige while unwahr ist. Das wird so nix ;-)
Grüße,
Freakazoid
Vielen Dank für eure schnelle Hilfe!!!
@Stefan "stefb" B.
Habe deine Überarbeitung meines Codes ausprobiert, aber egal ob ich die
Spannung an den beiden Pins anlege oder nicht ändert das nichts an den
Ausgangspins, die bleiben auf 5V.
Oder habe ich einen kompletten Denkfehler in der Struktur meines
Programmes???
Das Programm soll nur die Zustände an den 4 Eingangspins prüfen und wenn
eine der vorgegebenen Kombinationen (durch die unteren 3 while
Bedingungen gegeben) eintritt die Ausgänge entsprechend schalten.
@Freakazoid
>Du weißt aber schon, daß ein while (a) {x} x erst verläßt, wenn a unwahr>ist?
aber "a" wird doch durch die Spannung an den pins vorgegeben. Ich hatte
mir gedacht, solange die Spannung an beiden Pins anliegt, dann soll die
Bedingung erfüllt sein und sobald einer der beiden Pins LOW ist sollte
die Bedingung nicht mehr erfüllt sein. Oder kann man das nicht auf diese
Weise machen?
Vielen Dank
> Oder habe ich einen kompletten Denkfehler in der Struktur meines> Programmes???
Yes!
Wie oben beschrieben kann ich zum Rest nichts schreiben, weil du nicht
angibst, was die Ausgangspins machen sollen, wenn die Bedingung nicht
erfüllt ist.
Ich schlage vor, dass du alle Zustände, die seine Steuerung annehmen
kann zunächst mit Worten beschreibst.
Beispiel:
1/ Lift wartet unten
2/ Lift fährt hoch
3/ List wartet oben
4/ Lift fährt runter
5/ Lift wartet mitten auf der Treppe
6/ Lift stoppt sofort
...
Ein Schaltplan ist auch nützlich, in dem steht, wo welche Taster
angeschlossen sind und welche PORTPINS zur Steuerung welcher Funktion
benutzt werden.
Daraus lässt sich ein Zustandsdiagramm (state machine) machen, bei dem
exakt festgelegt ist, wie man mit welchen Aktionen von einem Zustand in
den anderen kommt.
Beispiel:
A/ 6/ wenn nicht mindestens zwei Tasten gedrückt
B/ Von 1/ nach 2/, wenn Taste PINB0 UND PINB1 gedrückt
...
Erst wenn das steht, kann man eigentlich ein sinnvolles und sicheres
Programm für alle denkbaren Zustände machen.
Die Ausgangspins sollen auf LOW sein.
Wenn eine Bedingung erfüllt ist sollen die entsprechenden Pins auf HIGH
geschaltet werden bis die Bedingung nicht mehr erfüllt ist.
PB0..3 sollen die Eingänge sein
PA0..3 sollen die Ausgänge sein
Bed.1: PB0 und PB1 gehen beide auf HIGH
=> PA0, PA1 und PA3 sollen daraufhin auf HIGH gehen
Bed.2: PB0 und PB3 gehen beide auf HIGH
=> PA0 und PA3 sollen auf HIGH gehen
Bed.3: PB2 und PB3 gehen beide auf HIGH
=> PA0, PA2 und PA3 sollen auf HIGH gehen
@Stefan "stefb" B.
Kommt diese Aufstellung Deiner Vorstellung näher?
MfG
Andyloco wrote:
> Wenn eine Bedingung erfüllt ist sollen die entsprechenden Pins auf HIGH> geschaltet werden bis die Bedingung nicht mehr erfüllt ist.>> PB0..3 sollen die Eingänge sein> PA0..3 sollen die Ausgänge sein
Formuliere deine Bedingungen in der Programmiersprache im
ersten Anlauf in der Langversion
>> Bed.1: PB0 und PB1 gehen beide auf HIGH
Aha: Also genau dann, wenn PB0 auf High ist UND PB1
auf Hight ist.
In C
if( ( PINB & ( 1 << PB0 ) ) &&
( PINB & ( 1 << PB1 ) ) {
}
Deine bisherigen Abfragen
while (PINB & (1<<PINB0 & 1<<PINB1)) {
bzw.
while (PINB & (1<<PINB0 | 1<<PINB1)) {
sind andere Abfragen. Im ersten Fall kann die Bedingung
überhaupt nie erfüllt werden, weil ( 1 << PINB0 & 1 << PINB1 )
immer den Wert 0 ergibt.
Im zweiten Fall ist das immer noch eine andere Abfrage, weil
es hier bereits reicht, wenn einer der beiden Eingänge
entweder PINB0 oder PINB1 oder beide 1 sein können, damit
die Bedingung wahr ergibt.
-> Formuliere deine Logik zunächst mal einfach und überlege
dir welche Verknüpfung (und oder oder) du brauchst.
Wenn du dir nicht sicher bist, dann stell dir Tabellen auf, in
denen du alle Möglichkeiten der Eingangspins aufschreibst und
dann den Ausdruck auswertest
> // solange PINB0 und PINB1 == HIGH sollen
Das ist die falsche Denkweise. Deine Bedingungen sind
grundsätzlich immer von dieser Natur
Variable == Wert
aber nicht
Variable und eine andere Variable == Wert
statt dessen muss es lauten:
Variable == Wert UND andere Variable == Wert
und genau so musst du es auch programmieren.
Habe mein Programm erstmal vereinfacht, weil (so denke ich)in der
Bedingung irgendwo ein Fehler steckt. Ich habe eure Verbesserungen
ausprobiert aber hat nicht so funktioniert wie ich das gerne hätte.
Das Programm reagiert nicht so auf Änderungen der Eingangspins wie ich
das vorgesehen habe.
Die if-Bedingung soll prüfen ob PINB0 UND PINB1 HIGH sind und dann
PORTA0 UND PORTA1 UND PORTA3 auf HIGH schalten ansonsten PORTA auf LOW.
Das Ergebnis dieser Programmierung ist allerdings, dass wenn der Taster
am Eingang nicht gedrückt ist (es ist nur ein Taster angeschlossen sonst
nix; also keine 5V anliegen) die 3 Ausgänge schon auf HIGH sind und sich
auch nicht ändern wenn die Eingänge auf HIGH gesetzt werden.
Dagegen wenn einer der beiden Eingänge auf Masse gelegt wird dann gehen
die Ausgänge auf LOW...
Kann ich leider überhaupt nicht nachvollziehen...
Ich hoffe einer von euch kann mir da weiterhelfen.
Vielen Dank. MfG Andyloco
#include <avr/io.h>
#include <stdint.h>
int main (void)
{
DDRA = 0xff; // alle Pins von Port A als Ausgang
DDRB = 0x00; // alle Pins von Port B als Eingang
PORTB = 0xff; // interne Pull-Ups an allen Port-Pins
// aktivieren
while (1)
{
if( (PINB & (1<<PINB0)) && ( PINB & (1<<PINB1)) )
PORTA |= (1<<PORTA0) | (1<<PORTA1) | (1<<PORTA3);
else PORTA = 0x00;
}
return 0;
}
Andyloco wrote:
> Die if-Bedingung soll prüfen ob PINB0 UND PINB1 HIGH sind und dann> PORTA0 UND PORTA1 UND PORTA3 auf HIGH schalten ansonsten PORTA auf LOW.> Das Ergebnis dieser Programmierung ist allerdings, dass wenn der Taster> am Eingang nicht gedrückt ist (es ist nur ein Taster angeschlossen sonst> nix; also keine 5V anliegen)
Die Taster schalten also nach Masse.
Das heist aber auch:
Ist keine Taste gedrückt, dann liegt an diesem Eingang eine 1
an. Wird dies Taste gedrückt, dann liegt an diesem Eingang eine
0 an.
die 3 Ausgänge schon auf HIGH sind und sich
> auch nicht ändern wenn die Eingänge auf HIGH gesetzt werden.> Dagegen wenn einer der beiden Eingänge auf Masse gelegt wird dann gehen> die Ausgänge auf LOW...> Kann ich leider überhaupt nicht nachvollziehen...
Ja. Ist logisch. Das ist genau das erwartete Verhalten, wenn die
Tasten nach Masse durchschalten.
1
>#include<avr/io.h>
2
>#include<stdint.h>
3
>
4
>
5
>intmain(void)
6
>{
7
>
8
>DDRA=0xff;// alle Pins von Port A als Ausgang
9
>DDRB=0x00;// alle Pins von Port B als Eingang
10
>PORTB=0xff;// interne Pull-Ups an allen Port-Pins
11
>// aktivieren
12
>
13
>while(1)
14
>{
15
>if((PINB&(1<<PINB0))&&(PINB&(1<<PINB1)))
16
17
if(!(PINB&(1<<PINB0))&&!(PINB&(1<<PINB1)))
Jetzt wird der if Teil nur dann genommen, wenn beide Taster
geschaltet sind, also beide Eingangspins eine 0 liefern.
Andyloco wrote:
> Kommt diese Aufstellung Deiner Vorstellung näher?
Nicht wirklich. Du bist schon am Dachdecken, aber die Fundamente sind
noch nicht betoniert ;-)
So habs fertig gekriegt so wie es mir vorgestellt habe. Funzt erste
Sahne ;) zumindest wenn man davon absieht das ich an den Ausgängen nur
3,3V bzw 2,1V habe... :(
Muss wohl noch n bissl an meiner Hardware basteln (ohne angeschlossene
Relais waren es 5V).
Hatte auch das mit den Widerständen für Active-High-Schaltung mit Taster
noch nicht verstanden gehabt... Dachte die internen Pull-Down
Widerstände würden reichen.
Ich möchte euch noch mal sehr für eure Hilfe danken!!! Ihr habt mir sehr
geholfen!!!
MfG Andyloco
#include <avr/io.h>
#include <stdint.h>
int main (void)
{
DDRA = 0xff; /* alle Pins von Port A als Ausgang */
DDRB = 0x00; /* alle Pins von Port B als Eingang */
PORTB = 0x00; /* interne Pull-Ups an allen Port-Pins aktivieren */
while (1)
{
if( (PINB & (1<<PINB0)) && ( PINB & (1<<PINB1)) )
{ PORTA |= (1<<PORTA0) | (1<<PORTA1) | (1<<PORTA3);
PORTA &= ~(1<<PORTA2);
}
if( (PINB & (1<<PINB0)) && ( PINB & (1<<PINB3)) )
{ PORTA |= (1<<PORTA0) | (1<<PORTA3);
PORTA &= (~(1<<PORTA1) | ~(PORTA2));
}
if( (PINB & (1<<PINB2)) && ( PINB & (1<<PINB3)) )
{ PORTA |= (1<<PORTA0) | (1<<PORTA2) | (1<<PORTA3);
PORTA &= ~(1<<PORTA1);
}
if( !( (PINB & (1<<PINB0)) && ( PINB & (1<<PINB1)) ) ||
!( (PINB & (1<<PINB0)) && ( PINB & (1<<PINB3)) ) ||
!( (PINB & (1<<PINB2)) && ( PINB & (1<<PINB3)) ) )
PORTA = 0;
}
return 0;
}
Andyloco wrote:
> So habs fertig gekriegt so wie es mir vorgestellt habe. Funzt erste> Sahne ;) zumindest wenn man davon absieht das ich an den Ausgängen nur> 3,3V bzw 2,1V habe... :(> Muss wohl noch n bissl an meiner Hardware basteln (ohne angeschlossene> Relais waren es 5V).
Du wirst doch nicht die Relais direkt an die Pins geschaltet haben?
> Hatte auch das mit den Widerständen für Active-High-Schaltung mit Taster> noch nicht verstanden gehabt... Dachte die internen Pull-Down> Widerstände würden reichen.
Das sind keine Pull-Downs. Im AVR sind Pull-Ups integriert.
Sie sorgen dafür, dass der Eingangspin definiert auf 1
gezogen wird, solange der Taster nicht geschlossen ist.
> #include <avr/io.h>> #include <stdint.h>>>> int main (void)> {>> DDRA = 0xff; /* alle Pins von Port A als Ausgang */> DDRB = 0x00; /* alle Pins von Port B als Eingang */> PORTB = 0x00; /* interne Pull-Ups an allen Port-Pins aktivieren */
Der Kommentar stimmt nicht.
Die Pullups sind hier deaktiviert.
Dein resltiches Programm stimmt damit überein, dass du keine
Pull-Ups brauchst.
Dann brauchst du aber externe Pull-down Widerstände. Ein
auf Eingang geschalteter Pin darf niemals einfach nur offen sein!
Du fängst dir sonst an diesem Pin jede Menge Störungen ein.
Es muss also so aussehen:
+--------------o +5V
|
/
/ Taster
/
|
|
PB0 --------+
|
---
| |
| | 10k
| |
---
|
GND --------+---------------o GND
Und sieh dir an, wie man ein Relais korrekt an einen µC
anschliesst. Sonst wird dein Opa nicht lange Freude an deiner
Elektronik haben.
http://www.mikrocontroller.net/articles/Relais_mit_Logik_ansteuern