Komunikácia s MCU cez sériovú linku
Už dlho mám doma pár mikrokontrolérov AT89C2051 a zatiaľ jediné čo som s nimi spravil bolo blikanie LED. Po tohtoročnej skúsenosti s Freescale som si povedal, že by som sa na ne mohol lepšie pozrieť a skúsiť niečo lepšie ako len zapínanie a vypínanie vstupov. Vytiahol som teda knižku od Dávida Matouška "Práce s mikrokontroléri ATMEL AT89C2051" a nalistoval kapitolu o komunikácií cez sériovú linku.
Prvý problém na ktorý som narazil, bolo že keď som si zmeral výstupné napätia RS232 na pc, tak som zistil, že z pc lezie 9V a mikrokontrolér je napájaný asi 5V, maximálne však 6V a teda, že priamo ich spojiť nemôžem a teda MAX232 budem musieť použiť. Počkal som teda chvíľu kým sa zjavil na stole a pustil sa do toho.
Vytiahol som nepájivé pole, načrel do zásob a vylovil pár tantalových kondenzátorov. Pozapájal podľa schémy, skontroloval zapojenie a zapol. Samozrejme, že na prvýkrát sa nič nestalo, takže som opätovne musel skontrolovať zapojenie a potom napísať do programu pár riadkov, aby som videl, či MCU niečo robí alebo sa len niekde nezacyklil. Nakoniec po niekoľkých pokusoch a mnoho hodín strávených nad assemblerov skúšaním či z obslužnej rutiny prerušenia naozaj musím vyskakovať pomocou príkazu (skúšal som v rutine vynulovať príznaky prerušenia a vybrať zo zásobníku uložené adresy a pokračovať bez vyskočenia z rutiny no nefungovalo to) som dokopal všetko do šťastného konca.
Konštrukčný plánik (pin 16 = napájanie +5V, pin 15 = zem)
Takto vyzeralo zapojenie vo finálnej podobe:
Naľavo je MAX232, napravo ATMEL 89c2051
Výsledok programovania v assembleri, všetko funguje tak ako má. V pamäti programu je uložený reťazec a hneď za ním je uložená 0, dĺžku reťazca si zistím tak, že skočím na jeho začiatok a posúvam sa po pamäti kým nenarazím na nulu. Potom od aktuálnej adresy odčítam adresu začiatku reťazca a dostanem jeho dĺžku.
prgm: ch1 equ 243 portA equ 90h length: ds 1 ;premmena na ulozenie dlzky retazca org 0 ;obsluha prerusenia resetu ajmp reset org 0023h ;obsluha prerusenia serioveho portu ajmp serial reset: call debug ;pri starte parkrat bliknem LED aby som overil ci vsetko funguje mov dptr, #text ;ulozim si poziciu zaciatku textu mov r0, #text-1 nacitajDlzkuRetazca: ;nacitam si dlzku retazca, inkremetujem A, kym sa nerovna 0 co je koniec stringu inc r0 mov a, @r0 jz nacitajDlzkuRetazca mov a, r0 subb a, #text mov length, r0 mov th1, #ch1 mov tmod, #00100000B ;nastavenie casovacu do rezimu RELOAD mov scon, #01010000B ;8-bit prijem riadeny casovacom setb EA ;povolenie prerusenia setb ES ;nastavenie prerusenia od seriovej linky setb tr1 ;zapnutie casovaca mov pcon, #10000000B ;SMOD=1 sjmp $ ;skace na aktualne miesto, nerobi nic serial: ;obsluzna rutina prerusenia jb RI, pocetVysielani ;ak prislo prerusenie od prijimaca, tak musim zacat posiealt text vysielajText: mov a, r7 jz serialKoniec-2 ;ak som na konci retazca, tak skocim na instrukciu umoznujucu prijem mov a, length ;od dlzky odcitam r7 a dostanem adresu pismena ktore chcem vypisat subb a, r7 movc a, @a+dptr ;vyberiem si potrebne pismeno mov sbuf, a ;a tu ho zapisem do registra na odoslanie dec r7 sjmp serialKoniec pocetVysielani: clr REN ;zakazem prijem kym vysielam text mov r7, length ;nacitam si dlzku retazca sjmp vysielajText ;a pustim sa do vysielania setb REN serialKoniec: clr RI ;odstranim priznaky RI a TI clr TI reti ;vyskocim z rutiny debug: ;blikanie LED na kontrolu ci program vobec bezi mov a, #0FFh mov r0, #0 mov r1, #0 mov r3, #5 blikaj: cpl a mov portA, a mov r2, #10 slucka: djnz r0, slucka djnz r1, slucka djnz r2, slucka djnz r3, blikaj mov portA, #0FFh ret text: db 'Hello world! by Lubo ',0 ;samotny text koniec: end ;koniec programu
Tu možno vidieť výsledok v Hypertermináli. Použil som ho, aby mi odpadla starosť s tým či mám správne napísaný program na čítanie sériovej linky.
Po každom stlačení klávesy dôjde k odoslaniu informácie po sériovej linke do MCU a ten pošle naspäť reťazec z pamäte, teda po každom stlačení nejakej klávesi sa mi na obrazovk vypíše text.
Jediné čo k tomu môžem dodať je: Bol to pôrod!