首页 > 解决方案 > Linux UART)多次十六进制写入后如何按顺序读取-C

问题描述

我将通过UART编写一个由十六进制排列组成的命令并读取它。

在这个过程中,随着要写入的命令数量的增加,它们在读取的时候并不是在每个排列中读取,而是随着缓冲区分配大小而飞。

例如)

我想要的读取值(Printf):

a5 01 90 08 01 21 00 00 75 30 03 e4 ec

a5 01 91 08 10 2d 07 10 27 03 03 e4 a4

a5 01 92 08 42 01 42 01 27 03 03 e4 d7

输出值(printf):

a501900801210000753003e4eca5019108102d07102703 
03e4a4a501920842014201270303e4d7

在分析代码时,似乎在Read之前write是同时完成了几件事,并作为一个整体存储在Read缓冲区中,但我不知道如何解决。

如何按照写1时的read排列进行剪切打印?目前,它只是使用 print 进行测试,但由于我们将来必须将其发送到服务器,因此我们使用 printf 将其打印为 data3 变量。(我必须在有效载荷上飞行)

目前正在写的代码如下,10个写变量中只放了3个,做个简单的测试。这可能是一个基本问题,因为我不擅长它,但我请求你的帮助。

#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <pthread.h>

int main(void)
{
    int fd;
    fd=open("/dev/ttyHSL6", O_RDWR|O_NOCTTY );
    struct termios newtio;

    unsigned char buffer[40]={0};
    int bytes_read=0;
    char data[40];
    char *data3;
    int i=0;
    if (fd == -1)
    {
        printf("Error! in opening port");
        exit(-100);
    }

    memset(&newtio, 0, sizeof(struct termios));
    newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;

    newtio.c_iflag = IGNPAR;

    newtio.c_oflag = 0;
    newtio.c_lflag = 0;
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 1;
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &newtio);
    unsigned char str[13] = {0xA5,0x80,0x95,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2};
    unsigned char str1[13] = {0xA5,0x80,0x90,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBD};
    unsigned char str2[13] = {0xA5,0x80,0x91,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xBE};

    while(1){
        data3=malloc(sizeof(char)*100);
        memset(buffer, 0, sizeof(buffer));
        strcpy(data3,data);
        for(i=0;i<10;i++){
            switch(i){
                case 1:
                    write(fd, str, sizeof(str)/sizeof(str[0]));
                    usleep(100000);
                    break;
                case 2:
                    write(fd, str1, sizeof(str1)/sizeof(str1[0]));
                    usleep(100000);
                    break;
                case 3:
                    write(fd, str2, sizeof(str2)/sizeof(str2[0]));
                    usleep(100000);
                    break;
            }



            bytes_read = read(fd, buffer, sizeof(buffer)/sizeof(buffer[0]));
            sprintf(data,"%02x",buffer[0]);
            
            if (bytes_read > 0)
            {
                buffer[bytes_read]=0;
                for (int j=1; j< sizeof(buffer)/sizeof(buffer[0]); j++)        
                {
                    sprintf(data,"%02x",buffer[j]);
                    strcat(data3,data);
                }
                sprintf(data3,"\n");
                printf("%s\n",data3);   
            }

        }
    }
    close(fd);
    return 0;
}


(目前,执行此代码时不会打印任何值)

标签: clinuxuart

解决方案


for 循环以i = 0.

i = 1仅当或i = 2或时,交换机才会将数据写入端口i = 3

我的猜测是线路read(fd, buffer, sizeof(buffer)/sizeof(buffer[0]));被阻塞(等待有人写东西)。因为你第一次没有写任何东西。

请记住,阻塞 IO 读取器将阻塞,直到写入器写入某些内容(除非涉及超时)。如果需要,您可以尝试使用非阻塞 IO(请参阅 参考资料O_NONBLOCK)。

顺便说一句,这段代码:

            buffer[bytes_read]=0;
            for (int j=1; j< sizeof(buffer)/sizeof(buffer[0]); j++)        
            {
                sprintf(data,"%02x",buffer[j]);
                strcat(data3,data);
            }

第一次最终会打印一堆零,并且可能会在接下来的时间打印来自先前消息的一些数据。你应该停止 for in bytes_read

最后,如果您的unsigned char长度为 1 字节(在大多数平台中),您可以绕过除法并使用sizeof(buffer).


推荐阅读