MATLAB Language
Использование последовательных портов
Поиск…
Вступление
Последовательные порты представляют собой общий интерфейс для связи с внешними датчиками или встроенными системами, такими как Arduinos. Современная последовательная связь часто реализуется через USB-соединения с использованием USB-последовательных адаптеров. MATLAB обеспечивает встроенные функции для последовательной связи, включая протоколы RS-232 и RS-485. Эти функции могут использоваться для аппаратных последовательных портов или «виртуальных» USB-последовательных соединений. Примеры здесь иллюстрируют последовательную связь в MATLAB.
параметры
Параметр последовательного порта | что оно делает |
---|---|
BaudRate | Устанавливает скорость. Наиболее распространенным сегодня является 57600, но 4800, 9600 и 115200 также часто видны |
InputBufferSize | Количество байтов, хранящихся в памяти. Matlab имеет FIFO, что означает, что новые байты будут отброшены. Значение по умолчанию - 512 байт, но его можно легко установить на 20 МБ без проблем. Есть только несколько краевых случаев, когда пользователь хотел бы, чтобы это было маленьким |
BytesAvailable | Количество байтов, ожидающих чтения |
ValuesSent | Количество байтов, отправленных с момента открытия порта |
ValuesReceived | Число байтов, считанных с момента открытия порта |
BytesAvailableFcn | Укажите функцию обратного вызова, которая будет выполняться, когда указанное количество байтов доступно во входном буфере, или считывается терминатор |
BytesAvailableFcnCount | Укажите количество байтов, которое должно быть доступно во входном буфере для генерации bytes-available события |
BytesAvailableFcnMode | Укажите, будет ли генерируемое bytes-available событие генерироваться после того, как указанное количество байтов будет доступно во входном буфере или после чтения терминатора |
Создание последовательного порта на Mac / Linux / Windows
% Define serial port with a baud rate of 115200
rate = 115200;
if ispc
s = serial('COM1', 'BaudRate',rate);
elseif ismac
% Note that on OSX the serial device is uniquely enumerated. You will
% have to look at /dev/tty.* to discover the exact signature of your
% serial device
s = serial('/dev/tty.usbserial-A104VFT7', 'BaudRate',rate);
elseif isunix
s = serial('/dev/ttyusb0', 'BaudRate',rate);
end
% Set the input buffer size to 1,000,000 bytes (default: 512 bytes).
s.InputBufferSize = 1000000;
% Open serial port
fopen(s);
Чтение из последовательного порта
Предполагая, что вы создали объект последовательного порта s
как в этом примере, тогда
% Read one byte
data = fread(s, 1);
% Read all the bytes, version 1
data = fread(s);
% Read all the bytes, version 2
data = fread(s, s.BytesAvailable);
% Close the serial port
fclose(s);
Закрытие последовательного порта, даже если он потерян, удален или перезаписан
Предполагая, что вы создали объект последовательного порта s
как в этом примере, затем закройте его
fclose(s)
Однако иногда вы можете случайно потерять порт (например, очистить, перезаписать, изменить область действия и т. Д.), А fclose(s)
больше не будет работать. Решение легко
fclose(instrfindall)
Дополнительная информация в instrfindall()
.
Запись на последовательный порт
Предполагая, что вы создали объект последовательного порта s
как в этом примере, тогда
% Write one byte
fwrite(s, 255);
% Write one 16-bit signed integer
fwrite(s, 32767, 'int16');
% Write an array of unsigned 8-bit integers
fwrite(s,[48 49 50],'uchar');
% Close the serial port
fclose(s);
Выбор режима общения
Matlab поддерживает синхронную и асинхронную связь с последовательным портом. Важно выбрать правильный режим связи. Выбор будет зависеть от:
- как инструмент, с которым вы общаетесь, ведет себя.
- какие другие функции ваша основная программа (или графический интерфейс) придется делать помимо управления последовательным портом.
Я опишу 3 различных случая, чтобы проиллюстрировать, от самых простых до самых требовательных. Для 3-х примеров инструмент, к которому я подключаюсь, представляет собой печатную плату с инклинометром, который может работать в трех режимах, которые я буду описывать ниже.
Режим 1: синхронный (ведущий / ведомый)
Этот режим является самым простым. Это соответствует случаю, когда ПК является Мастером, а инструмент является подчиненным . Инструмент ничего не отправляет на последовательный порт, он отвечает только после ответа на задание / команду мастера (ПК, ваша программа). Например:
- ПК отправляет команду: «Дайте мне измерение сейчас»,
- Прибор получает команду, выполняет измерение, а затем возвращает значение измерения в последовательную линию: «Значение инклинометра - XXX».
ИЛИ ЖЕ
- ПК отправляет команду: «Переход из режима X в режим Y»
- Инструмент получает команду, выполняет ее, а затем отправляет подтверждающее сообщение в последовательную строку: « Выполненная команда » (или « Команда НЕ выполнена »). Обычно это называется ответом ACK / NACK (для «Acknowledge (d)» / «NOT Acknowledged»).
Резюме: в этом режиме инструмент ( ведомый ) только отправляет данные в последовательную линию сразу же после того, как компьютер спросил ( мастер )
Режим 2: асинхронный
Теперь предположим, что я начал свой инструмент, но это больше, чем просто глупый сенсор. Он постоянно контролирует собственный склон и до тех пор, пока он вертикальный (в пределах допуска, скажем, +/- 15 градусов), он остается тихим. Если устройство наклонено более чем на 15 градусов и приближается к горизонтали, оно отправляет аварийное сообщение на последовательную линию, сразу же после чего считывается наклон. Пока наклон выше порога, он продолжает посылать показания наклона каждые 5 секунд.
Если ваша основная программа (или графический интерфейс) постоянно «ждет» сообщения, поступающего на последовательную линию, это может сделать это хорошо ... но пока это не может сделать ничего другого. Если основной программой является графический интерфейс, очень сложно сделать графический интерфейс «замороженным», потому что он не будет принимать какие-либо данные от пользователя. По существу, он стал рабом, а инструмент - Мастером . Если у вас нет причудливого способа управления вашим графическим интерфейсом от инструмента, этого можно избежать. К счастью, асинхронный режим связи позволит вам:
- определить отдельную функцию, которая сообщает вашей программе, что делать, когда сообщение получено
- удерживайте эту функцию в углу, она будет вызываться и выполняться только при поступлении сообщения на последовательную линию. В остальное время GUI может выполнять любой другой код, который должен выполнить.
Описание: В этом режиме инструмент может отправлять сообщение на последовательную линию в любое время (но не обязательно все время). Компьютер не ждать постоянно для сообщения для обработки. Разрешено запускать любой другой код. Только когда приходит сообщение, оно активирует функцию, которая будет читать и обрабатывать это сообщение.
Режим 3: Потоковое (в реальном времени )
Теперь давайте развяжем всю мощь моего инструмента. Я помещаю его в режим, когда он будет постоянно отправлять измерения в последовательную линию. Моя программа хочет получить эти пакеты и отобразить их на кривой или цифровом дисплее. Если он отправляет только значение каждые 5 секунд, как указано выше, не проблема, сохраните вышеуказанный режим. Но мой инструмент с полным ударом отправляет точку данных в последовательную линию на частоте 1000 Гц, то есть посылает новое значение каждые миллисекунды. Если я останусь в асинхронном режиме, описанном выше, существует высокий риск (на самом деле гарантированная уверенность), что специальная функция, которую мы определили для обработки каждого нового пакета, займет более 1 мс (если вы хотите построить или отобразить значение, графические функции довольно медленные, даже не учитывая фильтрацию или FFT-сигнал). Это означает, что функция начнет выполнение, но прежде чем она закончится, появится новый пакет и снова активирует функцию. Вторая функция помещается в очередь для выполнения и запускается только тогда, когда первая выполняется ... но к этому времени появилось несколько новых пакетов, и каждая из них помещала функцию в очередь. Вы можете быстро предвидеть результат: к тому моменту, когда я рисую 5 баллов, у меня уже сотни ожиданий, которые тоже будут заложены ... gui замедляется, в конце концов зависает, стек растет, буферы заполняются, пока что-то не дает. В конце концов вы остаетесь полностью замороженной программой или просто разбитой.
Чтобы преодолеть это, мы еще больше отключим связь синхронизации между ПК и инструментом. Мы позволяем прибору отправлять данные в своем собственном темпе, без немедленного запуска функции при каждом приходе пакета. Буфер последовательного порта просто накапливает полученные пакеты. ПК будет собирать данные только в буфере с темпом, которым он может управлять (регулярный интервал, настроенный на стороне ПК), что-то делать с ним (пока буфер заполняется инструментом), а затем собирайте новую партию данные из буфера ... и так далее.
Описание: В этом режиме прибор непрерывно посылает данные, которые собираются буфером последовательного порта. На регулярной основе ПК собирает данные из буфера и что-то делает с ним. Между ПК и прибором нет жесткой синхронизации. Оба выполняют свои задачи самостоятельно.
Автоматическая обработка данных, полученных от последовательного порта
Некоторые устройства, подключенные через последовательный порт, отправляют данные в вашу программу с постоянной скоростью (потоковые данные) или отправляют данные с непредсказуемыми интервалами. Вы можете настроить последовательный порт для выполнения функции автоматически для обработки данных всякий раз, когда он прибывает. Это называется «функцией обратного вызова» для объекта последовательного порта.
Существует два свойства последовательного порта, которые должны быть установлены для использования этой функции: имя функции, которую вы хотите для обратного вызова ( BytesAvailableFcn
), и условие, которое должно инициировать выполнение функции обратного вызова ( BytesAvailableFcnMode
).
Существует два способа запуска функции обратного вызова:
- Когда определенное количество байтов было получено на последовательном порту (обычно используется для двоичных данных)
- Когда определенный символ принимается на последовательном порту (обычно используется для текстовых или ASCII-данных)
Функции обратного вызова имеют два обязательных входных аргумента, называемых obj
и event
. obj
- последовательный порт. Например, если вы хотите распечатать данные, полученные от последовательного порта, определите функцию для печати данных, называемых newdata
:
function newdata(obj,event)
[d,c] = fread(obj); % get the data from the serial port
% Note: for ASCII data, use fscanf(obj) to return characters instead of binary values
fprintf(1,'Received %d bytes\n',c);
disp(d)
end
Например, чтобы выполнить функцию newdata
всякий раз, когда newdata
64 байта данных, настройте последовательный порт следующим образом:
s = serial(port_name);
s.BytesAvailableFcnMode = 'byte';
s.BytesAvailableFcnCount = 64;
s.BytesAvailableFcn = @newdata;
С текстовыми или ASCII-данными данные обычно делятся на строки с «символом терминатора», как текст на странице. Чтобы выполнить функцию newdata
всякий раз, когда получен символ возврата каретки, настройте последовательный порт следующим образом:
s = serial(port_name);
s.BytesAvailableFcnMode = 'terminator';
s.Terminator = 'CR'; % the carriage return, ASCII code 13
s.BytesAvailableFcn = @newdata;