PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Anfänger erbittet Hilfe(2)



oderlachs
29.03.2017, 14:09
Hallo Freunde !

Nachdem ich mich einigermaßen, Dank Eurer Mithilfe !!!, in die PIC- Programmierung einarbeiten konnte, habe ich doch noch offene Grundfragen.:(
Ich Programmiere ja fast ausschließlich in C/C++. Fast 80%, wenn nicht noch mehr, der PIC -Anleitungen sind in ASSR gehalten, die C-Beispiele fast alle in Micro-C gehalten.
Nicht das ich es erst mal nicht verstehe damit umzugehen, aber das Ansprechen der I/O Ports macht mir noch große Sorgen und ist damit bei meinen Programm oft eine Fehlerquelle.

Das von Microchip als PDF verfasste I/O Referendum, ist auch fast nur in ASSR gehalten.
Nun steht vor mir die Frage wie spreche ich I/O-Ports/Pins in MPLABX XC-8 an , da lese ich was ConbitsXX und LATxx, :confused:
aber so richtig kann ich mich damit nicht darüber Klar werden, wie ich es bewerkstelligen kann, einzelne Port-Pins zu setzen, lesen usw...:(



void init()
{
TRISD = 0b00001111; // D0..D3 INPUT D4..D7 OUTPUT
PORTD = 0b00001111; // PULLUP D0...D3
}

void main(void) {
init();
while(1){//Endlosschleife
/// RD4 = 1; // geht LED4 ON
RD4 = RD0; // RD4(LED4 ON ) = HIGH wenn RD0 = HIGH Geht nicht ?????
}
return;
}


Wer hätte denn mal die Freundlichkeit an Hand von einem 3..4 Zeilen Beispiel, mir das aufzuzeigen , wie das richtig zu bewerkstelligen ist ??

Ich danke schon mal im Voraus

Mit Gruss
Gerhard

witkatz
29.03.2017, 20:58
Die Konfiguration der Portpins ist leider nicht allgemeingültig für alle PICs, da ist das Datenblatt dein A&O für I/O ;-)
Der PIC16F877A z.B. hat keine Pullups am PortD. Also müssen Pullups extern angeschlossen oder auf dem Entwicklungsboard gejumpert werden. Auch hat der 877 keine LAT Register, man gibt also direkt auf PORT aus.

Die Pullups der Ports, die welche haben werden über Flags in den SFR (special function register) aktiviert. Z.B. um die Pullups am PortB des PIC16F877A zu aktivieren wird das Flag nRBPU im Register OPTION_REG gelöscht. Der XC8 bringt für alle Register Definitionen und Strukturen mit Bitfeldern mit und so gibt es diverse Möglichkeiten auf die Register und auf die Flags zuzugreifen. Um das nRBPU Flas im OPTION _REG zu löschen fallen mir drei gleichwertige ein:

OPTION_REG &= ~(1 << _OPTION_REG_nRBPU_POSN);
OPTION_REG &= ~_OPTION_REG_nRBPU_MASK;
OPTION_REGbits.nRBPU = 0;
nRBPU = 0;


Auch beim Zugriff auf die I/O Pins gibt es diverse Möglichkeiten. Ich definiere mir meistens Labels für die Hardwarezuordnung und nutze die von XC8 fürs PORTD definierte Struktur PORTDbits mit Bitfeldern. Für die meisten Register definiert XC8 solche Strukturen mit ABCbits im Namen. Um nah an deinem Beispiel zu bleiben würde ich die Pins für Taster und LED mit Labeln benennen und so sähe das bei mir vielleicht aus
#include <xc.h>
#define TasterLEDan PORTDbits.RD0
#define TasterLEDaus PORTDbits.RD1
#define LED4 PORTDbits.RD4

void main(void) {
TRISD = 0b00001111; // D0..D3 INPUT D4..D7 OUTPUT
while(1){
if(TasterLEDan == 0){
LED4 = 1;
}
if(TasterLEDaus == 0){
LED4 = 0;
}
}
}


Hier noch ein paar deutschsprachige Tutorials, die das Thema Benutzung der I/O Pins in C beleuchten:
https://pic-projekte.de/blog/pic-c-tutorial-speziell-fur-pic/
http://www.hs-ulm.de/users/vschilli/Mikrocontroller/uCQ/_downloads/uCquick-X.pdf -> s. Kapitel 3
http://www.sprut.de/electronic/pic/c/pic_c/pic_c90_pic_spezifisches.html#io

*******
Noch ein Nachtrag. Um nachzusehen, welche Definitionen für ein bestimmtes Register im XC8 vorliegen, schaue ich im entspr. Header nach. Dafür reicht ein STRG+Klick auf den Registernamen. Gebe z.B. im Quelltext PORTD ein, mach ein STRG+Klick drauf und schwups bist du z.B. im pic16f877a.h an der Stelle der für PORTD relevanten Definitionen. Nur die Bitdefinitionen wie RD0 und RD4 findet man an etwas anderer Stelle in der Headerdatei. Ob man in C PORTDbits.RD4 = 0 hinschreibt oder RD4 = 0 ist letztendlich Geschmacksache. Aus beidem wird im Assembler das gleiche BCF PORTD, 0x4

Gruß
witkatz

Klebwax
29.03.2017, 21:53
Ok, also erst mal ein paar grundsätzlich Dinge:

Die I/O Pins sind in Ports organisiert. Diese belegen eine Position im Speicher und sind (theoretisch) so breit, wie der Datenbus des Rechners. Bei den PIC12, PIC16 und PIC18 also 8Bit ( dazu der XC8 ), bei den PIC24 und den dsPIC33 16Bit ( dazu der XC16 ) usw. Das "theoretisch" soll sagen, daß nicht in jedem Port alle Bits vorhanden sind.

Die Ports heißen PORTA, PORTB ... und können so direkt angesprochen werden.

PORTA = 0b101010;

Wenn man beim Projekt den richtigen Prozessor eingestellt hat, zieht xc.h die passenden Headerfiles an, damit PORTA auch an der Adresse landet, die zum Prozessor passt.

Eigentlich will man meist nicht einen Port sondern nur ein Bit in einem Port ansprechen. Auch dafür gibts Unterstützung in den Headerfile. Für jeden Port wie auch für jedes Special Function Register ist ein Bitfeld definiert, über das man Bits einzeln ansprechen kann. Bitfelder in C sind Structuren und werden wie solche angesprochen. Den Namen haben die Microchip-Leute so konstruiert: zuerst der Portname (oder das SFR) dann (kleingeschrieben) bits. Das ist der Structurname, danach folgt ein Punkt, wie in C üblich, und dann der Name des Bits oder Bitfelds.

Das klingt jetzt bestimmt sehr trocken, daher ein paar Beispiele:

PORTA = 0b10101010; // ganzen Port setzen

Wobei, es gibt Gründe, die ich jetzt hier nicht vertiefen will, nicht auf den Port sondern auf das Portlatch zu schreiben. Also

LATA = 0b10101010;

Und jetzt einzelne Bits:

LATAbits.LATA0 = 1; // Bit 0 von Porta bzw RA0 auf 1
TRISAbits.TRISA0 = 1; // RA0 auf Input
if ( PORTAbits.RA0 == 1) {....}

So läßt sich jedes Portbit einzeln steuern. Und die Headerfiles sorgen dafür, daß man nicht vorhandene Bits eines Ports garnicht erst ansprechen kann.

Damit man den Code besser mit der Hardware in Zusammenhang bringt, definiere ich mir meisst passende Namen.

#define LED_RED LATBbits.LATB3

Wenn jetzt noch die LED vom Port nach GND geht, kann ich im Programm einfach schreiben:

LED_RED = 1;

und sie geht an.

Diese Definition der Bitfelder gibt es für alle Register der PICs. Daher sind die Headerfile recht lang. Selbst für den simplen PIC16F1825 sind es über 7000 Zeilen, bei den großen wesentlich mehr. Hier noch ein Beispiel für ein Bitfeld mit Felder größer als ein Bit. CCP1CON ist ein Register aus dem PWM Controller

CCP1CONbits.CCP1M ist 4 Bits breit, CCP1CONbits.DC1B und CCP1CONbits.P1M jeweils 2 Bit. Die Bezeichnung CCP1CON und CCP1M findet man genauso im Datenblatt.

Man kann also schreiben

CCP1CONbits.CCP1M = 0b0100; // Capture mode: every falling edge

exakt wie es im Datenblatt steht.

Sorry, wenn das etwas lang geworden ist. Ich hoffe aber, es ist verständlich.

MfG Klebwax

Klebwax
30.03.2017, 01:34
. Ob man in C PORTDbits.RD4 = 0 hinschreibt oder RD4 = 0 ist letztendlich Geschmacksache

Ist schon richtig, RD4 ist ja auch nur ein #define auf PORTDbits.RD4. Ist aber wohl nicht überall durchgehalten worden, bin damit schon mal auf die Nase gefallen. Ich mach mir daher immer eigene die ich auf die generische lange Bezeichnung beziehe, selbst wenn sie nur AUX1, AUX2 oder DEBUGBIT heißen. Die gleichen Labels trag ich dann auch bei meinem saleae LA ein, dann kann ich direkt Source und LA vergleichen und wenn alles Gute zusammenkommt, steht im Schaltplan auch noch der gleiche Name.

MfG Klebwax

witkatz
30.03.2017, 02:46
RD4 ist ja auch nur ein #define auf PORTDbits.RD4.
Nein, ist es nicht. Die SFR Bit Definitions sind absolut adressierte Bitvariablen und haben in der Definition keinen Bezug zu den Bitfeldstrukturen. Das RD4 des PIC16F877a ist definiert als:
extern volatile __bit RD4 @ (((unsigned) &PORTD)*8) + 4;

Klebwax
30.03.2017, 08:16
Nein, ist es nicht. Die SFR Bit Definitions sind absolut adressierte Bitvariablen und haben in der Definition keinen Bezug zu den Bitfeldstrukturen. Das RD4 des PIC16F877a ist definiert als:
extern volatile __bit RD4 @ (((unsigned) &PORTD)*8) + 4;

Hast recht. Hab das mit den 16 Bittern durcheinandergebracht. Da sind die kurzen Bezeichnungen nur #defines. Und da haben diese auch ein Underline vorne.

#define _RA4 PORTAbits.RA4

Das mit dem Underline ist wohl auch der Grund, warum ich mir die "kurzen" Namen abgewöhnt habe. Da muß man beim Wechseln zwischen 8 und 16 Bittern immer umdenken.

MfG Klebwax

witkatz
30.03.2017, 10:07
der Grund, warum ich mir die "kurzen" Namen abgewöhnt habe.
Ich benutze auch die Bitfeldstrukturen und Definitionen die ich im Header nach STRG+Click auf den Registernamen sehe, die sehe ich dann sofort. Die kurzen Namen stehen im Header verstreut und man muss schon wissen, wonach man sucht. Für I/O Pins mag das evtl. praktikabel sein, nicht aber für SFR Flags.
In den Bitfeldern der SFR gibt es oft Subsets, wie das von dir genannte 4 Bit Große CCP1CONbits.CCP1M. Das geht mit Bitdefinitions schon mal nicht.

oderlachs
30.03.2017, 12:37
Hallo Freunde....
recht , recht herzlichen Dank das hat mich ein ganzes Stück weitergebracht und ich habe aus Euren Antworten mehr Wissen entnehmen können, als wie aus dem "Grossem PIC Micro Handbuch" vom Franzi'sVerlag u.a.m.
Wenn man da nur rein schaut, kann man zwar ganze " C/C++ Bibeln" schreiben, mit Strukturen und Klassen von Katzen,Hunden, Autos und was weiss ich, aber nicht einen Port abfragen oder einen Port setzen...
Leider merkt man erst nach dem Kauf , für was für "literarischen Schrott" man sein gutes Geld ausgegeben hat :(
Vielleicht mache ich meine Fehler auch noch deswegen, da ich ja bislang nur AVR Chips programmierte und das so im Hinterkopf noch habe. Nun ich habe ja auch erst 3Monate die PIC Schule besucht ;)

Gruss und Dank

Gerhard

Nachtrag : Habe jetzt so recht und schlecht ein Input/Output Code fertig gebracht der auch geht, aber "begriffe" mit "LATxx" will mein CX8 Compiler gar nicht...wahrscheinlich bin ich wirklich für die PIC s zu blöde... ;)

- - - Aktualisiert - - -






Wobei, es gibt Gründe, die ich jetzt hier nicht vertiefen will, nicht auf den Port sondern auf das Portlatch zu schreiben. Also

LATA = 0b10101010;

Und jetzt einzelne Bits:

LATAbits.LATA0 = 1; // Bit 0 von Porta bzw RA0 auf 1
TRISAbits.TRISA0 = 1; // RA0 auf Input
if ( PORTAbits.RA0 == 1) {....}

So läßt sich jedes Portbit einzeln steuern. Und die Headerfiles sorgen dafür, daß man nicht vorhandene Bits eines Ports garnicht erst ansprechen kann.

Damit man den Code besser mit der Hardware in Zusammenhang bringt, definiere ich mir meisst passende Namen.

#define LED_RED LATBbits.LATB3

Wenn jetzt noch die LED vom Port nach GND geht, kann ich im Programm einfach schreiben:

LED_RED = 1; und sie geht an.

MfG Klebwax

Kann es sein das mit meinem CHIP :"PIC16F877A" gar keine "LATxx-Programmierung" geht und ich deshalb immer Fehlermeldungen bekomme ???

witkatz
30.03.2017, 14:19
Vielleicht wusste Klebwachs nicht um welchen PIC es sich handelt bzw. hat allgemein geantwortet. Den Blick ins Datenblatt wird dir leider keiner abnehmen.

Kann es sein das mit meinem CHIP :"PIC16F877A" gar keine "LATxx-Programmierung" geht und ich deshalb immer Fehlermeldungen bekomme ???

Auch hat der 877 keine LAT Register, man gibt also direkt auf PORT aus.

oderlachs
30.03.2017, 15:05
Lach Witkatz...als ich gepostet hatte und nochmals alles gelesen hatte da wusste ich es, das ich es in Deinem Posting überlesen hatte.
Den Blick ins Datenblatt soll mir auch eigentlich keiner abnehmen, wenn ich mich auch mit English sehr sehr schwer tue...nur als Einsteiger sei mir mal solch Unwissenheit noch mal verziehen werden können....

Zum grossen (UN-)Glück fiel jetzt noch einen 8 polige Stiftleiste aus dem Entwicklerbord, nur Klebelötung...
Ich dachte eigentlich das das Nachlöten von Nah und Fernost-Leiterplatten der Vergangenheit angehört, aber wurde des besseren belehrt.
Ich kenne das vom Beruf her, von 10 def. Funkgeräten der CB Funk-Branche waren bestimmt von 8 nur Leiterplatten nur nach zulöten um wieder zu funktionieren...
Wer weiss welche Überraschungen ich noch erlebe, aber alle Wege zum Erfolge sind nun mal mit Stolpersteinen gepflastert...

Gerhard

Klebwax
30.03.2017, 15:44
Kann es sein das mit meinem CHIP :"PIC16F877A" gar keine "LATxx-Programmierung" geht und ich deshalb immer Fehlermeldungen bekomme ???

Sorry, hab erstens nicht auf den Typ geachtet und zweitens auch nicht gewusst, das der keine LAT-Register hat. Ich hab nur schnell in einem Projekt mit dem PIC16F1825, das ist einer der wenigen 8-Bitter, die ich verwende, in die Headerfiles geschaut.

MfG Klebwax

oderlachs
30.03.2017, 16:53
Hallo Klebwax !
ist doch nicht so schlimm habe ich wieder dazu gelernt.....:) Mein Board ärgert mich auch, schon die 3. Pinleiste nach gelötet...nun auch noch die ICSP Stifte, erklärt mir warum oft der PIC Chip nicht "Anwesend" war für das PICKit3...

Ja mein Entwicklerbord ist für den 40 Pinner gebaut...für meinen Experimente reicht das vollkommen..

Trotzdem Danke vielmals....Als Rentner habe ich ja Zeit zu probieren, aber man muss schon die Grundlagen wissen...
Ich weiss ja nun wo ich im Datenblatt nachschauen kann um die Namen der I/O zu finden, bzw. auch der der LAT.. falls es welche gibt.

Gruss & Danke

Gerhard