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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|