PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Port Pins als Ein- und Ausgänge



tornado
04.02.2007, 09:49
Ich Experiementiere jetzt schon seit einiger Zeit mit meinem PIC 16F876 rum und wollte jetzt etwas neues versuchen.

Wenn man zum Beispiel RA7 und RA6 verbindet, soll etwas passieren.
Jetzt habe ich im Internet gelesen, dass man einige Pins eines Ports als Eingang und Andere als Ausgang definieren kann. Das wusste ich nicht.
Ich dachte ein ganzer Port ist entweder Ein- oder Ausgang.

Wie kann ich das denn anstellen?
Ich müsste ja zum Beispiel RA7 als Ausgang auf "1" setzen und RA6 müsste ein Eingang (auf 0) sein. Wenn man beide verbindet, müsste man dann doch nur mit einem "if" Überprüfen ob RA6 1 oder 0 ist, oder liege ich da falsch?
Sinn der ganzen Sache ist erst mit einem Knopf zwichen zwei Pins zu arbeiten, um spÄter eine 3x4 Matrix Tastatur an Port A anzuschliessen.
DIe Beispielprogramme die ich gefunden habe waren leider alle in Assambler, und ich programiere in "c".

Ich habe gerade in einem Thread gelesen, dass man sagen muss ob die Pins von Port A Digital oder Analog sein sollen.
Wie macht man das? Ich dachte es gäbe nur in PortC einen oder zwei analoge Pins.
Viele Grüsse,
Tornado

tornado
04.02.2007, 19:01
Uff!!!!!
Ich sitze jetzt schon seit Stunden hier dran. Ich habe jetzt selber rausgefunden wie man manche Pins von einem Port als Ausgang und andere als Eingang festlegt.
Aber was stimmt denn an meinem Code nicht?
Wenn RB7 ein Eingang auf 0 ist und ich ihn mit RB6 (Ausgang auf 1) verbinde, müsste RB7 doch 1 werden.
Egal was ich mache, es leuchtet immer nur die erste LED (RA0) aber nie RA1.
Ist hier ein Denkfehler, oder ist mein PIC schon kaputt?
Viele Grüsse,
Tornado




void main (void){
TRISA = 0x00; //Port A = Ausgang mit LEDs
TRISB = 0x10000000; //RB7= Eingang, der Rest --> Ausgänge
PORTA = 0b00000000;
PORTB = 0b00000000; //RB7 = Low
RB6=1; //RB1 = Ausgang auf High
// Wenn RB7 und RB6 verbunden werden wird RB7 High
do{
if (RB7==0){
PORTA = 0b00000001;
}
else if (RB7==1){
PORTA = 0b00000010;
}
}while (1);
}//()

kalledom
04.02.2007, 21:49
Die TRIS-Register sind in Register-Bank 1. In Assembler ist für mich das Umschalten der Registerbänke kein Problem, in C schon:


bsf STATUS,RP0 ; Umschalten auf Bank 1

; TRIS-Register setzen

bcf STATUS,RP0 ; Zurück auf Bank 0

tornado
05.02.2007, 15:58
@Kalledom
Fanke für dein Antwort. Leider verstehe ich garnichts :-(

Was bedeutet Register Bank 1?. Welche ist seine Funktion? Warum muss man ihn Umschalten?
Vieleicht komme ich dann ja weiter.

Benji
05.02.2007, 19:39
In Assembler gibt es verschiendene "Banken" in welchen sich diverse Register befinden. Je nach dem was man für ein Register bearbeiten will, muss man die Register-Bank wechseln....

In C ist das aber nicht notwendig. Jedenfalls nicht beim CCS Compiler...

MfG Benji

kalledom
05.02.2007, 21:59
@Benji
Ich darf Dich ein wenig korrigieren, die Registerbänke 0...3 haben nichts mit Assembler zu tun, die sind in den PICs so als 'Hardware' vorhanden.
Da nur 8 Bits (= 256) zur Adressierung zu Verfügung stehen, die Register jedoch im Bereich 0...0x1FF liegen, sind 4 Bänke mit jeweils 128 Register eingerichtet worden.
In Assembler ist wohl darauf zu achten, daß beim Zugriff auf ein Register auch die richtige Registerbank ausgewählt wurde; sonst wird auf ein anderes Register zugegriffen.
Was bei C passiert, wenn z.B. TRISA = 0x00 da steht, ob dann automatisch auf die richtige Registerbank und wieder zurück geschaltet wird, entzieht sich meiner Kenntnis.

Benji
06.02.2007, 07:12
Danke für die Korrektur. Stimmt :D

Jedenfalls beim CCS Compiler wird automatisch die richtige Registerbank ausgewählt. Also braucht man sich in C um diese nicht zu kümmern.

MfG

phaidros
07.02.2007, 00:42
Wenn RB6 und RB7 verbunden sind, müsste dein Code eigentlich RA1 auf High setzen, weil RB7 dann auch 1 ist.
Wenn die beiden nicht verbunden sind, hängt RB7 in der Luft. Er ist dann mit nichts verbunden. Das sollte nicht vorkommen. Ergebnis ist undefiniert.
Bestenfalls sind die internen Pullup-Widerstände von Port B eingeschaltet, dann zieht der PIC den Eingang automatisch auf High, wenn er mit nichts verbunden ist. Was du in Port B reinschreibst (nämlich 00h) ist für PB7 völlig egal, weil das ein Eingang ist.

Normalerweise macht man daher die Logik genau umgekehrt (nennt sich active-low):

Der Port wird so eingestellt, dass die Pull-Ups aktiviert sind. Die Eingänge (und nur die) sind dann erstmal alle auf High. Der Ausgang (PB6) wird auf LOW gelegt. Wenn jetzt PB6 und PB7 verbunden werden, geht PB7 auch auf LOW. Das wird abgefragt.

(Achtung: Schalter prellen. D. h. der Wert wechselt innerhalb weniger Millisekunden häufiger zwischen geschlossen und offen. Man fragt daher meistens längere Zeit ab und nimmt den letzten stabilen Wert.)
Für dein Problem gibt es bestimmt viele Beispiele im Netz. Suche mal nach "microchip pic key matrix c" weil meistens mit dem Vorgehen eine Tastaturmatrix abgefragt wird.

Gruß
Phaidros

tornado
07.02.2007, 12:07
Danke für eure Antworten.
Dann werde ich es jetzt erst mal mit pull up Wiederständen versuchen.
Falls das nicht funktioniert, dann halt mit der umgekehrten Logik.
Werde auch nach Beispielen im Netz gucken.
Ich werde mich dann in ein par Tagen noch mal melden und sagen ob es geklappt hat oder nicht.
Tornado

michas_rob
07.02.2007, 20:00
Hallo Tornado...

Wie ich sehe programmierst du den PIC 16F876 mit C...
Funktioniert das bei dir gut, denn ich programmier den bis jetzt mittels Assembler und würde gerne mit C Anfangen und das wäre spitze wenn es mit diesem Typen funktionieren würde.

Danke

Michael

tornado
08.02.2007, 11:41
Hi michas_rob!

Den PIC 16F876 kann man sehr gut in C programieren.
Ich hatte das schon letztes Jahr in der Uni gemacht und es geht eigendlich gut.
Ich wollte jetzt halt nur noch mal von null anfangen da uns viele Sachen nicht erklärt wurden.
Mann könnte eigendlich sagen, dass obwohl ich schon 2 Roboter mit diesem Pic in C gemacht habe ich noch immer am lernen bin.
Zum Glück kann man mit diesem PIC und C schnell Erfolge feiern :-)

Du solltest es ruhig versuchen. Wenn es mal nicht funktionierte, war es eher weil ich einen blöden Fehler gemacht hatte.
Viele Grüsse,
Tornado

tornado
08.02.2007, 15:24
@Phaidros
Wie kann ich in C die internen Pull-up Wiederstände aktivieren?
Ich habe jetzt 4,7k pull up wiederstände an RB1 bis RB4 gemacht und RB5-RB7 sind mit dem PIC über jeweilst einen 200 Ohm Wiederstand verbunden. Diese Wiederstände sollten den PIC vor Kurzschlüsse schützen, sollten aber noch klein genug sein um die Pins RB1 bis RB4 auf Low ziehen zu können.
Warscheinlich habe ich die Werte der Wiederstände nicht gut gewählt.

Die erste sache ist, dass um RB1 bis RB4 auf High zu haben ich folgendes schreiben musste:
00001110 Ja, RB4 muss 0 sein. keine Ahnung warum. Wenn er 1 ist, dann ist er Low.
Naja, mit 00001110 sind RB! bis RB4 auf High.

NÄchste Sache:
Ich kann RB4 mit den Pins RB5-Rb7 (wo die 200Ohm Wiederstände sind) ohne Probleme anschliessen und RB4 wird auf Low gezogen.

Mit RB1 bis RB3 geht das aber nicht. Um die auf Low zu ziehen muss ich die 200Ohm Wiederstände überbrücken, alls wenn keine da wären.

Das wÄre ja alles kein Problem, aber wenn ich jetzt eine Tastatur anschliesse und mehrere Tasten auf einmal drücke, kann der PIC kaputt gehen. Ich wollte ausserdem noch einen Display an den Port anschliessen.

Auf Spruts seite sollte man für RB5-RB7 2,7K nehmen. Dann funktioniert bei mir aber gar nichts mehr.

Habt ihr eine Lösung für die Wiederstände oder wie man die internen pull up Wiederstande von RB1 bis RB4 aktiviert?
Vielen Dank für eure Hilfe.
Tornado

phaidros
08.02.2007, 17:40
Die internen Pull-Ups werden durch das Löschen von Bit RBPU im OPTION_REG aktiviert. In C? Keine Ahnung, bei den PICs mache ich nur in Assembler.

4,7 kOhm ist perfekt (bei 5 Volt).
200 Ohm sind auch gut, scheinen mir aber nicht unbedingt nötig zu sein.

Zu dem Rest:
Bist du sicher, dass du RB1 bis RB4 auf Input gesetzt hast und RB5-RB7 auf Output?

Hast du einen Schaltplan?

Gruß
Phaidros

tornado
08.02.2007, 18:12
Ich werde mal googeln um das mit Bit RBPU in C zu finden.
Bis eben war ich mir eigendlich schon sicher, dass die In- und Outputs richtig sind. Funktioniert ja eigendlich, aber halt nicht optimal.
Schaltplan habe ich nicht. Ich könnte morgen aber einen machen falls das weiter hilft.
Grüsse,
Tornado

tornado
08.02.2007, 18:45
Ich habe hier zwar etwas gefunden, aber leider ist die Lösung nicht erklärt.
Vieleicht kann jemand ja den code endziffern.
https://www.roboternetz.de/phpBB2/viewtopic.php?t=4867
Wo wir da in C der Pull up Wiederstand aktiviert?

Benji
09.02.2007, 08:00
Hi tornado

In C kannst du genau gleich auf die Register zugreifen wie in Assembler. Jedes Register hat eine bestimmte Adresse. Du hast sicher ein .h-File welches included wird. In diesem sind die Register definiert. Falls das OPTION_REG nicht aufgeführt ist, kannst du es manuell nachtragen.
(Adressen siehe Datasheet Seite 104).

Dann definiert man das Register in etwa so:
#byte PORTA = 0x0F80 ; Beispiel am PORTA

(Die Adresse stimmt nicht mit deinem PIC überein)

Auf das Bit 0 greift man wie folgt zu:
PORTA.0 = 1 ; PIN_A[0] = 1

tornado
09.02.2007, 17:02
Die einzige .h-File die ich "included" habe ist die vom PIC.
Ist das dort wo ich gucken muss?

Ich habe so das blöde gefühl, dass ich das hier nicht packe. Naja, ich werde mich weiter durchbeissen und weiter probieren.
FAlls noch jemand eine gute Idee hat für die Tastatur lasst es mich bitte wissen.

tornado
09.02.2007, 18:16
Mir ist da noch etwas eingefallen.

Wenn ein Pin als Ausgang auf High steht, kommen 5V raus. Das stimmt bei mir so weit. Um eine LED anzuschliessen braucht man einen Vorwiederstand, damit die LED nicht kaputt geht.
Bei mir ist das nicht nötig. Die brennt ganz normal wenn ich sie an den Pic anschliesse.
Wenn ich dann die Spannung an den beiden Beinchen der Diode messe, kann man nur noch 2V messen.

Kann es sein, dass der Trafo einfach nicht genug Saft liefert?
Wäre das dann auch ein Grund weswegen das mit den pull up Wiederständen nicht richtig geht?

Ich habe noch mal nachgeguckt.
Um zu sagen ob ein pin Ein- oder Ausgang ist, habe ich folgendes stehen: 00011111 RB0 ist egal. Danach sind RB1 bis RB4 auf Eingang und RB5 - RB7 als Ausgang.

phaidros
10.02.2007, 00:56
Wie bitte?
Du schließt eine LED ohne Vorwiderstand an den PIC an?
Das ist das zweitbeste Rezept, um ihn kaputt zu kriegen. (Fass ihn doch mal im laufenden Betrieb an. Wird er schön warm? Dann am besten gleich wegschmeissen.)

Jeder Ausgang kann ungefähr 20 mA liefern, also ungefähr soviel wie eine Standard-Diode braucht. ABER: Der Strom wird ohne Vorwiderstand nicht begrenzt. Wie der PIC auf so etwas reagiert, ist völlig undefiniert.
Dass du an den Beinchen der Diode eine Spannung von 2 V misst, ist völlig normal, weil das genau die Spannung ist, die über der Diode abfällt. (Die Diode "verbrät" quasi immer 2 V Spannung, wenn sie leuchtet. Die genaue Spannung ist je nach Typ und Farbe verschieden.)

Poste doch bitte einen Schaltplan, so wie du es jetzt aufgebaut hast und das komplette Programm. Dein Problem ist eigentlich eine Standardanwendung und sollte nicht schwer zu lösen sein.

Ich kann auch nur empfehlen, das entsprechende "Data Sheet" des PIC wirklich (und am besten von vorne nach hinten) durchzulesen. Ja, ich weiß, es ist mühselig. Man muss (und kann) auch beim ersten Lesen längst nicht alles davon verstehen. Aber das ist die beste Chance, sich mit PICs vertraut zu machen. "Trial and Error" funktioniert bei den Teilen eher schlecht.

Gruß
Phaidros

kalledom
10.02.2007, 10:37
Jeder Ausgang kann ungefähr 20 mA liefern, ....Das ist so nicht richtig.
30 Ausgänge wie z.B. beim PIC16F877 mal 20mA wären 600mA !!!
Richtig ist aber:
Absolute Maximum Ratings †

Total power dissipation (Note 1) ............................1.0W
Maximum current out of VSS pin ..............................300 mA
Maximum current into VDD pin ................................250 mA
Input clamp current, IIK (VI < 0 or VI > VDD).............. ± 20 mA
Output clamp current, IOK (VO < 0 or VO > VDD) ............ ± 20 mA
Maximum output current sunk by any I/O pin....................25 mA
Maximum output current sourced by any I/O pin ................25 mA
Maximum current sunk by PORTA, PORTB and PORTE (combined) ...200 mA
Maximum current sourced by PORTA, PORTB and PORTE (combined) 200 mA
Maximum current sunk by PORTC and PORTD (combined) .........200 mA
Maximum current sourced by PORTC and PORTD (combined) .......200 mA
Das sind Angaben, ab denen der PIC gerade noch nicht zerstört wird.
Kein Lebensmüder, der 70kg wiegt, wird sich an einem Seil aufhängen, das bei 70kg reißt.

tornado
10.02.2007, 17:53
So, hier ist der Schaltplan. Ich hatte leider nur Paint zur Hand :oops: aber ich hoffe, dass man das wichtigste erkennen kann.

Die Wiederstände sind folgende:
drei 220 Ohm --> R1
R2 --> an Pin RB3 --> 800 Ohm
an den anderen Pins --> 4,7k
drei 270 Ohm --> R3 habe ich jetzt nachträglich dran gemacht


R2 sind pull up Wiederstände.
Die Vierecke am Port B sind Pins um später ein Display anzuschliessen.

So, hier kommt der Code:



#include <pic1687x.h>
#define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit))
//-------------------------------------------------------------------------
void main (void)
{
TRISA = 0x00; //Port A = Ausgang mit LEDs
TRISB = 0x00011111; //RB0 - RB4 = Eingänge, RB5 - RB7
//= Ausgänge
//RB0 brauchen wir im Moment nicht
PORTA = 0b00000000;
PORTB = 0b00001110; // RB5-RB7 auf Low und RB1-RB4 auf High
//RB1 - RB4 auch mit Pull-up Wiederständen auf High
//RB4 scheint vertauscht zu sein. Bei 0 ist er High,
//bei 1 Low

do{
if (RB4 == 0){ //RB4 mit RB5, 6 oder 7 verbunden
PORTA = 0b00000001; //Led 1 geht an (das funktioniert richtig)
}
else if (RB3 == 0){ //funktioniert nur an RB5, 6 oder 7 OHNE
//Wiederstand R1!!!
PORTA = 0b00000010; //Led 2 geht an
}
else if (RB2 == 0){ //funktioniert nur an RB5, 6 oder 7 OHNE
//Wiederstand R1!!!
PORTA = 0b00000000; //Led 1 und 2 aus
}
else { //Keine Taste gedrück
PORTA = 0b00000011; //Led 1 und 2 an (funktioniert richtig)
}
}while (1); //immer wiederholen
}//()



Also ich habe keinen Grund gefunden warum das so nicht funktioniert.
Bei RB1 bis RB3 geht es ja nur wenn man R1 überbrückt.

Grüsse,
Tornado

phaidros
10.02.2007, 19:11
Du musst noch die PortA Pins als digital definieren, also ADCON1=6.
Sonst sind das analoge Eingangspins für den A/D-Converter.

phaidros
10.02.2007, 19:13
Der zweite Fehler ist :

TRISB = 0x00011111;

NEIN! Nicht 0x..., du meinst 0b...!

tornado
13.02.2007, 13:31
Ok, danke. Ich habe das korriegiert.

Ich werde diese Woche dann den fertigen code posten. Kann ja vieleicht noch jemanden anderen nützlich sein.

phaidros
13.02.2007, 21:28
Freut mich, wenn es funktioniert.

Gruß
Phaidros

tornado
16.02.2007, 17:07
So, hier ist der fertige und korrigierte Code.

Die 3x4 Tastatur kann man wie im Schaltplan anschliessen.

Ich habe das Programm so geschrieben, dass der PIC zwichen den Tasten 1, 2 und 3 und den Zeilen 2, 3 und 4 unterscheiden kann.
Ich brauche halt nicht alle 12 Tasten.
Wer sie doch braucht, muss nur den Code der ersten Zeile Kopieren und die Pins ändern.

Der Code ist schwar nicht sehr "sauber", aber ich hoffe man kann ihn verstehen und es nützt ja vieleicht auch noch jemanden der auch eine Tastatur an einen PIC anschliessen will.




#include <pic1687x.h>
#define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit))
//-------------------------------------------------------------------------

unsigned int zahl;

void main (void)
{
ADCON1=6; // PortA Pins als digital definiert
TRISA = 0x00; //Port A = Ausgang mit LEDs
TRISB = 0b00011111; //RB0 - RB4 = Eingänge, RB5 - RB7 = Ausgänge
//RB0 brauchen wir im Moment nicht
PORTA = 0b00000000;
PORTB = 0b00011110; // RB5-RB7 auf Low und RB1-RB4 auf High
//RB1 - RB4 auch mit Pull-up Wiederständen auf High
//--------------------------------------------------------------------------------
// 3x4 Matrix Tastatur
do{
zahl=0;
if (RB1 == 0){ // 1, 2 oder 3. RB5-7 werden nacheinander auf
//High gesetzt


RB5=1;
if (RB1==1){ //Taste=1
zahl=zahl+1;
RB5=0;
}
else{
RB5=0;
RB6=1;
if (RB1==1){ //Taste=2
zahl=zahl+2;
RB6=0;
}
else{
RB6=0;
RB7=1;
if (RB1==1){ //Taste=3
zahl=zahl+3;
RB7=0;
}
}
}
} //if (RB1==0)
else if (RB2 == 0){ // 4, 5 oder 6
zahl=3; // hier kann man den selben Code wie bei den
//Tasten 1-3 schreiben
zahl=3+1; //nur RB1 durch RB2 ersetzen usw.
}
else if (RB3 == 0){ // 7, 8 oder 9 das selbe wie eben
zahl=6;
zahl=6+1;
}
else if (RB4 == 0){ //#, 0 oder *
zahl=10; //10 ist eigendlich 0
}
else {
PORTA = 0b00000000;
}

for(j=0;j<2;j++){ // wenn j=2, dann muss resetet werden um eine
//andere Zahl zu drücken
// Schutz vor nicht gewollter Tasten-Eingabe

if (zahl==1){
PORTA = 0b00000001; //An dieser Stelle könnte auch ein
//Unterprogramm starten.
}
else if (zahl==2){
PORTA = 0b00000010;
}
else if (zahl==3){
PORTA = 0b00000011;
}
else if (zahl==4){//der Code müsste geändert werden. Im
//Moment würde er das hier
PORTA = 0b00000100; //Für die Tasten 4,5 und 6 ausgeben.
}
else if (zahl==7){
PORTA = 0b00001001;
}
else if (zahl==10){
PORTA = 0b00001010;
}
else{
PORTA = 0b00000000;
}
}
//zahl=0;

}while (1); //immer wiederholen
}//()



Viele Grüsse und noch mal Danke an alle die geholfen haben,
Tornado