C ++ Последовательная связь при чтении данных работает, но запись не выполняется

Я создаю класс для последовательной связи между встроенной системой и приложением C ++, работающим в среде Linux. Поэтому я использовал API-интерфейс termios для Linux, который описан здесь.

Конструктор откроет последовательный порт устройства. В моем случае это ttyUSB0 для микроконтроллера Arduino, который я использовал. Затем он установит скорость передачи и другие параметры порта.

Я также добавил функции для чтения или записи данных в последовательный порт. Поскольку чтение является блокирующей функцией (не возвращает до тех пор, пока данные не получены или истекло время ожидания), я добавил функцию, которая проверяет, доступны ли байты, что вы можете сделать перед вызовом Read ().

После создания тестового примера чтение, похоже, прошло нормально. Функция Available () действительно возвращает количество доступных байтов. После прочтения они выводятся на консоль.

Однако по какой-то неизвестной причине моя функция записи не работает, хотя я «верю», что правильно выполнил шаги из руководства. Я сделал тестовый пример для функции записи: arduino должен мигать своим встроенным светодиодом, как только он получит правильное сообщение. Сообщение является правильным, если оно начинается с метки начала "#" и заканчивается знаком конца "$".

Когда я отправляю правильное сообщение с помощью шпатлевки инструмента тестирования или с помощью монитора последовательного порта Arduino, светодиод будет мигать. Но этого не происходит, когда я отправляю сообщение через свою собственную функцию записи.

В Arduino есть и другие встроенные светодиоды, которые указывают данные на выводах RX и TX. Эти светодиоды действительно загораются, когда я отправляю данные из моей собственной функции записи, но функция мигания в моем тестовом примере никогда не вызывается. Затем я проверил, были ли вообще прочитаны какие-либо байты, но Arduino Serial.available () никогда не возвращает значение выше 0, когда данные отправляются из моей собственной функции записи.

Думаю, ошибка либо в самой функции записи, либо в конфигурации последовательного порта. Так далеко я не могу этого понять. Есть ли у кого-нибудь опыт или знания об этом или есть какие-либо советы о том, как мне подойти к этой проблеме?

Заранее спасибо,

Дирк

Код для Linux:

main.cpp

#include "serial.h"
#include <iostream>

using namespace std;

int main()
{
    //TEST CASE FOR WRITING DATA
    Serial serial("/dev/ttyUSB0");
    serial.Write("#TEST$"); 

    //TEST CASE FOR READING DATA
    /*while (true)
    {
        char message[100];
        char * ptr = NULL;
        while (serial.Available() > 0)
        {
            char c; 
            serial.Read(&c);
            switch(c)
            {
            case '#':
                ptr = message;
                break;
            case '$':
                if (ptr != NULL)
                {
                    *ptr = '\0';
                }
                std::cout << "received: " << message << std::endl;
                ptr = NULL;
                break;
            default:
                 if (ptr != NULL)
                {
                    *ptr = c;
                    ptr++;
                }
                break;
            }
        }
    }*/
    return EXIT_SUCCESS;
}

Serial.h

#ifndef SERIAL_H
#define SERIAL_H

#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

class Serial
{
    private:
        int fd;
    public:
        Serial(std::string device);

        ~Serial()
        {
            close(fd);
        };     

        int Available();
        void Read(char * buffer, int amountOfBytes);
        void Read(char * bytePtr);
        int Write(std::string message);
};

#endif

Serial.cpp

#include "serial.h"
#include <stdexcept>
#include <string.h>

Serial::Serial(std::string device)
{   
    // Open port
    fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0)
    {
        throw std::runtime_error("Failed to open port!");
    }

    // Config
    struct termios config;

    tcgetattr(fd, &config);

    // Set baudrate
    cfsetispeed(&config, B9600);
    cfsetospeed(&config, B9600);

    // 9600 8N1
    config.c_cflag &= ~PARENB;
    config.c_cflag &= ~CSTOPB;
    config.c_cflag &= ~CSIZE;
    config.c_cflag |=  CS8;

    // Disable hardware based flow control
    config.c_cflag &= ~CRTSCTS;

    // Enable receiver
    config.c_cflag |= CREAD | CLOCAL;                               

    // Disable software based flow control
    config.c_iflag &= ~(IXON | IXOFF | IXANY);

    // Termois Non Cannoincal Mode 
    config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 

    // Minimum number of characters for non cannoincal read
    config.c_cc[VMIN]  = 1;

    // Timeout in deciseconds for read
    config.c_cc[VTIME] = 0; 

    // Save config
    if (tcsetattr(fd, TCSANOW, &config) < 0)                        
    {
        close(fd);
        throw std::runtime_error("Failed to configure port!");
    }

    // Flush RX Buffer
    if (tcflush(fd, TCIFLUSH) < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to flush buffer!");
    }
}

int Serial::Available()
{
    int bytes = 0;
    if (ioctl(fd, TIOCINQ, &bytes) < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to check buffer!");
    }
    return bytes;
}

void Serial::Read(char * buffer, int amountOfBytes)
{
    if (read(fd, buffer, amountOfBytes) < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to read bytes!");
    }
}

void Serial::Read(char * bytePtr)
{
    return Serial::Read(bytePtr, 1);
}

int Serial::Write(std::string message)
{
    int length = message.size();
    if (length > 100)
    {
        throw std::invalid_argument("Message may not be longer than 100 bytes!");
    }

    char msg[101];
    strcpy(msg, message.c_str());

    int bytesWritten = write(fd, msg, length);

    if (bytesWritten < 0)
    {
        close(fd);
        throw std::runtime_error("Failed to write bytes!");
    }

    return bytesWritten;
}

Код Arduino

void setup() 
{
    Serial.begin(9600);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop() 
{
    //TEST-CASE FOR WRITING DATA
    /*Serial.print("#TEST$");
    delay(1000);*/

    //TEST-CASE FOR READING DATA
    char message[100];
    char * ptr = NULL;
    while (Serial.available() > 0)
    {
        char c = Serial.read();
        switch(c)
        {
        case '#':
            ptr = message;
            break;
        case '$':
            if (ptr != NULL)
            {
                *ptr = '\0';
            }
            ptr = NULL;
            int messageLength = strlen(message);
            Blink();
            break;
        default:
            if (ptr != NULL)
            {
              *ptr = c;
              ptr++;
            }
            break;
        }
    }
}

void Blink()
{
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000);
}

person Dirk    schedule 27.11.2018    source источник


Ответы (1)


Решено. Функция open отправляет сигнал на последовательный порт, который Arduino интерпретирует как сигнал для перезагрузки. Я исправил проблему, отключив автоматический сброс.

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

Эта проблема особенно актуальна для микроконтроллеров Arduino.

person Dirk    schedule 04.12.2018
comment
Если я проверил, ваш код в main () вы все равно поставите inactive / * - * / ТЕСТОВЫЙ СЛУЧАЙ ДЛЯ ЧТЕНИЯ ДАННЫХ, то есть с while (true) до return EXIT_SUCCESS . Можно ли, добавив резистор на 120 Ом, активировать эту (истинную) часть? Во-вторых: не могли бы вы объяснить, где я поставлю 2-х секундную задержку? Вместо того, чтобы добавлять оборудование (резистор на 120 Ом), добавление задержки, вероятно, будет лучшим выбором. - person AirCraft Lover; 12.02.2021