【问题标题】:Read USB data without IDE in Arduino UNO在 Arduino UNO 中读取没有 IDE 的 USB 数据
【发布时间】:2021-07-12 03:38:44
【问题描述】:

我有一个 Arduino UNO。我编写了一个脚本来控制连接到 Arduino 上 PIN 2、3、4 的灯。可以使用我的笔记本电脑关闭或打开灯:

  • 0 关闭所有 LED
  • 1 打开引脚 1 上的 LED
  • 2 打开引脚 2 上的 LED
  • 3 打开引脚 1 和 2 上的 LED
  • 4 打开引脚 3 上的 LED
  • 5 开启引脚 1 和 3 上的 LED
  • 6 打开引脚 2 和 3 上的 LED
  • 7 点亮所有 LED。

我实际上只对从我的笔记本电脑发送数据并相应地闪烁灯感兴趣。

这是我的程序:

# pragma GCC optimize ("Ofast")

# define LED1 2
# define LED2 3
# define LED3 4

char buf[4] ;
unsigned char inp, len ;

void setup() {
    pinMode(LED1, OUTPUT) ;
    pinMode(LED2, OUTPUT) ;
    pinMode(LED3, OUTPUT) ;

    Serial.begin(115200) ;
    Serial.setTimeout(1) ;
}

void loop() {
    if (Serial.available() > 0) {
        len = Serial.readBytes(buf, 3) ;
    
        if (len) {
            buf[3] = '\0' ;
            inp = atoi(buf) ;
    
            // Illuminate LEDs
            digitalWrite(LED1, 1 & inp ? HIGH : LOW) ;
            digitalWrite(LED2, 2 & inp ? HIGH : LOW) ;
            digitalWrite(LED3, 4 & inp ? HIGH : LOW) ;
        }
    }
}

当我打开 IDE 的串行监视器并写 printf 1 > /dev/ttyUSB0 时,它工作正常。

但是当我关闭串行监视器和printf 1 > /dev/ttyUSB0 时,它不起作用,我唯一得到的是板载 LED 闪烁。

所以每次我需要点亮一个 LED 时,我必须确保 IDE 是打开的。

有没有办法在不打开 IDE 的情况下从任何 Linux 计算机写入 Arduino 串行端口?

【问题讨论】:

  • Uno 在新的 USB 连接上重置。如果要发送 1,为什么要发送带有串行监视器的 printf 1 > /dev/ttyUSB0
  • 您的代码正在等待 3 个字节。 printf 1 发送一个字节。但是,由于您有 1ms 超时,您会收到 1 个字节。很难说 buf[1]buf[2] 在这一点上包含什么。如果您只需要 3 位,那么您应该只发送和接收一个字节。
  • 你试过echo 1 > /dev/ttyUSB0吗?它添加了一个像串行监视器这样的换行符。 -- 你检查过 Uno 上的复位信号电平吗?
  • 您好,是的,如果我回显,它也不起作用。在回声之前,我必须这样做:exec 3<> /dev/ttyUSB0

标签: c arduino usbserial


【解决方案1】:

好的,所以问题是 arduino 有 Serial.read() 代码。除非我打开 Arduino IDE 的串行监视器,否则我发送的数据会失败。换句话说,如果我想创建一个热插拔设备,我的笔记本电脑会循环搜索并在插入时向其写入数据,这是不可能的。

现在要解决这个问题,我需要看看 IDE 的串行监视器做了什么,它设置波特率,并在所选端口上打开文件描述符 3。

所以要解决热插拔问题,我首先需要设置波特率和匹配标志。然后我需要使用 fcntl 文件描述符 3 打开文件,就像 IDE 的串行监视器一样。

自从我用 Ruby 编写发送字节以来,我有机会编写 C Ruby。我用这个代码设置波特率:

VALUE setBaudRate(volatile VALUE obj, volatile VALUE dev, volatile VALUE speed) {
    char *device = StringValuePtr(dev) ;
    unsigned int spd = NUM2UINT(speed) ;

    int serial_port = open(device, O_RDWR) ;
    struct termios tty ;

    char status = tcgetattr(serial_port, &tty) ;

    // IDE sets these flags
    // speed 57600 baud; line = 0;
    // min = 0; time = 0;
    // -brkint -icrnl -imaxbel
    // -opost
    // -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke

    if(status != 0) return Qnil ;
    tty.c_cflag &= ~CSIZE ;
    tty.c_cflag |= CS8 ;
    tty.c_cflag |= CREAD | CLOCAL ;
    tty.c_oflag &= ~OPOST ;

    tty.c_lflag &= ~ECHO ;
    tty.c_lflag &= ~ECHOCTL ;
    tty.c_lflag &= ~ECHOK ;
    tty.c_lflag &= ~ECHOE ;
    tty.c_lflag &= ~ECHOKE ;
    tty.c_lflag &= ~ISIG ;
    tty.c_lflag &= ~ICRNL ;
    tty.c_lflag &= ~IEXTEN ;
    tty.c_lflag &= ~ICANON ;

    tty.c_cc[VTIME] = 0 ;
    tty.c_cc[VMIN] = 0 ;

    cfsetispeed(&tty, spd) ;
    cfsetospeed(&tty, spd) ;
    status = tcsetattr(serial_port, TCSANOW, &tty) ;

    if (status == 0) return Qtrue ;
    else return Qfalse ;
}

如果您正在编写 C,您只需将 VALUE 函数名称替换为您想要的任何名称。并在失败时返回任何你喜欢的值,它可以是 0 表示成功,1 和 2 表示失败。

现在,确保波特率与 arduino 完美匹配。在我的 Ruby C 扩展中,我实际上是从 Ruby volatile VALUE speed 获取波特率的。然后它设置速度。纯 C 实现不会有太大不同。

但是,在 BASH 中,您可以只使用 stty:

sudo stty -F /dev/ttyUSB0 -cread -clocal -isig -iexten -echo -echoe -echok -echoctl -echoe -brkint -icrnl -imaxbel -opost -icanon min 0 time 0 57600

无论如何,要写入文件,您需要以读写模式打开文件。 Ruby 提供了这一点,我附上代码以防它对某人有所帮助:

require 'fcntl'
device = '/dev/ttyUSB0'

fd = IO.sysopen(device, Fcntl::O_RDWR | Fcntl::O_EXCL)
file = IO.open(fd)
file.syswrite("Hello world!")
file.close

在 BASH 中,你可以使用这个命令:

exec 3<> /dev/ttyUSB0

现在,如果您不想硬编码 /dev/ttyUSB0,则需要从 arduino 发送一些字节,并在设置与 arduino 匹配的正确波特率后读取。

通过这种方式,我们可以在 arduino 中读取和写入值!

【讨论】:

    猜你喜欢
    • 2016-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多