Archiv verlassen und diese Seite im Standarddesign anzeigen : Byte auswerten ?
Blamaster
08.02.2008, 16: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
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, 17: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.
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, 18: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
Ö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, 19: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.
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, 11: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
//------------------------
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, 12:02
Jo Danke an alle. Problem ist gelöst. Mache es jetzt über Select Case.
mfg Blamaster
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.