8. Общение с Arduino — программирование работы с COM-портом.
Правильным местом с которого стоит начать своё изучение написание программ для взаимодействия с Arduino/CraftDuino является официальный сайт: http://www.arduino.cc/playground/Main/InterfacingWithSoftware
— там приведены примеры работы с последовательным портом из разных языков и сред программирования.
Ниже рассмотрим примеры работы с Arduino на С, С++, С#, PERL и Python.
приводится в пример консольная POSIX C – программа, исходник которой можно скачать здесь
— программа может принимать и передавать данные на плату Arduino/Freeduino
Использование:
laptop% gcc -o arduino-serial arduino-serial.c
laptop% ./arduino-serial
Usage: arduino-serial -p <serialport> [OPTIONS]
Options:
-h, --help Print this help message
-p, --port=serialport Serial port Arduino is on
-b, --baud=baudrate Baudrate (bps) of Arduino
-s, --send=data Send data to Arduino
-r, --receive Receive data from Arduino & print it out
-n --num=num Send a number as a single byte
-d --delay=millis Delay for specified milliseconds
Примечание:
Порядок параметров имеет значение! '-b' нужно устанавливать перед указыванием порта '-p'.
Можно устанавливать несколько флагов для выполнения последовательности действий:
'-d 2000 -s hello -d 100 -r'
Означает: «ждать 2 секунды, отправить 'hello', ждать 100msec, считать ответ»
Примеры использования:
1. Отправить в Arduino один ASCII-символ «6»
Работа с последовательным портом с использованием библиотеки libSerial
libSerial работает в POSIX-системах (на Windows работать не будет)
подключение библиотеки:
#include < SerialStream.h >
#include < iostream >
#define PORT "/dev/ttyUSB0" // указывается порт, к которому подключена Arduino
SerialStream ardu;
using namespace std;
using namespace LibSerial;
примеры работы:
void open()
{
ardu.Open(PORT);
/*The arduino must be setup to use the same baud rate*/
ardu.SetBaudRate(SerialStreamBuf::BAUD_9600);
ardu.SetCharSize(SerialStreamBuf::CHAR_SIZE_8);
}
int get(char out)
{
int res;
char str[SOME_BIG_SIZE];
ardu << out;
ardu >> str;
sscanf(str,"%d",&res);
return res;
}
по ссылке можно найти пример класса для работы с последовательным портом в системах на базе Windows:
SerialClass.h (header)
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
#define ARDUINO_WAIT_TIME 2000
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
class Serial
{
private:
// дескриптор COM-порта
HANDLE hSerial;
// статус соединения
bool connected;
// различная информация о соединении
COMSTAT status;
// последняя ошибка
DWORD errors;
public:
// инициализация с указанным COM-портом
Serial(char *portName);
// закрытие соединения
//NOTA: по каким-то причинам не удаётся переподключиться
// нужно перезапускать программу
~Serial();
// считываем данные в буфер – если nbChar больше, чем
// число доступных байт – возвращает только
// доступные данные
// возвращает -1 при ошибке
int ReadData(char *buffer, unsigned int nbChar);
// записывает данные из буфера в порт
// возвращает true при удаче
bool WriteData(char *buffer, unsigned int nbChar);
// возвращает статус соединения
bool IsConnected();
};
#endif // SERIALCLASS_H_INCLUDED
Serial.cpp (source code file)
#include "SerialClass.h"
Serial::Serial(char *portName)
{
// пока ещё не подключились
this->connected = false;
// пытаемся подключиться к порту посредством CreateFile
this->hSerial = CreateFile(portName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// проверяем – было ли соединение успешным
if(this->hSerial==INVALID_HANDLE_VALUE)
{
//если не было – выводим ошибку
if(GetLastError()==ERROR_FILE_NOT_FOUND){
// печатаем ошибку
printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);
}
else
{
printf("ERROR!!!");
}
}
else
{
// подключились – теперь устанавливаем параметры
DCB dcbSerialParams = {0};
// считываем текущие параметры
if (!GetCommState(this->hSerial, &dcbSerialParams))
{
// если невозможно – говорим о неудаче
printf("failed to get current serial parameters!");
}
else
{
// устанавливаем параметры для соединения с Arduino
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
// применяем параметры
if(!SetCommState(hSerial, &dcbSerialParams))
{
printf("ALERT: Could not set Serial Port parameters");
}
else
{
// отлично! Мы успешно подлючились :)
this->connected = true;
//ждём пока Arduino перезагрузится
Sleep(ARDUINO_WAIT_TIME);
}
}
}
}
Serial::~Serial()
{
// проверяем статус подключение
if(this->connected)
{
// отключаемся
this->connected = false;
// закрываем дескриптор порта
CloseHandle(this->hSerial);
}
}
int Serial::ReadData(char *buffer, unsigned int nbChar)
{
// число считываемых байт
DWORD bytesRead;
// число байт, которое мы действительно хотим считать
unsigned int toRead;
// используем ClearCommError для получения информации о статусе последовательного порта
ClearCommError(this->hSerial, &this->errors, &this->status);
// проверяем – есть ли информация для считывания
if(this->status.cbInQue>0)
{
// если количество данных меньше требуемого – считываем
// столько, сколько есть
if(this->status.cbInQue>nbChar)
{
toRead = nbChar;
}
else
{
toRead = this->status.cbInQue;
}
// Пытаемся считать нужное количество данных и
//возвращаем число считанных байт при удачном завершении.
if(ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL) && bytesRead != 0)
{
return bytesRead;
}
}
// ничего не считали или где-то была ошибка – возвращаем -1
return -1;
}
bool Serial::WriteData(char *buffer, unsigned int nbChar)
{
DWORD bytesSend;
// пытаемся записать значение буфера buffer в COM-порт
if(!WriteFile(this->hSerial, (void *)buffer, nbChar, &bytesSend, 0))
{
// если не получилось – получаем код ошибки и возвращаем false
ClearCommError(this->hSerial, &this->errors, &this->status);
return false;
}
else
return true;
}
bool Serial::IsConnected()
{
// просто возвращаем статус соединения :)
return this->connected;
}
Пример использования:
#include <iostream>
#include "SerialClass.h"
#define COM_PORT "COM1"
#define BUF_SIZE 256
int main()
{
Serial com1(COM_PORT);
// обнуляем буфер
char buf[BUF_SIZE];
for(int i=0;i<BUF_SIZE;i++)
buf[i]='\0';
// считываем и выводим данные из порта
com1.ReadData(buf,BUF_SIZE-1);
std::cout <<buf<< std::endl;
return 0;
}
Данный пример тестировался в CodeBlocks
, но должен прекрасно работать и в Visual Studio :)
.Net 2.0 предоставляет возможность просто работать с System.IO.Ports
— поэтому очень просто написать программу, например, которая будет принимать вводимую информацию с клавиатуры и перенаправлять её в порт.
using System;
using System.IO.Ports;
namespace test
{
class Program
{
static void Main(string[] args)
{
SerialPort port = new SerialPort("COM1", 9600);
port.Open();
while (true)
{
String s=Console.ReadLine();
if (s.Equals("exit"))
{
break;
}
port.Write(s+'\n');
}
port.Close();
}
}
}
Скомпилировать данный пример можно даже без сред разработки, а просто имея установленный .NET Framework. Для этого нужно перейти в директорию Framework-а – обычно это что-то вроде:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\
теперь нужно скопировать туда файл с программой на C# — пусть это будет
com-cs.cs
Чтобы скомпилировать — нужно выполнить команду:
csc com-cs.cs
Компилятор отработает и в директории появится исполняемый файл
com-cs.exe
# установка параметров COM-порта
use Device::SerialPort;
my $port = Device::SerialPort->new("/dev/tty.usbserial");
# 19200, 81N on the USB ftdi driver
$port->baudrate(19200);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
Передача данных в порт:
$port->write("Whatever you feel like sending");
Получение данных от Arduino:
while (1) {
# пытаемся получить данные из порта
my $char = $port->lookfor();
# если данные есть – распечатываем :)
if ($char) {
print "Recieved character: $char \n";
}
}
Arduino + Python http://www.arduino.cc/playground/Interfacing/Python
работая в UNIX-подобных системах, с последовательным портом можно общаться, как с файлом – считывать и записывать данные.
Но есть кросплатформенная библиотека – pySerial
, которая делает эти операции более наглядными.
Однако, для её работы под Windows понадобится ещё pyWin32
#
# для работы с COM-портом нужна библиотека
# pySerial, кроме того, под винду понадобится еще pyWin32
#
import serial
SERIAL_PORT = 'COM1'
SERIAL_SPEED = 38400
ser = serial.Serial(SERIAL_PORT, SERIAL_SPEED)
while 1:
#s = ser.read() # считывается один байт
s = ser.readline().strip() # считывается строка и убираются символы “\r\n”
print s # печатаем на экран
писать данные в порт так же просто:
import serial
ser = serial.Serial('/dev/tty.usbserial', 9600)
ser.write('5')
Всем привет!
Кто нибудь пробовал работать с библиотекой LibSerial при написании программ в Linux???
Считываю из буфера порта всякую фигню, а программа «cu» всё читает идеально!..
Комментарии (2)
RSS свернуть / развернутьКто нибудь пробовал работать с библиотекой LibSerial при написании программ в Linux???
Считываю из буфера порта всякую фигню, а программа «cu» всё читает идеально!..
SinauRus
Связка Arduino + C в AltLinux, показывает эффективные результаты!
При чтении информации из буфера, не забудьте его почистить (buf[i]).
SinauRus
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.