【问题标题】:Gtk+ and serial input (UART)Gtk+ 和串行输入 (UART)
【发布时间】:2018-06-28 01:33:51
【问题描述】:

我有以下问题:

我通过 UART(每 10 毫秒)接收传感器数据,我想在 gtk 中处理这些数据。这个想法是以特定的时间间隔(例如每 100 毫秒)处理这些数据。因此,我使用 g_timeout_add() 函数。 被调用的函数包含用于 UART 通信的通用集 -> 在我的情况下,它会阻塞,直到我收到 10 个字符。 这就是问题所在 - 在我的 read() (-> 系统调用) 函数中,程序挂断了。

我的串口设置如下:

struct termios oldtio,newtio;
tcgetattr(fd,&oldtio); 

bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;

// set input mode (non-canonical, no echo,...) 
newtio.c_lflag = 0;

newtio.c_cc[VTIME]    = 0;   // inter-character timer unused 
newtio.c_cc[VMIN]     = 10;  // blocking read until 10 chars received 

res = read(fd,buf,20);   // returns after 10 chars have been input 

无论我如何更改 g_timeout_add 函数中的间隔参数,都不会发生任何事情。

我阅读了很多关于这个问题的信息,但我找不到任何关于我的问题的解释。此外,我什至找不到处理 UART - GTK 组合的线程。

代码很长,所以我现在只想问你,你是否认为这个想法基本上可行,或者我的概念是否存在根本问题?

仅供参考:我在没有 GUI (->GTK) 的情况下测试了这段代码,它运行良好。在纯 C 中,我可以读取数据并打印它。

我很高兴得到任何答案。

【问题讨论】:

  • read 是一个阻塞函数,主线程/主循环将冻结。您必须使用非阻塞函数或将读取设置为非阻塞或使用 GLib/GIO 异步函数。如果您不从线程更新 UI,也可以使用线程。
  • 欢迎来到 Stack Overflow,请拨打tourHow to create a Minimal, Complete, and Verifiable example。您是否也尝试过编写一个只读取 UART 的小程序?如果小程序也失败了,可能是你没有权限从串口读取。
  • 这是可能的,我已经用 Gtk 和 Python 做到了。 Jose Fonte 的回答很好地解释了这一点。

标签: c gtk uart


【解决方案1】:

与大多数工具包一样,GTK+ 是事件驱动的。事件在主循环中调度和处理,主循环是进程的主线程。所以你不能做阻塞调用(例如sleep(5)),你不能做需要很长时间才能在回调中执行的处理。

想想两个只有孔要挖而且只有一把铲子(CPU 时间)的工人(主循环和回调)。主循环看到有一个超时事件要处理,并将铲子交给回调,以便它可以工作。如果回调占用 shovel 5 小时,则主循环无法完成其工作(例如绘制 UI 窗口),也无法将 shovel 交给任何其他等待它的回调。

在您的情况下,您正在以阻塞方式等待数据。您正在等待 10 个字节的到达。如果这需要他们 5 小时才能到达,您保留铲子。要解决这个问题,您需要:

  • 在单独的线程中执行阻塞调用(这样两个工作人员都有一个铲子,可以并行工作)
  • 或异步执行(可能使用GTask?我自己从未使用过)
  • 或(效率较低)进行一些轮询,这已经是您已经在做的事情了,因为您每 100 毫秒查找一次数据

对于轮询解决方案,您可能可以实现VMIN = 0 and VTIME > 0 案例,但您需要处理这样一个事实,即您必须重新构建消息,因为您可能一次收到比预期更多的字节。

对于线程解决方案,我会使用GThread 来执行阻塞read 调用,就像你现在正在做的那样,并删除g_timeout_add。您不需要它,因为您将从轮询模型(“我收到数据了吗?”每秒 10 次)更改为通知模型(“您收到数据!”)。相反,当您在线程中读取了一些字节时,使用g_idle_add 将它们发送到主循环。在关联的回调中,您将收到您的数据并能够将其呈现给用户。但是请记住,您不应该从主线程以外的线程调用 GTK+ 函数,因为该工具包不是线程安全的。这就是我们 g_idle_add 的原因(这来自 GLib,没关系)。

【讨论】:

  • 非常感谢!我选择了第一个建议,并通过 pthread 将其分成两个线程,效果很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多