Hallo zusammen,
habe da etwas zum Knobeln in einem AVR-Assemblerprogramm.
Also ein HD44780 kompatibles LCD im 4-Bit Mode erwartet ja D7-D4,
also das High-Nibble und danach das Low-Nibble D3-D0. Allerdings dieses
Low-Nibble auch wieder an der High-Nibble Position P7-P4. Man würde
also mit dem SWAP-Befehl um die Bits D3-D0 zu senden, einfach das
Low-Nibble und High-Nibble tauschen und die Sache wäre erledigt.
Nun habe ich jedoch auf Grund eines vorgegebenen Layouts, das sich die
Datenbits D7-D4 an den Portbits so anliegen müssen.
P7 P6 P5 P4 P3 P2 P1 P0
XX XX D4 D5 D6 D7 XX XX
XX bedeutet diese Bits müssen am Ende unverändert bleiben.
Der Weg der mir einfällt wäre die Bits D7 mit D6 tauschen sowie D5 mit
D4.
P7 P6 P5 P4 P3 P2 P1 P0
D6 D7 D4 D5 YY YY YY YY
YY bedeutet erstmal irrelevant
Danach müsste das High-Nibble ins Low-Nibble kopiert werden
P7 P6 P5 P4 P3 P2 P1 P0
D6 D7 D4 D5 D6 D7 D4 D5
und hiernach P7, P6, P1, P0 verodert so das diese am Ende halt
unverändert bleiben.
P7 P6 P5 P4 P3 P2 P1 P0
XX XX D4 D5 D6 D7 XX XX
Nur wie mach ich das in AVR-ASM ?
Der erste Schritt ist hierbei für mich ein riesen Problem.
Nämlich D7 mit D6 tauschen sowie D5 mit D4.
Ich schiebe schon einige Stunden Bits hin und her, rotiere diese,
tausche die Nibbles, arbeite mit dem T-Flag, aber bekomms einfach nicht
hin.
Bernd_Stein
Hi
>Ich schiebe schon einige Stunden Bits hin und her, rotiere diese,>tausche die Nibbles, arbeite mit dem T-Flag, aber bekomms einfach nicht>hin.
Dann spiegel doch einfach erst mal dein Byte, das du ausgeben willst:
[asm]
; Byte in r16
mirror_fast: push r17
swap r16
mov r17,r16
lsr r16
lsr r16
lsl r17
lsl r17
andi r16,$33
andi r17,$CC
or r16,r17
mov r17,r16
lsr r16
lsl r17
andi r16,$55
andi r17,$AA
or r16,r17
pop r17
ret
[/asm]
Und dann schiebst du die Nibble zur Ausgabe an die richtige Stelle.
MfG Spess
meine lösung wären 2 Variablen typ Char und 6*ROR
RRR char 'Rotationsregister
PSHADOW char 'Port_Schattenregister
LDA ausgabechar
ROR
ROR
STA RRR
LDA PORTA
AND 0xC3
STA PSHaDOW
LDA RRR
AND 0x3C
OR PSCHADOW
STA PORTA
LDA RR
ROR
ROR
ROR
ROR
AND 0x3C
OR PSCHADOW
STA PORTA
Das kann doch nicht wahr sein !!!
Drei Lösungen in wenigen Minuten.
Ich Danke Euch erstmal, aber mir raucht der Kopf und ich hoffe morgen
Zeit für die Analyse zu haben.
Bernd_Stein
Bernd Stein schrieb:> Also ein HD44780 kompatibles LCD im 4-Bit Mode erwartet ja D7-D4,> also das High-Nibble und danach das Low-Nibble D3-D0. Allerdings dieses> Low-Nibble auch wieder an der High-Nibble Position P7-P4. Man würde> also mit dem SWAP-Befehl um die Bits D3-D0 zu senden, einfach das> Low-Nibble und High-Nibble tauschen und die Sache wäre erledigt.> Nun habe ich jedoch auf Grund eines vorgegebenen Layouts, das sich die> Datenbits D7-D4 an den Portbits so anliegen müssen.>> P7 P6 P5 P4 P3 P2 P1 P0> XX XX D4 D5 D6 D7 XX XX
Welcher grenzdebile Vollidiot hat denn dieses Layout so vorgegeben, wie
es ungünstiger kaum vorliegen kann (und zwar für praktisch jede
beliebige Architektur gleich ungünstig)?
Wenn du den Kerl gefunden hast, dann laß' den doch das Problem lösen...
> Ich schiebe schon einige Stunden Bits hin und her, rotiere diese,> tausche die Nibbles, arbeite mit dem T-Flag, aber bekomms einfach nicht> hin.
Tja, keine Arme, keine Kekse. Bist du eventuell mit dem Typen verwandt,
der das Layout vorgegeben hat oder sogar mit ihm identisch? Wundern
würde mich das nicht...
Wie auch immer: Für jeden, der überhaupt programmieren kann, ist es
natürlich kein Problem, irgendeine Lösung zu finden. Wer das nicht
schafft, kann einfach nicht programmieren. Ende der Ansage.
Ein klein wenig anders ist die Lage, wenn nicht irgendeine, sondern die
schnellstmögliche Lösung gesucht ist. Da wären dann erstmal einige
Randbedingungen zu klären. Aber wenn man diese mal so vorgibt, daß die
Quelldaten wie gezeichnet in einem Register vorliegen und wie benötigt
in einem anderen erscheinen sollen, wäre beim AVR wohl der Weg über das
T-Flag der schnellste, viermal bst/bld, also acht Takte insgesamt.
c-hater, liebenswürdig wie immer.
>natürlich kein Problem, irgendeine Lösung zu finden
Genau, das schaffe sogar ich und biete es hier an, ohne Anspruch auf
Schnelligkeit oder gar Genialität.
@c-hater (Gast)
>> P7 P6 P5 P4 P3 P2 P1 P0>> XX XX D4 D5 D6 D7 XX XX>Welcher grenzdebile Vollidiot hat denn dieses Layout so vorgegeben, wie>es ungünstiger kaum vorliegen kann (und zwar für praktisch jede>beliebige Architektur gleich ungünstig)?
Was bist du denn für ein Mädchen? Selbst der älteste 8051 kann die paar
Bits problemlos und nahezu in Null,Nix vertauschen. Aber das lernst du
auch noch, wenn du mal aus der Programmiererpubertät rausgekommen bist
und die ASM-Pickel langsam zurück gehen. Dann lernst du auch was über
Hochsprachen und deren Vorteile ;-)
der alte Hanns schrieb:> Genau, das schaffe sogar ich und biete es hier an, ohne Anspruch auf> Schnelligkeit oder gar Genialität.
Gut gemacht, keine Einwände.
Hatte auch mal so etwas ähnliches, beim ATTiny2313. Danach habe ich
es verglichen, da der LcdPort auch Steuerleitungen hatte, müßte ich
Port einlesen, AND Steuerleitungen, OR Dataleitungen - am Ende war es
mit einzelnen bits viel übersichtlicher.
Bernd Stein schrieb:> Nur wie mach ich das in AVR-ASM ?>> Der erste Schritt ist hierbei für mich ein riesen Problem.> Nämlich D7 mit D6 tauschen sowie D5 mit D4.>> Ich schiebe schon einige Stunden Bits hin und her, rotiere diese,> tausche die Nibbles, arbeite mit dem T-Flag, aber bekomms einfach nicht> hin.
Falls es tatsächlich schnell sein muß: Da böte es sich an, die
anzuzeigenden Texte gleich mit gespiegelten/rotierten Bitmustern zu
erzeugen. Für Textkonstanten ist das ja kein Problem, für Ziffern kann
man sich eine Tabelle anlegen.
an Marc Veseley
Bei mir war der Ursprung, dass ich für eine temporäre Hilfsanzeige
'übriggebliebene Pins zusammenklauben' musste, später fand ich es, wie
Sie, übersichtlicher und blieb generell dabei; nichts mit 'Null,Nix'
oder 'schnellstmöglich'.
der alte Hanns schrieb:> Bei mir war der Ursprung, dass ich für eine temporäre Hilfsanzeige> 'übriggebliebene Pins zusammenklauben' musste,
LOL.
Bei mir auch.
Da LCD-Ausgaben nicht zeitkritisch sind, habe ich meine Routine so
geschrieben, daß sie mit beliebigen 6 Pins zurechtkommt.
Auch von verschiedenen Ports, wenn z.B. Pins durch Spezialfunktionen
(UART, I2C, Timer usw.) belegt sind.
Man kann also völlig problemlos auf das Layout optimieren, auch wenn das
den ewigen Nörglern nicht gefällt.
1
staticvoidlcd_nibble(uint8_td)
2
{
3
LCD_D7=0;if(d&1<<7)LCD_D7=1;
4
LCD_D6=0;if(d&1<<6)LCD_D6=1;
5
LCD_D5=0;if(d&1<<5)LCD_D5=1;
6
LCD_D4=0;if(d&1<<4)LCD_D4=1;
7
LCD_E0=1;
8
_delay_us(LCD_TIME_ENA);
9
LCD_E0=0;
10
}
Der C-Compiler übersetzt das sehr effizient in Bitbefehle (CBI, SBI).
EDIT (sorry ich habe schon ein Weile nichts mehr in AVR ASM gemacht,
weshalb die mnemonics durchgewürfelt mit anderen ASM...
das prinzip bleibt
meine lösung wären 3 register ( r25, r26, r26 statt variablen und akku
) und 7*ROR (ROR durch carry läuft)
r26 'Rotationsregister
r25 'maskiertes Port_Schattenregister
r1 'hilfsregister für verknüpung des ersten nibbels
CLC 'der ordnung halber
IN r25,PORTA 'port einlesen
ANDI r25,0xC3 'maskieren
LD r26,x+ 'auszugebender char ausspeicherholen
ROR r26 'rotieren
ROR r26
ST r1,r26 'ins zwischenregister copieren
ANDI r1,0x3C 'dort maskieren
OR r1,r25 'verknüpfen mit maskierten portschattenregister
OUT PORTA,r1 'ausgeben
ROR r26 'rotiern
ROR r26 'rotiern
ROR r26 'rotiern
ROR r26 'rotiern
ROR r26 'rotiern und noch einmal fürs carry
CLC 'der ordnung halber
ANDI r26,0x3C 'kann glleich hier maskiert werden
OR r26,r25 'mit maskierten portschattenregister verknüpft
OUT PORTA,r26 'das kennst du schon
Peter Dannegger schrieb:> LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;Winfried J. schrieb:> ROR r26 'rotiern und noch einmal fürs carry> CLC 'der ordnung halber> ANDI r26,0x3C 'kann glleich hier maskiert werden> OR r26,r25 'mit maskierten portschattenregister verknüpft
LOL.
Und wenn die PORTS/PINS für LCD geändert werden ?
ASM .equ = DefLCD.h
Viel übersichtlicher, keine fummelei mit shift (Constant),
ANDI mit Constant...
Peter Dannegger schrieb:> LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;> 42: c5 98 cbi 0x18, 5 ; 24> 44: 87 fd sbrc r24, 7> 46: c5 9a sbi 0x18, 5 ; 24
Nur dass Databit 7 auf Portbit 3 geht.
Marc Vesely schrieb:> Peter Dannegger schrieb:>> LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;>> Winfried J. schrieb:>> ROR r26 'rotiern und noch einmal fürs carry>> CLC 'der ordnung halber>> ANDI r26,0x3C 'kann glleich hier maskiert werden>> OR r26,r25 'mit maskierten portschattenregister verknüpft>> LOL.> Und wenn die PORTS/PINS für LCD geändert werden ?>> ASM .equ = DefLCD.h> Viel übersichtlicher, keine fummelei mit shift (Constant),> ANDI mit Constant...
erst lesen dann posten !
Bernd Stein schrieb:> Nun habe ich jedoch auf Grund eines vorgegebenen Layouts, das sich die> Datenbits D7-D4 an den Portbits so anliegen müssen.>> P7 P6 P5 P4 P3 P2 P1 P0> XX XX D4 D5 D6 D7 XX XX
Dies ist nur ein Q&D-Vorschlag für diese spezielle Problem
wer ASM popelt baut kein universaleierlegendes Wollmilchvieh
Wer C nimmt (ich auch) schaut nur noch selten was der Compiler
produziert, obwohl das leh(h-/e+)rreich sein kann ;)
Natürlich kann man auch Einzelbits testen und manipulieren.
Ob das weniger Takte oder Flash benötigt ist aber noch nicht ausgemacht.
Weil: acht Bittest, acht bedingte Verzweigungen und acht
Bitmanipulationen
da lohnt sich schon fast eine loop.
Marc Vesely schrieb:>> Peter Dannegger schrieb:>> LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;>> 42: c5 98 cbi 0x18, 5 ; 24>> 44: 87 fd sbrc r24, 7>> 46: c5 9a sbi 0x18, 5 ; 24>> Nur dass Databit 7 auf Portbit 3 geht.
Sollte Portbit 2 heissen. Auch deswegen ist ein #define oder .equ
nützlich.
Winfried J. schrieb:> weil acht bittest , acht bedingte verzweigungen und acht bit> manipulationen> da lohnt sich schon fast eine loop
Es werden keine 8 bits gesendet, sondern 2 Nibbles.
Und deine Lösung ist keine Lösung, sondern zusammengewürfelltes
Unsinn.
1
>STr1,r26'inszwischenregistercopieren
2
>ANDIr1,0x3C'dortmaskieren
ST als Befehl existiert beim AVR nicht.
r1 und ANDI passen schon mal nicht zusammen.
Winfried J. schrieb:> ROR r26 'rotiern und noch einmal fürs carry> CLC 'der ordnung halber
Warum ?
Winfried J. schrieb:> erst lesen dann posten !
Erst lernen, dann posten !
lediglich um ein leeres carryflag zu hinterlassen wenn die procedur
beendet ist . ANDI hat keinen einfluss aufs carry ebenso wir or und out.
Daher ist egal wann du aufräumst nicht aber ob du es tust du kannst
natürlich auch noch 2 mal rotiren und auf clc ganz verzichten dann ist
alles beim alten.
Wie gesagt eine möglichkeit.
sollten noch Kinken drinn sein kann man das beheben. Ich wollte nur ein
prinzipeillen Lösungsansatz bieten, für genau diese konstellation. Siehe
oben.
Ich selbst tendiere dazu einen Port fürs LCD zu reservieren. Dann brauch
ich nur zu definieren welchen. Da aber die HW Funktionalität der IO/Pins
nicht unendlich flexibel ist... und Layout meist vor der SW entwickelt
wird, kann man wie der TO gebunden werden, sein, oder sich selbst binden
und muss dann ....
Wer hingegen wie Peter seit Jahren HW und SW entwickelt ist natürlich
eingeschossen und hat bewährte Konzepte. ;)
Namaste
spess53 schrieb:> Hi>> Mal ehrlich, der TO hat sich 21:09 für heute verabschiedet. Anscheinend> dient das Forum für einige eher zur Selbstdarstellungen.>> MfG Spess
war keine absicht, wollte nur meinen Schuss aus der hüfte aufräumen,
aber warum nicht ... drüber reden?
Marc Vesely schrieb:> Peter Dannegger schrieb:>> LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;>> 42: c5 98 cbi 0x18, 5 ; 24>> 44: 87 fd sbrc r24, 7>> 46: c5 9a sbi 0x18, 5 ; 24>> Nur dass Databit 7 auf Portbit 3 geht.
Das Listing entspricht dem Schaltplan, wie ich den Code mal verwendet
habe.
Die Definitionen LCD_D7 .. LCD_D4 muß natürlich jeder an seine Schaltung
anpassen.
Ich wollte damit nur das Prinzip verdeutlichen.
Peter Dannegger schrieb:> Die Definitionen LCD_D7 .. LCD_D4 muß natürlich jeder an seine Schaltung> anpassen.> Ich wollte damit nur das Prinzip verdeutlichen.
Nichts dagegen anzuwenden, ich habe mich beim PortPin auch vertippt,
deswegen ist .h Datei oder .equ viel besser - was ja dein Schnipsel
auch tut - aber auch der vom alten Hanns.
Nur eine Frage des Geschmacks - ASM oder C.
Johann L. schrieb:> Wenn es nicht glichtfrei sein muß, kann man den Code von Peter nehmen.> Wenn Glitches vermieden werden müssen, dann:
Glitches von 2us Dauer ?
Beim LCD ?
Johann L. schrieb:
1
bits:
2
...
3
...
4
bldr25,3
5
bstr24,7
6
bldr25,2
7
8
stsP,r25
9
ret
>> Hätt man auch selber drauf kommen können. jaja, nachher ist man immer> schlauer ;-)
Auweia.
No comment.
Marc Vesely schrieb:>> Wenn Glitches vermieden werden müssen, dann:> Glitches von 2us Dauer ?> Beim LCD ?
Nicht nur. Denk mal über den Tellerrand hinaus. DAC zum Beispiel
> Johann L. schrieb:
1
...
2
P=__builtin_avr_insert_bits(0xff4567ff,D,P);
3
...
das ist ja mal geil. Sollte ich im Hinterstübchen halten.
Karl Heinz schrieb:>>> Wenn Glitches vermieden werden müssen, dann:>> Glitches von 2us Dauer ?>> Beim LCD ?>> Nicht nur. Denk mal über den Tellerrand hinaus. DAC zum Beispiel
Ich kann mir viele Beispiele ausdenken, wo 2us Glitches störend sind,
aber nicht bei der LCD-Ausgabe.
Karl Heinz schrieb:> P = __builtin_avr_insert_bits (0xff4567ff, D, P);> ...>> das ist ja mal geil. Sollte ich im Hinterstübchen halten.
Hehe.
Das kannte ich schon, war in irgendeinem Forum schon vor 2 Jahren
oder so.
Kann sicher nützlich sein, mein No comment war wegen Bit Nummerierung
und späterer Änderung.
AVR-spezifische built-in Funktionen hat's seit 4.7, siehe 4.7 Release
Notes:
http://gcc.gnu.org/gcc-4.7/changes.html
"New Targets and Target Specific Improvements" -> "AVR"
spess53 schrieb:> Dann spiegel doch einfach erst mal dein Byte, das du ausgeben willst:>
Was genau ist spiegeln ?
Kopieren ?
Also r16 auf den Stack legen ?
1
.nolist
2
.include "m8def.inc" ;ATmega8 Labelzuweisungen
3
.list;
4
;
5
;Stackpointer initialisieren
6
;
7
ldi r16, low (ramend)
8
ldi r17, high(ramend)
9
out spl, r16
10
out sph, r17
11
12
ldi r16,0b01011010 ;Anfangswert
13
14
15
; Byte in r16
16
mirror_fast:
17
push r16
18
swap r16
19
mov r17,r16
20
lsr r16
21
lsr r16
22
lsl r17
23
lsl r17
24
andi r16,$33
25
andi r17,$CC
26
or r16,r17
27
mov r17,r16
28
lsr r16
29
lsl r17
30
andi r16,$55
31
andi r17,$AA
32
;geaenderter bzw. erweiterter Teil
33
or r17,r16
34
lsl r17
35
lsl r17
36
andi r17,$3C
37
pop r16
38
andi r16,$C3
39
or r16,r17
40
41
ret
>> Und dann schiebst du die Nibble zur Ausgabe an die richtige Stelle.>
Es war zwar noch ein bischen mehr zu machen, aber laut Simulator und
vergleich mit Papier und Bleistift scheint es zu funktionieren.
Danke.
@der alte Hanns
Du hast zwar zuerst gepostet aber dieser Code sah erstmal überschaubarer
aus. Es ist wiklich eine praktische Umsetzung eines vorgegebenen
Layouts, aber das weißt Du jetzt sicherlich schon. Werde mich evtl.
gleich noch motivieren Deinen angehangenen Code durch zu arbeiten.
Danke.
@Winfried J.
Auch Dir danke ich und werde wohl erst übermorgen dazu kommen Deinen
Code zu testen.
Ich sehe grad das der Code trotz Korretur immer noch nicht sauber
formatiert ist. Habe diesen direkt aus dem AVR-Studio kopiert und dann
die Stellen formatiert, die jetzt immer noch aus der Reihe tanzen.
Bernd_Stein
Bernd Stein schrieb:> Ich sehe grad das der Code trotz Korretur immer noch nicht sauber> formatiert ist. Habe diesen direkt aus dem AVR-Studio kopiert und dann> die Stellen formatiert, die jetzt immer noch aus der Reihe tanzen.>
Habe mich ein wenig erinnert.
Also im AVR-Studio unter Edit => Show Whitespace, kann man gut sehen ob
die Tabs mit Leerzeichen ausgefüllt werden oder nicht ( .... ) bzw. ( >>
>> ).
Um die Tabs mit Leerzeichen zu füllen muß unter Tools => Options =>
Editor das Häkchen bei Replace tabs with space gesetzt werden.
Leider wirkt sich das nicht sofort aus, so das das AVR-Studio erst
geschlossen und wieder geöffnet werden muss.
Bernd_Stein
Johann L. schrieb:> Bernd Stein schrieb:>> Was genau ist spiegeln ?>>
Weiß ich jetzt immer noch nicht genau.
Bitte kein C oder andere Programmiersprachen, davon habe ich keine
Ahnung und das wird mir dann zu krüptisch, deshalb auch im Titel :
*AVR-ASM...*
Was soll zero_reg_ sein ?
Ein Register mit Inhalt Null ?
Warum und wo wird _tmp_reg_ noch benutzt ?
> Oder so:> uint8_t mirror_faster (uint8_t val)> {> return __builtin_avr_insert_bits (0x01234567, val, 0);> }>> -->> mirror_faster:> lsl r24> adc r24,__zero_reg__> mov _tmp_reg_,r24> bst r0,1> bld r24,7> bst r0,2> bld r24,6> bst r0,3> bld r24,5> bst r0,5> bld r24,3> bst r0,6> bld r24,2> bst r0,7> bld r24,1> ret>> :-P>> Geht übrigens noch schneller weil man mirror_faster() im Gegensatz zu> einer Assemblerfunktion inlinen kann.>
Was bedeutet inlinen ?
Tut mir leid. Dein Beispiel ist mir zu undurchsichtig.
Ich übe mich noch in AVR-ASM ;-)
Bernd_Stein
Bernd Stein schrieb:> Was bedeutet inlinen ?> Tut mir leid. Dein Beispiel ist mir zu undurchsichtig.> Ich übe mich noch in AVR-ASM ;-)
Ja, dann probiere es mal mit ASM von der alte Hanns, wenn du schon
kein C willst, ansonsten ist Schnippsel von PeDa genauso klar.
Bei einem so verdrehtem Layout wie deinem, schiebt man nicht rum,
sondern setzt mit .EQU Anweisungen welches Datenbit auf welches
Portbit geht. Dann werden die bits in der Ausgaberoutine einzeln
gesetzt und fertig.
Eventuell kann man vorher mit einer Maske die Databits ausblenden,
Databits einzeln setzen und dann das Ganze auf einmal zum Port
schicken (um eventuelle Glitches zu vermeiden). ;-D
Etwa so:
1
;*(c)CopyleftbyderalteHanns
2
;*AllWrongsreservedbyich
3
.include"m88def.inc"
4
;***BenutztePorts
5
.equDDR_LCD=DDRB
6
.equPORT_LCD=PORTB
7
8
;***Kontrollbits
9
.equLCDrs=0
10
.equLCDen=1
11
.equSteuerMask=0xC3
12
13
;***Databits
14
.equLCDd3=2
15
.equLCDd2=3
16
.equLCDd1=4
17
.equLCDd0=5
18
19
;***Arbeitsregister
20
.deftmp0=r16
21
.deftmp1=r17
22
23
TstLCD:
24
;***DataPinsalsAusgang
25
lditmp0,1<<LCDd3|1<<LCDd2|1<<LCDd1|1<<LCDd0
26
;***KontrollPinsalsAusgang
27
oritmp0,1<<LCDrs|1<<LCDen
28
outDDR_LCD,tmp0
29
30
;***Loopzumtesten
31
T_1:
32
lditmp0,0x53
33
rcallLCD_Datbyt
34
rjmpT_1
35
36
;****Ausgaberoutine(KontrollByte)
37
LCD_Ctrlbyt:
38
cbiPORT_LCD,LCDrs
39
rjmpLCDb
40
;****Ausgaberoutine(DataByte)
41
LCD_Datbyt:
42
sbiPORT_LCD,LCDrs
43
LCDb:
44
pushtmp0
45
swaptmp0
46
rcallLCDn
47
poptmp0
48
;****Ausgaberoutine(Nibble)
49
LCDn:
50
intmp1,PORT_LCD
51
;*Kontrollbitsausblenden
52
anditmp1,SteuerMask
53
;*Undbitfurbitprufen...
54
sbrctmp0,3
55
sbrtmp1,1<<LCDd3
56
sbrctmp0,2
57
sbrtmp1,1<<LCDd2
58
sbrctmp0,1
59
sbrtmp1,1<<LCDd1
60
sbrctmp0,0
61
sbrtmp1,1<<LCDd0
62
;*ENABLEauf1
63
sbrtmp1,1<<LCDen
64
outPORT_LCD,tmp1
65
;*min.250nsfurENABLE,wennichmichrechterinnere
66
nop
67
nop
68
;*ENABLEwiederaufNull
69
cbiPORT_LCD,LCDen
70
ret
Nichts mit spiegeln, schieben und sonstigem. Sollte sich dein Layout
(zum Besseren) ändern, einfach nur die paar .EQU Anweisungen
entsprechenden ändern.
Etwas vom alten Hiddigeigei, ist auch mein letzter Beitrag, versprochen:
Von des Turmes höchster Spitze
Schau' ich in die Welt herein,
Schaue auf erhab'nem Sitze
In das Treiben der Partein.
Und die Katzenaugen sehen,
Und die Katzenseele lacht,
Wie das Völklein der Pygmäen
Unten dumme Sachen macht.
Doch was nützt's? ich kann den Haufen
Nicht auf meinen Standpunkt ziehn,
Und so laß ich ihn denn laufen,
's ist wahrhaft nicht schad' um ihn.
Menschentun ist ein Verkehrtes,
Menschentun ist Ach und Krach;
Im Bewußtsein seines Wertes
Sitzt der Kater auf dem Dach! –
Bernd Stein schrieb:> Die Methode von Johann L. gefällt mir am besten.
LOL.
Ich hoffe, ihr beide lernt es noch zu lebzeiten.
Und wenn das funktionieren sollte, erschiesse ich mich öffentlich.
Marc Vesely schrieb:> LOL.
Will meinen Beitrag nicht löschen, aber damit es nicht
ohne Begründung bleibt und weil du sagst, dass du
neu in Assembler bist:
Marc Vesely schrieb:> Ich hoffe, ihr beide lernt es noch zu lebzeiten.
Warum dein Programm nicht gut ist:
a) Was glaubst du, warum es in C .h Datei gibt und wozu
.equ in Assembler dient ?
(auch Assembler kennt .h oder .inc Dateien).
b) Dieses direktes setzen mit
bst r18,7 ;Bit7 an...
bld r16,2 ;...Portpin 2
ist somit auch schlecht, sobald da irgendein Pin geändert
werden soll, wirst du dir die Haare vom Kopf fressen.
Und man ändert nicht etwas mitten im Programm wenn es
am Anfang oder in einer besonderer Datei übersichtlicher
definiert werden kann. Sollte dein Programm mit der Zeit
größer werden, wirst du die entsprechende Zeile Nr.10047
kaum finden oder einfach übersehen.
c) der alte Hanns, PeDa und ich senden dir etwas das
einfach geändert und angepasst werden kann, aber du
hältst an den (so nicht funktionierenden) Zeilen
von Johann L. fest.
Wobei ich nicht sagen will, dass die Methode mit
bld und bst schlechter ist, nur mag ich persönlich
einfach nicht mit T-Flag rumspielen - Compiler benutzen
T-Flag manchmal, auch sind die beiden Befehlsabkürzungen,
zumindest für mich, unlogisch.
.
d) Etwas zweimal (unnötig) setzen und rücksetzen, zweimal etwas
(unnötig) abfragen, anstatt einfach die entsprechende Routine
aufzurufen und dann durchzufallen ist auch schlecht.
Man muß nicht etwas das funktioniert und gut ist, mit
Gewalt ändern und schlechter machen, nur um zu sagen:
- Ich habe das selbst geschrieben.
e) Programmteile die eine gewisse Aufgabe erfüllen, schreibt
man als Routinen (Unterprogramme) und versucht nachher
eine Bibliothek daraus zu machen. Bloßes aneinanderreihen
von Programmzeilen bringt bestimmt keine Vorteile, das wirst
du spätestens dann merken, wenn du nach 2-3 Monaten etwas
in deinem Code ändern oder an einem gemeinsamen Projekt
teilnehmen willst.
Marc Vesely schrieb:> Und wenn das funktionieren sollte, erschiesse ich mich öffentlich.
Warum dein Programm nicht funktionieren wird:
a) Weil Enable mindestens 250ns dauern muss, bei dir
wird das mit 8MHz schon ziemlich knapp und beim LCD ist
Einhaltung der Mindestzeiten äußerst wichtig. Es gibt keinen
Befehl der schneller als 35us ist, mit Cursor dauert es
sogar über 1ms, LCD ist halt langsam, gewöhne dich dran.
Ich hatte mal ein Graphic Display, da war die Zeit
zwischen 2 aufeinanderfolgenden Enable min. 1250ns.
b) Weil RS auf Log.1 für Daten und auf Log.0 für
Befehl gesetzt werden muss und bei dir sehe ich nicht,
daß RS auf irgendeinen definierten Pegel gesetzt wird.
Marc Vesely schrieb:> Will meinen Beitrag nicht löschen, aber damit es nicht> ohne Begründung bleibt und weil du sagst, dass du> neu in Assembler bist:>
Danke.
Deine Beründungen haben mir etwas die Augen geöffnet. Trotzdem fehlt mir
der totale Durchblick.
> ;*** Kontrollbits> .equ LCDrs = 0> .equ LCDen = 1> ;*** KontrollPins als Ausgang> ori tmp0, 1<<LCDrs | 1<<LCDen> out DDR_LCD, tmp0>
Mit so etwas tue ich mich noch schwer.
In r16 bzw. tmp0 werden da die Bitpositionen 0 und 1 auf 1 gesetzt oder
nur Bitpositon 1 ( LCDen ) - und Bitposition 0 ( LCDrs ) bleibt erhalten
?
Also, ich habe in einem für mich riesen Programm einige Änderungen
vorzunehmen, da einige Pinne durch das Layout anders verdrahtet sind.
Ich bin so vorgegangen, das ich z.B. nach " portb, ddrb, pinb " gesucht
habe und dann versuche die Programmabschnitte umzuschreiben.
ALTNEU
LCD_D7 PB5 PD2
LCD_D6 PB4 PD3
LCD_D5 PB3 PD4
LCD_D4 PB2 PD5
LCD_RS PC4 PD7
LCE_E PC5 PD6
Um mal den Programmierstil zu zeigen hier ein Ausschnitt aus dem
Orginalcode in dem ich zum Zeitpunkt der Threaderstellung feststeckte :
1
;
2
; LCD-Ausgabe eines Zeichens im 4-Bit Mode (Sensormodul2)
3
; Register: r16
4
; r17 <- 0 = Befehlsbyte, 1 = Datenbyte
5
; r18 <- LCD-Daten oder -Befehl
6
;
7
lcdout: tst r17 ;Datenbyte?
8
brne lcdo10 ;ja -> weiter
9
cbi portc, 4 ;LCD in Befehlsmodus setzen
10
rjmp lcdo20
11
lcdo10: sbi portc, 4 ;LCD in Datenmodus setzen
12
lcdo20: mov r16, r18 ;Datenbyte kopieren
13
ror r18 ;oberes Nibble an die richtige
14
ror r18 ;Position schieben
15
andi r18, 0x3c ;Nibble filtern
16
ori r18, 0x03 ;Pullup für Al1 und Al2 setzen
17
out portb, r18 ;Daten/Befehlsbyte ausgeben
18
sbi portc, 5 ;E auf High setzen
19
cbi portc, 5 ;E wieder auf Low setzen
20
;
21
mov r18, r16 ;Datenbyte kopieren
22
rol r18 ;unteres Nibble an die richtige
23
rol r18 ;Position schieben
24
andi r18, 0x3c ;Nibble filtern
25
ori r18, 0x03 ;Pullup für Al1 und Al2 setzen
26
out portb, r18 ;Daten/Befehlsbyte ausgeben
27
sbi portc, 5 ;E auf High setzen
28
cbi portc, 5 ;E wieder auf Low setzen
29
ret
Mir ist es auch wichtig, Code so zu schreiben, das er einfach angepasst
werden kann. Nur muss ich dies erstmal lernen.
Ich hänge mal den gesamten Code an, weil dies für den Einen oder Anderen
von Vorteil ist, um mein Problem besser zu verstehen.
Hier der Link zu dem wirklich sehr schönen und auch funktionierenden
Projekt :
Leider kommt man nicht direkt mit diesem Link dort hin. Also es geht um
das Temperaturmesssystem und dort für mich nun nur um das
*SENSORMODUL 2/3.* bzw. SENSORMODUL 2.
http://s-huehn.de/elektronik/
Habe das SENSORMODUL2 nochmal gebaut nun aber nicht gefädelt,
sondern mit einem Layout, um es auch für Andere einfach nachbaubar bzw.
nachbausicherer zu machen.
Bernd_Stein
Bernd K. schrieb:> 16 byte lookup table?
Hehehe, ist leider völlig untergegangen, dabei so simpel und an so gut
wie jede Portkonfiguration einfachst anpassbar. Auch bei mir die
Standardlösungen auch für exotische ROM Ausführungen des LCD
Controllers.
Bernd Stein schrieb:>> ldi tmp0, 1<<LCDd3 | 1<<LCDd2 | 1<<LCDd1 | 1<<LCDd0>> ori tmp0, 1<<LCDrs | 1<<LCDen>>> Mit so etwas tue ich mich noch schwer.> In r16 bzw. tmp0 werden da die Bitpositionen 0 und 1 auf 1 gesetzt oder> nur Bitpositon 1 ( LCDen ) - und Bitposition 0 ( LCDrs ) bleibt erhalten> ?
"|" steht fur OR, somit werden beide Pins auf 1 gesetzt (Ausgang).
Könnte das alles auch in der ersten Zeile setzen, aber ich wollte es
dir übersichtlicher machen.
Bernd Stein schrieb:> ALT NEU> LCD_D7 PB5 PD2> LCD_D6 PB4 PD3> LCD_D5 PB3 PD4> LCD_D4 PB2 PD5
Auch schlecht, versuche diese 4 Pins entweder im oberen oder unteren
Nibble zu plazieren. Damit ersparst du dir später unnötige Schieberei.
Bernd Stein schrieb:> lcdout: tst r17 ;Datenbyte?> brne lcdo10 ;ja -> weiter
Auch nicht besonders gut, so etwas sollte man grundsätzlich nicht
machen. Erstens braucht man nicht ein ganzes Register um so etwas
abzufragen (vor allem nicht r17, r16-r31 sind kostbar), zweitens
ist es besser Befehls- und Datenausgabe getrennt aufzurufen, da
sieht man wenigstens was ausgegeben werden soll.
Bernd Stein schrieb:> Ich hänge mal den gesamten Code an, weil dies für den Einen oder Anderen> von Vorteil ist, um mein Problem besser zu verstehen.
Bin nicht durch diesen Code durch, eben aus der schon genannten
Gründen:
> (auch Assembler kennt .h oder .inc Dateien).
Also, die ganzen .equ, #define und Variablen in eine oder zwei
.inc oder .h Datei packen wäre viel besser. Warum ?
a) Dein Programm, zumindest die wichtigen Teile davon wird viel
übersichtlicher.
b) Solltest du irgendwann mal in irgendeinem Programm noch die
LCD Ausgabe oder Sensor Abfrage brauchen, ist es einfacher:
I) Durch 4785 Zeilen Code durchzugehen, die benötigten Zeilen
mit Copy&Paste ins neue Program ?
II) Einfach eine Datei mit .include einbinden ?
EDIT:
Ich glaub's nicht, dieses Programm hat tatsächlich 4785 Zeilen !
Marc Vesely schrieb:> Bernd Stein schrieb:>> Die Methode von Johann L. gefällt mir am besten.>> LOL.> Ich hoffe, ihr beide lernt es noch zu lebzeiten.> Und wenn das funktionieren sollte, erschiesse ich mich öffentlich.
Oje, welche Laus hat dir denn an der Leber geknabbert?
...da kann man echt froh sein, wenn man nicht mit so nem arroganten
GRÖPAZ zusammen arbeiten muss.
Aber zu Sache.
Glitches:
Es ist ein Unterschied, ob man Glitches nicht berücksichtigt, weil sie
nicht berücksichtigt werden müssen, oder ob man sie nicht
berücksichtigt, weil man sich keine Gedanken darüber gemacht hat.
Man wird doch noch drauf hinweisen dürfen?
Zum Code:
Dass man Code beliebig mit Makros verunstalten und verallgemeinern kann
ist hier wohl jedem klar. Es ging aber zunächst mal nur um eine
Befehlssequenz als solche, die die gewünschte Abbildung erledigt. Und
für den Überblick ist eine explizite Sequenz erst mal einfacher zu
erfassen als ein
super-duper-allgemein-und-auch-für-haste-nicht-gesehn-verwendbarer Code.
Übrigens ist der von mir gepostete Code nicht von mir sondern von GCC.
Beschwer dich also bei den GCC-Entwicklern darüber.
Marc Vesely schrieb:> nur mag ich persönlich einfach nicht mit T-Flag rumspielen
ok, alles klar
Johann L. schrieb:> Oje, welche Laus hat dir denn an der Leber geknabbert?
Keine Ahnung, bin sonst ein ganz netter Kerl.
Johann L. schrieb:> Glitches:> ...> Man wird doch noch drauf hinweisen dürfen?
Hmmm, jein.
Radio Eriwan:
Im Prinzip ja, aber bei der LCD Ausgabe...
Johann L. schrieb:> Dass man Code beliebig mit Makros verunstalten und verallgemeinern kann> ist hier wohl jedem klar.
Ein bisschen hart formuliert, finde ich.
> Es ging aber zunächst mal nur um eine> Befehlssequenz als solche, die die gewünschte Abbildung erledigt. Und> für den Überblick ist eine explizite Sequenz erst mal einfacher zu> erfassen als ein
Da kann ich mich nur mit dem ersten Teil einverstanden erklären.
Für mich ist
cbi LCD_Port, LCD_RS
leichter zu verstehen als
cbi PortB, 6
Johann L. schrieb:> Übrigens ist der von mir gepostete Code nicht von mir sondern von GCC.> Beschwer dich also bei den GCC-Entwicklern darüber.
Meine Bemerkung betraff nicht deinen oder GCC Code, sondern die direkte
Adressierung der Portbits.
Natürlich steht es jedem frei, Portbits direkt zu adressieren oder den
bits sinnvolle Namen zu geben. Aber TO fängt ja gerade mit Assembler
an und da ist es besser, richtig anzufangen. Und bei solch verdrehtem
Layout fährt er mit Pinnamen weitaus besser als mit Pinnummern.
Johann L. schrieb:> ...da kann man echt froh sein, wenn man nicht mit so nem arroganten> GRÖPAZ zusammen arbeiten muss.
Halte mich weder für GRÖPAZ, noch bin ich arrogant, versuche immer
zu helfen, manchmal mit Erfolg, manchmal ohne. Unterschätze niemanden,
habe aber auch kein Problem jemandem die Wahrheit zu sagen, und auch
kein Problem von jemandem die Wahrheit zu hören.
>>>> ;*** Kontrollbits>> .equ LCDrs = 0>> .equ LCDen = 1>> ;*** KontrollPins als Ausgang>> ori tmp0, 1<<LCDrs | 1<<LCDen>> out DDR_LCD, tmp0>>
Habe jetzt erst gelesen, das es hier weiter geht. Jetzt ist auch der
Haken für " E-Mail-Benachrichtigung einschalten " gesetzt.
Nun nochmal konkret.
LCDrs ist ja Null, also wird ja diese Bitposition ( Bit0 ) so gelassen
und nur Bitposition ( Bit1 ) eins gesetzt, da ja LCDen Eins ist und die
Veroderung ( | ) dies bewirkt.
oder
Die Bitpositionen ( Bit0 und Bit1 ) werden auf Eins gesetz, weil LCDrs
die Bitposition0 ist und LCDen die Bitposition1 und diese mit 1<< durch
die Veroderung überschrieben werden.
Was ist jetzt richtig ?
Bin nämlich jetzt so verwirrt, weil Du unteres Beispiel mit dem darunter
geschriebenen Text eklärst.
Marc Vesely schrieb:>>> ldi tmp0, 1<<LCDd3 | 1<<LCDd2 | 1<<LCDd1 | 1<<LCDd0>>> ori tmp0, 1<<LCDrs | 1<<LCDen>>>>>>>>> "|" steht fur OR, somit werden beide Pins auf 1 gesetzt (Ausgang).>>> Könnte das alles auch in der ersten Zeile setzen, aber ich wollte es>>> dir übersichtlicher machen.>>>Beitrag "Re: AVR-ASM Knobelei : Bitmanipulation am LCD im 4-Bit Mode"
Was würde
ori tmp0, 0<<LCDrs | 1<<LCDen
bewirken ?
Die Null bei LCDrs ist beabsichtigt.
Bernd_Stein
Bernd Stein schrieb:> Nun nochmal konkret.
Da steht 1 << LCDrs
Das dröseln wir mal auf. << ist die binäre Schiebeoperation. Der linke
Operand wird um so viele Stellen nach links geschoben, wie der rechte
Operand angibt.
Links steht 1. In Bits aufgedröselt also
1
0000 0001
(Ich mach zwischen die Nibble ein Leerzeichen rein. 4 Bits zählen sich
leichter als 8)
dieses Bitmuster wird als nach links geschoben. Wegen den <<.
Um wieviele Stellen wird nach links geschoben?
Um LCDrs Stellen.
Was war nochmal LCDrs?
1
.equ LCDrs = 0
aha. LCDrs ist nichts anderes als 'ein anderer Name' für 0.
D.h. das Bitmuster soll um 0 stellen nach links geschoben werden.
Das ist aber einfach, dann wenn ich was um 0 STellen nach links schiebe,
dann verändert sich ja nichts.
Das erste Teilergebnis ist also das Bitmuster
1
0000 0001
Aber. Der Ausdruck geht ja noch weiter. Da gibt es noch den zweiten
Teilausdruck
1
1 << LCDen
was kommt da raus?
Wieder. Es beginnt mit dem linken Teil, der 1 ist. Oder in binärer Form,
als Bits aufgedröselt
1
0000 0001
Dieses Bitmuster soll wieder nach links geschoben werden. Um wieviele
Stellen? Um LCDen Stellen. LCDen war was?
1
.equLCDen=1
Aha. LCDen ist nur ein anderer Name für 1. D.h. das Bitmuster soll also
um 1 Stelle nach links geschoben werden.
Das Bitmuster war
1
0000 0001
um eine Stelle nach links geschoben, ist das also
1
0000 0010
Gut. Damit sind die beiden Teilausdrücke erledigt. Jetzt werden sie noch
miteinander verodert.
1
0000 0001
2
| 0000 0010
3
-----------
4
0000 0011
5
6
(einfach in jeder Spalte auf die beiden Bits eine Oder Operation anwenden)
Das Ergebnis ist als ein Byte, in dem die beiden Bits 0 und 1 auf 1
gesetzt sind und alle anderen Bits 0 sind. Die Bits 0 und 1 deswegen,
weil LCDrs für die Bitposition 0 steht und LCDen für die Bitposition 1.
Wären die .equ andere
1
.equ LCDrs = 4
2
.equ LCDen = 7
dann würde da eben ein Byte rauskommen, bei dem an den Bitpositionen 4
bzw. 7 ein 1 Bit steht und alle anderen 0 sind.
Aber egal wie, damit ist bekannt, was das Ergebnis des Ausdrucks
1
......... , ( 1 << LCDrs ) | ( 1 << LCDen )
ist. Das ist ein Byte, in dem bestimmte Bits auf 1 sind und alle anderen
auf 0.
Und damit wird dann eben je nach der ....... Operation weiter gemacht.
> Was würde> ori tmp0, 0<<LCDrs | 1<<LCDen> bewirken ?>> Die Null bei LCDrs ist beabsichtigt.
Das Bitmuster
1
0000 0000
kannst du nach links bzw. nach rechts schieben so oft und solange du
lustig bist. Das Ergebnis davon wird wieder immer nur das Bitmuster
1
0000 0000
sein. Aus genau dem gleichen Grund kann man auch jede Zahl mit 0
multiplizieren und das Ergebnis davon wird trotzdem einfach nur 0 sein.
Bernd Stein schrieb:> Was würde> ori tmp0, 0<<LCDrs | 1<<LCDen> bewirken ?>> Die Null bei LCDrs ist beabsichtigt.
LCDen geht auf 1, LCDrs bleibt unverändert.
Hallo zusammen,
habe das Orginalprogramm jetzt soweit an das Layout angepasst, das ich
sieben Temperatursensoren angezeigt bekomme ( An jedem Bus nur ein
Temperatursensor ) nur der Bus_4 bei mir PortC2 funktioniert nicht.
Am Sensor selbst liegt es nicht, da ich ihn getauscht und er an einem
anderem Bus ( anderen Aderpaar ) funktioniert. Es wird ein 25-poliges
Flachbandkabel von ca. 1,5m länge verwendet und das Aderpaar an dem der
Temp.Sensor dran ist ist i.O.
Ich vermute also, das der Fehler weiterhin in der Software ist.
Nur finde ich diesen nicht, bin ich zu sehr auf PortC2 versteift der
bei mir dem Bus_4 zugeordnet ist ?
Habe leider keine Ahnung von dem 1-Wire-Bus von DALLAS, aber da ja
sieben andere Temp.Sensoren funktionieren, denke ich das dies doch
richtig implementiert wurde ( nicht von mir ).
Im Anhang das von mir veränderte Programm und hier noch der Link zu dem
SensorModul2.
*Es gilt noch zu beachten, das ich nur den Code bezüglich dem
SensorModul2 geändert habe.*
Hier unter Temperraturmesssytem => Kapitel 3: Sensormodul 2/3 zu
finden.
http://s-huehn.de/elektronik/
Bernd_Stein
Bernd Stein schrieb:> Ich vermute also, das der Fehler weiterhin in der Software ist.> Nur finde ich diesen nicht, bin ich zu sehr auf PortC2 versteift der> bei mir dem Bus_4 zugeordnet ist ?
Vielen vielen Dank, das Du mich direkt mit der Nase darauf gestossen
hast, sonst hätte ich es wahrscheinlich noch huntert mal übersehen.
Das war wirklich die einzige Stelle im Programm, die diesen Fehler
verursachte. Bitposition2 bzw. Bit2 hat natürlich die Wertigkeit 0x04.
Irgendwie muß ich wohl immer die 2 als Wert gesehen haben und nicht als
Bitpostition bzw. Bit und mein Gehirn machte daher immer 2^1 daraus,
also 2 hoch 1, was ja den Wert 2 ergibt. Aber es ging ja um die
Bitposition2 bzw.*Bit2* und nicht um den Wert 2.
Warum ich gerade in dieser Programmpassage diesen Gedankengang hatte und
nicht bei den anderen identischen, kann ich mir nur so erklären, das
sich irgendwie alles um die 2 ( PortC2 ) drehte.
Kannst Du mir bitte noch schreiben, wie Du vorgegangen bist, das Du den
Fehler so schnell ( < 20 min ) gefunden hast ?
Bernd_Stein
Bernd Stein schrieb:> Kannst Du mir bitte noch schreiben, wie Du vorgegangen bist, das Du den> Fehler so schnell ( < 20 min ) gefunden hast ?
Weil ich klug bin ?
Nö, im Ernst, deswegen soll man Programmteile trennen, Unterprogramme
benutzen, Kommentare schreiben etc. Bei dem geposteten Programm ist
das alles OK, war nicht so schwer.
Abschnitt mit 1-Wire Routinen gefunden.
Geguckt was die anderen bits machen, mit bit2 verglichen und...
Bernd Stein schrieb:> Vielen vielen Dank, das Du mich direkt mit der Nase darauf gestossen> hast, sonst hätte ich es wahrscheinlich noch huntert mal übersehen.
Bist nicht der einzige, dem es so geht, was glaubst warum ich so wenig
Haare auf dem Kopf habe ?
Bernd Stein schrieb:> Habe das SENSORMODUL2 nochmal gebaut nun aber nicht gefädelt,> sondern mit einem Layout, um es auch für Andere einfach nachbaubar bzw.> nachbausicherer zu machen.>
Und nochmals Danke an alle, die dazu beigetragen haben dies
fertigstellen zu können.
Hier nun der dazu passende Link :
Beitrag "Temperaturmesssystem Sensormodul 2 mit ATmega 8 in AVR-ASM"
Bernd_Stein