草庐IT

c - 串口ReadFile读取0字节返回true

coder 2024-06-04 原文

我正在尝试使用 Windows API 从 Windows 7 中的串行端口读取数据。当我尝试读入数据时,WaitCommEvent() 触发得很好并且 ReadFile() 调用返回 1 作为状态,但没有数据被读入。在ReadFile documentation它说:

When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero.

但是,我确信在通过串行端口发送的数据中没有EOT 字符。

我目前有两根 USB 电缆插入我的计算机并相互连接。我知道它们可以发送和接收数据,因为我已经用 Putty 对它们进行了测试。

为什么 ReadFile() 不读入任何数据?

我的代码如下。

标题:

typedef struct uart_handle
{
   uint8_t port_num;
   char port_name[10];
   uint32_t baud_rate;
   uint8_t byte_size;
   uint8_t stop;
   uint8_t parity;
   int32_t error;
   HANDLE handle;
} uart_handle;

主文件:

uart_handle* serial_comm_init(uint8_t port_num, uint32_t baud_rate, uint8_t byte_size, uint8_t stop, uint8_t parity)
{
   uart_handle*  uart;
   DCB           uart_params = { 0 };
   COMMTIMEOUTS  timeouts    = { 0 };
   int           status;

   uart         = (uart_handle*) malloc(1 * sizeof(uart_handle));
   status       = 0;

   // Set port name
   if (port_num > 9)
   {
      sprintf(uart->port_name, "\\\\.\\COM%d", port_num);
   }
   else
   {
      sprintf(uart->port_name, "COM%d", port_num);
   }

   // Set baud rate
   uart->baud_rate = baud_rate;

   // Set byte size
   uart->byte_size = byte_size;

   // Set stop bit
   uart->stop = stop;

   // Set parity
   uart->parity = parity;

   // Set up comm state
   uart_params.DCBlength = sizeof(uart_params);
   status = GetCommState(uart->handle, &uart_params);
   uart_params.BaudRate = uart->baud_rate;
   uart_params.ByteSize = uart->byte_size;
   uart_params.StopBits = uart->stop;
   uart_params.Parity   = uart->parity;
   SetCommState(uart->handle, &uart_params);

   // Setup actual file handle
   uart->handle = CreateFile(uart->port_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
   if (uart->handle == INVALID_HANDLE_VALUE) {
      printf("Error opening serial port %s.\n", uart->port_name);
      free(uart);
      return NULL;
   }
   else {
      printf("Serial port %s opened successfully.\n", uart->port_name);
   }

   // Set timeouts
   status = GetCommTimeouts(uart->handle, &timeouts);
   timeouts.ReadIntervalTimeout         = 50;
   timeouts.ReadTotalTimeoutConstant    = 50;
   timeouts.ReadTotalTimeoutMultiplier  = 10;
   timeouts.WriteTotalTimeoutConstant   = 50;
   timeouts.WriteTotalTimeoutMultiplier = 10;
   status = SetCommTimeouts(uart->handle, &timeouts);
   if (status == 0) {
      printf("Error setting comm timeouts: %d", GetLastError());
   }

   return uart;
}

int32_t serial_comm_read(void* handle, uint8_t* msg, uint32_t msg_size, uint32_t timeout_ms, uint32_t flag)
{
   uart_handle*  uart;
   uint32_t      num_bytes_read;
   uint32_t      event_mask;
   int32_t       status;

   uart            = (uart_handle*) handle;
   num_bytes_read  = 0;
   event_mask      = 0;
   status          = 0;

   memset(msg, 0, msg_size);

   // Register Event
   status = SetCommMask(uart->handle, EV_RXCHAR);

   // Wait for event
   status = WaitCommEvent(uart->handle, &event_mask, NULL);

   printf("Recieved characters.\n");

   do {
      status = ReadFile(uart->handle, msg, msg_size, &num_bytes_read, NULL);
      printf("Status: %d\n", status);
      printf("Num bytes read: %d\n", num_bytes_read);
      printf("Message: %s\n", msg);

   } while (num_bytes_read > 0);

   printf("Read finished.\n");

   return 0;
}

输出:

Serial port COM9 opened successfully.
Recieved characters.
Status: 1
Num bytes read: 0
Message:
Read finished.

最佳答案

显示的代码在未初始化 句柄上调用 GetCommState():

status = GetCommState(uart->handle, &uart_params); 

挑衅 UB 这样做。其返回状态未经测试。

由于这个 uart_params 可能包含 BS 没有有用的数据。


帮自己一个忙: 永远检查所有相关函数调用的返回值(并让代码相应地执行)!将所有返回或更改之后使用的数据的函数视为“相关”。

关于c - 串口ReadFile读取0字节返回true,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38248048/

有关c - 串口ReadFile读取0字节返回true的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  3. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  4. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  5. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  6. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  7. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. Ruby - 如何将消息长度表示为 2 个二进制字节 - 2

    我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi

  10. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

随机推荐