PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Byte auswerten ?



Blamaster
08.02.2008, 15:51
Hi,

ich müsste für mein Projekt ein Byte auswerten und damit einen Port Des Controllers für 500ms schalten.

Das Byte wird über rs485 an den Controller übertragen. Wenn es nun z.B. eine 1 enthält, soll es PORTB.0 schalten. Wenn es eine 2 enthält PORTA.1 usw.

Hat da jemand eine bessere Lösung als für jeden einzelnen zu schaltenden Port eine If Abfrage zu machen ?

mfg Blamaster

Monday
08.02.2008, 16:44
Hi Blamaster,

Wie du wahrscheinlich weist, besteht ein Byte aus 8 Bit. Wenn du nun ein Byte überträgst, kann es es z.B. in einer Variablen speichern und mit dem PortB gleichsetzen, z.B.


Config Portb as output
PortB=Empfangenes_Byte

Wenn du also einfach den Ascii-Code per RS485 überträgst, kannst du damit den gesamten Port schalten wie du möchtest.
Ist der Ascii-Code 0 so schaltet kein Ausgang, bei 1 schaltet PortB.0 bei 2 PortB.1, bei 4 PortB.2 usw.
Natürlich kannst du so auch mehrere Ports gleichzeitig schalten.

Gruß
Monday

Blamaster
08.02.2008, 16:58
Öhm joa aber was ist mit PORTA , PORTB , PORTC dann haut es ja nichtmehr hin.

Denn dann würde ja jeweils auf allen 3 PORTS der entsprechende pin schalten.

chr-mt
08.02.2008, 17:44
Hi,
dann musst du wohl doch eine If Abfrage (oder select case) machen..
Sind ja nur 8.. (Wenn du pro Bit einen Pin schalten willst)



if meinbyte.0 = 1 then
portb.0=1
else
portb.0=1
endif
..
..
..
..
if meinbyte.7 = 1 then
portba.5=1
else
porta.5=1
endif



Gruß
Christopher

mare_crisium
08.02.2008, 17:55
Blamaster,

die Alternative ist eine Tabelle: Das Datenbyte, das Du über den RS485 empfangen hast, dient als Zeiger auf ein Element in einer Tabelle von bis zu 255 Bytes. Jedes Byte in der Tabelle enthält die Angabe, an welchem Port welche Pins zu setzen sind. Das hat den Vorteil, dass Du alle möglichen Bitkombinationen im Datenbyte verarbeiten kannst.

mare_crisium

Monday
08.02.2008, 18:00
Öhm joa aber was ist mit PORTA , PORTB , PORTC dann haut es ja nichtmehr hin.

Denn dann würde ja jeweils auf allen 3 PORTS der entsprechende pin schalten.

Nein, das ist nicht der Fall, da du nur ja nur einen Port, in dem Fall PortB der Variablen gleich setzt.

Ich benutze die Gleiche Technik um einen SRAM zu beschreiben, bzw auszulesen. Da wird auch ein Byte auf einem Port ausgegeben.

Gruß
Monday

Blamaster
08.02.2008, 18:00
@ mare_crisium
Hört sich sehr interessant an. Praktisch eine Sprungtabelle. Könntest du ggf. anhand von einem code beispiel verdeutlichen wie das funkt ?

mfg Blamaster


Edit. hatte garnicht gesehen da so viel gepostet wurde. Ich sollte vielleicht nochmal näher beschreiben was geschehen soll. Datenspeicher(3) ist ein Byte welches die Nummer des Kanals enthält. Diese soll nun folgende Kanäle auslösen:

Datenspeicher(3) = 1 Löse aus PORTA.0
Datenspeicher(3) = 2 Löse aus PORTA.1
Datenspeicher(3) = 3 Löse aus PORTA.2
Datenspeicher(3) = 4 Löse aus PORTA.3
Datenspeicher(3) = 5 Löse aus PORTA.4
Datenspeicher(3) = 6 Löse aus PORTA.5
Datenspeicher(3) = 7 Löse aus PORTA.6
Datenspeicher(3) = 8 Löse aus PORTA.7
Datenspeicher(3) = 9 Löse aus PORTB.0
Datenspeicher(3) = 10 Löse aus PORTB.1
.
.
.
usw.

Nun ist es aber wohl sehr unschlauf nachher "hundert" ifs zu haben die jeden zustand einzeln abfragen.

PicNick
08.02.2008, 18:53
Am einfachsten ist für sowas eine Tabelle mit Port-Adresse und Pin-Maske
(sieht schräger aus, als es ist)


PORT_TAB:
DATA &H3B, 1 ' PORTA Pin 0 virtuell 0
DATA &H3B, 2 ' PORTA Pin 1 virtuell 1
DATA &H3B, 4 ' PORTA Pin 2 virtuell 2
DATA &H3B, 8 ' PORTA Pin 3 virtuell 3
DATA &H3B, 16 ' PORTA Pin 4 virtuell 4
DATA &H3B, 32 ' PORTA Pin 5 virtuell 5
DATA &H3B, 64 ' PORTA Pin 6 virtuell 6
DATA &H3B, 128 ' PORTA Pin 7 virtuell 7
DATA &H38, 128 ' PORTB Pin 0 virtuell 8

DATA &H38, 128 ' Port B Pin 7 virtuell 9
DATA &H38, 2 ' Pin 1 virtuell 10
DATA &H38, 128 ' Pin 7 virtuell 11

u.s.w.
DATA &H35, 1 ' Port C Pin 0 virtuell xxx

DATA &H32, 1 ' Port D Pin 0 virtuell xxx





DIM Portadr as byte
DIM Portmsk as byte
DIM Tabv as word at Portadr overlay
DIM Temp as byte

Temp = datenspeicher(3)
Tabv = lookup ( temp, PORT_TAB)

' z.B. einzelnes PortPin setzen (die anderen nicht anrühren):
Temp = INP ( Portadr)
TEMP = TEMP OR Portmsk
OUT ( Portadr, TEMP)

' z.B. einzelnes PortPin löschen (die anderen nicht anrühren):
Temp = INP ( Portadr)
Portmsk = Portmsk XOR &HFF
TEMP = TEMP AND portmsk
OUT ( Portadr, TEMP)

mare_crisium
09.02.2008, 10:51
blamaster,

so wie's PicNick in Basic geschrieben hat, hatte ich's auch gemeint. In Assembler sieht's ganz ähnlich aus. Nach ein bisschen Herumprobieren kam mir eine echte Sprungtabelle als die einfachste Methode (in Assembler) vor. Dann braucht man aber doppelt soviel Platz für die Tabelle, als wenn man Port- und Pin-Nummer in einem Byte kodiert ablegt. Es ist aber einfacher, über die Sprungtabelle direkt eine Auswertungsprozedur anzuspringen, als das gelesene Tabellenbyte zu dekodieren. Das kommt daher, dass man beim Atmel die Ports nur direkt (immediate) adressieren kann.

Zur Information hänge ich das Beispiel unten an.

mare_crisium



;*-----------------------------------
; BEISPIEL Tabelle_V01.asm
; Entwicklungsversion
;*-----------------------------------
;* Einbinden
;*

.device ATmega8
.include "m8def.inc"

;*-----------------------------------
;* Definitionen
;*

.equ PORTA = 0x1B


;*------------------------------------
;* PROCEDURE TBL_CALL
;*
;* Die Prozedure TBL_JMP liest aus einer Sprung-
;* tabelle, die im Programmspeicher abgelegt
;* ist, ein 2-Byte-Adresse aus. Sie wird als
;* Programmadresse angesprungen.
;
; Eingangsvariablen
; zh:zl: enhält den Zeiger auf die RAM-Adresse,
; an der die Sprungtabelle beginnt
; r16: enthält den Index der Adresse, die
; angesprungen werden soll
;
; Ausgangsvariablen
; keine
;
; geänderte Register
; zh,zl
;
; geänderte Ports
; keine
;

TBL_CALL:
push r17
in r17,SREG
push r17


clr r17
add zl,r16
adc zh,r17
add zl,zl
adc zh,zh

lpm r17,z+
lpm zh,z
mov zl,r17

pop r17
out SREG,r17
pop r17

ijmp


/*------------------------------------

SPRUNGTABELLE


*/
// 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
SPRUNG_TBL:
.dw SET_PORTA0, RES_PORTA0 ; ... usw.

//...

.dw SET_PORTC7, RES_PORTC7


/*------------------------------------
PROCEDURE EVAL_RS485

Die Prozedure EVAL_RS485 wertet ein Datenbyte aus,
das über die RS485 empfangen wurde. Das Datenbyte dient
als Zeiger in die Sprungtabelle SPRUNG_TBL. Die Einträge
enthalten die Adresse je einer Prozedur, die an einem
bestimmten Port einen bestimmten Pin setzt oder zurücksetzt.

Eingangsvariablen
r16: enthält den das Datenbyte, das
ausgewertet werden soll

Ausgangsvariablen
r16: enthält das ungeänderte Datenbyte

geänderte Register
keine

geänderte Ports
PORTA,PORTB,PORTC, je nach Datenbyte
*/


EVAL_RS485:
push r16
push zl
in zl,SREG
push zl
push zh

ldi zl,low(SPRUNG_TBL); zh:zl := Adresse der Tabelle
ldi zh,high(SPRUNG_TBL)
rcall TBL_CALL ; ausgewählte Prozedure anspringen

pop zh
pop zl
out SREG,zl
pop r16
ret ;

/*------------------------------------
PROZEDUREN SET_PORTA0/RES_PORTA0 bis SET_PORTC7/RES_PORTC7

Hier kommen die Prozeduren, die die ausgewählten Ports und
Pins ansprechen.

Eingangsvariablen
keine

Ausgangsvariablen
keine

geänderte Register
keine

geänderte Ports
PORTA,PORTB,PORTC, je nach Datenbyte
*/

SET_PORTA0:
sbi PORTA,0
ret

RES_PORTA0:
cbi PORTA,0
ret

// und so weiter

SET_PORTC7:
sbi PORTC,7
ret

RES_PORTC7:
cbi PORTC,7
ret

//------------------------

Vitis
10.02.2008, 09:22
a_byte=udr
if a_byte.0=1 then
set relais_0
else
reset relais_0
endif
if a_byte.1=1 then
set relais_1
else
reset relais_1
endif
if a_byte.2=1 then
set relais_2
else
reset relais_2
endif

... and so on

Blamaster
10.02.2008, 11:02
Jo Danke an alle. Problem ist gelöst. Mache es jetzt über Select Case.

mfg Blamaster