Как написать программу для rs232

В этой статье рассмотрена простейшая программа для подключения контроллера (PIC16F628A) к компьютеру с помощью встроенного модуля USART. Для экспериментов воспользуемся тестовой платкой, рассмотренной в статье «Подключение контроллера к компьютеру по RS-232 с помощью встроенного модуля USART.

Встроенный USART модуль контроллера позволяет реализовать как синхронный режим, так и асинхронный, но ввиду того, что синхронный режим практически не используется, мы будем рассматривать только асинхронный режим. В асинхронном режиме может быть использован восьмибитный или девятибитный формат данных, с одним стартовым и одним стоповым битами. Обычно, девятый бит — проверка четности, соответственно, если проверки нет, то используется восьмибитный формат данных.

Так как мы рассматриваем простейший пример, то будем использовать восьмибитный формат данных (без проверки четности) с одним стоповым битом. Аппаратный контроль использовать не будем, поэтому выводы нашей тестовой платы CTS и RTS просто закоротите между собой.

💬 Как передавать и принимать данные из Arduino в компьютер и обратно? Очень просто!

Итак, для начала немножко теории, поскольку дока от микрочипа, к сожалению, с ошибками (места, которые в родной доке описаны неверно, выделены красным шрифтом):

Регистры, которые нам понадобятся для работы с USART:

1) TXSTA (98h) — регистр управления и статуса передатчика. бит 1 (TRMT) — флаг очистки сдвигового регистра передатчика (0 — в регистре есть данные, 1 — регистр пуст) бит 2 (BRGH) — выбор высокоскоростного или низкоскоростного режима. (0 — низкоскоростной режим, 1 — высокоскоростной режим). Во-первых режим влияет на вычисление скорости передачи.

Во-вторых, у разных режимов разные алгоритмы определения уровня сигнала на входе приемника. бит 4 (SYNC) — выбор синхронного (1) или асинхронного (0) режима USART бит 5 (TXEN) — включение (1) или выключение (0) передатчика. Здесь есть одни очень веселые грабли. При выключении передатчика его вывод переводится в z-состояние.

То есть, если вы не используете контроль передачи, то включенный приемник компьютера (соединенный с передатчиком контроллера) окажется подвешен в воздухе, причем с довольно некислой антенной (провод от передатчика контроллера к приемнику компьютера) и естественно наловит всяких наводок, которые вы увидите на ПК в виде многочисленных ошибок передачи, в то время как вы ничего не передаете. В связи с вышеописанным, передатчик рекомендуется включить один раз при инициализации и больше не выключать. бит 6 (TX9) — выбор девятибитной (1) или восьмибитной (0) передачи.

2) RCSTA (18h) — регистр управления и статуса приемника. бит 1 (OERR) — ошибка переполнения внутреннего буфера (0 — нет переполнения, 1 — есть переполнение). Чтобы сбросить эту ошибку — нужно выключить и снова включить приемник. (сбросить и заново установить бит CREN). бит 2 (FERR) — бит ошибки кадра (выставляется в 1, если не обнаружен стоповый бит). Сбрасывается при чтении регистра RCREG.

бит 4 (CREN) — включение (1) или выключение (0) приемника. бит 6 (RX9) — выбор девятибитного (1) или восьмибитного (0) приема

#387 САМОДЕЛКА Перехват протокола RS-232 а также RS-485, RS-422, USB, Usart

3) SPBRG (99h) — регистр генератора скорости обмена (BRG). Скорость вычисляется по следующим формулам: для высокоскоростного режима (BRGH=1) V=Fosc/(16(X+1)), для низкоскоростного (BRGH=0) V=Fosc/(64(X+1)), где V — корость обмена в бодах, Fosc — частота, на которой работает контроллер в герцах, X — значение в регистре SPBRG.

4) TXREG (19h) — регистр данных передатчика USART.

5) RCREG (1Ah) — регистр данных приемника USART.

Работа передатчика USART в асинхронном режиме (восьмибитная передача):

Главным элементом передатчика является регистр TSR. Это сдвиговый регистр, который, собственно, и передает данные, со скоростью, установленной генератором обмена. Программно этот регистр не доступен, а данные в него загружаются автоматически из регистра TXREG.

Если регистр TSR пуст, а в регистре TXREG есть данные, то в последнем машинном машинном такте цикла генератора обмена TSR загружается данными из TXREG, после чего выставляется флаг прерывания TXIF (4-й бит регистра PIR1 (0Ch)). Само прерывание можно запретить сбросом бита TXIE ( 4-й бит регистра PIE1 (8Ch)), но флаг все равно будет выставляться. То есть, этот флаг сигнализирует — занят регистр TXREG (TXIF=0) или освободился (TXIF=1). Очистка флага происходит после загрузки новых данных в регистр TXREG.

Аналогично, флаг TRMT (первый бит регистра TXSTA) сигнализирует о состоянии регистра TSR (0 — в регистре есть данные, 1 — регистр пуст).

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

1) Инициализация: установить скорость, режим генератора скорости обмена, выбрать восьмибитный режим, разрешить/запретить прерывания, включить передатчик.

2) Работа: записать байт в регистр TXREG, при появлении флага TXIF можно писать в TXREG новый байт, он будет послан сразу после окончания передачи предыдущего, после записи в TSR последнего байта, дождаться появления флага TRMT. Всё, передача завершена.

Работа приемника USART в асинхронном режиме (восьмибитный прием):

Главным элементом приемника является регистр RSR. Это сдвиговый регистр, который, собственно, и принимает данные, со скоростью, установленной генератором обмена. Программно этот регистр не доступен, а данные из него автоматически загружаются в регистр RCREG после цикла получения стопового бита , если этот регистр не заполнен. После этого выставляется флаг прерывания RCIF (пятый бит регистра PIR1 (0Ch)). Само прерывание можно запретить сбросом бита RCIE (5-й бит регистра PIE1 (8Ch)), но флаг все равно будет выставляться.

Регистр RGREG представляет сбой двухуровневый FIFO, т.е. в него можно принять два байта. Чтобы считать из него два байта, нужно просто прочитать его два раза.

Если в регистр RSR принят байт (пришел стоповый бит), а в регистре RCREG уже есть два байта, то выставляется флаг переполнения приемника OERR (первый бит регистра RCSTA (18h)), а принятый байт теряется. Сбросить флаг OERR можно только выключив и заново включив приемник.

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

1) Инициализация: установить скорость, режим генератора скорости обмена, выбрать восьмибитный режим, разрешить/запретить прерывания, включить приемник.

2) Работа: ожидать появления флага RCIF, после этого проверить, нет ли ошибки FERR, затем считать данные из RCREG и, наконец, проверить (и, если надо, то сбросить) ошибку переполнения.

Ну всё, хватит теории, переходим к программе.

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

Алгоритм обмена данными контроллера с ПК по UART

Текст программы под катом

list p = 16f628a __config 03F30h ;*** Переменные ****************************************** CBLOCK 0x20 ; Начальный адрес блока Rbyte ;Принятый байт ENDC ;*** Константы / Адреса регистров ************************ Baudrate equ .12 ; скорость 19200 ;——————————————————— STATUS equ 03h ; Регистр выбора банка PORTA equ 05h ; Порт А PORTB equ 06h ; Порт В TRISA equ 05h ; Конфигурация порта А (банк 1) TRISB equ 06h ; Конфигурация порта В (банк 1) CMCON equ 1Fh ; Управление компараторами ;— Регистры передатчика и приемника——————— TXREG equ 19h ; буфер передатчика RCREG equ 1Ah ; буфер приемника PIR1 equ 0Ch ; регистр флагов передатчика PIE1 equ 0Ch ; разреш/запрет прерыв-й передатч.(1-й банк) TXSTA equ 18h ; конфигурация передатчика (1-й банк) RCSTA equ 18h ; конфигурация приемника SPBRG equ 19h ; настройка скорости ;********************************************************* org 0 ;*** Настройка портов (чтобы работал UART надo TRISB[2,1]=1) start movlw .7 movwf CMCON ; выкл. компараторы clrf PORTA ; инициализация защелок порта А clrf PORTB ; инициализация защелок порта В bsf STATUS,5 ; Перейти в 1-й банк movlw .4 ; Записать конфиг. порта A в аккум-р (W) ; .4=00000100 (RA2 — всегда вход) movwf TRISA ; Скопировать конфиг-ю порта А из W в TrisA movlw .7 ; Записать конфиг. порта В в аккум-р (W) ; .255=00000111 (RB0(CTS) — вход) movwf TRISB ; Скопировать конфиг-ю порта B из W в TrisB bcf STATUS,5 ; Перейти в 0-й банк ;*** Настройка приемо-передатчика ************************ bsf STATUS,5 ; перейти в первый банк movlw Baudrate ; загрузить устанавливаемую скорость в W movwf SPBRG ; установить скорость movlw b’00100100′ ; 8-разрядные данные, включить передачу, movwf TXSTA ; высокоскоростной асинхронный режим bcf PIE1, 4 ; запретить прерыв-я от передатчика (TXIE=0) bcf PIE1, 5 ; запретить прерыв-я от приемника (RCIE=0) bcf STATUS,5 ; перейти в нулевой банк movlw b’10000000′ ; 8-разрядные данные, выключить прием, movwf RCSTA ; включить модуль USART ;———- Прием ————————- bsf RCSTA,4 ; включаем приемник prog btfss PIR1,5 ; если 5-й бит PIR1 = 1, — в буфер пришли данные goto prog movf RCREG,0 ; читаем буфер приемника в аккумулятор movwf Rbyte ; помещаем это значение в принятый байт bcf RCSTA,4 ; выкл-ем приемник (можно его и не выключать, ; если комп свой передатчик не выключает) incf Rbyte,1 ; прибавляем к принятому байту 1 ;———- Передача ———————— movf Rbyte,0 ; помещаем это значение на передачу movwf TXREG bsf STATUS,5 ; в первый банк per btfss TXSTA,1 ; если 1-й бит регистра TXSTA = 1, ; то передача завершена (TSR пуст) goto per bcf STATUS,5 ; нулевой банк bsf RCSTA,4 ; включаем приемник goto prog end

Читайте также:
Руководство организации не имеет выраженной программы действий

list p = 16f628a __config 03F30h ;*** Переменные ****************************************** CBLOCK 0x20 ; Начальный адрес блока Rbyte ;Принятый байт ENDC ;*** Константы / Адреса регистров ************************ Baudrate equ .12 ; скорость 19200 ;——————————————————— STATUS equ 03h ; Регистр выбора банка PORTA equ 05h ; Порт А PORTB equ 06h ; Порт В TRISA equ 05h ; Конфигурация порта А (банк 1) TRISB equ 06h ; Конфигурация порта В (банк 1) CMCON equ 1Fh ; Управление компараторами ;— Регистры передатчика и приемника——————— TXREG equ 19h ; буфер передатчика RCREG equ 1Ah ; буфер приемника PIR1 equ 0Ch ; регистр флагов передатчика PIE1 equ 0Ch ; разреш/запрет прерыв-й передатч.(1-й банк) TXSTA equ 18h ; конфигурация передатчика (1-й банк) RCSTA equ 18h ; конфигурация приемника SPBRG equ 19h ; настройка скорости ;********************************************************* org 0 ;*** Настройка портов (чтобы работал UART надo TRISB[2,1]=1) start movlw .7 movwf CMCON ; выкл. компараторы clrf PORTA ; инициализация защелок порта А clrf PORTB ; инициализация защелок порта В bsf STATUS,5 ; Перейти в 1-й банк movlw .4 ; Записать конфиг. порта A в аккум-р (W) ; .4=00000100 (RA2 — всегда вход) movwf TRISA ; Скопировать конфиг-ю порта А из W в TrisA movlw .7 ; Записать конфиг. порта В в аккум-р (W) ; .255=00000111 (RB0(CTS) — вход) movwf TRISB ; Скопировать конфиг-ю порта B из W в TrisB bcf STATUS,5 ; Перейти в 0-й банк ;*** Настройка приемо-передатчика ************************ bsf STATUS,5 ; перейти в первый банк movlw Baudrate ; загрузить устанавливаемую скорость в W movwf SPBRG ; установить скорость movlw b’00100100′ ; 8-разрядные данные, включить передачу, movwf TXSTA ; высокоскоростной асинхронный режим bcf PIE1, 4 ; запретить прерыв-я от передатчика (TXIE=0) bcf PIE1, 5 ; запретить прерыв-я от приемника (RCIE=0) bcf STATUS,5 ; перейти в нулевой банк movlw b’10000000′ ; 8-разрядные данные, выключить прием, movwf RCSTA ; включить модуль USART ;———- Прием ————————- bsf RCSTA,4 ; включаем приемник prog btfss PIR1,5 ; если 5-й бит PIR1 = 1, — в буфер пришли данные goto prog movf RCREG,0 ; читаем буфер приемника в аккумулятор movwf Rbyte ; помещаем это значение в принятый байт bcf RCSTA,4 ; выкл-ем приемник (можно его и не выключать, ; если комп свой передатчик не выключает) incf Rbyte,1 ; прибавляем к принятому байту 1 ;———- Передача ———————— movf Rbyte,0 ; помещаем это значение на передачу movwf TXREG bsf STATUS,5 ; в первый банк per btfss TXSTA,1 ; если 1-й бит регистра TXSTA = 1, ; то передача завершена (TSR пуст) goto per bcf STATUS,5 ; нулевой банк bsf RCSTA,4 ; включаем приемник goto prog end

Для проверки работы и отладки можно воспользоваться любой программой для работы с com-портом, например, RH_Com, которую можно скачать здесь.

Источник: radiohlam.ru

Программа обмена по RS-232 на языке C# в среде Microsoft Visual Studio

Программа обмена по RS-232 на языке C# в среде Microsoft Visual Studio

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

Мне приходилось программировать в Turbo Pascal, затем в Delphi и, наконец, в Borland C++ Builder 6.0. Все они были по-своему интересны и полезны. Однако сейчас становятся популярны новые среды программирования, и надо не отставать от других пользователей в их освоении. Как мне кажется, наиболее перспективной является среда Microsoft Visual Studio 2010 (сокращенно MSVS2010) и программирование на языке C# (си шарп). Некоторые скажут зачем, но как поговариваю: летчик должен уметь летать на всем что летает, и немного на том, что не летает, если он конечно профессионал.
Книг по среде Microsoft Visual Studio 2010 и языку C# достаточно, учебные и пробные версии ПО можно найти в интернете, так что можно смело начинать.

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

При запуске программы PR14_RS-232.exe непосредственно или через оболочку MSVS2010 появится следующее основное окно, что на следующем рисунке.

Программа обмена по RS-232 на языке C# в среде Microsoft Visual Studio

В окне два поля для отображения кода выдачи и принятого кода и три кнопки управления. Сразу отмечу, что коды обмена отображаются байтами в 16-ричной системе счисления, а сами байты отделены пробелами. Например, для выдачи кода нужно в режиме обычного редактирования подготовить код, а затем кликнуть по кнопке «Выдать». В данном случае в качестве шаблона предлагается выдать код их шести байт: 0f 12 34 56 78 90. Если по ошибке будет введен символ, не принадлежащий 16-ричной системе, то при нажатии на кнопку, выдачи не произойдет, но появится следующее сообщение об ошибке.

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

То есть используя данную программу можно обмениваться через СОМ1 со скоростью 9600 бит/с, что вполне достаточно для многих приложений при работе с микроконтроллерами.

↑ А что же внутри программы, каков исходный код?

Основная часть написанной мною программы для проекта PR14_RS-232.sln содержится в файле Form1.cs.

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

Читайте также:
Как работать в программе сферум видео

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; // для работы с СОМ портом using System.IO.Ports; using System.Timers; // Для работы с таймером

Создание СОМ порта обеспечивают следующие строки в class Form1. Здесь же видно, что обмениваться данными будем через СОМ1, но легко можно задать и другие.

public partial class Form1 : Form < private SerialPort port = new SerialPort(«COM1»);// Создание СОМ-порта

Кстати, если скорость и другие параметры не устраивают, то их меняем подобно следующему:
private SerialPort port = new SerialPort(«COM1», 19200, Parity.None, 8, StopBits.One);

В основной функции public Form1() четыре строки. Первая формирует основную форму с кнопками и окошками, это стандартная строка, которая всегда создается автоматически. Следующие две строки создают обработчик прерываний для обменов по СОМ порту и отрывают сам СОМ порт. Четвертая строка выводит шаблон из шести байт в окно выдачи, к которому можно сделать привязку и, конечно, изменить.

public Form1() < InitializeComponent(); port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); port.Open(); // Open the port richTextBox2.Text = «0f 12 34 56 78 90»; >

В обработчике приема void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) имеется две строки, одна в самом начале, а другая в конце. Эти строки необходимы для синхронизаций, их обязательно надо применять. Управление передается обработчику, как только во входном буфере СОМ порта появляются принятые данные. Для считывания данных применяется следующие три строки. Здесь принятые коды считываются в байтовый буфер buffer.

int bytes = port.BytesToRead; byte[] buffer = new byte[bytes]; port.Read(buffer, 0, bytes);

Очередные следующие за ними три строки выводят данные в окно «Принятый код». Таким образом, в этом обработчике осуществляется прием по RS-232 и побайтный вывод принятого кода, а между байтами вставляются пробелы, что улучшает их обзор.

В обработчике выдачи private void button1_Click(object sender, EventArgs e), который запускается по кнопке «Выдать», осуществляются следующие действия. Проверяется, все ли символы в окне «Код выдачи» принадлежат 16-ричной системе счисления. Для этого используются первые двадцать строк кода, а при ошибке выводится сообщение через MessageBox.Show. Затем осуществляется собственно сама выдача, для этого применены следующие строки:

byte[] bytes = new byte[Str.Length / 2]; for (int i = 0; i < Str.Length / 2; i++) < char ch1 = Str[i * 2]; char ch0 = Str[i * 2 + 1]; bytes[i] = (byte)(STB(ch1) port.Write(bytes, 0, bytes.Length);

Где в последней строке, bytes – это сам подготовленный массив байт для выдачи, а bytes.Length – число выдаваемых в СОМ порт байт. Данный обработчик использует еще функцию private byte STB(char ch), служащую для преобразования знаковых символов в числа.

При нажатии кнопок «Очистить» работают обработчики private void button3_Click(object sender, EventArgs e) и private void button2_Click(object sender, EventArgs e), основная задача которых очистка окон приема и выдачи.
Вот такая небольшая программка.

↑ Файлы

В архиве проект на языке C# в среде Microsoft Visual Studio 2010 и готовый файл PR14_RS-232.exe
PR14_RS-232.zip 52.1 Kb ⇣ 189

Наш файловый сервис предназначен для полноправных участников сообщества «Datagor Electronics».

Для получения файла зарегистрируйтесь и войдите на сайт с паролем.

↑ Немного о себе

Я занимаюсь схемо-техникой с применением микроконтроллеров. Их было у меня достаточно много: это Intel 8080, 8051, 196, Atmel AT90, AVR, ATtiny и megaAVR, Silabs, а также NiosII. Их я программировал на ассемблере и С, и связывал с персональным компьютером по интерфейсу RS-232 на подобных программах, ну и с более сложным функционалом.

Источник: datagor.ru

Бинарный протокол обмена данными по RS232 BinExchange

Несмотря на свою древность, RS232 и его вариации до сих пор широко используются в различных системах автоматизации и в бытовых приборах. И это все потому, что COM-порт очень прост в освоении. И еще существует большое количество переходников USB-UART, которые позволяют добавить интерфейс USB в свой девайс без мучительного изучения стандарта USB и покупки VID. Однако, встает вопрос о том, каким образом передавать байты информации по последовательному порту. В этой статье мы рассмотрим мое решение данного вопроса, которое называется BinExchange protocol.

Обзор протокола Modbus

Для начала давайте рассмотрим одно из существующих решений, которое является промышленным стандартном, а именно протокол Modbus.

Modbus является пакетным протоколом обмена данными с архитектурой ведущий-ведомый. Modbus в основном используется для создания сетей поверх RS485. Существует 3 варианта Modbus:

  • Modbus ASCII — текстовый вариант протокола, начало пакета помечается символом «:», конец CR/LF. Из достоинств можно выделить простоту реализации. Из минусов — скорость обмена данными в 2 раза ниже в сравнении с двоичной реализацией Modbus RTU, так как на каждый байт приходится 2 ASCII-символа.
  • Modbus RTU — двоичная реализация протокола. Пакеты отделяются друг от друга интервалом тайм-аута, равного не меньше 3,5 символов при данной скорости передачи. Между байтами данных не должно быть пауз, превышающих 1,5 символа, т.е. данные должны идти сплошным потоком. В качестве достоинства можно выделить довольно высокую скорость передачи данных, так как в пакете содержится намного меньше служебной информации, чем в текстовой реализации протокола. Недостаток — сложнее реализовать, в сравнении с Modbus ASCII. Стоит отметить, что в некоторых микроконтроллерах STM32 в модуле UART есть аппаратная поддержка тайм-аутов, которую можно использовать для реализации протокола Modbus RTU.
  • Modbus TCP — Modbus через интернет, в данной статье нас не интересует.

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

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

Свой вариант протокола

Свою версию «идеального» протокола обмена данными по RS232/UART я вижу так:

  • соединение устройств типа точка-точка, обмен может инициировать любая сторона;
  • режим обмена данных — пакетный, длина макета может быть меньше, либо равна заранее установленного значения;
  • CRC16 для передаваемых данных;
  • простота реализации протокола как на стороне ПК, так и МК.

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

Давайте рассмотрим вариант текстовой реализации протокола. Пусть в нем начало пакета будет обозначаться символом «:», а конец «=». Каждый байт будет конвертироваться в HEX-строку, состоящую из 2-х ASCII-символов. Последние 2 байта пакета — CRC16. Итого, пакет будет иметь следующий вид:

Читайте также:
Как создать программу которая создает папки

где AABBCCDD — полезные данные, в данном случае 4 байта, EEFF — контрольная сумма, 2 байта.

В принципе удобно и наглядно. При большом желании, пакеты можно генерить в уме и отправлять вручную прямо из консоли, если научитесь устному счету CRC16))) Служебной информации в таком пакете 2*n + 6, n-количество передаваемых байт, но если скорость передачи не очень важна, то такой вариант является приемлемым. Такая реализация себя неплохо зарекомендовала в нескольких моих проектах.

Однако, хочется все же уменьшить количество служебной информации в пакете для увеличения пропускной способности протокола при той же скорости работы UART. Можно в качестве системы кодирования пакета использовать не HEX, а что-то типа Base64, Base128, и т.д. Но давайте все же обратимся к бинарной реализации протокола. Возникает вопрос, а как нам тогда отделять один пакет от другого?

Очень просто: зарезервируем один специальный байт, с которого будет начинаться каждый новый пакет. Но как быть, если этот байт будет встречаться в самих передаваемых данных? Ответ очень простой — будем использовать экранирование: если он будет попадаться в передаваемых данных, то мы просто отправим его 2 раза подряд.

Специальный символ конца пакета использовать не будем, вместо этого в начале пакета будем отправлять его длину. Ну и не забываем про контрольную сумму, она будет идти в самом конце. Итого, имеем следующую структуру пакета:

S 0 L0 L1 D0 D1 D2 D3 … Dn C0 C1

  • S — спец. байт начала пакета
  • L0, L1 — длина полезных данных пакета
  • D — полезные данные
  • C0, C1 — контрольная сумма CRC16

Если в передаваемых данных будет встречаться наш спец. симпол, то пакет будет выглядеть так:

S 0 L0 L1 D0 D1 S S D3 … Dn C0 C1

S 0 L0 L1 D0 D1 D2 D3 … Dn S S C1

S 0 L0 S S D0 D1 D2 D3 … Dn C0 C1

Думаю, с этим все понятно.

Реализация

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

Рассмотрим функции протокола:

void BinEx_Init(void); void BinEx_Process(void); BinExStatus_t BinEx_TxStatus(void); //статус передатчика BinExRetCode_t BinEx_TxBegin(uint16_t len); //Запустить передачу данных uint8_t *BinEx_TxGetBuffPntr(void); //получить указатель на буфер передатчика BinExStatus_t BinEx_RxStatus(void); //Получить статус приемника BinExRxExtendedStatus_t BinEx_RxExtendedStatus(void); //Получить статус приемника боллее подробно BinExRetCode_t BinEx_RxBegin(void); //Разрешить прием пакета uint16_t BinEx_RxDataLen(void); //Получить длину принятого пакета uint8_t *BinEx_RxGetBuffPntr(void); //Получить указатель на буфер приемника

BinEx_Init() — инициализация протокола

BinEx_Process() — процесс конечного автомата протокола, вызывается в бесконечном цикле в main()

Функции передатчика:

BinEx_TxStatus() — статус передатчика, возвращает следующие значения:

  • BINEX_READY — готов к следующей передаче;
  • BINEX_RUN — в данный момент ведется передача.

BinEx_TxBegin(len) — отправить len элементов из буфера передатчика. Возвращает:

  • BINEX_OK — передача успешно запущена;
  • BINEX_BUSY — в данный момент еще не закончена предыдущая передача данных.

BinEx_TxGetBuffPntr() — если в данный момент передатчик находится в состоянии BINEX_READY, то возвращает указатель на буфер передатчика uint8_t *, если передатчик в состоянии BINEX_RUN, то возвращает ноль.

Функции приемника:

BinEx_RxStatus() — Получить статус приемника. Возвращает следующие значения:

  • BINEX_READY — приемник находится в режиме ожидания и не обрабатывает входной поток данных;
  • BINEX_RUN — приемник находится в режиме приема данных и ждет получения пакета. После получения пакета перейдет в состояние BINEX_READY, либо в BINEX_ERROR, если возникла какая-либо ошибка;
  • BINEX_ERROR — произошла ошибка приема пакета, для получения более подробной информации необходимо воспользоваться функцией BinEx_RxExtendedStatus().

BinEx_RxExtendedStatus() — подробная информация о статусе приемника. Возвращает следующие значения:

  • RXPACK_OK — пакет принят успешно;
  • RXPACK_CRCERR — ошибка контрольной суммы пакета;
  • RXPACK_TOO_LONG — длина пакета, указанного в заголовке, больше максимальной длины пакета BINEX_BUFFLEN.

BinEx_RxBegin() — начать прием пакета, приемник переходит в режим обработки потока входных данных. Возвращаемые значения:

  • BINEX_OK — приемник запущен успешно.

BinEx_RxDataLen() — получить длину принятого пакета. Возвращает актуальные данные после перехода приемника из состояния BINEX_RUN в состояние BINEX_READY.

BinEx_RxGetBuffPntr() — если приемник находится в состоянии BINEX_READY, то возвращает указатель на буфер приемника, иначе ноль.

Практика

Перейдем теперь к практике работы с протоколом BinExchange. Приведу код, который принимает пакет данных и отправляет его обратно без изменений. Что-то типа ping-а))) Код IAR для stm32f030:

#include «stm32f0xx.h» #include «binex.h» #include «SysClock.h» static uint8_t state = 0; void TxTestProc(void) < static uint8_t *tx_buff; static uint8_t *rx_buff; static uint16_t rx_len; switch(state) < case 0: BinEx_RxBegin(); //Запускаем прием данных state = 1; break; ////////////////////////////////////// case 1: if(BinEx_RxStatus() == BINEX_READY) //Если получили пакет данных state = 2; else if(BinEx_RxStatus() == BINEX_ERROR) //Если возникла ошибка при приеме state = 3; break; ////////////////////////////////////// case 2: //отправляем принятый пакет if(BinEx_TxStatus() == BINEX_READY) //Если передатчик освободился после предыдущей передачи < //Получаем буферы приемника и передатчика tx_buff = BinEx_TxGetBuffPntr(); rx_buff = BinEx_RxGetBuffPntr(); rx_len = BinEx_RxDataLen(); //Копируем буфер приемника в буфер передатчика for(int i=0; i//Запускаем передачу принятого пакета BinEx_TxBegin(rx_len); //переходим в исходное состояние state = 0; > break; ////////////////////////////////////// case 3: //Ошибка приема if(BinEx_TxStatus() == BINEX_READY) //Если передатчик освободился после предыдущей передачи < //Получаем буферы приемника и передатчика tx_buff = BinEx_TxGetBuffPntr(); tx_buff[0] = 1; //Запускаем передачу принятого пакета BinEx_TxBegin(1); //переходим в исходное состояние state = 0; >break; ////////////////////////////////////// > > void main(void) < SysClockInit(); BinEx_Init(); for(;;) < BinEx_Process(); TxTestProc(); >>

Рассмотрим наш тестовый конечный автомат TxTestProc(). В исходном состоянии мы разрешаем прием пакета данных и переходим в состояние 1. В состоянии 1 мы дожидаемся окончания процесса, и в случае его успеха переходим в состояние 2, а если возникли ошибки, то в состояние 3.

Рассмотрим состояние 2. Первым делом мы убеждаемся в том, что передатчик в данный момент ни чем не занят. Далее, получаем указатели на буферы приемника и передатчика, получаем количество принятых байт, и копируем буфер приемника в буфер передатчика. Затем запускаем процесс передачи и переходим в исходное состояние.

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

Реализация протокола для ПК на C#

Для работы с протоколом со стороны ПК написал небольшой класс на C#, который реализует все необходимое. Класс называется BinExchange. Вот небольшой пример работы с ним:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BinExchange < class Program < static BinExchange BinEx = new BinExchange(32); static void Main(string[] args) < Random rnd = new Random(); BinEx.Open(«COM5″, 9600); byte[] tx = new byte[32]; rnd.NextBytes(tx); BinEx.Write(tx); byte[] rx = BinEx.Read(); for (int i = 0; i < rx.Length; i++) < Console.Write(rx[i].ToString() + » «); >Console.WriteLine(); Console.ReadKey(); > > >

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru