Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сафоненко Практикум по интерфейсам последователной передачи 2012

.pdf
Скачиваний:
3
Добавлен:
12.11.2022
Размер:
4.56 Mб
Скачать

Вызов оператора stopasync осуществляется со ссылкой на объект

последовательного порта:

>> stopasync(com1)

Byte order

При передаче числа важным параметром является порядок сле-

дования байт в многобайтовых числах. Многобайтовые числа – соответствуют форматам, которые занимают в памяти больше одного байта (например: int16 – 2 байта, float32 – 4 байта, double – 8 байт). При передаче такие числа разбиваются на отдельные байты, которые по очереди передаются в канал. Порядок следования байт определяет свойство ByteOrder: значение littleEndian (от младшего к старшему) соответствует передаче младший байта первым, bigEndian (от старшего к младшему) старшего байта первым. Рассмотрим пример ошибок при неправильной установке этого свойства.

Свойства установлены на передающей и принимающей сторонах:

>>com1.byteorder ans =

littleEndian

>>com2.byteorder ans =

littleEndian

Теперь на одной из сторон изменим порядок следования байт:

>> com1.byteorder='bigendian';

Таким образом, передающая и принимающая стороны по разному будут интерпретировать данные. Осуществим передачу и прием данных:

>>cmd=[1 4 257 17];

>>fwrite(com1,cmd,'int16')

>>fread(com2,4,'int16')

61

ans =

256

1024

257

4352

Как видно, данные передавались двухбайтовыми словами (int16). Принятые и переданные данные не совпадают (кроме числа 257). Для понимания происходящего рассмотрим числа в двоичном представлении:

110=00000000 000000012,

410=00000000 000001002,

2572=00000001 000000012,

1710=00000000 000100012.

Так как источник и приемник по-разному воспринимают порядок байт в слове, переставим местами байты (именно так они будут восприниматься приемником):

00000001 000000002=25610,

00000100 000000002=102410,

00000001 000000012=25710,

00010001 000000002=435210.

Таким образом, изменение порядка следования байт в числе объясняет искажение информации. В числе 25710, первый и второй байты совпадают.

Организация алгоритмического и событийного методов обмена информацией. События объекта serial в MATLAB

Как показывает опыт, эффективность конечного результата зависит от алгоритма упорядочения очередности выполнения ряда функций. Если процессору приходится часто переключаться на выполнение новой функции, рабочее расписание усложняется, и не всегда с положительным результатом. Автоматическое определение причины позволяет упорядочить вызовы по их значимости и своевременно реагировать.

62

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

В системах объектно-ориентированного программирования широко используются понятие «событие» как следствие функционирования среды и объекта. Каждое событие вызывает сигнал прерывания, который инициирует соответствующую программу-обработ- чик. В системе MATLAB применяется аналогичный механизм. Для объекта последовательного порта serial используют шесть собы-

тий: BreakInterrupt, BytesAvailable, Error, OutputEmpty, PinStatus, Timer.

Для обработки событий необходимо создать соответствующий M-файл (функцию-обработчик данного события). Заголовок M- файла должен содержать минимум две входные переменные:

function event_fcn(object, event)

В последующих примерах рассмотрена функция сигнализатор с именем alarm. С помощью нее можно наблюдать генерацию событий. М-файл будет выглядеть следующим образом:

function alarm (object, event)

disp('Alarm!');

Когда возникнет событие, в командной строке появится сообщение:

Alarm!

Количество входных параметров может быть больше, чем два. Но параметры object и event должны обязательно присутствовать. Они описывают объект, с которым произошло данное событие, и само событие.

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

Событие BreakInterrupt

Событие BreakInterrupt возникает, когда в линии передачи пропадает сигнал логического нуля. В отсутствие передачи данных, при асинхронном режиме, в канале устанавливается логическая

63

«1». При ее исчезновении через некоторое время (таймаут события) возникает событие Break. Это событие обычно вызывает функцию, которая аварийно завершает программу или указывает программепользователю на проблемы с подключением к порту. На практике это событие используют для того, чтобы перезапустить подключенное устройство. Для вызова этого события необходимо использовать оператор serialbreak. Он принимает два значения. Первое, обязательное, имя объекта порта, который вызывает событие, второе – необязательное, таймаут события в миллисекундах.

Для примера назначим порту com1 событие BreakInterrupt. И вызовем его с помощью порта com2:

>>com1.breakinterrupt=@timfun;

>>serialbreak(com2)

Alarm!

Можно использовать вызов с ожиданием на установленное время, прежде чем будет вызвано пррывание:

>> serialbreak(com2,1000)

Alarm!

В этот раз исполнение функции alarm задержано на одну секунду.

Событие BytesAvailable

Событие BytesAvailable возникает, когда во входной буфер порта приходят данные. Это событие используется для обработки входных данных на принимающей стороне по мере их поступления.

Пользователь должен выбрать условие генерации события. Таким условием может быть приход символа завершения передачи, или обнуление счетчика количества считанных байт, определяемого свойством BytesAvailableFcnCount. Условие задается в свойстве BytesAvailableMode. Для генерации события с первым типом условия для объекта порта com1 необходимо указать:

>> com1.bytesavailablefcnmode='terminator';

Событие второго типа возникнет, если установить свойство byte

>> com1.bytesavailablefcnmode='byte';

Напомним, что свойства BytesAvailableMode и BytesAvailableFcnCount необходимо изменять на этапе инициализации.

64

Рассмотрим примеры. Для генерации события первого типа ус-

тановим символ завершения передачи «E», и назначим функцию alarm как функцию обработки этого события:

>>com1.terminator={'E','E'};

>>com1.bytesavailablefcnmode='terminator';

>>com1.bytesavailablefcn=@alarm;

Только теперь можно открыть порты:

>>fopen(com1)

>>fopen(com2)

Теперь произведем передачу:

>> fwrite(com2, 'data');

Никакого события не произошло, так как символ окончания передачи «E» не был передан.

>>fwrite(com2, 'dataE'); Alarm!

>>fwrite(com2, 'dataE'); Alarm!

Как видно, после каждого оператора записи следует вызов события:

>> fscanf(com1,'%s')

ans =

datadataE

Чтение остановилось, так как был прочитан символ окончания передачи:

>> fscanf(com1,'%s')

ans =

dataE

Чтобы сгенерировать событие второго типа, сначала закроем порт:

>> fclose(com1)

65

Установим соответствующий режим:

>> com1.bytesavailablefcnmode='byte';

Назначим в качестве события факт накопления во входном буфере 5 байт:

>> com1.bytesavailablefcncount=5;

Откроем соответствующий порт:

>> fopen(com1)

Произведем запись:

>> fwrite(com2, 'data');

Никакого события не произошло, так как было передано только

4байта. Передаем 5 байт данных

>>fwrite(com2, 'dataE');

Alarm!

Как только в операции записи в противоположный порт (com2) количество байт станет больше или равно пяти, возникает событие

BytesAvailable.

Заметим, что в любой момент можно прочесть количество байт во входном буфере по свойству BytesAvailable:

>> com1.bytesavailable

ans =

9

Читаем весь буфер приемника:

>> fscanf(com1,'%s')

ans =

datadataE

В стандартных обработчиках чтение данных выполняется сразу после возникновения события

66

>>fwrite(com2, 'dataE'); Alarm!

>>fscanf(com1,'%s')

ans =

dataE

В порт записано 5 байт, что вызвало ожидаемое событие.

Событие Error

Событие Error возникает по ошибке передачи данных. Обычно по такому событию следует либо аварийно завершить программу, либо сигнализировать о возникновении ошибки и приостанавить передачу-прием.

Событие OutputEmpty

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

OutputEmptyFcn.

Событие генерируется только в режиме асинхронной записи в порт. Рассмотрим пример. Для этого назначим вышеописанную функцию alarm ответственной за данное событие:

>> com1.outputemptyfcn=@alarm;

Произведем асинхронную операцию записи:

>> fwrite(com1, 'data','async'); Alarm!

Как только завершилась операция передачи данных в линию, буфер опустел и произошел вызов события OutputEmpty.

Событие PinStatus

Событие PinStatus генерируется, когда состояние хотя бы одного из сигналов DCD, CTS, DSR или RI изменяется. Эти события можно

67

использовать при аппаратном управлении передачей. Как только принимающая сторона откажется принимать данные, она изменяет определенный сигнал (например, сбрасывает DTR) и, тем самым, изменяет состояние соответствующего сигнала на передающей стороне (например, DSR). Это вызывает генерацию события PinStatus. Затем произойдет вызов функции, отвечающей за данное событие, которая приостановит передачу данных. Для назначения функции, ответственной за данное событие, необходимо присвоить имя этой функции переменной PinStatusFcn.

Приведем пример. Назначим описанную выше функцию alarm ответственной за данное событие и проверим первоначальное состояние сигналов:

>>com1.pinstatusfcn=@alarm;

>>com1.pinstatus

ans =

CarrierDetect: 'on'

ClearToSend: 'off'

DataSetReady: 'on'

RingIndicator: 'off'

Изменим бит DTR на приемной стороне:

>> com2.dataterminalready='off'; Alarm!

Alarm!

Событие было вызвано дважды:

>> com1.pinstatus

ans =

CarrierDetect: 'off'

ClearToSend: 'off'

DataSetReady: 'off'

RingIndicator: 'off'

68

Как видно, изменились два сигнала CDC и DSR, и событие возникает при изменении каждого из них!

Немного изменим функцию alarm. Теперь она будет выглядеть так:

function alarm (object, event) disp('Alarm!'); event.Data.Pin event.Data.PinValue

Установим режим индикации типа прерывания и значений сигналов квитирования. Заново изменим бит DTR порта com2:

>> com2.dataterminalready='on'; Alarm!

ans =

Data Set Ready

ans = on Alarm! ans =

Carrier Detect

ans = on

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

Эти свойства избавляют нас от необходимости отслеживать состояние сигналов до прерывания. Достаточно прочесть значение сигнала, если оно изменилось.

69

Событие Timer

Событие Timer возникает по истечении интервала времени, определённого при инициализации свойством TimerPeriod. Имя функции, ответственной за обраблтку события, необходимо присвоить переменной TimerFcn. Это событие позволяет периодически контролировать состояние входного или выходного буферов, состояние передачи.

Рассмотрим пример. Установим период таймера равным 1 с:

>> com1.timerperiod=1;

откроем порты и поручим обработку данного события функции alarm:

>>fopen(com1)

>>fopen(com2)

>>com1.timerfcn=@alarm;

Через 1 с, как и установлено, начнут происходить вызовы функции обработки событий таймера:

Alarm!

Alarm!

Alarm!

Alarm!

Остановим вызов события:

>> com1.timerfcn='';

Вызов события Timer можно остановить, если издать команду закрыя порта fclose.

Свойства событий

При возникновении события вызывается функция его обработки, которой передаются переменные object и event. Эти переменные содержат информацию об объекте, с которым произошло событие и свойства события.

Для всех событий определены свойства Type и Data.AbsTime (их можно прочесть, обратившись к структуре event: event.Type и event.Data.AbsTime). Свойство Type содержит тип события (все

70

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]