Главная » Bascom-8051, Basic, Железо » Программирование вывода на индикатор Bascom-8051

0

Компилятор Bascom обеспечивает вывод на символьный индикатор значений числовых  переменных и символьных строк во всех возможных вариантах. Синтаксис операторов вывода  данных и команд управления курсором достаточно прост и не требует дополнительных, более  подробных пояснений, чем это сделано выше. Однако нужно заметить, что построение системы  отображения данных является более сложной задачей, чем применение  последовательности  операторов  вывода.  Проектируемые  устройства  с  символьным  индикатором должны  отвечать  требованиям  эргономики,  включающей  обязательное  форматирование  и  позиционирование выводимых цифровых данных и сообщений. С учетом этого, рассмотрим практические вопросы  построения и программирования системы отображения информации. Как обычно, перед началом программирования требуется разработать план системы отображения, включающий в себя следующие составляющие, перечисленные в порядке очередности:

а)  определить  число  и  разрядность,  отображаемых  параметров  (числовых).   Необходимо,  хотя  бы приблизительно, определить форматы отображения данных, чтобы зарезервировать место для десятичной точки, знака полярности и пробелов-разделителей. При отображении числовых данных нужно решительно избавляться

от избыточности – исключать незначащие разряды (за пределами точности или нестабильные);

б) определить номенклатуру и число, одновременно отображаемых параметров (переменных);

в)   определить   атрибуты   изображения   (выбрать   сообщения   или   символы   размерности   числовых параметров, разделителей полей данных, выбрать или разработать специальные символы);

г) придумать все текстовые сообщения таким образом, чтобы они были краткими, приблизительно одной длины  и  понятны.  Настоятельно  рекомендуется  применять  только   латинский  алфавит  потому,  что  коды

кириллических шрифтов и наборов символов (выше 7Fh) отличаются у разных изготовителей индикаторов;

д)  определить  число  и  расположение  полей  данных.  Для  правильного  восприятия   отображаемой информации расположение и размер полей данных должен быть фиксированным, включая и поле для текстовых сообщений. Так как текстовые сообщения обычно появляются на короткое время (постоянно не отображаются), лучше их размещать на полях малозначительных (второстепенных) параметров и таким образом экономить место. Наиболее важные параметры нужно располагать в середине рабочего поля. Менее важные сообщения по краям, на периферии.  Ввиду того, что все символы имеют одинаковый размер, для улучшения восприятия, размер  полей более важных параметров (сообщений) должен быть больше, чем у менее важных даже  путем использования аббревиатур  последних.  В  качестве  разделителей  полей  данных  рекомендуется  применять  пробелы  и  (или) специальные знаки в виде вертикальных и горизонтальных пунктирных линий;

е) произвести выбор типа символьного индикатора. Лучше применять модули индикации  стандартных размеров и наиболее употребляемых форматов (в порядке предпочтения): 16 символов х 2 строки, 20 х 2, 20 х 4, 16 х 1, 24 х 2, 40 х 4. Они более доступны, всегда дешевле, имеют лучшие светотехнические параметры (чаще совершенствуются  в  процессе  производства).   Индикаторы  уникальных  типоразмеров,  как  правило,  только заявлены   изготовителем   и   производятся   по   специальному   заказу.   Лучше   использовать   индикаторы   со светодиодной  подсветкой (они дает постоянную контрастность изображения при любом освещении) с черными знаками  на  желтом  поле  –  исполнение  для  стандартного  температурного  диапазона.  Не  рекомендуется  без необходимости  применять  индикаторы,  предназначенные    для  расширенного  температурного  диапазона  (они имеют заметно меньшую контрастность и угол видимости);

ж)   важно   выбрать   способ   подключения   индикатора   к   микроконтроллеру.   При    интенсивном использовании индикатора, например, для случаев полного обновления всех данных индикатора несколько раз в секунду  (это  характерно  для  измерительных  систем),  и  для  модулей  с  числом  знаком  более  32  необходимо применение 8-разрядной шины, иначе регенерация  изображения станет заметной (появляется эффект снижения контрастности и «паразитного свечения» неиспользуемых знакомест);

з) еще раз смоделировать (на  бумаге) возможность расположения и читаемость на выбранном индикаторе всех  возможных  сообщений  при  всех  возможных  комбинациях  и  режимах.  Уточнить  форматы  индикации параметров, текстовые сообщения, атрибуты,  аббревиатуры, стараясь максимально использовать общепринятые обозначения и термины.

Следующий  вопрос  –  программирование  изображений.  Существуют  два  подхода  к   формированию изображения на индикаторе:

а)  каждый  раз  при  обновлении  данных,  очищать  поле  индикации  и  затем  заполнять  его  данными,

зависимыми  от  текущего  состояния  выводимых  переменных.  Принципиально  то,  что  в   этом   случае  не производится анализ и выявление изменившихся данных. Преимущества такого подхода заключаются в том, что формирование и вывод данных в индикатор легко сосредоточить  в рамках одной универсальной процедуры и

сделать  регулярным,  со  скоростью  удобной  для  восприятия  (несколько  раз  в  секунду).  При  этом  процессы

формирования данных и   отображения данных становятся независимыми и параллельными, что  также очень удобно. Недостаток – повышенные требования к быстродействию интерфейса  индикаторного модуля и наличие кратковременного состояния неопределенности данных (старое  изображение стерто, а новое еще не записано). Если это время превышает 5-10 мс (более одного периода частоты сканирования всех сегментов), то становится видимым «мелькание» сегментов с частотой обновления данных;

б) обновлять только изменяющиеся данные. Достоинства такого подхода – немигающее  изображение, отсутствие проблем со способом подключения индикатора. Недостатки – усложнение программного интерфейса (он рассыпается на множество процедур по числу отображаемых переменных), вывод становится нерегулярным (с частотой изменения отображаемых переменных),  обработка изменения состояния переменной, в свою очередь, тормозится процедурой вывода в индикатор (единицы миллисекунд). Область применения – индикаторы с числом более 40 знаков и  системы с нерегулярным обновлением информации, например, при поступлении одиночных событий.

Ниже  представлена  большая  демонстрационная  программа,  в  которой  решаются  несколько  проблем вывода цифровых данных.

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

‘ Демонстрационная программа вывода данных в символьный индикатор

‘ показывает, как формируется показания на индикаторе

‘ измерительного прибора – мультиметра, работающего в пяти режимах

‘ и имеющего на каждом по пять пределов измерения. Все пределы

‘ измерения пронумерованы от 0 до 24 (сквозная нумерация).

‘ Программа построена так, что все режимы индикации привязаны

‘ к переменной Rang, определяющей номер предела. Данные АЦП

‘ и предел изменяются после цикла индикации (каждые 2 секунды) ‘

‘                                XXX: ±XXXXXX XX ‘ три знака режима работы        ^    ^ ^     ^

‘ полярности для сигналов пост. тока _| |     | ‘ цифровое значение                     |     | ‘ размерность показаний                       | ‘

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

$large                          ‘большая модель памяти

Dim B_nd As Bit                 ‘бит "Новые данные" Dim B_tim As Bit                ‘бит "Прошло 10 мс" Dim Cnt As Byte                 ‘счетчик мс

Dim Tmp As Byte                 ‘временные байтовые данные

Dim Rang As Byte                ‘это номер предела!!!

Dim Fld As Single               ‘данные "АЦП" – измеренное значение

Dim Rfld As Single              ‘индицируемые данные

Dim Temp As String * 10         ‘временная строка.

‘Внимание!!! При меньшей длине Temp программа «залезает» в стек.

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

‘ подключение индикатора

‘————————————————————– Config Lcd = 16 * 2             ‘размер индикатора

Config Lcdpin, Db4=P1.4, Db5=P1.5, Db6=P1.6, Db7=P1.7, E=P3.2, Rs=P3.4 ‘линия P3.3 не используется – ее надо заземлять

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

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

Enable Interrupts               ‘вообще разрешить прерывания Enable Timer0                   ‘разрешить прерывания таймера 0 ‘!!! ————————————–

Start Timer0 : Cnt = 100 : Rang = 0 : B_nd = 1 : B_tim = 1

Deflcdchar 1,228,228,234,234,241,241,255,224       ‘дельта

Deflcdchar 2,238,241,241,241,234,234,251,224       ‘омега

Cls                            ‘привести в действия новые символы

Cursor Off                     ‘сделать невидимым курсор Lcd "  Multimeter"             ‘стартовое приветствие Wait 1

Mc:

Do                             ‘главный цикл

If B_nd = 1 Then             ‘каждые 2 секунды индицировать

Reset B_nd : Goto Disp End If

If B_tim = 1 Then            ‘считаем 10 мс прерывания

Reset B_tim : Decr Cnt

If Cnt = 0 Then

Set B_nd : Cnt = 200

Fld = Lookup(rang , _tab_mes) : Incr Rang If Rang = 25 Then

Rang = 0

End If End If

End If Loop

‘————————————————————– ‘вывод данных в индикатор

Disp:

Fld = Lookup(rang , _tab_mes)  ‘считать значение выхода

Rfld = Lookup(rang , _tab_zc)  ‘считать масштабирующую константу

Rfld = Rfld * Fld              ‘вычислить в размерности индикации

Cls                            ‘очистить LCD

Gosub Lcd_attr1                ‘вывести сообщение о режиме работы

Tmp = Lookup(rang , _tab_polar)’нужно индицировать полярность?

If Tmp = 0 Then                ‘не нужно, если значение из табл. = 0

$asm

Anl {rfld + 3} , #&H7f ;сделаем показания безусловно положительными

$end Asm

Locate 1 , 7                   ‘сразу поставить в позицию вывода цифр

Goto Lcd_fp                    ‘и перейдем на форматирование

End If

‘нужно индицировать число со знаком

Locate 1 , 6                   ‘курсор в позицию вывода знака

If Rfld < 0 Then               ‘какая полярность?

Goto Lcd_fn                 ‘отрицательная – переход

End If

Lcd "+"                        ‘положительная – "+" на индикатор

Lcd_fp:

‘форматирование положительного числа. Выбираем программу форматирования, ‘соответствующую пределу измерения (все это должно быть записано в одну строчку ‘или переносится с помощию символа подчеркивателя

Goto Lcd_dat Lcd_fn:

‘форматирование отрицательного числа. Аналогично форматируем,

‘но длина результата будет на знак больше (добавится знак минуса)

On Rang Gosub M4

,

M2

,

M3

,

M4

,

M5

,

M4

,

M2

,

M3

,

_

M4

,

M5

,

M4

,

M2

,

M3

,

M4

,

M2

,

M4

,

_

M2

,

M3

,

M4

,

M2

,

M4

,

M2

,

M3

,

M4

,

M2

‘отбрасываем знак минуса и выводим его отдельно

Temp = Mid(temp , 2 , 6 ) : Lcd "-" Lcd_dat:

‘еще одна неприятность Bascom: он не выводит незначащие нули слева

‘перед десятичной точкой кроме одного. Будем исправлять и этот недостаток.

‘для чего проверим длину форматированной переменной

Tmp = Len(temp)

If Tmp = 5 Then                ‘длина = 5 – отброшен один нуль

Lcd "0"                     ‘добавим один нуль

Goto Lcd_od

End If

If Tmp = 4 Then                ‘длина = 4 – отброшено два нуля

Lcd "00"                    ‘добавим два нуля

Goto Lcd_od End If

If Tmp = 3 Then                ‘длина = 3 – отброшено три нуля

Lcd "000"                   ‘добавим три нуля

End If

Lcd_od:

Lcd Temp                       ‘наконец выводим цифровое значение Gosub Lcd_attr2                ‘и добавляем размерность показаний Goto Mc

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

Timer_0_int:

$asm

Mov Th0 , #&HD8

Mov Tl0 , #&HFD               ;уст. периода прерыв. 10 мс

$end Asm

Set B_tim                             ‘прошло 10 мс

Return

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

‘подпрограмма вывода сообщения о режиме работы

Lcd_attr1:

Temp = Lookupstr(rang , _tab_att1)    ‘считали из таблицы

Locate 1 , 1 : Lcd Temp : Lcd ":"     ‘вывели и добавили двоеточие

Return

‘————————————————————– ‘подпрограмма вывода сообщения о размерности показаний Lcd_attr2:

Temp = Lookupstr(rang , _tab_att2)    ‘считали из таблицы

Locate 1 , 13 : Lcd Temp              ‘вывели

Return

‘————————————————————– ‘ форматы отображения данных мультиметра

‘DCV: ±000.00 mV ±0.0000 V  ±00.000 V  ±000.00 V  ±0000.0 V ‘ACV:  000.00 mV  0.0000 V   00.000 V   000.00 V   0000.0 V ‘Ohm:  000.00 W   0.0000 kW  00.000 kW  000.00 kW  0.0000 MW ‘DCI: ±000.00 uA ±0.0000 mA ±00.000 mA ±000.00 mA ±0.0000 A ‘ACI:  000.00 uA  0.0000 mA  00.000 mA  000.00 mA  0.0000 A

‘————————————————————– ‘подпрограммы форматирования показаний положительной полярности F2:

Temp = Fusing(rfld , #.####) : Return F3:

Temp = Fusing(rfld , ##.###) : Return F4:

Temp = Fusing(rfld , ###.##) : Return F5:

Temp = Fusing(rfld , ####.#) : Return

‘подпрограммы форматирования показаний отрицательной полярности ‘требуется дополнительное место перед цифрами для знака минуса. M2:

Temp = Fusing(rfld , ##.####) : Return M3:

Temp = Fusing(rfld , ###.###) : Return M4:

Temp = Fusing(rfld , ####.##) : Return M5:

Temp = Fusing(rfld , #####.#) : Return

‘————————————————————– ‘ значения первого аттрибута – режима измерений

_tab_att1:

Data "DCV" , "DCV" , "DCV" , "DCV" , "DCV"

Data "ACV" , "ACV" , "ACV" , "ACV" , "ACV" Data "Ohm" , "Ohm" , "Ohm" , "Ohm" , "Ohm" Data "DCI" , "DCI" , "DCI" , "DCI" , "DCI" Data "ACI" , "ACI" , "ACI" , "ACI" , "ACI"

‘————————————————————– ‘ управление отображением полярности: 0 – нет, 1 – есть

_tab_polar:

Data

1

,

1

,

1

,

1

,

1

Data

0

,

0

,

0

,

0

,

0

Data

0

,

0

,

0

,

0

,

0

Data

1

,

1

,

1

,

1

,

1

Data

0

,

0

,

0

,

0

,

0

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

‘ значения второго аттрибута – размерности показаний

_tab_att2:

Data " mV" , "  V" , "  V" , "  V" , "  V"

Data " mV" , "  V" , "  V" , "  V" , "  V"

‘формируем формат строковых констант с дополнительным нулем данных

‘это константы: "  W", " kW", " kW"

Data &H20 , &H20 , 2 , 0 , &H20 , 107 , 2 , 0 , &H20 , 107 , 2 , 0 ‘это константы: " kW", " MW". W – это символ Омега (код 2)

Data &H20 , 107 , 2 , 0 , &H20 , 77 , 2 , 0

Data " uA" , " mA" , " mA" , " mA" , "  A"

Data " uA" , " mA" , " mA" , " mA" , "  A"

‘————————————————————– ‘масштабирующие коэффициенты, преобразующие размерность данных

‘к  размерности отображаемых данных с другим положение дес.точки

_tab_zc:

Data 1000! , 1! , 1! , 1! , 1!        ‘из Вольт Data 1000! , 1! , 1! , 1! , 1!        ‘из Вольт Data 1000! , 1! , 1! , 1! , 0.001!    ‘из килоом

Data 1000! , 1! , 1! , 1! , 0.001!    ‘из миллиампер

Data 1000! , 1! , 1! , 1! , 0.001!    ‘из миллиампер

‘————————————————————– ‘иммитируемые измеренные значения в соответствующей размерности

_tab_mes:

Data 0.001! , -1.9999! , -1.999! , 199.99! , 1999.9!  ‘DCV: Вольт Data 0.001! , 0.0123! , 10.000! , 100.00! , 1000.0!   ‘ACV: Вольт Data 0.09999! , 1.9999! , 19.9! , 199.99! , 1999.9!   ‘Ohm: Килоом

Data 0.20000! , -2.0000! , -20.0! , -19.00! , 20.0!   ‘DCI: Миллиампер Data 0.12345! , 1.2345! , 12.345! , 123.45! , 1234.5! ‘ACI: Миллиампер ‘————————————————————–

При программировании вывода на индикатор (и вывода в COM-порт тоже) нужно учитывать, что всегда имеет место погрешность представления чисел в формате с плавающей  точкой. Погрешность также возникает после арифметических действий и преобразований в  результате неопределенности младшего разряда мантиссы, который или теряется, или округляется.  Значение погрешности обычно не превышает ±0.000012 %, и   намного ниже погрешности  отображаемых данных. При отображении измеренных (или других определяемых) данных и записанных в формате с плавающей точкой, погрешность представления чисел не имеет большого значения, т.к. этого не видно. Однако, при индикации задаваемых значений чисел, например, с  помощью оператора INPUT и представленных в переменных типа Single, с этим могут возникать  проблемы. Например, введенное число 100 после обработки на индикаторе будет записано, как 99.999993. С точки зрения математики,  ничего страшного не произошло,  но  для  наблюдателя  это  явление  очень  неприятно  и,  зачастую,  непонятно.  Более  того,  будучи отформатировано,  отображаемое  значение  приобретет  вообще  недопустимый  вид.  Например,  если,  указанное выше, число 100 записать без дробной части, то получится 99. Чтобы исключить подобные неприятности, следует применять  округление   чисел   перед   форматированием.   Самый  простой   метод  округления   заключается   в добавлении  к числу значения  равного половине младшего  отображаемого разряда. В нашем  примере, чтобы получить правильное изображение, нужно к  числу 100 добавить число 0.5. Во многих случаях, округляющая добавка может быть значительно меньше и, вообще, приближаться к погрешности представления числа. Так как для округления используется операция суммирования, то нужно учитывать и знак округляемого числа.

Рассмотрим  еще  один  способ  форматирования  выводимых  чисел,  применимый  при   малом  числе отображаемых   разрядов   (до   пяти   включительно).   Этот   простой   способ    заключается   в   суммировании отображаемого числа с другим, заведомо большим числом, и выделении после преобразования в символьный вид необходимой средней части. Ниже приведен пример, демонстрирующий этот метод и округление для придания изображению строгого вида.

Dim R_fld As Single

‘индицируемые данные

Dim Temp As String *

16

‘временная строка

R_fld = -345.678

Locate 1 , 6             ‘курсор в позицию вывода знака

If R_fld < 0 Then        ‘какая полярность?

Goto Lcd_fn          ‘отрицательная – переход

End If

‘положительное: предстоит отображать число в R_fld в следующем виде: +xxx.xx

R_fld = R_fld + 1000.005 ‘добавим заведо большее число и добавку округления

Temp = Str(r_fld)        ‘преобразуем в строку

Temp = Mid(temp , 2 , 6) ‘выделим из середины то, что нужно – 6 символов

Lcd "+" ; Temp           ‘выведем со знаком полярности

Goto Lcd_e

Lcd_fn:

‘отрицательное: предстоит отображать число в R_fld в следующем виде: -xxx.xx R_fld = R_fld – 1000.005 ‘добавим заведо большее число и добавку округления

$asm

Anl {r_fld + 3} , #&H7f  ;сделаем показания безусловно положительными

$end Asm

Temp = Str(r_fld) : Temp = Mid(temp , 2 , 6) : Lcd "-" ; Temp Lcd_e:

End

В  последних  версиях  компилятора  расширены  возможности  функции  Fusing.  Теперь  по  умолчанию включается   режим   округления   и   предусмотрена   возможность   добавления   лидирующих   нулей.   Однако неприятности представления отрицательных чисел остались. Когда в маску записываются лидирующие нули, то

требуется записать их на один больше, чем количество выводимых цифр перед точкой. Все это  демонстрирует

следующий пример.

$large

Dim X As Single , Y As Single , Result As Single

Dim I As Integer , Buf As String * 16

X = 142 : Y = 3.157

Print "X+Y=" : Result = X + Y             ‘вычисления

Print Result                              ‘печать результата "145.69977"

Buf = Fusing(result , 000000.#)           ‘форматирование строки c округлением

Print Buf                                 ‘печать строки "00145.2"

Buf = Fusing(result , 0000.&&)            ‘с лидирующими нулями и без округления

Print Buf                                 ‘печать строки "145.15" X = -12 : Y = 3.157

Print "X+Y=" : Result = X + Y             ‘вычисления

Print Result                              ‘печать результата "-8.8430004"

Buf = Fusing(result , 000000.#)           ‘форматирование строки c округлением

Print Buf                                 ‘печать строки "000-8.8" Buf = Fusing(result , ####.&&)            ‘обычное, без округления Print Buf                                 ‘печать строки "-8.84" End

Источник: М.Л.Кулиш, СПРАВОЧНИК ПО ПРОГРАММИРОВАНИЮ BASCOM-8051, Краснодар 2001

По теме:

  • Комментарии