Forum: Mikrocontroller und Digitale Elektronik PIC18F1220 (C-Code) Port (einzelnen Pin) abfragen


von Gerrit (Gast)


Lesenswert?

Hi! Seit etwa einer Woche beschäftige ich mich mit PICs, z.Z. eigentlich 
nur mit dem 18F1220 (weil ich lieber in C schreiben möchte). Ich benutze 
MPLAB X und PICkit3. Soweit so gut!

Bis jetzt habe ich es geschafft Ports ein und auzuschalten (LED blinken 
lassen), den Wert eines Potis mit ADC zu bestimmen und ein LCD zu 
initialisieren (mehr oder weniger gut). Nun wollte ich wegen dem LCD die 
Busy-Flag abfragen können und da viel mir auf, dass ich bis dahin noch 
nie ein High-Low Signal an einem Pin abgefragt habe. Doch genau das 
bekomm ich einfach nicht gebacken und weiß nun einfach nicht mehr 
weiter... :(

Also, ich habe mir einen PIN vom PORTB (RB4 - Pin 11) als Eingang 
deklariert:

    TRISB = 0b00001000;   oder TRISB=0x08;    (da 1 = Input)
    PORTB = 0x00;

Laut Datenblatt ist PORTB prinzipell auf TTL geschaltet.

Ich frage RB4 ab:

    if (PORTB & 0b00001000) { LED_blink(); }

Wenn ich 5V auf RB4 lege passiert aber nichts! -Warum? Was mache ich 
falsch? (die if-Abfrage wird natürlich permanent abgefragt)

Würde mich wirklich freuen, wenn mir jemand hier unter die Arme greifen 
könnte! :)

von Dirk H. (dirk09)


Lesenswert?

Gerrit schrieb:
> Ich frage RB4 ab:
>
>     if (PORTB & 0b00001000) { LED_blink(); }

Kann es sein, dass du Bit 3 abfragst? Zähliung gebinnt ja mit 0.
(Kenne mich aber nicht mit PICs aus !)

von Master S. (snowman)


Lesenswert?

funktioniert "LED_blink();" alleine? falls nein, liegt da der hund 
begraben.

ps: busy-flag (pin) abfragen, macht eigentlich niemand; warte lieber ein 
bischen, wie alle anderen auch ;-)

von Gerrit (Gast)


Lesenswert?

Das war nur ein Tippfehler. Ich frage so natürlich RB3 ab. Aber genau an 
dem "arbeite" ich auch... :(

von Gerrit (Gast)


Lesenswert?

ja, wenn ich die if-Abfrage mit irgend einem Mist auf 1 setze, läuft das 
Unterprogramm.

von Lehrmann M. (ubimbo)


Lesenswert?

Gerrit schrieb:
> Also, ich habe mir einen PIN vom PORTB (RB4 - Pin 11) als Eingang
> deklariert:
>
>     TRISB = 0b00001000;   oder TRISB=0x08;    (da 1 = Input)
>     PORTB = 0x00;

soweit gut.

Die Zuweisung PORTB = 0x00;? Die läuft doch hoffentlich nicht in der 
Endlosschleife oder?

In PORTx wird NIE NIE NIE NIE geschrieben. Wenn ich schreiben möchte 
(nur bei Output) dann schreibt man in LATx. In PORTx wird nur gelesen.

Gerrit schrieb:
> Ich frage RB4 ab:
>
>     if (PORTB & 0b00001000) { LED_blink(); }

Auch das ist soweit strukturtechnisch richtig. Du frägst Bit3 ab. Also 
RB3 und nicht wie von dir gewünscht RB4. Da hat mein Vorredner 
vollständig recht.

von Gerrit (Gast)


Lesenswert?

also, ich habs jetzt geändert... ich pack jetzt mal das gesamte programm 
hier rein. im moment läuft das programm so ab: eien led blinkt in 
anhängigkeit eines potis. dann die besagte abfrage. WENN LED_blink 
läuft, blink es nur noch sehr sehr langsam. nur komm ich da so nie 
hin...

---------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <p18f1220.h>
#include "delays.h"
#include <adc.h>

#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF

int speicher = 0, i = 0;

void LED_blink(void);

void main(void) {

    INTCON = 0X00;
    ADCON0 = 0b00000100;
    ADCON1 = 0b00000000;
    ADCON2 = 0b10000011;
    TRISA = 0xFE;
    LATA = 0x00;
    TRISB = 0b00010000;
    LATB = 0x00;

while (1) {
    ADCON0bits.ADON = 1;
    ADCON0bits.GO_DONE = 1;
    while(ADCON0bits.GO_DONE) {
        speicher = ADRES;
        }

    if (i>speicher) {
        LATA=0x00;
    }
    if (i<speicher) {
        LATA=0x01;
    }
    if (i==1024) {
        i=0;
    }
    i++;

     if (PORTB & 0b00010000) {
        LED_blink();
        }
    }
}

void LED_blink(void) {
    PORTA=0x00;
    Delay1KTCYx(1000);
    PORTA=0x01;
    Delay1KTCYx(1000);
}

von Gerrit (Gast)


Lesenswert?

Jetzt versteh ich garnicht mehr...

Ich schreibe nun PORTB ständig in eine Variable und mach ein break bei 
write. Habe PORTB komplett als Eingang deklariert und dann alle Pins mal 
auf 5V gelegt. Ergebnis. RB4 funktioniert nicht!!! Habs jetzt auf RB5 
umgestellt un nun klappt alles wie gewünscht! Dabei habe ich 
festgestellt, dass die "1" auch noch kurz nachdem das Kabel gezogen 
wurde noch steht. Daher hab ich nun RB5 über einen Widerstand an GND 
gelegt, damit der Pin sofort wieder auf 0 fällt.

Kann es sein, dass ich mir den RB4 PIN zerstört habe, weil ich keinen 
Widerstand verwendet habe???

von Frank K. (fchk)


Lesenswert?

Gerrit schrieb:

>      if (PORTB & 0b00010000) {

Du kannst auch schreiben:

       if (PORTBbits.RB4) {

Genauso gibts:
LATBbits.LATBx
PORTBbits.RBx
TRISBbits.TRISBx

(x zwischen 0 und 7)
Das gibt auch für die anderen Ports. Das ist vielleicht übersichtlicher.

Und LATAbits.LATA0=1; funktioniert natürlich auch.

fchk

von Frank K. (fchk)


Lesenswert?

Gerrit schrieb:

> Kann es sein, dass ich mir den RB4 PIN zerstört habe, weil ich keinen
> Widerstand verwendet habe???

Wahrscheinlicher ist, dass Du in die Analogpin-Falle getappt bist. Schau 
mal, welche Funktionen noch auf dem Pin liegen. Siehst Du das AN6? Bei 
den PICs ist es so, dass alle Pins mit Analogfunktionen auf Analog 
stehen. Du musst die Pins, erst auf digital umschalten. Das machst Du 
mit dem Register ADCON1 (falls die Familie nur max 8 Analogpins hat) 
oder ADCONx (x=1...n, je nachdem, wie viele Analogpins da sind, siehe 
Datenblatt). Wenn Du keine Analogfunktionen nutzt, mach einfach ein 
ADCON1=0xff; und dann geht das.

PS: Da fällt jeder mal drauf rein.

fchk

von Gerrit (Gast)


Lesenswert?

VIELEN, VIELEN, VIELEN DANK!!! -Das scheint es gewesen zu sein! Jetzt 
klappt´s an allen Pins!

Das einzige, was mich noch ein wenig stuzig macht ist aber, dass an 
manchen Pins ohne Widerstand zu GND die Spannung recht lange gehalten 
wird! Das scheint so aber normal zu sein, oder?

Nochmals danke!

von Michael S. (rbs_phoenix)


Lesenswert?

Lehrmann Michael schrieb:
> In PORTx wird NIE NIE NIE NIE geschrieben. Wenn ich schreiben möchte
> (nur bei Output) dann schreibt man in LATx. In PORTx wird nur gelesen.

Ich hab das schon öfter gelesen und gehört. Doch im Datenblatt steht ja: 
"Reading the PORTA register reads the status of the pins, whereas 
writing to it will write to the port latch. The Data Latch register 
(LATA) is also memory mapped. Read-modify-write operations on the LATA 
register read and write the latched output value for PORTA."
...
"EXAMPLE 10-1: INITIALIZING PORTA:
1
CLRF PORTA  ; Initialize PORTA by
2
    ; clearing output
3
    ; data latches
4
CLRF LATA  ; Alternate method
5
    ; to clear output
6
    ; data latches
-> ALTERNATE, also Alternative Methode.

Ich frag nur aus einem Grund:
Ich hab mit PIC-Programmierung auf einem 16F84A angefangen und dieser 
hat wie manch andere alte PICs kein LATx Register. Deshalb ist bei mir 
drinne in PORTx zu schreiben und zu lesen. Und auch bei den neueren 
PICs, die ein LATx Register haben, funktioniert es auch mit PORTx. Warum 
MUSS/SOLL man UNBEDINGT das LATx-Register benutzen?


Frank K. schrieb:
> PS: Da fällt jeder mal drauf rein.

Das stimmt;)


Gerrit schrieb:
> Das einzige, was mich noch ein wenig stuzig macht ist aber, dass an
> manchen Pins ohne Widerstand zu GND die Spannung recht lange gehalten
> wird! Das scheint so aber normal zu sein, oder?

Welche denn genau? Vielleicht hängt es mit einem Internem Modul 
zusammen. Eine Kapazität hast du aber nicht dran, oder?

von Michael S. (rbs_phoenix)


Lesenswert?

Gerrit schrieb:
> Dabei habe ich
> festgestellt, dass die "1" auch noch kurz nachdem das Kabel gezogen
> wurde noch steht. Daher hab ich nun RB5 über einen Widerstand an GND
> gelegt, damit der Pin sofort wieder auf 0 fällt.

Welches Kabel ziehst du denn? Wenn es das Kabel vom Netzteil ist, dann 
ist es klar, wobei es bei allen PINs sein sollte. Im Netzteil ist ein 
Kondensator drin, der erstmal entladen werden muss. Wie beim Fernseher, 
wo die Standby-LED auch langsam ausgeht.

von Gerrit (Gast)


Lesenswert?

ne ne... nur das kabel, was ich auf RB4 gelegt hab... das meine ich mit 
"ziehen".

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Gerrit schrieb:
> Das einzige, was mich noch ein wenig stuzig macht ist aber, dass an
> manchen Pins ohne Widerstand zu GND die Spannung recht lange gehalten
> wird! Das scheint so aber normal zu sein, oder?

Als Eingänge sind µC Ports sehr hochohmig, Sie halten die Ladung lange 
und wenn nichts dranhängt ist der Wert Zufall.

von Gerrit (Gast)


Lesenswert?

Der Rächer der Transistormorde schrieb:
>> Das einzige, was mich noch ein wenig stuzig macht ist aber, dass an
>> manchen Pins ohne Widerstand zu GND die Spannung recht lange gehalten
>> wird! Das scheint so aber normal zu sein, oder?
>
> Als Eingänge sind µC Ports sehr hochohmig, Sie halten die Ladung lange
> und wenn nichts dranhängt ist der Wert Zufall.

perfekt! habs mir aber schin iwie gedacht... ;)

danke euch allen!

von Frank K. (fchk)


Lesenswert?

Michael Skropski schrieb:

> Ich frag nur aus einem Grund:
> Ich hab mit PIC-Programmierung auf einem 16F84A angefangen und dieser
> hat wie manch andere alte PICs kein LATx Register. Deshalb ist bei mir
> drinne in PORTx zu schreiben und zu lesen. Und auch bei den neueren
> PICs, die ein LATx Register haben, funktioniert es auch mit PORTx. Warum
> MUSS/SOLL man UNBEDINGT das LATx-Register benutzen?

Read-Modify-Write-Zyklen.

PORTA|=0x01;
heißt:
PORTA lesen
Bit setzen
LATA(!!!) schreiben (PORTA ist ja read-only, Schreibzugriffe auf PORTA 
landen tatsächlich in LATA)

Heißt: LATA wird abhängig von externen Zuständen modifiziert. Das kann 
dazu führen, dass bei der obigen Anweisung nicht nur Bit 0 in LATA 
geändert wird, sondern auch andere Bits, was aber beim Anblick der 
Programmzeile so nicht auf dem ersten Blick klar ist. Das garantiert 
viele Stunden Spaß bei der Fehlersuche insbesondere bei 
Open-Collector-Schaltungen.

Bei
LATA|=0x01;
heißt das:
LATA lesen
Bit setzen
LATA schreiben.
Heißt also: In LATA wird unter Garantie nur Bit 0 geändert, sonst 
nichts. Das ist auch das Verhalten, das ich erwarte.

fchk

von Michael S. (rbs_phoenix)


Lesenswert?

Frank K. schrieb:
> Heißt: LATA wird abhängig von externen Zuständen modifiziert. Das kann
> dazu führen, dass bei der obigen Anweisung nicht nur Bit 0 in LATA
> geändert wird, sondern auch andere Bits, was aber beim Anblick der
> Programmzeile so nicht auf dem ersten Blick klar ist. Das garantiert
> viele Stunden Spaß bei der Fehlersuche insbesondere bei
> Open-Collector-Schaltungen.

Versteh mich nich falsch, ich glaub dir ja und will keinen auf trozig 
machen, nur will ich es verstehen.

Bei "PORTA|=0x01;" ließt er die Pegel am PORT, setzt das bit und 
schreibt es wieder ins Latch (da WR PORT und WR LAT gleich sind, Siehe 
Datenblatt Seite 88 [PDF 90], 
http://ww1.microchip.com/downloads/en/DeviceDoc/39605F.pdf ).

Bei "LATA|=0x01;" ließt er die Latches, also die Soll-Pegel, und setzt 
dort das Bit und schreibt es ins Latch. Doch die Soll-Pegel sind doch 
dann am PORT. Zumindest bei den als Ausgang definierten Pins, doch die 
sind ja auch nur die von interesse.

So wie ich das im Moment verstehe, ist es so, dass es nur einen 
Unterschied macht, wenn der Sollwert nicht am Pin anliegt. Und dies wäre 
ja nur, wenn von außen ein Pegel erzwungen wird was einem Kurzschluss 
gleichkommt. Danach kann man den Pin sowieso vergessen.

Kleines Beispiel:
1
TRISB = 0xF0;   // An RB4..7 sind Pulldown-R's, RB0..3 ist Ausgang
2
3
PORTB |= 0x01;   // RB0 soll auf High gesetzt werden
4
                 // 1. Schritt: PORTB lesen -> 00000000
5
                 // 2. Schritt: bit setzen -> 00000001
6
                 // 3. Schritt: PORTB bzw LATB schreiben -> 00000001
7
                 // Ausgang ist auf High, dass Latch wird ja geschaltet und der MOSFET schaltet den Ausgang
8
9
PORTB |= 0x02;   // RB1 soll auf High gesetzt werden
10
                 // 1. Schritt: PORTB lesen -> 00000001
11
                 // 2. Schritt: bit setzen -> 00000011
12
                 // 3. Schritt: PORTB bzw LATB schreiben -> 00000011
13
                 // Ausgang ist auf High, dass Latch wird ja geschaltet und der MOSFET schaltet den Ausgang


Frank K. schrieb:
> Heißt also: In LATA wird unter Garantie nur Bit 0 geändert, sonst
> nichts. Das ist auch das Verhalten, das ich erwarte.

Das ergibt Sinn, nur frag ich mich eben, warum das im anderen Fall nicht 
so ist. Das Latch schaltet ja den Ausgang auf den gewünschten Zustand 
und den liest man dann mit PORTB ein. Im Blockdiagramm für RB2 sieht man 
das ganz gut. Das D-FF wird gesetzt, es geht durch den (durch TRISB) 
"angeschalteten" Buffer zum Ausgang. Wenn man dann ließt, ließt man 
genau das, was man vorne reingegeben hat.

von Frank K. (fchk)


Lesenswert?

Michael Skropski schrieb:

> So wie ich das im Moment verstehe, ist es so, dass es nur einen
> Unterschied macht, wenn der Sollwert nicht am Pin anliegt. Und dies wäre
> ja nur, wenn von außen ein Pegel erzwungen wird was einem Kurzschluss
> gleichkommt. Danach kann man den Pin sowieso vergessen.

Nicht unbedingt. Du könntest z.B. den Pin mit dem ODCx Register auf Open 
Drain schalten.(*) Dann kann der Pin nur noch gegen Ground ziehen, gegen 
VDD wird er durch einen Pullup gezogen. Wenn der Pin extern auf Ground 
gezogen wird, willst Du es garantiert nicht, dass Du dann den zufällig 
auch auf Ground ziehst, nur weil Du irgendeinen anderen Pin änderst. Das 
würde garantiert Ärger mit dem Protokoll geben, bei 1-Wire z.B.

(*) Schau, ob Dein PIC das kann. Wenn ja, dann gibts nicht nur ein 
TRISB, LATB und PORTB, sondern auch ein ODCB. Manche können auch nur 
spezielle Pins auf Open Drain schalten. Dann gibts mehrere 
ODCONx-Register.

Blöd wird es auch, wenn Du bidirektional arbeitest und die Datenrichtung 
mittendrin umkehrst. Dann musst Du auch darauf achten, wie Dein LAT vor 
dem Umschalten steht.

Das sind nur zwei Beispiele, die mir gerade so einfallen. Es ist auf 
jeden Fall sauberer.

fchk

PS: Das ganze gilt nicht nur für PIC18, sondern genauso für PIC24/dsPIC 
und PIC32. Da isses genauso.

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.