Hallo,
ich möchte die Bits eines 8-Bit Registers nacheinander über den PORTD
ausgeben, allerdings soll vorher ein Startbit kommen, was immer 1 ist
und nach dem Byte ein Stopbit, was immer 0 ist (für Synchronisation).
Hier mein Code:
1
.include "tn2313def.inc"
2
3
.def temp = R16
4
.def mask = R17
5
.def input = R18
6
.def output = R19
7
.def timer = R20
8
9
.org 0x0000 RJMP reset
10
.org 0x0006 RJMP tim0_ovf
11
12
reset:
13
LDI temp, (1<<CS02)|(1<<CS00) ;Prescale 1024
14
OUT TCCR0B, temp
15
LDI temp, (1<<TOIE0) ;Interrupt bei Overflow
16
OUT TIMSK, temp
17
SEI ;Interrupts erlauben
18
LDI temp, 0 ;PortB als Input
19
OUT DDRB, temp
20
LDI temp, 255 ;Interne Pull-ups anziehen
21
OUT PORTB, temp
22
LDI temp, 127 ;PortD als Output
23
OUT DDRD, temp
24
LDI mask, 1 ;Maske auf 00000001 bringen
25
CLR timer
26
CLR output
27
28
loop:
29
;IN input, PINB
30
LDI input, 1
31
OUT PORTD, output
32
RJMP loop
33
34
tim0_ovf:
35
CBI PORTD, 0 ;"Impuls" ,das nullte Bit 0 setzen
36
INC timer
37
CPI timer, 1
38
BRNE normal ;wenn Timer = 1
39
LDI output, 1 ;Startbit immer 1
40
LDI mask, 1
41
RETI
42
normal:
43
MOV temp, mask
44
AND temp, input ;(Maske AND Input) in temp
45
CPI temp, 1
46
LDI output, 0
47
BRCS sendNull ;wenn (Maske AND Input) > 0 dann 1 senden, sonst 0
48
LDI output, 1
49
sendNull:
50
ROL mask ;Maske vorbereiten zur Abfrage des nächsten Bits
51
BRCC resetNotTimer
52
CLR timer ;Wenn alle Bits des Bytes durch sind, dann Timer = 0
53
LDI output, 0 ;Stopbit immer 0
54
resetNotTimer:
55
RETI
Zu Testzwecken - und weil ich zu faul war, Jumper zu bauen :) -
definiere ich "input" direkt in der der Loop.
Wenn ich 255 oder 0 als Input nehme, dann scheint es auch zu
funktionieren, aber bei allen anderen Werten (als Bsp 1) macht der nur
Murks, die LED, die ich an PD0 angeschlossen habe, blinkt nur apathisch
:(
Was mache ich falsch? Ich hoffe, jemand kann mir helfen.
CPI temp, 1
LDI output, 0
BRCS sendNull
Wieso BRCS? Du willst doch hier einen Vergleich auf Gleichheit. Das wird
vom Zero-Flag angezeigt.
Ansonsten ist das schon sehr konfus. In der ISR das auszugebende Bit zu
bestimmen, welches dann in der Hauptschleife tatsächlich ausgegeben
wird. Und die Sache mit der Mask ist auch ein wenig konfus. Wenn du
sowieso schon ein Hilfsregister brauchst, warum lädst du dir nicht dort
den auszugebenden Wert hinein und shiftest den bei jedem ISR Aufruf eine
Stelle nach Rechts. Dazu noch ein Counter, der die ISR Aufrufe mitzählt.
Counter = 0 ? 1 Bit ausgeben, fertig
Counter = 9 ? 0 Bit ausgeben, fertig
ansonsten Das jeweils 0. Bit ausgeben und 1 mal rechts shiften
>ich möchte die Bits eines 8-Bit Registers nacheinander über den PORTD>ausgeben, allerdings soll vorher ein Startbit kommen, was immer 1 ist>und nach dem Byte ein Stopbit, was immer 0 ist (für Synchronisation).
Das klingt doch sehr nach UART(Bis auf: start:0 stop:1), wofür brauchst
du das eigentlich?
julian
Niklas Beuster schrieb:> ich möchte die Bits eines 8-Bit Registers nacheinander über den PORTD> ausgeben, allerdings soll vorher ein Startbit kommen, was immer 1 ist> und nach dem Byte ein Stopbit, was immer 0 ist (für Synchronisation).
UART verwenden, Inverter dahinter und Daten vor dem Schreiben ins
Transferregister invertieren.
Software-UART auf dem fast einzigen Tiny mit Hardware-UART ist schon ein
wenig pervers. Es sei denn die Hardware-UART ist anderweitig belegt.
Hm, danke erst mal.
vom UART hör ich zum ersten mal, habe gerade die Funktionsweise
überflogen, dass scheint ja genau das zu sein, was ich machen will^^.
Ansonsten,
> CPI temp, 1> LDI output, 0> BRCS sendNull>>> Wieso BRCS? Du willst doch hier einen Vergleich auf Gleichheit. Das wird> vom Zero-Flag angezeigt.
Ich bin immer davon ausgegangen, dass sowas nicht geht, dass man erst
eine Rechenoperation á la CPI macht, also CPI temp, 1 heißt ja temp - 1
und wenn temp = 0 ist, dann gibt's einen Carry, wie soll dass anders
gehen?
> Und die Sache mit der Mask ist auch ein wenig konfus. Wenn du> sowieso schon ein Hilfsregister brauchst, warum lädst du dir nicht dort> den auszugebenden Wert hinein und shiftest den bei jedem ISR Aufruf eine> Stelle nach Rechts.
Das verstehe ich jetzt gar nicht, ich will doch nur 1 oder 0 an PD0
ausgeben, wie soll ich dass anders machen als über eine Maske, die sich
die Bits rauspickt, die ich im Inputregister habe, also genau so, wie
ich das gemacht habe. Also beispielsweise:
Input: 00000110
Maske: 00000001
mit AND würde das 00000000 werden.
Input: 00000110
Maske: 00000010
mit AND würde das 00000010 werden.
ich frage anschließend halt ab, ob die Verknüpfung 0 oder größer ist.
Danke nochmal, ich werde mir das mit UART in Ruhe durchlesen.
> also CPI temp, 1 heißt ja temp - 1> und wenn temp = 0 ist, dann gibt's einen Carry,
Zero! das Zwischenergebnis ist 0, daher Zero!
Einen Carry gibts bei Über- oder Unterlauf.
Ich empfehle ganz dringend einen Blick ins AVR-Tutorial
Auch ein Blick dort hinein bestätig, das 0 - 1 nicht 0 ist^^.
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Arithmetik8#Carry
Bei dieser Operation dürfte das Carryflag 1 werden?!
Geht das hier vielleicht? CPI temp, 0 ? und dann auf Zeroflag
überprüfen?
Also dann würde:
LDI temp, 0
CPI temp, 0
BREQ null
null:
dasselbe bewirken wie:
LDI temp, 0
CPI temp, 1
BRCS null
null:
Karl Heinz Buchegger schrieb:> warum lädst du dir nicht dort> den auszugebenden Wert hinein und shiftest den bei jedem ISR Aufruf eine> Stelle nach Rechts.
Ach, jetzt verstehe ich, was du meinst, ok.
Niklas Beuster schrieb:>> Also dann würde:>> LDI temp, 0> CPI temp, 0> BREQ null> null:>> dasselbe bewirken wie:>> LDI temp, 0> CPI temp, 1> BRCS null> null:
Nein.
Bei deinen spezifischen Zahlen vielleicht (hab ich nicht durchdacht),
aber im allgemeinen nicht.
Zero Bei Vergleichen auf gleich/ungleich
Carry Bei Vergleichen auf größer/kleiner
"nicht gleich" ist aber nicht dasselbe wie "kleiner"
-1 ist zwar kleiner als 0, aber +1 ist größer als 0 und trotzdem ist +1
nicht dasselbe wie 0
Im Tutorial ist im Kapitel über Verzweigungen eine schöne
Zusammenfassung, welche Branches es gibt und wann sie eingesetzt werden.
Aufgeschlüsselt je nachdem, ob man es mit vorzeichenlosen oder
vorzeichenbehafteten Zahlen zu tun hat.
Das Carry Flag ost zwar wichtig, aber nicht alles wird über das Carry
Flag geregelt. In deinem Fall gibt es nur 2 Möglichkeiten: entweder das
Teil ist nach der Maskierung 0, oder es ist nicht 0. Daher Branch if
equal bzw. Branch if not equal.
Niklas Beuster schrieb:> Also dann würde:>> LDI temp, 0> CPI temp, 0> BREQ null> null:>> dasselbe bewirken wie:>> LDI temp, 0> CPI temp, 1> BRCS null> null:
Ja. Aber dem Programmverlauf entsprechend anpassen!
Frage 1: 'ist temp gleich 0?'
Frage 2: 'tritt ein Überlauf ein?' (das ist hier eigentlich nicht die
Frage, und verwirrt etwas)
Für die Frage: 'Ist temp gelöscht?' kann man auch 'tst temp' nehmen.
Würde hier genauso gehen. Führt alles zum gleichen Ergebnis. ('tst' geht
sogar ab R0)
Und nein. Du willst hier nicht
AND temp, input ;(Maske AND Input) in temp
CPI temp, 1
LDI output, 0
BRCS sendNull ;wenn (Maske AND Input) > 0 dann 1 senden, sonst
0
mit 1 vergleichen, weil je nachdem wie deine Maske gerade steht, da eben
nicht 0 oder 1 rauskommt, sondern 0 oder 1 bzw. 0 oder 2 bzw. 0 oder 4
bzw. 0 oder 8 etc....
Dein Kommentar ist nämlich irreführend. Da hast nämlich nicht mit 0
verglichen, sondern mit 1.
Man könnte zb auch ausnutzen, dass der AND das Zero Flag schon ganz von
alleine setzt und der ldi die Flags überhaupt nicht beeinflusst
LDI output, 0
AND temp, input
BREQ sendNull
LDI output, 1
sendNull:
Niklas Beuster schrieb:> vom UART hör ich zum ersten mal, habe gerade die Funktionsweise> überflogen, dass scheint ja genau das zu sein, was ich machen will^^.
Fast. Da ist das Startbit 0, das Stopbit 1 und die Leitung ist im
Ruhezustand auf 1.
Hi
>Ich habe nochmal komplett neu angefangen und nun funktioniert's :)
Aber nur, weil dein Programm weiter nichts macht. Gewöhne dir, in deinem
Interesse, an, in Interruptroutinen SREG und alle Register, die nicht
verändert werden sollen, zu sichern. Sowie dein Programm etwas größer
wird hat die Nichtbeachtung dieser Regel ganz lustige Effekte (außer für
dich) zur Folge.
MfG Spess