Програмування послідовного порту Bascom-8051

Застосування послідовного асинхронного порту передбачається в більшості мікропроцесорних систем Навіть у тих випадках, коли він не потрібен для роботи схеми, його використовують (і необхідно використовувати) на етапі налагодження програми, для технологічного настроювання або при випробуваннях Послідовний порт процесора 8051 здатний одночасно приймати і передавати дані, що вимагає такої побудови програм, в яких процеси прийому і передачі незалежні А внаслідок того, що послідовний порт відноситься до розряду повільних пристроїв, то часто при програмуванні потрібне здійснювати прийом і передачу паралельно роботі основної програми Щоб організувати паралельну роботу програм введення (прийому), виведення (передачі) та обробки даних доводиться задіяти переривання Найкраще для цього використовувати переривання послідовно інтерфейсу, що відбувається при заповненні регістра SBUF-приймача (після прийому байта) і спустошенні регістра SBUF-передавача (після видачі байти) Можливий і екзотичний варіант тимчасового поділу завдань прийому, передачі та обробки за допомогою переривання одного з таймерів У кожному разі, реалізація всіх можливостей і інтенсивної роботи послідовного порту представляється дуже складною програмним завданням

Використання в системі послідовного інтерфейсу майже завжди обумовлено роботою в багатопроцесорної середовищі безпосередньо або в прихованій формі, як наприклад, при роботі з COM-портом персонального компютера При програмуванні подібних інтерфейсів виникають проблеми обліку

глобальних тимчасових співвідношень, тобто обліку в поточній програмі часу реакції іншої системи на

передані дані і навпаки Ці проблеми часто і марно ігноруються, хоча саме глобальні процеси визначають швидкість взаємодії систем, а не тільки фізична швидкість передачі даних, як прийнято думати У результаті таких прорахунків може бути втрачена працездатність багатопроцесорноїсистеми тільки через зміни продуктивності одного компонента, наприклад, при його модернізації При програмуванні також необхідно передбачати і можливість виникнення аварійних ситуацій в периферії одного з компонентів у момент взаємодії

Наступний важливий компонент програмування системи з послідовним портом – вибір протоколу звязку і формату даних Вважається, що чим коротше передане повідомлення, тим краще В принципі це правильно, але за однієї умови, що це повідомлення має бути зрозумілим, і, найголовніше, залишатися зрозумілим у спотвореному вигляді Мається на увазі, не те, що в повідомленні повинна міститися надлишкова інформація, що дозволяє відновити втрачене, а тільки те, що приймаюча сторона повинна виявити факт збою Особливо небезпечно застосування протоколів з чисто двійковими даними Спотворення таких даних може виявитися не тільки непоміченим, але і привести до втрати синхронізації (опознаванию початку і кінця пакетів даних) Автор продовжує наполягати на необхідність застосування в протоколах тільки текстових структур з роздільниками у вигляді символів 0Dh («ВК» – повернення каретки) і 0Ah («ПС» – переклад рядка) Передача даних у вигляді чисел, також повинна виробляється символами Особливо це важливо для відкритих систем Причому, чим більше система відкрита, тим зрозуміліше повинна бути мова переданих повідомлень За застосування протоколів з текстовим форматом даних доводиться платити приблизно дворазовим збільшенням довжини переданих повідомлень і фізичним ускладненням каналу звязку (щоб при необхідності компенсувати втрату швидкості) Однак це окупає себе надійністю роботи, простотою моніторингу (спостереження) за каналом звязку, відмінну сумісністю зі стандартними мовами програмування, в тому числі Bascom-8051

У проектованої програмі інтерфейсу, з самого початку, має бути закладений резерв продуктивності (не менше ніж дворазовий), що включає в себе можливості розширення протоколу (введення додаткових команд) і запаси за швидкістю передачі та обробки даних, наприклад, збільшення

тактової частоти процесора Досвід програмування та експлуатації мікропроцесорних систем звязку

показує, що майже завжди ці ресурси виявляються затребуваними – на етапі налагодження для покриття помилок планування, а пізніше для модернізації

Облік зазначених факторів повинен проводиться на етапі проектування системи і при оптимальному рішенні може забезпечити значне скорочення часу програмування і налагодження, а також обсяг використовуваних ресурсів процесора Навпаки, непродумане прямолінійне рішення протоколу звязку і

ігнорування реальних часових співвідношень в системі можуть призвести до значного ускладнення

програми, і навіть неможливість завершення роботи з огляду на те, що раніше будуть вичерпані ресурси процесора Настільки довгий вступ, не стосується безпосереднього програмування мовою Bascom, тим не менш, необхідно Це обумовлено особливою важливістю правильного рішення частини програми, що забезпечує інтерфейс з іншими мікропроцесорами

Нижче пропонується програми деякого типового периферійного пристрою, що приймає команди в вигляді текстових рядків і повертає дані також у вигляді текстового рядка У програмі є всі звичайні для даного випадку (але трохи спрощені) компоненти: налаштування системи, входження в

стаціонарний стан, декодування і виконання прийнятих повідомлень, генератора подій реального

часу, формування переданих повідомлень, системи введення та виведення через роздільні буфери Структура програми забезпечує можливість паралельно (або майже паралельно) приймати і передавати дані,

обробляти прийняті повідомлення і формувати вихідні дані Програма може бути доповнена операторами, які дозволять обробляти зовнішні події (через зовнішні переривання) і вчиняти дії, що задаються лічильником реального часу Особливістю програмування послідовного порту в даному прикладі є використання у перериванні підпрограм буферирован введення-виведення, написаних на асемблері Видається, що це найоптимальніший варіант, який не обмежує швидкість роботи послідовного інтерфейсу навіть при частоті тактового генератора 3 МГц

‘———————————————-

‘Демонстраційна програма буферирован введення-виведення даних через

‘Послідовний канал Програма приймає повідомлення і аналізує

‘———————————————- Якщо виявляється наступні повідомлення, то:

‘”R – Видається рядок з даними стану системи

‘”Lxxxxx – Завантажуються дані в ЦАП

‘”Sx – Встановлюється режим

‘Формат рядка стану системи: SxLxxxxxTxxx Режим     ^ ^     ^

‘Напруга ЦАП       | | Поточний час             |

‘———————————————-

$ Large велика модель памяті

Dim B_nd As Bit біт Прийнято нові дані Dim B_sd As Bit біт Передати нові дані Dim B_entx As Bit біт Передача дозволена

Ri Alias ​​Scon0 біт RI Ti Alias ​​Scon1 біт TI

Dim Rang As Byte регістр стану системи Dim Tmp As Byte тимчасові байтові дані Dim Cnt As Byte лічильник часу

Dim R_ch As Byte прийнятий або переданий символ

Dim R_bui As Byte покажчик буфера введення Dim R_buo As Byte покажчик буфера виводу Dim Udac As Integer регістр даних ЦАП

Dim Temp As String * 6 тимчасова рядок

Dim Inp_buf As String * 10 буфер введення Dim Out_buf As String * 32 буфер виводу ———————

‘Підключення ЦАП AD766

B_datu Alias P10 : B_clku Alias P11 : B_ldu Alias P12

‘———————————————-

Config Timer0 = Timer , Gate = Internal , Mode = 1 : Start Timer0 ———————

‘TIMER2 в режимі 16-біт таймера з внутр тактується для синхронізації UART Config Timer2 = Timer, Gate = Internal, Mode = 2

$ Baud = 9600 швидкість 96 кБ

$ Crystal = 12000000 при кварці 12 МГц

‘Инициализируем регістри, що визначають режим послідовного каналу

Scon = & H52 режим

Rcap2h = & HFF: Rcap2l = & HD9: Start Timer2 швидкість, тільки таким чином

‘———————

On Timer0 Timer_0_int Nosave вектор переривання

On Serial Ser_int Nosave вектор переривання

Enable Interrupts взагалі дозволити переривання Enable Timer0 дозволити переривання таймера 0 ! ————————————–

B_entx = 0 : Reset Ri : Reset Ti

Enable Serial дозволити переривання послінтерфейса

Out_buf = &quotTest_com&quot + Chr(13) + Chr(10)

R_buo = Varptr (out_buf) покажчик буфера на початок

Tmp = Peek (r_buo): Sbuf = Tmp перший символ на передачу Incr R_buo вкажемо на другий символ УВАГА Наступний рядок принципово важливе місце

Waitms 100 чекаємо поки стартове повідомлення буде передано

‘Тепер буфер порожній і його вже не можна зіпсувати

‘Ініціалізувати систему

B_entx = 1 : B_nd = 0 : B_sd = 1 : Cnt = 0 : Rang = 0 : Udac = 0

R_bui = Varptr (inp_buf) покажчик буфера на початок

Mc:

Do головний цикл

If B_nd = 1 Then активізується по приходу повідомлення

Reset B_nd : Goto N_dat End If

If B_sd = 1 Then активізується при необхідності передачі

Goto S_dat End If

‘Idle Loop

‘—————————————— Обробка прийнятих даних

N_dat:

Temp = Left (inp_buf, 1) виділимо перший символ для аналізу

‘—–

‘—–

If Temp = R Then запит стану

Set B_sd: Goto Mc рядок оброблена – в головний цикл

End If

If Temp = L Then дані ЦАП

‘—–

бр рядок в число з полярністю

Gosub Sload_766 завантажимо ЦАП

Goto Mc рядок оброблена – в головний цикл

End If

Перші режиму

бразуя

рядок в число

P2 = Rang завантажимо в порт P2

Goto Mc рядок оброблена – в головний цикл

End If Goto Mc

‘—————————————— Обробка даних на висновок

S_dat:

If B_entx = 1 Then почнемо, якщо передача дозволена

Reset B_sd скидаємо біт, визв передачу

Reset B_entx і запр передачу до повн Вив буфера Формуємо рядок стану системи: SxLxxxxxTxxx, ВК, ПС Out_buf = S + Str (rang) + L + Str (udac) + T + Str (cnt) + Chr (13) + Chr (10) R_buo = Varptr (out_buf) покажчик буфера на початок

Tmp = Peek (r_buo): Sbuf = Tmp перший символ на передачу цією операцією инициализируем систему виведення з переривання решта символи буфера будуть виводитися автоматично

Incr R_buo поставимо покажчик буфера на другий символ

End If Goto Mc

‘———————

‘Підпрограма завантаження даних в ЦАП AD766, AD1851

Sload_766:

‘Висунути дані з Udac в режимі 0 (ст спочатку,-_-) Shiftout B_datu, B_clku, Udac, 0

Reset B_ldu: Set B_ldu завантажити дані

Return

‘———————————————-

‘Обробка переривання таймера 0

Timer_0_int:

$asm

Mov Th0 , #&ampHD8

Mov Tl0, # & HFD вуст періоду прерів 10 мс

$end Asm

Incr Cnt вважаємо переривання

Return

‘———————————————- Обробка переривання послідовного інтерфейсу Ser_int:

$asm

$end Asm Return

$asm

Intsr:

Ints1: Ints2:

Intse: Ints3:

Ints4: Ints5:

Intst:

Ints6:

Jbc {Ri}, Intsr шукаємо джерело переривання

Jbc {Ti}, Intst заодно і скидаємо біт викликав переривання

; переривання приймача

Push Psw Push Acc

Mov {R_ch}, Sbuf зберегти прийнятий символ

Mov A , {R_ch}

Cjne A , #&amph0d , Ints3

Setb {B_nd} 0Dh – прийнята рядок

Mov A, {R_bui} покажчик буфера

Xch A, R0 зберегти R0

Mov @ R0, # & h00 записати в буфер кінець рядка

Xch A, R0 відновити R0

Mov {R_bui}, # {inp_buf} переініціалізіровать покажчик буфера

Pop Acc Pop Psw Reti

Cjne A , #&amph0a , Ints4

Sjmp Intse 0Ah – ігнорувати

Mov A , #{inp_buf + 10} Cjne A , {R_bui} , Ints5

Sjmp Intse

Mov A, {R_bui} покажчик буфера

Xch A , R0

Mov @ R0, {R_ch} все інше записувати в буфер

Xch A , R0

Inc {R_bui} якщо буфер незаполнен – ​​змінимо покажчик

Sjmp Intse

; переривання передавача

Push Psw Push Acc

Mov A, {R_buo} вважаємо символ з буфера виводу

Xch A , R0

Mov {R_ch} , @R0

Xch A , R0

Mov A, # {out_buf + 10} якщо це відбулося за межами буфера

Cjne A, {R_bui}, Ints6 закінчуємо повідомлення

Sjmp Ints7

Mov A, {R_ch} черговий символ дорівнює 0

Jz  ints7

Mov Sbuf , {R_ch}

Inc {R_buo} змінимо покажчик буфера виводу

Ints7:

$end Asm

Sjmp Intse

Setb {B_entx} установами покажчик дозволу передачі

Sjmp Intse спочатку символу повернення каретки

‘——————————————

Для багатьох систем виявляється достатнім компромісне рішення, коли з переривання

здійснюється тільки введення даних, які можуть надходити в довільний момент часу, а висновок даних проводиться прямо з головної програми за допомогою оператора Print При цьому програми виведення даних і програма переривань набувають інший вигляд і спрощуються У прикладі, наведеному вище, при цьому також

стають непотрібними змінні B_entx, R_bui і Out_buf Спрощується фрагмент в стартовому блоці програми:

Enable Serial дозволити переривання послінтерфейса

Print Test_com Ініціалізувати систему

Програма формування і виведення рядка стану також може бути побудована простіше:

‘—————————————— Обробка даних на висновок

S_dat:

‘Скидаємо біт, що викликав передачу і друкуємо рядок стану системи: SxLxxxxxTxxx, ВК, ПС

Reset B_sd : Print &quotS&quot Rang &quotL&quot Udac &quotT&quot Cnt Goto Mc

При цьому найбільше змінюється програма обробки переривання послідовного інтерфейсу Вона також спрощується і в ній необхідно обробляти тільки переривання приймача Біт Ti тепер обробляється всередині оператора Print До складу нової підпрограми переривання додатково введено корисний модуль перетворення малих латинських символів в прописні

‘—————————————— Обробка переривання послідовного інтерфейсу Ser_int:

$asm

Intsr:

Ints0: Ints1:

Ints2:

Intse:

Jbc {Ri} , Intsr Reti

Push Psw переривання приймача

Push Acc

Mov {R_ch}, Sbuf зберегти прийнятий символ

Mov A, {R_ch} перетворимо малий символ у великій Add A, # & h9f код символу a? (Нижня межа) Jnc Ints0 ( Not A +1)

Mov A, {R_ch} код символу z? (Верхня межа) Add A, # & h85 ( Not Z)

Jc Ints0

Mov A, {R_ch} скорегувати

Anl A , #&amphdf Mov {R_ch} , A Sjmp Ints1

Mov A , {R_ch}

Cjne A , #&amph0d , Ints3

Setb {B_nd} 0Dh – прийнята рядок

Mov A, {R_bui} покажчик буфера

Xch A, R0 зберегти R0

Mov @ R0, # & h00 записати в буфер кінець рядка

Xch A, R0 відновити R0

Mov {R_bui}, # {inp_buf} переініціалізіровать покажчик буфера

Pop Acc Pop Psw

Ints3: Ints4:

Ints5:

$end Asm

Reti

Cjne A , #&amph0a , Ints4

Sjmp Intse 0Ah – ігнорувати

Mov A , #{inp_buf + 10} Cjne A , {R_bui} , Ints5

Sjmp Intse

Mov A, {R_bui} інше записувати в буфер

Xch A , R0

Mov @R0 , {R_ch} Xch A , R0

Inc {R_bui}

Sjmp Intse

‘——————————————

Далі розглянемо програму, в якій взагалі не використовується переривання Це програма є частиною класичного монітора, що забезпечує перегляд памяті в текстовому вигляді і HEX-кодах Ядро цієї програми може служити основою багатьох інших інструментальних програм Це повільна програма, яка, виконавши команду або вчинивши дію, знаходиться в режимі очікування приходу символу в послідовний канал

‘————————————————- ————- Демонстраційна програми монітора, працюючого

‘Через послідовний канал

‘————————————————————–

$ Large велика модель памяті

Dim Tmp As Byte тимчасові байтові дані

Dim R_ch As Byte прийнятий або переданий символ

Dim L_adr As Word початкова адреса Dim H_adr As Word кінцевий адресу Dim S_adr As Word поточний адресу

Dim Big_buf As String * 64 великий буфер введення-виведення

‘———————

‘TIMER2 в режимі 16-біт таймера з внутр тактується для синхронізації UART Config Timer2 = Timer, Gate = Internal, Mode = 2

$ Baud = 9600 швидкість 96 кБ

$ Crystal = 12000000 при кварці 12 МГц

‘———————

Print Monitor Виведемо стартове повідомлення

Goto Begin на початок

_error: точка входу помилково

Gosub Dis_err переклад рядка і повідомлення про помилку

Begin:

‘Виведемо запрошення BC> без роздільників ВК та ПС

Gosub _promt

R_ch = Waitkey чекати введення символу

If R_ch = & H0D Then це символ ВК

Goto Ignore так – його не можна друкувати

End If Beg1:

Printbin R_ch вивести введений символ в тому ж рядку

Select Case R_ch вибрати програму обробки

Case & H44: Goto Dump_mem це символ D Case & H4C: Goto List_mem це символ L Case & H48: Goto Help це символ H

Case Else: Goto _error все інше сприймається як помилка

End Select

‘Увагу важливий момент – обробка символу ВК

‘Він може приходити в парі з символом ПС, який потрібно ігнорувати

‘А може бути це вже наступна команда або знову символ ВК

Ignore:

Waitms 50 чекаємо приходу другого символу 50 мс

R_ch = Inkey опитуємо вхідний буфер

If R_ch = 0 Then якщо вважали нуль, значить буфер порожній

Goto _error можна индицировать повідомлення про помилку

Elseif R_ch = & H0A Then прийшов ПС

Goto _error теж вважаємо, що помилка

Elseif R_ch = & H0D Then якщо знову прийшов ВК

Goto Ignore значить все повторити

End If інше – вважаємо це простим введенням Gosub Dis_err переклад рядка і повідомлення про помилку Gosub _promt висновок запрошення

Goto Beg1 і на обробку нової команди

‘————————————————————–

‘Вивести вміст памяті в HEX-коді

Dump_mem:

Print – Damp of memory Розшифрувати назву команди

Gosub Inp_ladr: Gosub Inp_hadr введемо адреси поч і кінця блоку

S_adr = L_adr поточний адресу почнемо з початкового

D_mem0:

Big_buf = Hex (s_adr) + Адресу початку рядка даних

Goto D_mem2 перехід при першому вході

D_mem1:

Tmp = Low (s_adr) аналізуємо: молодші розряди адреси

If Tmp = 0 Then дорівнюють нулю – почати новий блок Gosub E_cnk запросити: продовжувати або вийти If R_ch = & H1B Then якщо введений ESC,

Goto Begin вийти

End If

End If

Tmp = Tmp And & H0F аналізуємо:

If Tmp = 0 Then молодший напівбайт дорівнює 0

Print Big_buf да – друкувати буфер

Goto D_mem0 і на початок наступного рядка

End If D_mem2:

Tmp = Cpeek (s_adr) зчитування з памяті

Big_buf = Big_buf + + Hex (tmp) і додамо зображення в буфер

Incr S_adr змінимо поточний адресу

If S_adr> H_adr Then він досяг верхньої межі

Goto D_mem3 так – на вихід

End If

Goto D_mem1 немає – повторити

D_mem3:

Print Big_buf перед виходом отпечат останній рядок

Goto Begin

‘————————————————- ————- вивести вміст памяті в в текстовому вигляді

List_mem:

Print – List of memory Розшифрувати назву команди Gosub Inp_ladr: Gosub Inp_hadr ввести кордону перегляду S_adr = L_adr поточний адресу в початок блоку

L_mem0:

Big_buf = Hex (s_adr) + Формуємо початковий адресу даних з рядку

Goto L_mem2 перехід при першому вході

L_mem1:

Tmp = Low (s_adr) аналізуємо: молодші розряди адреси

If Tmp = 0 Then дорівнюють нулю – почати новий блок Gosub E_cnk запросити: продовжувати або вийти If R_ch = & H1B Then якщо введений ESC, вийти

Goto Begin End If

End If

Tmp = Tmp And & H0F аналізуємо:

If Tmp = 0 Then молодший напівбайт дорівнює 0

Print Big_buf да – друкувати буфер

Goto L_mem0 і на початок наступного рядка

End If L_mem2:

Tmp = Cpeek (s_adr) зчитування байта з памяті

If Tmp> 127 Then недруковані символи перетворимо в точку

Tmp = & H2E з кодами вище 7fh

Elseif Tmp < & H20 Then 'і також з кодами нижче 20h

Tmp = & H2E це приклад використання оператора Elseif End If

Big_buf = Big_buf + Chr (tmp) додамо символ

Incr S_adr переходимо до наступного адресою

If S_adr> H_adr Then перевіримо: не перейшли верхню межу

Goto L_mem3 так – перехід

End If

Goto L_mem1 немає – повторимо

L_mem3:

Print Big_buf друк буфера перед виходом

Goto Begin

‘————————————————- ————- видати таблицю допомоги

Help:

Print &quot&quot

Print &quot —— MONITOR —— &quot Print &quot| D – Display memory  |&quot Print &quot| L – List memory     |&quot Print &quot| H – This help       |&quot Print &quot ——————— &quot Print &quot&quot

Goto Begin

‘————————————————- ————- підпрограми: все, що повторюється більше одного разу

‘——————– Введення початкової адреси Inp_ladr:

Inputhex &quotBegin=&quot , L_adr : Return ——————–

‘Введення кінцевого адреси

Inp_hadr:

Inputhex &quotEnd=&quot , H_adr : Return ——————–

‘Запит: вийти або продовжувати

E_cnk:

Print &quotExit – Esc, Continue – any key&quot

R_ch = Waitkey: Return чекаємо введення символу

‘——————–

‘Переклад рядка і повідомлення про помилку

Dis_err:

Print &quot&quot : Print &quotError&quot : Return ——————–

‘Висновок запрошення BC> без символів ВК ПС

_promt:

Printbin & H42 & H43 & H3E: Return запишемо коди символів

‘————————————————————– End

У наведених програмах дано приклади використання майже всіх операторів, що працюють з послідовним портом При програмуванні виведення деякі незручності доставляють оператори, завершальні передане повідомлення роздільником (ВК ПС) Для усунення цього явища, неприпустимого при виведенні складових повідомлень, застосовується буфер, в якому формується результуюча рядок, або використовується оператор Printbin

Інша проблема виведення даних полягає в тому, що іноді потрібно включення у що видається повідомлення цифрових даних в форматованому вигляді Для вирішення цього завдання необхідно використовувати ті ж прийоми, що і при виведенні даних в символьний LCD-модуль

Джерело: МЛКуліш, ДОВІДНИК З ПРОГРАМУВАННЯ BASCOM-8051, Краснодар 2001

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*