PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Register-Port-Bits direkt ansteuern



theodrin
28.12.2007, 11:42
Hallo!

Edit: Programmieren in C und zwar C18 von Microchip

Ich hab ne Frage bezüglich der Ansteuerung von einzelnen Port-Bits eines Registers. Also ich dachte das geht so ähnlich:

#define E PORTBbits.RB0
#define F PORTBbits.RB1

TRISB = 0x00; //Alle Bits von Port B als Ausgang verwenden

E = 1; //RB0 auf HIGH setzen -> Leuchtdiode leuchtet
F = 1; //RB1 auf HIGH setzten -> Leuchtdiode an RB1 leuchtet, Leuchtdiode an RB0 ist dunkel

Da liegt auch schon das Problem. Ich will das beide leuchten! Wieso leuchtet nach F = 1; nur mehr die an RB1 und die an RB0 nicht mehr? Ich hab ja beide Ausgänge auf HIGH geschalten!!
Bitte um Hilfe!!

Anbei noch der gesamte Code.




/** I N C L U D E S ************************************************** ********/
#include <p18cxxx.h>
#include <stdlib.h>
#include <delays.h>
#include "waits.h" // für die Warteschleife
/** D E C L A R A T I O N S **************************************************/

#define LCD_TEST 1
#define PORT_TEST 1
#define WAIT_TEST 0

#define TRIS_LCD TRISB
#define LCD_PORT PORTB
#define LCD_STEUER_PORT PORTD

#define D0 PORTBbits.RB0 //Dx .... Datenleitung x
#define D1 PORTBbits.RB1
#define D2 PORTBbits.RB2
#define D3 PORTBbits.RB3
#define D4 PORTBbits.RB4
#define D5 PORTBbits.RB5
#define D6 PORTBbits.RB6
#define D7 PORTBbits.RB7
#define RS PORTDbits.RD0 //Register Select
#define RW PORTDbits.RD1 //Read / Write
#define E PORTDbits.RD2 //Enable


/** Configuration ************************************************** ******/
#pragma config FOSC = HS //Externer Takt
#pragma config PWRT = ON
#pragma config BOR = OFF
#pragma config WDT = OFF //Watchdog Timer
#pragma config LVP = ON //Low Voltage ICSP
#pragma config CPUDIV = OSC1_PLL2 //CPU-Frequenz nicht dividiert, PLL durch 2;
#pragma config PLLDIV = 5

#pragma code

void main(void)
{

#if WAIT_TEST
{
int a=0;
TRISB = 0x00;
while(a<5)
{
LATB = 0x0F;
wait_s(1);
LATB = 0x00;
wait_s(1);
a++;
}
}
#endif

#if PORT_TEST
{
int a=0;
TRISB = 0x00;
TRISD = 0x00;
while(a<5)
{
D0 = 1;
E= 1;
wait_s(1);
D1 = 1;
wait_s(1);
D2 = 1;
wait_s(1);
D3 = 1;
wait_s(1);
D3=0;
D2=0;
D1=0;
D0=0;
wait_s(2);
a++;
}
}

}


Im Code stecken noch mehr Dinge drinnen. Die wait_s(x); sind in einem anderen C-File, aber funktionieren ganz gut. Also da wartet er x-Sekunden.

Ja ich hoffe euch fällt dazu was ein.

lg

HF SHOOTER
28.12.2007, 14:25
Hi,

um einezlene Bits zu ändern musst du das mit einem Komma hinter dem Register angeben:


bsf PORTB,0 ; RB0 wird gesetzt
bcf PORTB,7 ; RB7 wird gelöscht

Mal ein Beispeil:

#define E PORTB,0
#define F PORTB,1

; E = 1 geht nicht, das ist Syntax einer Hochsprache. Du musst machen:
bsf E
bsf F

; um es auf 0 z6u setzen:
bcf E
bcf F

Hier eine Befehlsliste (http://sprut.de/electronic/pic/assemble/befehle.html)


Edit: Huuups habe nur die ersten paar Zeilen gesehn und dachte daher es sei Assembler, mein Beitrag ist somit hinfällig! Sorry.

mfg
Benny

theodrin
30.12.2007, 13:23
Hallo!

Problem gelöst!

Ich muss einfach nicht PORTB sondern LATB verwenden.

also
#define D0 LATBbits.LATB0
...

Pfu, wäre das mal geschafft. Aber wieso das so ist weiß ich nicht. Falls einen schlauen Programmierer gibt der mir das sagen kann, bitte.

lg,

Siro
07.01.2008, 18:15
Auf die Falle mit PORTx und LATx bin ich genauso reingefallen.
Die Erklärung ist leider nicht ganz einfach zu verstehen bzw. zu Beschreiben:
Das Problem liegt bei den "Read Modify Write" Befehlen.
Die ersten PICs hatten lediglich PORTx
Beim Zugriff auf PORTx wird der gerade aktuelle Pegel der Portpins
gelesen, NICHT das was vorher auf den Port geschrieben wurde.
Hier kann es passieren, daß man vorher ein beliebiges Ausgangsbit auf
High gesetzt hatte und beim Lesen ein Low zurückgeliefert wird.
Dies passiert z.B. dann, wenn der Ausgangspin stärker belastet wird.
Deshalb trennte man bei Microchip die "Inputs PORT"
von den "Outputs LAT".

Bei Bitbefehlen z.B. BSF PORTB,3 wird zunächst der GESAMTE Port,
also alle 8 Bits vom Prozessor gelesen, dann wird das Bit 3 gesetzt
und der komplette Port wieder zurückgeschrieben.
Unterliegt nun ein Ausgangsbit deines Ports einer stärkeren Belastung,
liest der Prozessor fälschlicherweise ein Low und beim Zurückschreiben
wird diese Bit dann ebenfalls fasch gesetzt.
Mit den getrennten Registern kann dies nicht mehr passieren.

mfg. Siro

Maulwurf
10.04.2008, 17:25
Ich denke, daß mein Problem hierher passt, deshalb setze ich diesen Thread einmal fort...

Die Aufgabe besteht darin, einen ST6 durch einen PIC 16F685 zu ersetzen. Meine ersten Übungen verlaufen ganz vielversprechend. Doch belibe ich an einem (sicher banalen) Problem hängen.
Am Port C (0-3) sind 3 LEDs, die ich separat schalten will. Ich dachte mit "BSF PORTC,x" und "BCF PORTC,x" ans Ziel zu kommen. Das stimmt jedoch nur zum Teil.
Wenn ich ein (beliebiges) Bit setze, werden die anderen auf jeden Fall gelöscht.

Beispiel 1, LED an RC1 ist an, LED an RC0 jedoch nicht


CALL LED_RC0_ON
CALL LED_RC1_ON

LED_RC0_ON:
banksel PORTC
BSF PORTC, 0
RETURN

LED_RC1_ON:
banksel PORTC
BSF PORTC, 1
RETURN


Beispiel 2, LED an RC0 erlischt, obwohl Bit 1 gelöscht wird


CALL LED_RC0_ON
CALL LED_RC1_OFF

LED_RC0_ON:
banksel PORTC
BSF PORTC, 0
RETURN

LED_RC1_OFF:
banksel PORTC
BCF PORTC, 1
RETURN



Meine Fragen:
1. Was mache ich falsch und wie kann ich das Problem lösen.
2. In einem weiteren Schritt käme noch ein PWM-Signal an RC5 hinzu. Die Schaltung der LEDs darf dies natürlich auch nicht beeinflussen. Die Lösung für (1) muß diesen Punkt also schon berücksichtigen.

Vielen Dank für die Hilfe

HF SHOOTER
10.04.2008, 17:57
Hi,

kannst Du mal etwas mehr Code posten? Zumindest die Initialisierung währe interessant und deine Mainloop.

mfg
Benny

Maulwurf
10.04.2008, 19:21
Sorry, ich war der Meinung, die wichtigen Snippets gepostet zu haben.


processor 16F685
#include <P16F685.INC>
__config (_INTOSCIO & _WDT_OFF & _PWRTE_ON)


org 0

init:
banksel OSCCON
MOVLW B'01110001'
MOVWF OSCCON

MOVLW B'00000000' ; Ports C output
MOVWF TRISC

MOVLW 0x3f ; Pulsweite 255
MOVWF PR2

BCF STATUS, RP0 ; Bank 0
MOVLW 0x00
MOVWF 0x70 ; Startwert Pulsweite = 0
MOVWF CCPR1L ; Pulsweite MSB = 0
MOVLW B'00001100' ; Pulsweite LSB = 0
; Schalte CCP auf PWM
MOVWF CCP1CON
BCF PIR1, TMR2IF ; Interruptflag von Timer 2 löschen
MOVLW 0x04
MOVWF T2CON ; Timer 2 on, Vorteiler = 1

PROGRAM_LOOP:
NOP
CALL LED_RC0_ON
CALL LED_RC1_ON
CALL PAUSE_1_SEK
CALL LED_RC0_OFF
CALL LED_RC1_OFF
CALL PAUSE_1_SEK
GOTO PROGRAM_LOOP


PAUSE_1_SEK:
BSF STATUS, RP0 ; Bank 1
BCF STATUS, RP1
CLRF 0xa0
CLRF 0xa1
MOVLW 0x0f ; Zähler 15 mal bis 0xffff
MOVWF 0xa2
LOOP_PAUSE_1S:
DECFSZ 0xa0, 1
GOTO LOOP_PAUSE_1S
NOP
DECFSZ 0xa1, 1
GOTO LOOP_PAUSE_1S
DECFSZ 0xa2, 1
GOTO LOOP_PAUSE_1S
RETURN


LED_RC0_ON:
banksel PORTC
BSF PORTC, 0
RETURN
LED_RC1_ON:
banksel PORTC
BSF PORTC, 1
RETURN
LED_RC0_OFF:
banksel PORTC
BCF PORTC, 0
RETURN
LED_RC1_OFF:
banksel PORTC
BCF PORTC, 1
RETURN

end

Maulwurf
10.04.2008, 23:01
Ich habe noch ein wenig experimentiert. Wenn ich alle Bits in TRISC setze, leuchten (wie zu erwarten) erst einmal alle LEDs. Wenn ich dann in der Programmschleife dann 2 (beliebige) Bits (0-7) ein- und auschalte, erlöschen alle. Nur nicht Bit 4 und 5, diese beiden leuchten weiter.
Bit 4 und 5 sind also die einzigen zwei, die sich nicht gegenseitig beinflussen. (Beschränke ich mein Testprogramm also auf die Bits 4 und 5, funktioniert es.)
Bit 4 und 5 sind die beiden einzigen von Port C, die nicht als Analogeingang benutzt werden können.
Obwohl das das Data Sheet sagt, ANSEL (ANSELH) würde die Ports bei Digital-Out nicht beinflussen, habe ich testweise beide Register mit "00" gefüllt, weil die als Resetvorgabe gestzte Bits haben sollen. Allerdings hat es auch nichts gebracht.

Maulwurf
11.04.2008, 08:31
Ich habe folgendes gefunden: https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=15449#161798
Das würde letztendlich bedeuten, daß man einzelne Pins der Portregister nicht sinnvoll ansprechen kann.
Nach dem lesen des obigen Beitrags versteht man den knapp gehaltenen Hinweis 1 (Data Sheet PIC16F631/677/685/689/690, Seite 218) doch etwas besser.

Die Quitessenz ist also, daß man das LAT-Register selbst im RAM nachbilden muß und stets dieses "LAT" komplett in den Port schreiben muß.
Doch wie verhält es sich dann mit als (Analog-) Eingang programmierten Pins? Ich brauche, wie gesagt RC5 als PWM-Ausgang. Da ist doch sicher zu erwarten, daß das Schreiben eines kompletten Bytes auch RC5 und damit dessen Signal beinflusst.
Und last but not least wären da noch die Analogeingänge (außer 4/5), deren Portbits wohl auch nicht auf einen Schreibzugriff scharf sind.

PICture
11.04.2008, 08:31
Hallo!

@ Maulwurf

Um einzelne Bits in einem Register zu setzen benutzt man "OR" ("iorlw") und zu löschen "AND" ("andlw"). Dabei werden die andere Bits nicht beeinflüsst.

MfG

Maulwurf
11.04.2008, 12:45
Hmm. Sicher sind das 2 Möglichkeiten. Doch das Grundproblem liegt ja außerhalb dieser logischen Verknüpfung. PORTC muß erst einmal gelesen werden. Der durch Ausgangstrom herunter gezogene Portpin wird nicht als "1", sondern als "0" gelesen und folglich als "0" zurück geschrieben, wenn er durch die Verknüpfung (BSF, IORWF...) nicht explizit gesetzt wiurde.
Wenn ich jedoch für den gesamten Port ein Schatten anlege, funktioniert das nicht, weil ja auch noch analoge Eingänge und das PWM-Signal sind. Dort blind hineinzuschreiben, dürfte ebenso kontraproduktiv sein. Beim Analogeingang wäre es ja nicht so tragisch. Aber was sagt der PWM-Ausgang dazu? Leider habe ich erst nächste Woche wieder Zugang zum Oszi. Eigentlich wollte ich bis dahin fertig sein.
Auf einen PIC18 wollte ich nun auch nicht mehr unbedingt umsteigen.

HF SHOOTER
11.04.2008, 17:50
Hi,

Geht es nicht wenn Du ein paar NOPs zwischen den beiden unmittelbar folgenden Bitmanipulationen setzt?


PROGRAM_LOOP:
NOP
CALL LED_RC0_ON
NOP
NOP
NOP
CALL LED_RC1_ON
NOP
NOP
NOP
CALL PAUSE_1_SEK
CALL LED_RC0_OFF
NOP
NOP
NOP
CALL LED_RC1_OFF
NOP
NOP
NOP
CALL PAUSE_1_SEK
GOTO PROGRAM_LOOP

Ggf. musst Du selbst herausfinden wie viele NOPs nötig sind.

mfg
Benny

Maulwurf
11.04.2008, 20:00
Nein, leider nicht. Selbst meine Sekundenschleife bringt keinen Effekt. Die Erklärung, die ich verlinkt habe, ist auch recht plausibel. Ich denke, dieses Problem wird Microchip veranlasst haben, im PIC18 das LAT einzusetzen.
Ich habe die I/O jetzt so organisiert, daß PortC nur das PWM, ein statisch gesetztes Bit und 6 analoge Eingänge besitzt.
Port B steuert die LEDs, wo ich alles über ein eigenes Register puffern kann.

An Port B tritt übrigens genau der gleiche Effekt auf. Das setzen/löschen einzelner Bits in PORTx ist also NICHT möglich, ohne andere Bits löschen. Es kann gut möglich sein, daß dieser Effekt nur ab einer bestimmten Ausgangstromstärke (gegen Vss) auftritt. Bei einer Belastung mit einer LED und Vorwiderstand von ca. 500Ohm passiert es jedenfalls.

Zu unterscheiden sind jedoch Ports, die auch als Analogeingang nutzbar sind. Ports OHNE Analogeingangsoption (RB6, RB7, RC4, RC5) werden NICHT durch die Bitmanipulationen beinflusst. Ansonsten gehen gesetzte Bits durch die Read-Modify-Write-Aktionen verloren.

Port A habe ich nicht mehr getestet. Ich hoffe, es hilft mal jemandem, der ebenfalls über dieses Problem stolpert.

PICture
12.04.2008, 07:12
Hallo!

Ich versuche es am Beispiel zu erklären.
Wir haben in einem "Register" unbekannte binäre Zahl (XXXXXXXXb) in der wir bestimmte Bits löschen/setzen wollen. Angenommen wir wollen Bits 3 und 2 löschen und Bits 1 und 0 setzen. Das geschieht mit sich im Code befindlicher ASM Befehlsfolge ohne Bits 7 bis 4 zu beeinflüssen.

MfG


movf Register,0 ; XXXXXXXXb, Register ins W-Register laden
andlw 0xF3 ; 11110011b, danach im W-Register ist XXXX00XXb
iorlw 3 ; 00000011b, danach im W-Register ist XXXX0011b
movwf Register ; XXXX0011b, W-Register ins Register schreiben

the_Ghost666
13.04.2008, 19:06
Wenn es deine Last erlaubt (dh. sie muss nur von 5V getrennt werden, nicht auf Masse gezogen), könntest du auch die TRIS-Bits benutzen um den Port aktiv oder hochohmig zu ziehen. Das sollte ganz gut klappen, ich habs bei den CCP-Pins benutzt um das PWM Signal an und auszuschalten.