Forum: Mikrocontroller und Digitale Elektronik myAVR PORT Expander


von Sven W. (sickone4)


Lesenswert?

Hallo Leute,

soeben kamen zwei Platinen per Post bei mir eingeflattert:

myAVR Port Expander. 16 weitere I/O Ports.

und das nun halt 2mal.

Diese werden wohl über den TWI I²C Bus gesteuert.

Nun habe ich mich versucht ein wenig auf der myAVR Seite schlau zu 
machen, wie ich diese PORTS anstprechen kann.

Weiß das jemand?

Dort wird ein Beispielprogramm gelistet um 1 LED anzusteuern.
1) Werden dort sämtliche einstellungen in HEX dargestellt und ich 
arbeite nur in binärschreibweise.

2) frage ich mich ob man all das benötigt um die ports abzufragen doer 
damit irgendwie zu arbeiten (DDR festlegen usw)

hier mal ein Link:
http://www.myavr.info/download/produkte/mytwi/techb_mytwi-portexpander_de_en.pdf

Ab Seite 11

Vielleicht kann mir ja wer sagen, wie ich die neuen Ports ansteuern 
kann.

Danke

Gruß Sven

von Udo (Gast)


Lesenswert?

Wenn Du Hex nicht in Binär umrechnen kannst, bist Du noch sehr weit weg 
von der Ansteuerung über TWI.

Zu der Ansteuerung der Ports: So wie es in der Beschreibung steht!

von Sven W. (sickone4)


Lesenswert?

hi udo!

natürlich kann ich das umrechnen....

aber nicht lesen... und ich hatte nun nicht vor jede zeile in der hex 
ist zuerst umzurechnen!

was ich wissen wollte ist,

wie spreche ich z.b. den zusätzlichen port A pin 4 an.
oder eben jeden anderen.

zum thema quellcode: ich arbeite nicht mit interupts, warum brauche ich 
dann diesen codeteil?

von Udo (Gast)


Lesenswert?

Den ganzen Code habe ihc auch nicht gelesen, aber der Interrupt dürfte 
für die Tastendruckerkennung sein, wenn die Tasten nicht zyklisch 
gelesen werden. Ist ja schließlich ein Beispielprogramm.

Ausgänge werden z.B. durch "outPorts(1,0xFF" beschrieben wobei FF durch 
die von dir gewünschte Bitfolge ersetzt wird, natürlich wieder in HEX:

von Udo (Gast)


Lesenswert?

Enschuldige Klammer vergessen outPorts(1,0xFF)

von Sven W. (sickone4)


Lesenswert?

ja gut die zeile habe ich rausgelesen.

nun habe ich aber zwei port expander, sprich insgesamt 4 neue ports

aber in der zeile

outPorts(1,0xFF)                     od.
outPorts(1,0b11111111)

sehe ich kein A oder B wie kann ich also feststellen, welcher Port es 
ist?

von Udo (Gast)


Lesenswert?

Du musst es an die richtige TWI Adress senden. Jeder Portexpander hat 
eine einstellbare Adresse. Daher weiß auch der Briefträger in welches 
Haus er die Rechnungen bringen soll :-)

von Josef D. (jogedua)


Lesenswert?

Das Beispiel ist dazu gedacht, einem Einsteiger erst mal auf die Beine 
zu helfen. Wenn du das für deine Anwendung anpassen willst, musst du das 
Beispiel erst einmal verstehen.
In outPorts ist z.B. die Addresse fest codiert:
     twiWriteByte(0x40,1); // TWI-Adresse
Und in twiInitPCA() wird der eine Port des PCA fest auf Eingang un der 
andere fest auf Ausgang eingestellt. Das passt vermutlich auch nicht auf 
deine Anwendung.
In dem Bespiel darf der Paramter "port" nur die Werte 0 oder 1 haben.
Hier könnte man die höherwertigen Bits benutzen, um die Adresse des PCA 
zu bestimmen.
z.B. in outPorts()
  twiWriteByte(0x40 | (port & 0b00001110),1); // TWI-Adresse
  twiWriteByte(port & 1,1);

Für weiter Hilfe benötigt man mehr Information, was genau du damit 
machen willst.

von Josef D. (jogedua)


Lesenswert?

sorry, muss
  twiWriteByte(0x02+port&1,1); // Kommandoregister 2/3 -> Output P0/P1
heißen

von Sven W. (sickone4)


Lesenswert?

Hallo Josef!

danke für deine erklärung.

tja was will ich tun.

ich hab ein programmierboard mit 3 ports mit je6 pins.

das ist für mein programm zu wenig. ich brauche 8 weitere für eine 7 
segmentanzeige sowie 8 für seperate 8 LED´s

also habe ich mir mal schnell zwei erweiterungskarten besorgt mit dem 
gedanken "super reinstecken, und schon haste 2x 16 weitere ports."

dem is aber garnicht so...

ich wünsche mir eine addressierung wie bei den anderen z.b.
portb |= (1<<4) o.ä.

bei outPorts(1,0b11111111) hab ich schon keinen schimmer wie ich das 
machen kann.

zudem ist das schön ein beispielprogramm zu lesen, doch von fester 
zuweisung und so hab ich schon garnichts rausgelesen....

bin ich nun ein blutiger anfänger, weil ich die TWI anweisungen nicht 
kenne?

kann man das denn nicht irgendwie programmeiren, dass ich die zwei 
karten nutzen kann,

dann einfach die DDR festlege und die pins ansprechen wie ich will?

eig sind alles nur outputs, was benötigt wird

von Sven W. (sickone4)


Lesenswert?

das beste aber ist, das ich vorher den ganzen quellcode schon 
vorprogrammiert hatte und nurnoch die ports austauschen musste.

nun funktioniert nichtmal mehr eine zuweisung eines integers i....

programmier ich ihn auf 0 funktioniert es
programmier ich ihn auf 1 gehts nimma und auf 1 muss er sein, da es nur 
die werte 1-8 gibt...

von Josef D. (jogedua)


Lesenswert?

Hast du es denn das Beispiel-Programm schon am laufen?

von Sven W. (sickone4)


Lesenswert?

das beispiel programm hab ich reingeladen, läuft
ist ja nur mit zwei drähten


ich hab auch schon die outports belegt und nutze sie auch, aber ich 
nutze nur diese anweisung:

outPorts(1,0b11111111) <- halt dann entsprechend belegt.

das geht im moment aber nur mit dem neuen B port, da a auf eingang 
geschaltet ist.

ich versteh die TWI befehle nicht, dass ich sagen könnte, was da wie 
muss, damit ich A) beide karten nutzen und B) die ports belegen kann wie 
ich will

von Josef D. (jogedua)


Lesenswert?

Schon mal ins Datenblatt des PCA9555 geschaut?
Man sollte wenigstens in etwa wissen, wo es lang geht.
Man kann z.B. die jeweils 2 Ports auch als 16-Bit-Port benutzen;
Je nach Anwendung kann das günstiger sein.

um die Ports einzeln ansprechen zu können, würde ich twiInitPCA()
z.B. so ersetzen (ich kann mangels Chip nichts testen):
1
#define ADDRESSMASK 0b00001110
2
#define PORTMASK    0b00000001
3
4
// DDR einzeln setzte, port=0..15; je 2 auf einem PCA9555
5
void twiInitPCA_DDR(uint8_t port, uint8_t ddr)
6
// ddr: 0=Ausgang, 1=Eingang
7
{
8
   twiStart();
9
   twiWriteByte(0x40 + (port & ADDRESSMASK), 0); // TWI-Adresse
10
   twiWriteByte(0x06 + (port & PORTMASK),0); // Adressierung des Kommandoregister = Config 0
11
   twiWriteByte(ddr,0); // 
12
   twiStop();  // ist das hier erforderlich???
13
}
Wenn die die Adress-Eingänge der beiden Chips auf 0 bzq. 1 einstellst, 
kann du damit die Ports 0..3 auf Eingang oder Ausgang stellen.

von Sven W. (sickone4)


Lesenswert?

hi josef,

ich versuche mich dort gerade einzulesen.

ich komme aber auch mit deinem code nicht klar.
ich muss irgendwie durch zwei sachen durchsteigen. ich nutze mehrere 
programme für mein board. bei einem, dem myavr workpad plus gibt es 
codebeispiele und auch die der TWI.

aber zunächst zu deinem code:
1
#define ADDRESSMASK 0b00001110              // ???
2
#define PORTMASK    0b00000001              // ???
3
4
// DDR einzeln setzte, port=0..15; je 2 auf einem PCA9555
5
void twiInitPCA_DDR(uint8_t port, uint8_t ddr)
6
// ddr: 0=Ausgang, 1=Eingang
7
{
8
   twiStart();
9
   twiWriteByte(0x40 + (port & ADDRESSMASK), 0); // TWI-Adresse
10
   twiWriteByte(0x06 + (port & PORTMASK),0); // Adressierung des Kommandoregister = Config 0
11
   twiWriteByte(ddr,0); // 
12
   twiStop();  // ist das hier erforderlich??? weiß ich nicht, denn ich weiß noch nicht warum das überhaupt gestartet/gestoppt werden muss.
13
}


kurz reinkommentiert :)

und nun hier mal die maske aus dem myavr workpad plus:
1
//------------------------------------------------------------------------
2
// outPorts: Gibt data über das Outputregister des gewünschten Ports aus
3
// PE: twiAdr = Adresse des TWI-Gerätes
4
//     port: = 0 für PortA, 1 für PortB
5
//     data: = der Wert welcher über das Outputregister ausgegeben wird
6
// PA: -
7
//------------------------------------------------------------------------
8
void twiInitPCA(uint8_t twiAdr, uint8_t conf_portA, uint8_t conf_portB);
9
uint8_t readPorts(uint8_t twiAdr, uint8_t port);
10
void outPorts(uint8_t twiAdr, uint8_t port, uint8_t data);
11
void outPorts(uint8_t twiAdr, uint8_t port, uint8_t data)
12
{
13
        twiStart();
14
        twiWriteByte(twiAdr,1);           // TWI-Adresse
15
        twiWriteByte(0x02+port,1);        // Adressierung des Kommandoregister
16
        twiWriteByte(data,0);                //
17
}
18
//------------------------------------------------------------------------
19
20
//------------------------------------------------------------------------
21
// readPorts: Liest das Inputregister des gewünschten Ports aus
22
// PE: twiAdr = Adresse des TWI-Gerätes
23
//     port = 0 für PortA, 1 für PortB
24
// PA: Wert = des Inputregisters
25
//------------------------------------------------------------------------
26
uint8_t readPorts(uint8_t twiAdr, uint8_t port)
27
{
28
        twiStart();
29
        twiWriteByte(twiAdr,1);      // TWI-Adresse
30
        twiWriteByte(port,1);        // Adressierung des Kommandoregister
31
        twiStart();
32
        twiWriteByte(twiAdr+0x01,1); // TWI-Adresse und Read
33
        return twiReadByte(0);
34
}
35
36
//-----------------------------------------------------------------------
37
//  Funktionen für den Portexpander
38
//------------------------------------------------------------------------
39
// twiInitPCA: Initialiesiert den PCA9555
40
// PE: twiAdr = Adresse des TWI-Gerätes
41
//     conf_portA = 8 Bit Wert der die Konfiguration für PortA darstellt
42
//     0 = Ausgang, 1 = Eingang
43
//     conf_portB = 8 Bit Wert der die Konfiguration für PortB darstellt
44
//     0 = Ausgang, 1 = Eingang
45
// PA: -
46
//------------------------------------------------------------------------
47
void twiInitPCA(uint8_t twiAdr, uint8_t conf_portA, uint8_t conf_portB)
48
{
49
        twiStart();
50
        twiWriteByte(twiAdr,0);       // TWI-Adresse
51
        twiWriteByte(0x06,0);         // Adressierung des Kommandoregister
52
        twiWriteByte(conf_portA,0);   // ConfigDaten für Port A schreiben
53
        twiWriteByte(conf_portB,0);   // ConfigDaten für Port B schreiben
54
        twiStop();
55
}

dummerweise kommen da beim kompilieren fehlermeldungen, sodass ich damit 
nicht arbeiten kann...
1
compilieren ... test.cc:8  8: error: variable or field 'twiInitPCA' declared void 
2
 8: error: 'uint8_t' was not declared in this scope 
3
 8: error: 'uint8_t' was not declared in this scope 
4
 8: error: 'uint8_t' was not declared in this scope 
5
test.cc:9  9: error: 'uint8_t' does not name a type 
6
test.cc:10  10: error: variable or field 'outPorts' declared void 
7
 10: error: 'uint8_t' was not declared in this scope 
8
 10: error: 'uint8_t' was not declared in this scope 
9
 10: error: 'uint8_t' was not declared in this scope 
10
test.cc:11  11: error: variable or field 'outPorts' declared void 
11
 11: error: 'uint8_t' was not declared in this scope 
12
 11: error: 'uint8_t' was not declared in this scope 
13
 11: error: 'uint8_t' was not declared in this scope 
14
test.cc:26  26: error: 'uint8_t' does not name a type 
15
test.cc:47  47: error: variable or field 'twiInitPCA' declared void 
16
 47: error: 'uint8_t' was not declared in this scope 
17
 47: error: 'uint8_t' was not declared in this scope 
18
 47: error: 'uint8_t' was not declared in this scope

vielleicht kann mir das wer kurz erklären.

lg sven

von Josef D. (jogedua)


Lesenswert?

Hallo Sven,
da scheinen bei dir aber noch weitere Baustellen zu sein.

Wenn du mit "#define ADDRESSMASK 0b00001110" nichts anfangen kannst,
wirst du vermutlich erst ein C-Buch durcharbeiten müssen. Das wird dir 
hier keiner vorkauen wollen.

Die Fehlermeldung "'uint8_t' was not declared in this scope" erscheint 
vermutlich, weil ein "#include <stdint.h>" fehlt.

Wenn du Hilfe für die anderen Fehlermeldungen möchtest, wirst du wohl 
deinen kompletten Code (als Anhang) einstellen müssen, so dass ein 
potentieller Helfer den auch kompilieren kann.

Für meine Vorschläge für die Code-Änderungen hatte ich die Beispiele aus 
deinem Link weiter oben benutzt. Die stimmen aber gar nicht mit denen 
überein, die du verwendest (z.B. die Funktion twiInitPCA ist einmal mit 
Parametern und einmal ohne); das macht es auch nicht einfacher.

mfg Josef

von Sven W. (sickone4)


Angehängte Dateien:

Lesenswert?

ja ich kann dir wohl kaum widersprechen...

ich lerne das programmieren in der schule (technikerschule). und wie?

man bekommt ein thema und muss es sich erarbeiten. prima.
hab kürzlich die PWM modi des atmega 8 durchgemacht. hat mich knapp 2 
monate gekostet.

vorher haben wir bissi mit interupts und den ports gearbeitet.
alles schön und gut, aber C-programmierung ist DAS nicht!

d.h. alles was ich hier jetzt mache ist freiwillig und ich versuche es 
mir zu erarbeiten. daher bitte nicht verzweifeln und sagen "der hat nix 
druff" ne, der versucht es und bemüht sich.

zu den quellcodes:

das erste was ich reingestellt hatte war der quellcode von myavr.de, ein 
beispielquellcode.

das zweite war deiner

und der dritte oben ist eine maske, von myavr workbench plus wie man twi 
erstellt.

gut. zu meinem quellcode. ich stelle ihn in den anhang, nicht 
verzweifeln, wenn er nicht gut ist, bitte.

ich habe ne menge kommentare dazu geschrieben, was denke ich mal einige 
fragen eklärt

mfg Sven

von Christian H. (christian_h)


Lesenswert?

Gerade, wenn du es freiwillig machst, was ja auch lobenswert und gut 
ist, solltest du dir dringend ein C Buch kaufen und das durcharbeiten, 
um nicht hier und da ein paar Lücken zu haben, auch wenn du vielleicht 
den großen Teil schon verstehst.

von Sven W. (sickone4)


Lesenswert?

ja ich glaube das ist schon sinnvoll.

kann mir da wer was empfehlen, bezüglich der arbeit mit avr sachen?

und eine kleine frage am rand:

ich möchte folgendes machen:

var1 = port
var2 = belegung1
var3 = belegung2
.
.
.

if (xy)  { port = belegung1 )
if (xyz) { port = belegung2 )

was ich also tun will ist, ich will einen x-beliebigen port einmal in 
eine variable schreiben und dann die jeweilige belegung in andere 
variablen.
das ist ein teil meines programmes.

das geht aber nicht, wenn ich das mit int mache.

sieht bei mir so aus:
1
int eff_port  = PORTB;
2
   int s_Effekt1 = 0b00100100; 
3
   int s_Effekt2 = 0b00010000;          // bis 8
4
5
if ( i == 1 ) { eff_port = s_Effekt1;}  // Kanal A1
6
if ( i == 2 ) { eff_port = s_Effekt2;}  // Kanal A1

was ich haben will soll dann generiert so aussehen:
1
if ( i == 1 ) { PORTB = 0b00100100;}  // Kanal A1
2
if ( i == 2 ) { PORTB = 0b00010100;}  // Kanal A1

ich vermute es liegt daran, dass ich aus der webprogrammierung komme.
ich kann vermutlich int keine buchstaben zuweisen od?

von Sven W. (sickone4)


Lesenswert?

ach gott... habs per hand geschrieben... es sollt nicht heissen

"int eff_port  = PORTB;"

sondern

"char eff_port  = 'PORTB';"

char a = 'b'; so gehts doch auch....
1
    char eff_port = 'PORTB';
2
    
3
    char s_Effekt[8];
4
    
5
       s_Effekt[0] = '0b00011000'; 
6
       s_Effekt[1] = '0b00010100'; 
7
       s_Effekt[2] = '0b00010000'; 
8
       s_Effekt[3] = '0b00001100'; 
9
       s_Effekt[4] = '0b00011100'; 
10
       s_Effekt[5] = '0b00000100'; 
11
       s_Effekt[6] = '0b00001100'; 
12
       s_Effekt[7] = '0b00010100'; 
13
       
14
15
    if ( i == 1 ) { eff_port = s_Effekt[0];}                // Kanal A8 
16
    if ( i == 2 ) { eff_port = s_Effekt[1];}                // Kanal A2
17
    if ( i == 3 ) { eff_port = s_Effekt[2];}                // Kanal A2
18
    if ( i == 4 ) { eff_port = s_Effekt[3];}                // Kanal A4
19
    if ( i == 5 ) { eff_port = s_Effekt[4];}                // Kanal A5
20
    if ( i == 6 ) { eff_port = s_Effekt[5];}                // Kanal A6
21
    if ( i == 7 ) { eff_port = s_Effekt[6];}                // Kanal A7
22
    if ( i == 8 ) { eff_port = s_Effekt[7];}                // Kanal A8

geht auch nicht...

von Sven W. (sickone4)


Lesenswert?

char s_Effekt[8];

is natürlich quatsch....

tz tz tz charlänge auf 8... ich hab mal wieder an arrays gedacht....

von Josef D. (jogedua)


Lesenswert?

Hallo Sven,

ich glaube, das wird so nichts.

Du musst dich entscheiden, was du willst.

Wenn Programmieren nicht dein Hobby ist (oder werden soll), dann lass es 
und mach das, was dir Spaß macht.

Wenn du den Fußschalter für ein anderes Hobby brauchst, such dir 
jemanden vor Ort, der dir das macht.

Wenn du dir das Projekt nur als Ziel gesetzt hast, das du erreichen 
willst,
dann stell es erst einmal zurück und such dir einfachere.

Wenn du µCs in C programmieren willst, führt kein Weg daran vorbei, erst 
einmal C von Grund auf zu lernen (die Ziele sind dann erst einmal die 
Übungsaufgaben in dem C-Buch deiner Wahl; und zwar auf einem PC). Wenn 
dir das keinen Spaß macht, ist Programmieren vermutlich nichts für dich.


Sven Weinmann schrieb:
> was ich haben will soll dann generiert so aussehen:
> if ( i == 1 ) { PORTB = 0b00100100;}  // Kanal A1

Was du hier brauchst, sind Pointer.
Sehr viele deiner IF-Abfragen in deinem Programm ließen sich mit Arrays 
viel einfacher und vor allem übersichtlicher gestalten.
Es gibt so viele Werkzeuge, die C zu bieten hat. Wenn du sie nicht 
kennst, kannst du viele Ideen nicht verwirklichen.

mfg Josef

von Josef D. (jogedua)


Lesenswert?

statt der IFs im letzten Beitrag z.B. nur eine Zeile:
   eff_port = s_Effekt[i-1];

von Sven W. (sickone4)


Lesenswert?

das ist ne gute sache! stimmt :) viele zeilen gespart!

warum funktionieren die char variablen denn nicht, hab eben darüber 
gelesen, dass ich so, wie ich sie formatiert habe buchstaben übergeben 
kann

eben nach dem motto: char a = 'b';

so hatte ich zumindest vor es zu machen^^

von Josef D. (jogedua)


Lesenswert?

mit Try & Error lernt man nicht programmieren.

Arbeite ein C-Buch durch, sonst brauchst du wieder zwei Monate und hast 
trotzdem nichts gelernt.

von Sven W. (sickone4)


Lesenswert?

naja ich weiß nicht ob das eleganz ist, aber ich habs mal so gemacht:
1
    #define eff_port PORTB
2
    
3
    char s_Effekt[8];
4
    
5
       s_Effekt[0] = 0b00111111;                    // gespeicherte Effekte Kanal 1
6
       s_Effekt[1] = 0b00010100;                    // gespeicherte Effekte Kanal 2 
7
       s_Effekt[2] = 0b00010000;                    // gespeicherte Effekte Kanal 3 
8
       s_Effekt[3] = 0b00001100;                    // gespeicherte Effekte Kanal 4 
9
       s_Effekt[4] = 0b00011100;                    // gespeicherte Effekte Kanal 5 
10
       s_Effekt[5] = 0b00000100;                    // gespeicherte Effekte Kanal 6 
11
       s_Effekt[6] = 0b00001100;                    // gespeicherte Effekte Kanal 7
12
       s_Effekt[7] = 0b00010100;                     // gespeicherte Effekte Kanal 8
13
       
14
    eff_port = s_Effekt[i-1];                      // Zuweisung Kanal und Effektbänke

anders hab ich keine buchstaben in die variable eff_port bekommen....

von Josef D. (jogedua)


Lesenswert?

Sven Weinmann schrieb:
> anders hab ich keine buchstaben in die variable eff_port bekommen....

eff_port ist keine Variable, und selbst wenn's eine wäre, "wären keine 
Buchstaben drin".

Ich geb's auf.

von Sven W. (sickone4)


Lesenswert?

1
eff_port ist keine Variable, und selbst wenn's eine wäre, "wären keine
2
Buchstaben drin".

ok dann hab ich irgendwas falsch verstanden.

wenn ich z.b. int i schreibe dann ist i doch eine variable???

so und i ist nunmal ein integer => ganze zahl und variabel.

so, gleiches wollte ich bei eff_port machen, NUR sollte da keine ganze 
Zahl drin stehen sondern das wort PORTB, also keine deklaration o.Ä. nur 
das wort, weil ich gleiches an anderer stelle ausgeben lassen möchte, 
dort soll es dann seinen sinn erfüllen.

was nutzt es mich wenn ich schreibe eff_port = PORTB dann hab ich den 
wert von portb in eff_port stehen was mir reichlich wenig bringt.

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
Noch kein Account? Hier anmelden.