40.7.1. Morse Talker

Při expertimentech s ATtiny15L jsem zjistil, že nemám volné vývody na připojení nějakého zobrazovače hodnoty. Například LCD displeje. Dostal jsem tedy nápad a k jednomu volnému pinu PB4 připojil sluchátko. Hlavní myšlenka je, že když nemohu hodnotu zobrazovat, můžu ji odvysílat morseovkou.

Následující kód je místy velmi divoký a řadu instrukcí jsem nahradil jen komentáři. Jsou to totiž imstrukce značně závislé na způsobu kterým měřím čas. Rovněž tento kód není moc přehledný. Ke své lítosti jsem opravdu nemohl použít podprogramy, které by kód velmi zpřehlednily. Program vznikal a ladil jsem jej na MCU ATtiny15L, který má zásobník návratových adres jen 3 úrovně hluboký. Počítaje přerušení které si může vzít kdykoliv jednu úrověň, a proceduru TX_Message která vysílá celý řetězec znaků a používá pro vysílání jednotlivých znaků tuto proceduru TX_Symbol. Tím jsem vyčerpal všechny úrovně zásobníku návratových adres.

; Transmit one morse symbol (character) given in register ARG.
TX_SYMBOL:
        ; Code to handle 0x20 (Space) as a special case.
        CPI     Arg, 0x20
        BREQ    Send2T

        ; Initialize Z pointer to MorseTab
        LDI     ZL, low(MorseTab << 1)
        LDI     ZH, high(MorseTab << 1)

        ; Make some correction to arg.  The table begins with space, code=0x20.
        SUBI    Arg, 0x20

        ; Add Arg to Z, so Z will point to character given by Arg.
        ADD     ZL, Arg
        BRCC    LoadCode
        INC     ZH

LoadCode:
        LPM                     ; Now R0 contains encoded symbol.
        MOV     Seq, R0

SendLoop:
        CLC                     ; Must be cleared before ROR
        ROL     Seq
        ; The C contains dih/dat, but only if Seq is non zero.
        ; In such case Seq is empty and C contains stop mark.
        BREQ    EndSymbol

        ; We can send a . or - depending on the Carry value.
        SBR     BITF, 0b00000001 ; Sound On
        BRCC    SendDih

	; Vysíláme čárku (dah).  Protože zvuk je zaplý.

	;Wait 1T
	;Wait 1T
	;Wait 1T

	CBR     BITF, 0b00000001 ; Sound Off

	;Wait 1T
	RJMP    SendLoop


EndSymbol:
        ;Wait 1T
        ;Wait 1T
        RET

Na kódu je zvláštní jedna věc. Se zdrojem časových impulsů a zdrojem tónu komunikuje přes bity v registru BitF. Bit 0 tohoto registru určuje, zdali je vytvářen tón. 0 znamená že nikoliv a je tedy ticho, 1 znamená že se generuje tón. Další bit 1 tohoto registru slouží ke komunikaci se zdrojem času. Zdroj času totiž tento bit v pravidelných intervalech 1T nastavuje na 1. Všechna čekání jsou tedy krátké posloupnosti tří instrukcí podobné této:

        ; Wait 1T
        CBR     BitF, 0b00000010 ; smaž bit 1
Loop:   SBRS    BitF, 1          ; čekej dokud jej zdroj času opět nenastaví
        RJMP    Loop

Kód programu je rovněž „zkrácen“ vzájemným nakombinováním různých větví do sebe. Například vysílání čárky a tečky je udělané tak že tečka je poslední třetina čárky.

        Sound On
        If tečka Go tecka
        Wait 1T
        Wait 1T
tecka:  Wait 1T
        Sound Off
        Wait 1T

Za každou tečku nebo čárku je rovněž ihned vysláno ticho o délce 1T což mi zjednodušuje vysílání posloupnosti teček a čárek. Na to pak musím myslet, když dělám mezeru mezi písmeny, že kousek ticha o délce 1T už byl odvysílán a že zbývají jen dva kousky ticha.

Poslední částí, která je nutná k pochopení programu je tabulka morse kódů.

MorseTab:
	.db	0b00000000, 0b10101110, 0b01001010, 0b00000000 ; SP ! " #
	.db	0b00000000, 0b00000000, 0b01000100, 0b01111010 ; $ % & '
	.db	0b10110100, 0b10110110, 0b00000000, 0b01010100 ; ( ) * +
	.db	0b11001110, 0b10000110, 0b01010110, 0b10010100 ; , - . /

	; 0x30 - 0x39 Numbers
	.db	0b11111100, 0b01111100, 0b00111100, 0b00011100 ; 0 1 2 3
	.db	0b00001100, 0b00000100, 0b10000100, 0b11000100 ; 4 5 6 7
	.db	0b11100100, 0b11110100                         ; 8 9

	; 0x3A - 0x3F
	.db	0b11100010, 0b10101010, 0x00000000, 0b10001100 ; : ; < =
	.db	0b00000000, 0b00110010                         ; > ?

	; 0x40 Alphabet
	.db	0b10000000, 0b01100000, 0b10001000, 0b10101000	; @ A B C
	.db	0b10010000, 0b01000000, 0b00101000, 0b11010000 	; D E F G
	.db	0b00001000, 0b00100000, 0b01111000, 0b10110000 	; H I J K
	.db	0b01001000, 0b11100000, 0b10100000, 0b11110000 	; L M N O
	.db	0b01101000, 0b11011000, 0b01010000, 0b00010000 	; P Q R S
	.db	0b11000000, 0b00110000, 0b00011000, 0b01110000 	; T U V W
	.db	0b10011000, 0b10111000, 0b11001000, 0b00000000 	; X Y Z [
	.db	0b00000000, 0b00000000, 0b00000000, 0b00110110 	; \ ] ^ _

Vymyslel jsem spoustu složitých kódování a způsobů jak pospat morse pro jedno písmeno v jednom bajtu. Ale pak se mi rožlo a já byl osvícen. Kódování se kterým jsem přišel je velmi jednoduché a ke všemu ještě dokáže kódovat o jednu tečku nebo čárku více než nejsložitější se kterým jsem příšel. Princip je takový že tečku kóduji nulovým bitem a čárku jedničkovým bitem. Jediné co potřebuji jednoznačně detekovat, je konec posloupnosti. A v tom je ten ftip. Konec posloupnosti je označen 1 po které následují již jen samé 0. Protože při vysílání posouvám kódové slovo jedním směrem, v mém případě do leva, a zajišťuji že se zprava plní nulami je detekce konce dána tím že posledním bitem který se do Carry načetl je 1 a v registru jsou jen samé nuly. Toto čtení kódu je realizováno jen třemi instrukcemi:

SendLoop:
        CLC                     ; Must be zero before ROR
        ROR     Seq
        BREQ    EndSymbol
Licence Creative Commons
Elektronika a počítače, jejímž autorem je Radek Hnilica, podléhá licenci Creative Commons Uveďte autora-Nevyužívejte dílo komerčně-Zachovejte licenci 3.0 Česká republika .