我已经设置了连接到Linux PC的远程微控制器,该微控制器吐出连续的字符串。我已经使用屏幕配置了端口(通过发布屏幕/dev/ttys0 57600(。
我用OD命令验证了数据,并得到了我的预期。数据以8位十六进制值...
0006040 03 01 09 00 00 00 00 00 00 00 00 00 00 00 00 00
0006060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006100 00 00 00 00 00 00 00 00 00 00 00 06 0b a5 00 03
0006120 01 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006160 00 00 00 00 00 00 00 00 00 00 06 0b a5 00 03 01
0006200 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006240 00 00 00 00 00 00 00 00 00 06 0b a5 00 02 01 09
0006260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006320 00 00 00 00 00 00 00 00 0f 0c a5 00 02 01 09 00
0006340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006400 00 00 00 00 00 00 00 0f 0c a5 00 02 01 09 00 00
0006420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006460 00 00 00 00 00 00 0f 0c a5 00 01 01 09 00 00 00
0006500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006520 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006540 00 00 00 00 00 05 0c a5 00 01 01 09 00 00 00 00
0006560 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006620 00 00 00 00 05 0c a5 00 01 01 09 00 00 00 00 00
0006640 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006660 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0006700 00 00 00 05 0c a5 01 08 01 09 00 00 00 00 00 00
然后,我创建一个简单的C程序来尝试读取相同的数据,但是我从C程序中获得的只是以下输出:
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1 a5:1
a5:1
基于该输出,看来读取函数确实返回一个字节正在读取,但是每次返回的值是A5时,它是Micro发送到PC的标志字节,以指示固定的新流 - 尺寸数据。
所以我的程序是正确的,可以覆盖读取缓冲区中现有的" a"值,但是它需要始终使用正确的数据(无论是00或01(进行更新,但不仅是A5
我在做什么错?
我附上了下面的完整代码,如果有人想尝试复制问题,则可以使用。是的,我配置了波特和数据位,并正确停止位。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#define TIMEOUT 5
int main(){
char inb[3]; //our byte buffer
int nread=0; //number bytes read from port
int n; //counter
int iosz=128; //Lets get 128 bytes
int fd=open("/dev/ttyS0",O_NOCTTY | O_RDONLY | O_SYNC); //Open port
for(n=0;n<iosz;n++){
int s=time(NULL); //Start timer for 5 seconds
while (time(NULL)-s < TIMEOUT && nread < 1){
inb[0]='A'; //Fill buffer with bad data
inb[1]='B';
inb[2]='C';
nread=read(fd,inb,1); //Read ONE byte
if (nread < 0 || time(NULL)-s >= TIMEOUT){
close(fd); //Exit if read error or timeout
return -1;
}
}
printf("%x:%d ",inb[0] & 0xFF,nread); //Print byte as we receive it
}
close(fd); //program ends so close and exit
return 0;
}
ASCII字符在某些值下未通过串行读取
这是对您程序缺陷的虚假分析。
事实证明,收到的最大价值似乎是0xa5,而小样本转储似乎总是先于0x0b和0x0c的字节。
如果转储要显示更多数据,最终会在0xa5字节之前有一个0x0D(返回(吗?
因此,如果规范模式处于活动状态(通常是默认模式(,而0x0d(即行定界线字符(先于它,则0xA5
将是行的第一个字符。
由于您的程序一次仅请求一个字符,因此规范 read((只会返回该行的第一个字符。
我在做什么错?
您的程序有两个重要的错误。
首先,您的程序忽略了配置串行终端,因此您不知道程序是使用规范还是非典型模式。
第二,您的程序仅打印单个 read((的相同结果。
您仅读取某些值的分析是不准确的,因为实际上只打印了单个 read((的结果。
printf((在的范围之外 loop(执行读取(,因此您的程序不会打印每个 read((获得,但仅打印出 first 成功 read((已获得。
之后,第一个成功 read((,变量nread
具有值1
,并且的nread < 1
比较 loop将始终评估为false。
因此,不再会在第一个成功之后发生 read(( S将发生,但是第一个结果将因 loop而重复打印。
因此,如果您运行程序时非传统模式在活动中处于活动状态,而'0xa5`恰好是第一个 read((,那就是打印(很多次(通过您的程序。
由于接收到的数据是二进制的,而不是ASCII文本,因此您需要为非典型(又名RAW(模式配置串行终端。
然后,您可以一次持续一次读取一个字节。
我终于弄清楚了!
经过几天的大脑扭曲,我发现了最终的答案。
是的,我已经在串行端口上实现了I/O,一次使用更多字节而不是一个字节,但这并没有解决。
字面上解决的问题是两个项目:
-
我需要使该程序具有很高的优先级,因为串行时机很严格(每173us每173us每173us时为56K(。为此,我在主要功能的开头添加了此内容:
const struct Sched_param Schedp = {99};sched_setscheduler(0,sched_fifo,&amp; schedp(;
,我还添加了以下内容:
#include <sched.h>
这使程序可以优先,但是令人惊讶的是,蛋糕最高的东西是内存锁定围绕需要至关重要的部分,这些关键部分是从/到/写的。端口。
mlockall(MCL_CURRENT);
//use read() or write() in here with file descriptor as serial port
munlockall();
,我还添加了以下内容:
#include <sys/mman.h>
我考虑使用mcl_future作为参数,但这意味着要求在内存中锁定更多资源,但是在发现不必要之后,我将使用mcl_current。
我不在乎系统上的其余过程是否锁定了5秒钟,但至少现在数据I/O在串行端口上运行100%。