Практическое программирование Arduino/CraftDuino — общение с Arduino — программирование работы с COM-портом


0. Начало
1. Цифровой ввод — кнопка
2. Аналоговый вывод — Fading
3. Аналоговый ввод – потенциометр
4. Аналоговый ввод – осциллограф
5. Генерация звука – пьезоизлучатель.
6. Фоторезистор
7. Сенсор на светодиоде

8. Общение с Arduino — программирование работы с COM-портом.

Правильным местом с которого стоит начать своё изучение написание программ для взаимодействия с Arduino/CraftDuino является официальный сайт:
http://www.arduino.cc/playground/Main/InterfacingWithSoftware
— там приведены примеры работы с последовательным портом из разных языков и сред программирования.

Ниже рассмотрим примеры работы с Arduino на С, С++, С#, PERL и Python.

Arduino + C
http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/

приводится в пример консольная POSIX C – программа, исходник которой можно скачать здесь
— программа может принимать и передавать данные на плату Arduino/Freeduino

Использование:

laptop% gcc -o arduino-serial arduino-serial.c
laptop% ./arduino-serial
Usage: arduino-serial -p  [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»

laptop% ./arduino-serial -b 9600 -p /dev/tty.usbserial -s 6

2. Отправить в Arduino строчку “furby”

laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s furby

3. Получить данные от Arduino

laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -r
read: 15 Hello world!

Данный пример показывает вывод данных от скетча serial_hello_world.pde
из проекта Spooky Arduino (Зловещий Ардуино).

Отправить ASCII-строчку “get” в Arduino и получить результат:

laptop% ./arduino-serial -b 9600 -p /dev/cu.usbserial -s get -r
read: d=0

И немножко о внутреннем устройстве программы:
Там всего три интересных функции, которые показывают пример работы с последовательным портом на C:

int serialport_init(const char* serialport, int baud)

— получает имя порта («/dev/tty.usbserial»,»COM1″) и скорость работы, а возвращает файловый дескриптор открытого порта.

int serialport_write(int fd, const char* str)

– отправляет в порт (по файловому дескриптору) строчку данных

int serialport_read_until(int fd, char* buf, char until)

– считывает данные из последовательного порта в буфер, пока не встретит определённый символ (char until)

Arduino + C++ (using libSerial)
http://devlog.bigmonachus.org/2008/08/interfacing-arduino-with-c-and.html

Работа с последовательным портом с использованием библиотеки 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;
}

Ссылки:
Serial Programming Guide for POSIX Operating Systems

Arduino + C++ (for windows)
http://www.arduino.cc/playground/Interfacing/CPPWindows

по ссылке можно найти пример класса для работы с последовательным портом в системах на базе 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 🙂

Arduino + C#
http://www.arduino.cc/playground/Interfacing/Csharp

.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

Примеры:
C# with Arduino Duemilanove + Led On/Off/Pwm Control
C# + Arduino Duemilanove + RGB Led Control

Arduino + PERL
http://www.arduino.cc/playground/Interfacing/PERL

требуется модуль Device::SerialPort

# установка параметров 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')

Примеры:
если не хочется ничего ставить – можно посмотреть или использовать питоновский порт
arduino_serial.py
программы Tod E. Kurt-а arduino-serial.c

Arduino и IRC-бот на Python-е
Контроль Arduino с использованием HTML-форм на Python-е

Arduino + Processing
http://www.arduino.cc/playground/Interfacing/Processing

читать далее: 9. Аналоговый датчик температуры – LM335
Программа для управления портами Arduino/CraftDuino

По теме
Arduino, термины, начало работы
КМБ для начинающих ардуинщиков
Состав стартера (точка входа для начинающих ардуинщиков)
Arduino и Matlab
Arduino и LabVIEW
Processing и Arduino
openFrameworks и Arduino


0 комментариев на «“Практическое программирование Arduino/CraftDuino — общение с Arduino — программирование работы с COM-портом”»

  1. Всем привет!
    Кто нибудь пробовал работать с библиотекой LibSerial при написании программ в Linux???
    Считываю из буфера порта всякую фигню, а программа «cu» всё читает идеально!..

    • Вопрос снимается, всё работает )))

      Связка Arduino + C в AltLinux, показывает эффективные результаты!
      При чтении информации из буфера, не забудьте его почистить (buf[i]).

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение