Hallo Zusammen,
(Zu erst einmal: Ich hoffe, es ist der richtige Bereich. Einen anderes
Thema zum Programmieren habe ich nach einem Tag hier und nicht mehr in
der Codesammlung gefunden. Falls es falsch ist, bitte Verschieben.)
Nun zu meinem Vorhaben und dem Problem dabei:
Ich habe mir vorgenommen, ein LCD an einem 74164 über einen Tiny13 zu
steuern. Der Tiny13 soll lediglich die erhaltenen Daten der seriellen
Kommunikationsmöglichkeit an das Display weiterreichen.
Da ich das ganze in Assembler realisieren möchte, weil ich dort genug
Erfahrung für das geplante vorgehen habe (wie ich denke), bin ich zur
Zeit dabei, den 124Bus von PeDa in Assembler zu übersetzen. (Ich habe
keine ASM-Version gefunden, oder habe den falschen Suchbegriff genutzt.)
- Vorgestellt wird der Bus hier:
Beitrag "mehrere MC seriell über Datenbus verbinden (1Draht)"
Das Übersetzen macht mir bislang auch keine Probleme, da der Code auch
ausreichend kommentiert ist. Jedoch habe ich ein Problem im
Compare-Match-A Vektor seines Codes. Es geht um folgenden Ausschnitt:
1
ISR( TIMER2_COMPA_vect ) // Transmit interrupt
2
{
3
uint8_t *dp; // locals for faster access
4
5
if( tx_idx < DATA_SIZE * 8 ){
6
OCR2A = BIT_TIME * 1 - 0.5; // 0-bit: 1T
7
dp = &tx_buff[tx_idx++ / 8]; // get byte address
8
if( *dp & 0x80 ) // msb first
9
OCR2A = BIT_TIME * 2 - 0.5; // 1-bit: 2T
10
*dp <<= 1; // shift bits
11
}else{
12
OCR2A = BIT_TIME * 4 - 0.5; // stop: 4T
13
if( DATA_PIN ) // after output = high
14
TCCR2B = 0; // then stop T1
15
}
16
}
Umgesetzt habe ich bereits folgendes:
1
T0CMA:
2
cpi TX_IDX, DATA_SIZE*8
3
brlo GETDATA
4
;; Stop: 4T
5
ldi iwr0, tBIT*4 - 0.5
6
out OCR0A, iwr0
7
;; Nach Output=High
8
in iwr0, DIN
9
andi iwr0, (1 << DPIN)
10
ldi iwr1, 0
11
cpse iwr0, iwr1
12
rjmp T0W
13
;; Wenn Bed. WAHR, Timer stoppen
14
ldi iwr0, 0
15
out TCCR0B, iwr0
16
rjmp T0W
17
GETDATA:
18
;; 0-Bit: 1T
19
ldi iwr0, tBIT - 0.5
20
out OCR0A, iwr0
21
22
; get byte address
23
; dp = &tx_buff[tx_idx++ / 8];
24
; if(*dp & 0x80)
25
;; 1-Bit: 2T
26
ldi iwr0, tBIT*2-0.5
27
out OCR0A, iwr0
28
; *dp <<=1;
29
30
T0W:
31
reti
Mein Problem ist jetzt aber der Pointer "dp". Wie wird mit diesem
gearbeitet und wie wird er bearbeitet? Mein C-Verständnis hört an dieser
Stelle leider auf.
Kann mir bitte einer erklären, was im WAHR-Zweig
der " if( tx_idx < DATA_SIZE * 8 ){ " - Bedingung Stück für Stück
bearbeitet wird?
OCR2A = BIT_TIME * 1 - 0.5; // 0-bit: 1T
Der OCR2A-Wert wird auf BIT_TIME - 0.5 gesetzt
dp = &tx_buff[tx_idx++ / 8]; // get byte address
Aber hier stehe ich auf dem Schlauch. TX_IDX wird um 1 erhöht, und als
Index des TX_BUFF-Arrays wird ein 8tel des erhöhten TX_IDX-Wertes
genutzt.
Aber welchen Wert nimmt "dp" in diesem Fall an? (Wg. _&_tx_buff)
Meine nächste Problem-Stelle -kommentiert mit "msb first" - ist:
if( *dp & 0x80 )
Was (Adresse oder Wert) wird hier mit 0x80 ver-und-et und geprüft?
Das Verständnis dieser Abfrage erschließt sich mit wahrscheinlich, wenn
ich das vorhergehende Problem verstehe.
*dp <<= 1;
Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1
aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?
Nach so viel Text erstmal recht herzlichen Dank, dass ihr Versucht, mein
Problem zu verstehen. ;)
Gruß,
Marcel
Marcel Papst schrieb:> dp = &tx_buff[tx_idx++ / 8]; // get byte address> Aber hier stehe ich auf dem Schlauch. TX_IDX wird um 1 erhöht, und als> Index des TX_BUFF-Arrays wird ein 8tel des erhöhten TX_IDX-Wertes> genutzt.> Aber welchen Wert nimmt "dp" in diesem Fall an? (Wg. _&_tx_buff)
dp ist die Adresse dieses Bytes im Speicher
> Meine nächste Problem-Stelle -kommentiert mit "msb first" - ist:> if( *dp & 0x80 )
Hier wird das Byte, dessen Adresse vorher ausgerechnet wurde mit 0x80
und verknüpft.
> Das Verständnis dieser Abfrage erschließt sich mit wahrscheinlich, wenn> ich das vorhergehende Problem verstehe.>> *dp <<= 1;> Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1> aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?
Selbiges.
Das ganze hat nur 'optimierende' Eigenschaften. Du kannst dp auch
einfach loswerden (für deine Transkription) durch Rückübersetzung
1
if(tx_idx<DATA_SIZE*8){
2
OCR2A=BIT_TIME*1-0.5;// 0-bit: 1T
3
if(tx_buff[tx_idx/8]&0x80)// msb first
4
OCR2A=BIT_TIME*2-0.5;// 1-bit: 2T
5
tx_buff[tx_idx/8]<<=1;// shift bits
6
tx_idx++;
7
}else{
und jetzt siehst du, dass hier in diesem Code um Grunde die
Adressberechnung des Bytes an 2 Stellen gemacht werden müsste. Der
Pointer hat hier einfach nur die Aufgabe, die Arrayindizierung an einer
Stelle zusammenzuziehen und so zu garantieren, dass sie nur einmal
gemacht wird.
Marcel Papst schrieb:> *dp <<= 1;> Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1> aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?
Nein. Die 1 bedeutet "um eine Stelle". Aufgefüllt wird immer mit 0.
Hallo nochmal,
Erst mal an Stefan:
Stefan Ernst schrieb:> Nein. Die 1 bedeutet "um eine Stelle". Aufgefüllt wird immer mit 0.
Das immer mit einer 0 aufgefüllt wird, war mir eigentlich klar, das
zusätzliche "=" jedoch, machte mich nachdenklich bzgl. der Funktion
dieses Operators. Ich habe es zuvor noch nie so bewusst gesehen. KHB hat
dazu eine ausreichende Erklärung geliefert. Trotzdem vielen Dank für
deine Antwort.
Karl Heinz Buchegger schrieb:> Du kannst dp auch> einfach loswerden (für deine Transkription) durch Rückübersetzung> if( tx_idx < DATA_SIZE * 8 ){> OCR2A = BIT_TIME * 1 - 0.5; // 0-bit: 1T> if( tx_buff[tx_idx / 8] & 0x80 ) // msb first> OCR2A = BIT_TIME * 2 - 0.5; // 1-bit: 2T> tx_buff[tx_idx / 8] <<= 1; // shift bits> tx_idx++;> }else{>> und jetzt siehst du, dass hier in diesem Code um Grunde die> Adressberechnung des Bytes an 2 Stellen gemacht werden müsste.
Ja, das sehe ich. Es hilft dem Code-Verständnis ungemein.
Ich habe mir zur weiteren Übersetzung auch das LST-File des
Original-Codes angeschaut. Ich denke, dass es mir geholfen hat.
Analog zu Assembler:
Ist der folgende ASM-Code gleichwertig zu der oberen Vorgehensweise,
oder habe ich noch Fehler eingebaut? (Ohne Beachtung von Push und Pop,
welche ich noch nicht eingebaut habe.
Die Quelle der Übersetzung - um sie genauer zu bezeichnen - ist der
Timer2-Compare-Match-A-Vector aus der "Slave1.c".
1
.def iwr0 = r16
2
.def iwr1 = r17
3
.def temp1 = r20
4
.def temp2 = r21
5
.def TX_IDX = r22
6
.equ tBIT = 1000 / 64
7
.equ DIN = PINB
8
.equ DPIN = PB0 ;; PB0 = OC0A
9
.equ DATA_SIZE = 2
10
11
T0CMA:
12
cpi TX_IDX, DATA_SIZE*8
13
brlo GETDATA
14
;; Stop: 4T
15
ldi iwr0, tBIT*4 - 0.5
16
out OCR0A, iwr0
17
;; Nach Output=High
18
in iwr0, DIN
19
andi iwr0, (1 << DPIN)
20
ldi iwr1, 0
21
cpse iwr0, iwr1
22
rjmp T0W
23
;; Wenn Bed. WAHR, Timer stoppen
24
ldi iwr0, 0
25
out TCCR0B, iwr0
26
rjmp T0W
27
GETDATA:
28
;; 0-Bit: 1T
29
ldi iwr0, tBIT - 0.5
30
out OCR0A, iwr0
31
;; TX_IDX sichern
32
mov temp1, TX_IDX
33
inc TX_IDX
34
;; Durch 8 Teilen
35
lsr temp1
36
lsr temp1
37
lsr temp1
38
;; Zeiger einstellen:
39
ldi ZL, LOW(TX_BUFF)
40
ldi ZH, HIGH(TX_BUFF)
41
;; und "temp1" dazuaddieren
42
ldi temp2, 0
43
add ZL, temp1
44
adc ZH, temp2
45
;; Wert laden
46
ld iwr0, Z
47
;; Wert sichern und nach links verschieben
48
mov temp2, iwr0
49
lsl temp2
50
;; Wert mit 0x80 verknüpfen
51
ldi iwr1, 0x80
52
and iwr0, iwr1
53
;; OCR-Wert vorladen
54
ldi temp1, tBIT*2-0.5
55
ldi iwr1, 0
56
;; If-Bedingung ausführen
57
cpse iwr0, iwr1
58
;; und wenn sie wahr ist, OCR laden
59
out OCR0A, temp1
60
;; Wert zurückschreiben
61
st Z, temp2
62
;; TX_IDX erhöhen
63
inc TX_IDX
64
T0W:
65
reti
66
67
.dseg
68
TX_BUFF: .byte DATA_SIZE
(Ich halte diese Routine noch für kurz, daher noch nicht als File
angehängt.)
Gruß,
Marcel