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! :)
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 !)
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 ;-)
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.
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);
}
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???
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
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
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!
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?
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.
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.
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!
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
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
// 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.
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.