Light-electric.com

IT Журнал
4 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Программирование com порта на c

Обмен данными через СОМ-порт

Обмен данными по СОМ-порту
Доброго времени суток. Пишу 2 программы, обменивающиеся данными по COM-порту. Одна посылает.

Обмен данными через COM- порт
Добрый день, пытаюсь освоить передачу данных. Отсылаю на мк скажем "1", приходит "1" и "-38".

Обмен данными через COM порт
Нашел исходник программы для работы с com портом. Какие есть стандартные команды, чтобы получить.

Обмен данными через COM-порт
Всем доброго времени суток! Подскажите пожалуйста как передать введенные данные из компонента.

Обмен данными через COM-порт в Windows
Разработчики высокоуровневых языков программирования, очевидно, считают прием/передачу данных по протоколу rs232 через коммуникационный порт экзотической процедурой: мол, рядовому пользователю как бы и без надобности, а нерядовой — разберется самостоятельно. Потому ни в turbo pascal, ни в delphi нет штатных средств обмена данными таким способом. Однако в последнее время, особенно в связи с распространением микропроцессорных устройств, такая задача встает в любительских программах все чаще — в силу простоты и дешевизны реализации последовательным портом оборудованы многие научные и инженерные приборы, разнообразные датчики и измерители.

Простота аппаратного исполнения (для обычной двусторонней связи требуется всего три провода) асинхронного коммуникационного порта ведет, однако, к некоторому усложнению необходимого программного обеспечения. Можно, конечно, попробовать послать байт на устройство com1 средствами dos, подобно тому, как это делается для lpt1 (оно же prn), но успех вряд будет достигнут — как минимум, надо сначала настроить скорость обмена. Потому для dos-программ это делается средствами bios или прямым программированием порта «по железу». А в windows, к счастью, есть соответствующие функции api.

Для организации обмена нужно проделать следующие шаги:

получить дескриптор порта (handle — указатель, куда посылать все относящееся к порту);
получить адрес dcb — data control block;
установить новые параметры dcb;
послать установленные параметры в порт;
приступить к чтению принимаемых данных или к передаче.
Рассмотрим все по порядку. Получить дескриптор можно с помощью универсальной функции createfile. Так как СОМ — устройство последовательное, то его можно рассматривать как файл, что и делается (и в dos, между прочим, тоже). У этой функции множество применений (описание в help, если распечатать, занимает страниц семь). Для нее требуется масса входных параметров, но большинство из них нам не нужны и приравниваются, в зависимости от типа, либо к 0, либо к величине nil (указатели, которые никуда не указывают). В нашем случае получается следующий синтаксис функции:

createfile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);

Здесь stcom — строка типа pchar, в которой записано имя файла, в данном случае — просто ‘com1’ или ‘com2’, смотря какой порт нужен. Параметр generic_read+generic_write означает, что порт открывается как для вывода, так и для ввода. open_existing означает проверку существования, и если объявленного порта нет, после вызова функции возникнет ошибка, которую можно проанализировать обычным методом delphi: try . except.

Получить адрес dcb можно, если применить функцию getcommstate (pcom, pdcb); здесь pcom — дескриптор порта, pdcb — возвращаемый адрес структуры dcb. Установить параметры порта в этой структуре можно непосредственно, но если вы обратитесь к ее описанию в help, то бессонная ночь вам обеспечена. Поэтому проще сделать это с помощью вызова функции buildcommdcb (stcom, pdcb), в которой stcom в данном случае содержит набор устанавливаемых параметров в виде строки (см. пример ниже). Установленные параметры посылаются в порт с помощью функции setcommstate (pcom, pdcb). Все эти функции возвращают значение типа boolean, которое равно true, если операция прошла успешно. Чтение из порта и запись в порт осуществляются с помощью симметричных функций readfile и writefile, также универсальных и потому содержащих ненужный нам параметр, который мы приравняем к nil:

boolean readfile (pcom, xb, 1, xn, nil);

Здесь xb — переменная любого целого типа, в которой возвращается прочитанное значение (для writefile в ней содержится, наоборот, записываемое), 1 — столько байт прочесть из xb (для СОМ-порта это, очевидно, всегда 1), xn — сколько байт действительно прочитано. Следующий программный фрагмент инициализирует порт СОМ1 и осуществляет прием данных до тех пор, пока не будет нажата любая клавиша на клавиатуре. Принимаемые данные преобразуются в строку и выводятся на экран через пробел в компоненте label1 (с переводом строки через каждые 32 значения; разумеется, можно выводить в любой компонент, имеющий свойство text или caption, или еще куда-нибудь):

stcom:=’com1′;
try
pcom:= createfile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);
except ;
if getcommstate(pcom,pdcb)
then stcom:=’com1: baud=9600 parity=n data=8 stop=1′
else ;
if buildcommdcb(stcom,pdcb) then setcommstate(pcom,pdcb)
else ;
while (msg.message <> wm_keydown) do
begin
bb:=readfile(pcom,xb,1,xn,nil);
if not bb then break;
st:=st+’ ‘+inttostr(xb);
if length(st) mod 32=0
then st:=st+chr(10)+chr(13);
label1.caption:=st;
peekmessage(msg,form1.handle,0, 0,pm_remove); <читаем сообщение из очереди, если есть - удаляем>
application.processmessages; <очищаем очередь сообщений - на всякий случай>
end;

Прежде чем подключать к компьютеру какие-либо устройства, следует сказать пару слов о технике безопасности. Если прибор беспаспортный или, тем более, самодельный, следует проверить следующее: а) напряжение на выходе порта прибора не должно превышать значений +/-15 В (минимум +/-3 В), и на экране осциллографа не должно наблюдаться заметных выбросов и «шпилек», превышающих эти значения, — в противном случае вы рискуете лишиться com-порта (это особенно неприятно, если порт расположен на материнской плате; в сомнительных случаях лучше экспериментировать с дополнительной isa-картой, оборудованной com-портами; б) нужно убедиться, что выход прибора электрически развязан с сетью.

Программирование com порта на c

Эта статья показывает, как записывать и читать данные от устройства, подключенного к последовательному порту (COM-порт) из приложения на языке C# в среде .NET. Мы будем читать и записывать данные через TextBox на форме, и будем работать с потоками.

В недалеком прошлом для работы с Serial Port в среде .Net 1.1, мы должны были использовать либо Windows API, либо использовать управление из сторонних библиотек. В среде .Net 2.0 (и в более поздних версиях .NET) компания Microsoft добавила поддержку последовательного порта включением класса SerialPort как части пространства имен System.IO.Ports. Реализация класса SerialPort сделана очень прямо и очевидно. Чтобы создать экземпляр класса SerialPort class, просто передайте опции SerialPort конструктору класса:

Для приема данных нам нужно создать обработчик события EventHandler для «SerialDataReceivedEventHandler»:

Вы можете также установить другие опции, такие как ReadTimeout и WriteTimeout (таймауты чтения и записи):

Как только Вы готовы использовать последовательный порт, Вам нужно открыть его:

Сейчас мы готовы принять данные. Однако чтобы записать эти данные в область ввода TextBox на форме, нам нужно создать так называемого делегата (delegate). Библиотеки .Net не позволяют межпотоковое взаимодействие (cross-thread action), так что нам нужно использовать делегат. Делегат используется для записи в поток пользовательского интерфейса (User Interface, UI) из другого потока (не UI).

Читать еще:  Объектно ориентированное программирование инкапсуляция

Мы создадим теперь метод «sp_DataReceived», который будет выполнен при поступлении данных в последовательный порт:

Теперь создадим наш метод «si_DataReceived»:

Мы можем теперь принять данные из последовательного порта от устройства и отобразить их на форме. Некоторые устройства отправляют данные сами, без запроса. Однако некоторым устройствам нужно отправить определенные команды, чтобы они ответили на них какими-то своими данными. Для этих устройств Вы будете записывать данные в последовательный порт, и будете использовать предыдущий код, чтобы получить данные обратно. В этом примере будет происходить обмен со шкалой. Для отдельной шкалы отправка команды «SIrn» приведет к возврату веса, который имеется на шкале. Эта команда является специфической именно для этого устройства, в Вашем же случае нужно читать документацию по протоколу устройства, чтобы найти команды, принимаемые устройством. Для записи в последовательный порт создайте кнопку «Start» на форме, и добавьте код в событие клика на ней Click_Event:

Это все, что нужно Вам сделать. См. ссылку [1] для загрузки готового проекта Microsoft Visual C# 2010.

[Как передавать по одному символу, с задержкой]

В случае, когда нужно реализовать обмен с устройством, рассчитанным на взамодействие с пользователем (управляющая консоль). Так как пользователь вводит символы команды медленно, устройство успевает принять все символы и обработать. Если передавать символы быстро (методом SerialPort.Write), по несколько байт, то есть риск потери данных. Во врезке ниже приведен пример класса COMdevice, где реализован метод Write, который передает символы через задержку.

[Как перекодировать символы ANSI в UTF8]

Очень часть устройства на микроконтроллерах передают русские символы в кодировке ANSI (Windows-1251). Однако среда разработки Visual Studio C# хранит и обрабатывает русскоязычный текст в кодировке UTF8, и при попытке отобразить принятый текст (методом ReadExisting) выводятся кракозябры.

Решить проблему можно, если организовать байтовый буфер, и перекодировать массив байт с помощью класса Encoding (методом GetEncoding(1251).GetString). Пример кода в классе COMdevice приведен во врезке ниже.

Программирование com порта на c

§ 54. С чего начать? Или получение первых результатов от COM порта

Вот мы и добрались до COM порта. Но с ним все не так просто как с LPT, и его полноценное использование потребует значительно больших усилий. Главной загвоздкой является и его главное преимущество — передача данных в последовательном виде. Если в LPT байт данных передается по 8-ми линиям по биту на каждую, и состояние каждой линии можно было легко посмотреть, то в COM порту байт данных передается бит за битом по одной линии (относительно земли, конечно) и посмотреть что там передается с помощью одних светодиодов не удастся. Для этого нужно специальное устройство — преобразователь потока последовательных данных в парраллельный, т.н. USART (Universal Synchronous/Asynchronous Receiver Transmitter). Например, он есть в составе материнской платы компьютера, снабженного COM портом, в любом более мение серьезном микроконтроллере.

Надеюсь, вы еще пали духом в освоении COM порта. Все не так уж и мрачно. Некоторые результаты можно получить и без USART. Сформулируем задачу, которую реализуем на начальном этапе работы с COM портом:

«Хочу что бы к компьютеру через COM порт подключался светодиод. Запускаю программу. Далаю какое-то действие в этой программе, светодиод загорается, делаю другое — светодиод тухнет.»

Задача довольно специфичная (с учетом того, что USART не используется) и является чистой «самопальщиной», но вполне реализуема и работоспособна. Давайте приступим к ее реализации.

Опять берем системный блок вашего ПК и смотрим в тыловую часть. Примечаем там 9-ти штырьковй разъем — это и есть COM порт. Реально их может быть неколько (до 4-х). На моем ПК установлено два COM порта (см. фото).

2. Удлинитель COM порта

Нам потребуется удлинитель COM порта, но не просто удлинитель, а т.н. нуль-модемный кабель. Как он выглядит? Так как на фото, причем на обох его концах установлен разьем типа «мама». Далее втыкайте его в любой COM порт Вашего ПК и выводите его на рабочее место.

3. Аппаратная часть

С аппаратной частью нам тоже придется «повозиться», в том смысле что она будет сложнее чем с первым устройством для LPT порта. Дело в том что протокол RS-232 по которому идет обмен данными в COM порту, имеет несколько отличное соотношение логическое состояние — напряжение. Если обычно это логический 0 0 В, логическая 1 +5 В, то в RS-232 это соотношение следующее: логический 0 +12 В, логическая 1 -12 В.

И например, получив -12 В не сразу понятно что с этим напряжением делать. Обычно проводят преобразование уровней RS-232 в ТТЛ (0, 5 В). Самый простой вариант — стабилитроны. Но я предлагаю сделать этот преобразователь на специальной микросхеме. Называется она MAX232.

Микросхема эта дешевая и широко распространенная. Особенных проблем в ее добывании возникнуть не должно. Что она умеет? Она одновременно может преобразовывать два сигнала из RS-232 в ТТЛ и еще два из ТТЛ в RS-232.

Теперь давайте посмотрим, а какие сигналы из COM порта мы можем посмотреть на светодиодах? В действительности, в COM порту есть аж 6 независимых линий, представляющих интерес для разработчика устройств сопряжения. Две из них пока для нас недоступны — линии по передаче последовательных данных. А вот оставшиеся 4 предназначены для управления и индикации процесса передачи данных и мы сможем «передалать» их под свои нужды. Две из них предназначены для управления со стороны внешнего устройства и мы их пока трогать не будем, а вот последние две оставшиеся линии мы сейчас и поиспользуем. Они называются:

  • RTS — Запрос на передачу. Линия взаимодействия, которая показывает, что компьютер готов к приему данных.
  • DTR — Компьютер готов. Линия взаимодействия, которая показывает, что компьютер включен и готов к связи.

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

Итак, давайте соберем схему, которая позволит нам проводить задуманные действия.

А вот ее практичекая реализация. Я думаю вы меня простите, что я сделал ее в таком стремном макетном варианте, ибо делать плату для такой «высоко продуктивной» схемы не хочется.

4. Программная часть

Тут все попроще. Давайте создадим Windows приложение в Microsoft Visual C++ 6.0 на основе MFC для управления двумя линиями взаимодействия COM порта. Для этого создаем новый проект MFC и указываем ему имя, например, TestCOM. Далее выбираем вариант построения на основе диалога.

Читать еще:  C веб программирование

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

Далее, в файле TestCOMDlg.h в описание класса диалога добавьте строчку: HANDLE hFile;.

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

С помощью стандарной функции Win API CreateFile() открываем COM-порт COM2. Далее проверяем успешность открытия с выводом информационного сообщения. Вот тут надо сделать важное замечание: COM2 — это в моем компьютере, а на Вашем компьютере Вы могли подключить его к другому COM порту. Соответственно, его имя нужно изменить на то, кокай порт Вы используете. Посмотреть, какие номера портов присутствуют на Вашем компьютере, можно так: Пуск -> Настройка -> Панель управления -> Система -> Оборудование -> Диспетчер устройств -> Порты (COM и LPT).

В итоге, функция CTestCOMDlg::OnInitDialog(), расположенная в файле TestCOMDlg.cpp, класса нашего диалога должна принять вид:

Теперь добавим обработчики кнопок управления линиями. Я дал им соответствующие имена: функция, которая устанавливает еденицу на линии DTR — OnDTR1(), 0 — OnDTR0(). Для линии RTS соответственно аналогичным образом. Напомню, что обработчик создается при двойном щелчке на кнопке. В итоге, эти четыре функции должны принять вид:

Поясню немного как они работают. Как видно, внитри себя они содержат вызов одной и той же Win API функции EscapeCommFunction() с двумя параметрами. Первый из них — это хэндл (HANDLE) на открытый порт, второй — специальный код действия, соответствующий необходимому состоянию линии.

Все, комилируем, запускаем. Если все хорошо, должны увидеть сообщение об успешном открытии порта. Далее, нажатием соответствующих кнопок мигаем светодиодами, подключенными к COM порту.

Работа с последовательными портами — работа с COM портами

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

Но, как это ни странно, информации по работе с последовательными портами в программах под Win32 очень мало. Материал этой статьи основан на статье Олега Титова Работа с коммуникационными портами (COM и LPT) в программах для Win32 — ознакомиться с ней можно по адресу. Автором очень подробно описаны функции для работы с коммуникационными портами, основное внимание уделено синхронному обмену информацией. Мы же рассмотрим вариант обмена между компьютером и периферийным устройством в асинхронном режиме (как правило, используемом наиболее часто) — причем для простейшего соединения по трем проводам, без использования управляющих сигналов. Таким же образом можно организовать связь между двумя компьютерами (хотя бы для проверки работы своей программы).

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

Начинается работа с открытия порта как файла, причем для
асинхронного режима ввода-вывода возможен только один вариант:

HANDLE handle = CreateFile(«COM1», GENERIC_READ |
GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
NULL);

Других вариантов быть не может, поэтому не будем рассматривать
параметры этой функции подробно, единственное, что можно сделать —
это заменить “COM1” на “COM2”. Больше последовательных портов на
компьютере, как правило, нет. При успешном открытии порта функция
возвращает дескриптор handle, с которым и будем работать в
дальнейшем. При неудачном открытии порта функция вернет значение
INVALID_HANDLE_VALUE.

Получив доступ к порту, необходимо его настроить — задать
скорость обмена, формат данных, параметры четности и т. д. Основные
параметры последовательного порта задают структуры DCB и
COMMTIMEOUTS. Структура DCB содержит основные параметры порта и,
кроме этого, довольно много специфических полей.

typedef struct _DCB <

DWORD DCBlength; // sizeof(DCB)

DWORD BaudRate; // current baud rate

DWORD fBinary:1; // binary mode, no EOF check

DWORD fParity:1; // enable parity checking

DWORD fOutxCtsFlow:1; // CTS output flow control

DWORD fOutxDsrFlow:1; // DSR output flow control

DWORD fDtrControl:2; // DTR flow control type

DWORD fDsrSensitivity:1; // DSR sensitivity

DWORD fTXContinueOnXoff:1; // XOFF continues Tx

DWORD fOutX:1; // XON/XOFF out flow control

DWORD fInX:1; // XON/XOFF in flow control

DWORD fErrorChar:1; // enable error replacement

DWORD fNull:1; // enable null stripping

DWORD fRtsControl:2; // RTS flow control

DWORD fAbortOnError:1; // abort reads/writes on error

DWORD fDummy2:17; // reserved

WORD wReserved; // not currently used

WORD XonLim; // transmit XON threshold

WORD XoffLim; // transmit XOFF threshold

BYTE ByteSize; // number of bits/byte, 4-8

BYTE Parity; // 0-4=no,odd,even,mark,space

BYTE StopBits; // 0,1,2 = 1, 1.5, 2

char XonChar; // Tx and Rx XON character

char XoffChar; // Tx and Rx XOFF character

char ErrorChar; // error replacement character

char EofChar; // end of input character

char EvtChar; // received event character

WORD wReserved1; // reserved; do not use

Мы рассмотрим назначение только некоторых основных полей этой
структуры, используемых для нашего случая ввода-вывода, так как
многие поля можно заполнить значениями “по умолчанию”, пользуясь
функцией GetCommState:

Таким образом, нет необходимости вникать во все тонкости
структуры. После этого некоторые поля DCB все же придется заполнить
вручную, а именно:

BaudRate — скорость передачи данных. Возможно указание
следующих констант: CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400,
CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400, CBR_56000,
CBR_57600, CBR_115200, CBR_128000, CBR_256000. Можно просто указать
соответствующее число, например 9600, но предпочтительнее все-таки
пользоваться символическими константами.

ByteSize — определяет число информационных бит в
передаваемых и принимаемых байтах. Может принимать значение 4, 5, 6,
7, 8.

Parity — определяет выбор схемы контроля четности. Данное
поле должно содержать одно из следующих значений:


  • EVENPARITY — дополнение до четности;
  • MARKPARITY — бит четности всегда равен 1;
  • NOPARITY — бит четности отсутствует;
  • ODDPARITY — дополнение до нечетности;
  • SPACEPARITY — Бит четности всегда 0.

StopBits — задает количество стоповых бит. Поле может
принимать следующие значения:


  • ONESTOPBIT — один стоповый бит;
  • ONE5STOPBIT — полтора стоповых бита (практически не
    используется);
  • TWOSTOPBIT — два стоповых бита.

После того как все поля структуры DCB заполнены, необходимо
произвести конфигурирование порта, вызвав функцию SetCommState:

В случае успешного завершения функция вернет отличное от нуля
значение, а в случае ошибки — нуль.

Второй обязательной структурой для настройки порта является
структура COMMTIMEOUTS. Она определяет параметры временных задержек
при приеме-передаче. Вот описание этой структуры:

typedef struct _COMMTIMEOUTS <

Поля структуры COMMTIMEOUTS имеют следующие значения:


  • ReadIntervalTimeout — максимальное временной промежуток
    (в миллисекундах), допустимый между двумя считываемыми с
    коммуникационной линии последовательными символами. Во время
    операции чтения временной период начинает отсчитываться с момента
    приема первого символа. Если интервал между двумя
    последовательными символами превысит заданное значение, операция
    чтения завершается и все данные, накопленные в буфере, передаются
    в программу. Нулевое значение данного поля означает, что данный
    тайм-аут не используется.
  • ReadTotalTimeoutMultiplier — задает множитель (в
    миллисекундах), используемый для вычисления общего тайм-аута
    операции чтения. Для каждой операции чтения данное значение
    умножается на количество запрошенных для чтения символов.
  • ReadTotalTimeoutConstant — задает константу (в
    миллисекундах), используемую для вычисления общего тайм-аута
    операции чтения. Для каждой операции чтения данное значение
    плюсуется к результату умножения ReadTotalTimeoutMultiplier на
    количество запрошенных для чтения символов. Нулевое значение полей
    ReadTotalTimeoutMultiplier и ReadTotalTimeoutConstant означает,
    что общий тайм-аут для операции чтения не используется.
  • WriteTotalTimeoutMultiplier — задает множитель (в
    миллисекундах), используемый для вычисления общего тайм-аута
    операции записи. Для каждой операции записи данное значение
    умножается на количество записываемых символов.
  • WriteTotalTimeoutConstant — задает константу (в
    миллисекундах), используемую для вычисления общего тайм-аута
    операции записи. Для каждой операции записи данное значение
    прибавляется к результату умножения WriteTotalTimeoutMultiplier на
    количество записываемых символов. Нулевое значение полей
    WriteTotalTimeoutMultiplier и WriteTotalTimeoutConstant означает,
    что общий тайм-аут для операции записи не используется.

Немного поподробнее о тайм-аутах. Пусть мы считываем из порта 50
символов со скоростью 9 600 бит/с. Если при этом используется 8 бит
на символ, дополнение до четности и один стоповый бит, то на один
символ в физической линии приходится 11 бит (включая стартовый бит).
Значит, 50 символов на скорости 9 600 бит/с будут приниматься

или примерно 57,3 миллисекунды, при условии нулевого интервала
между приемом последовательных символов. Если же интервал между
символами составляет примерно половину времени передачи одного
символа, т. е. 0,5 миллисекунд, то время приема будет

или примерно 82 миллисекунды. Если в процессе чтения прошло более
82 миллисекунд, то мы вправе предположить, что произошла ошибка в
работе внешнего устройства и можем прекратить считывание, тем самым
избежав зависания программы. Это и есть общий тайм-аут операции
чтения. Аналогично существует и общий тайм-аут операции записи.

Формула для вычисления общего тайм-аута операции, например,
чтения, выглядит так:

NumOfChar x ReadTotalTimeoutMultiplier +
ReadTotalTimeoutConstant

где NumOfChar — число символов, запрошенных для операции чтения.

В нашем случае тайм-ауты записи можно не использовать и
установить их равными нулю.

После заполнения структуры COMMTIMEOUTS, необходимо вызвать
функцию установки тайм-аутов:

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

Допустим, вы обмениваетесь с внешним устройством пакетами
информации размером 1024 байта, тогда разумным размером буферов
будет значение 1200. Функция SetupComm интересна тем, что она может
просто принять ваши размеры к сведению, внеся свои коррективы, либо
вообще отвергнуть предложенные вами размеры буферов — в таком случае
эта функция завершится ошибкой.

Приведу пример открытия и конфигурирования последовательного
порта COM1. Для краткости — без определения ошибок. В данном примере
порт открывается для работы со скоростью 9 600 бит/c, используется 1
стоповый бит, бит четности не используется:

handle = CreateFile(«COM1», GENERIC_READ | GENERIC_WRITE,
NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

SetupComm(handle, SizeBuffer, SizeBuffer);

Электроника для всех

Блог о электронике

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

Тут возникают два, на первый взгляд, противоречивых требования:

  • 1)Драйвера внешней периферии хочется писать максимально абстрагировавшись от конкретного способа подключения к микроконтроллеру, а ещё лучше независимо от типа микроконтроллера. Переписывать «библиотечный» код для каждого проекта не очень хорошо.
  • 2)Скорость и размер кода в большинстве случаев имеют большое значение.

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

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

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

  • 1) Определение портов и линий ввода-вывода с помощью препроцессора.
  • 2) Передача порта в код, который его использует, посредствам указателя.
  • 3) Виртуальные порты.

Примеры приведены для МК семейства AVR. Компилятор avr-gcc, но описываемые подходы могут быть применены к любым другим МК, для которых имеется стандартный Си/Си++ компилятор.

1. Препроцессор
Способов использования препроцессора для работы с портами в МК существует великое множество. В самом простом и самом распространенном случае просто объявляем порт и номера ножек, к которым подключено наше устройство с помощью директивы #define, не забыв, конечно, про DDR и PIN регистры, если они нужны.
Нет ничего проще, чем помигать светодиодом, подключенным к одному из выводов МК:

Ссылка на основную публикацию
ВсеИнструменты
Adblock
detector
×
×