串口通信——接收串口数据并处理(C语言)

本文提供了一个详细的串口数据接收程序示例,包括编程逻辑、通用函数模块和完整的代码实例。介绍了如何设置波特率、数据位、停止位和奇偶校验位等关键参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要内容包含:

 1.接收串口数据程序的编程逻辑示意图;

 2.接收串口数据程序要用到的通用函数模块(可直接引用,无需更改);

 3.接收串口数据程序的示例。


1.接收串口数据程序的编程逻辑示意图:

2.与串口有关的函数模块及数组(可直接引用到自己的程序中):

//设置波特率函数会用到的数组
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
        B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300,
        38400,  19200,  9600, 4800, 2400, 1200,  300, };
int OpenDev(char *Dev) //打开串口
{
	int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK);
	if(-1 == fd)
	{
		perror("Can't Open Serial Port");
		return -1;
	}
	else
	{
		printf("Open com success!!!!!!!!!!!");
		return fd;
	}
}

void set_speed(int fd, int speed)  //设置波特率
{
  int   i;
  int   status;
  struct termios   Opt;
  tcgetattr(fd, &Opt);
  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
   {
    if  (speed == name_arr[i])
    {
        tcflush(fd, TCIOFLUSH);
        cfsetispeed(&Opt, speed_arr[i]);
        cfsetospeed(&Opt, speed_arr[i]);
        status = tcsetattr(fd, TCSANOW, &Opt);
        if  (status != 0)
            perror("tcsetattr fd1");
        return;
        }
   tcflush(fd,TCIOFLUSH);
   }
}

int set_Parity(int fd,int databits,int stopbits,int parity)  //设置数据位、奇偶位、停止位等
{
   struct termios options;
 if  ( tcgetattr( fd,&options)  !=  0)
  {
    perror("SetupSerial 1");
    return(0);
  }
  bzero(&options,sizeof(options));
  options.c_cflag |= CLOCAL | CREAD;
  options.c_cflag &= ~CSIZE;
  switch (databits) /*设置数据位*/
  {
    case 7:
        options.c_cflag |= CS7;
        break;
    case 8:
        options.c_cflag |= CS8;
        break;
    default:
        fprintf(stderr,"Unsupported data size\n");
        return (0);
    }
  switch (parity)/*设置校验位*/
    {
    case 'n':
    case 'N':
        options.c_cflag &= ~PARENB;  
        //options.c_iflag &= ~INPCK;    
        break;
    case 'o':
    case 'O':
        options.c_cflag |= (PARODD | PARENB);  
        options.c_iflag |= (INPCK | ISTRIP);            
        break;
    case 'e':
    case 'E':
        options.c_cflag |= PARENB;    
        options.c_cflag &= ~PARODD;  
        options.c_iflag |= (INPCK | ISTRIP);       
        break;
    case 'S':
    case 's':  
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported parity\n");
        return (0);
        }
  switch (stopbits)/*设置停止位*/
    {
    case 1:
        options.c_cflag &= ~CSTOPB;
        break;
    case 2:
        options.c_cflag |= CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported stop bits\n");
        return (FALSE);
    }
  if (parity != 'n')
    options.c_iflag |= INPCK;
    options.c_cc[VTIME] = 0; 
    options.c_cc[VMIN] = 0;
  tcflush(fd,TCIFLUSH); 
  if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        perror("SetupSerial 3");
        return (0);
    }
  return (1);
 }

3.示例:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0

int analysis(char *buff);
int OpenDev(char *Dev);
void set_speed(int fd, int speed);
int set_Parity(int fd,int databits,int stopbits,int parity);

int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };
int OpenDev(char *Dev)
{
  int fd = open(Dev,O_RDWR | O_NOCTTY | O_NONBLOCK);
  if(-1 == fd)
    {
      perror("Can't Open Serial Port");
      return -1;
    } 
  else 
    {
      printf("Open com success!!!!!!!!!!!");
      return fd;
    }
} 
void set_speed(int fd, int speed)
{ 
  int i; 
  int status; 
  struct termios Opt;
 tcgetattr(fd, &Opt); 
  for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
   { 
      if (speed == name_arr[i]) 
        { 
          tcflush(fd, TCIOFLUSH); 
          cfsetispeed(&Opt, speed_arr[i]);
         cfsetospeed(&Opt, speed_arr[i]);
         status = tcsetattr(fd, TCSANOW, &Opt); 
          if (status != 0) perror("tcsetattr fd1");
         return;
       } 
    tcflush(fd,TCIOFLUSH);
    }
}
int set_Parity(int fd,int databits,int stopbits,int parity) 
{ 
  struct termios options; 
  if ( tcgetattr( fd,&options) != 0) 
  {
   perror("SetupSerial 1");
   return(FALSE);
 } 
  bzero(&options,sizeof(options)); 
  options.c_cflag |= CLOCAL | CREAD;
 options.c_cflag &= ~CSIZE; 
  switch (databits) 
  { 
    case 7: 
    options.c_cflag |= CS7;
   break;
   case 8:
   options.c_cflag |= CS8;
   break; 
    default: fprintf(stderr,"Unsupported data size\n");
   return (FALSE); 
  } 
  switch (parity) 
  {
   case 'n': 
    case 'N':
   options.c_cflag &= ~PARENB;
   options.c_iflag &= ~INPCK; 
    break; 
    case 'o':
   case 'O': 
    options.c_cflag |= (PARODD | PARENB);
   options.c_iflag |= (INPCK | ISTRIP); 
    break; 
    case 'e': 
    case 'E': 
    options.c_cflag |= PARENB;
   options.c_cflag &= ~PARODD; 
    options.c_iflag |= (INPCK | ISTRIP); 
    break; 
    case 'S': 
    case 's': 
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB;
   break;
   default: fprintf(stderr,"Unsupported parity\n"); 
   return (FALSE); 
  } 
  switch (stopbits)
 { 
    case 1:
   options.c_cflag &= ~CSTOPB; 
    break; 
    case 2: 
    options.c_cflag |= CSTOPB;
   break; 
    default: fprintf(stderr,"Unsupported stop bits\n"); 
    return (FALSE); 
    } 
    if (parity != 'n') 
    options.c_iflag |= INPCK; 
    options.c_cc[VTIME] = 0;
   options.c_cc[VMIN] = 0;
   tcflush(fd,TCIFLUSH); 
    if (tcsetattr(fd,TCSANOW,&options) != 0)
   {  
        perror("SetupSerial 3"); 
        return (FALSE);
   } 
    return (TRUE);
}

int analysis (char *buff)
{
  int i;
  char *p;
  p=buff;
  for(i=0;i<255,i++)
    {
      printf("%s ",p[i]);
    }
  return 0;
}

void main(void)
{
  int fd;
  int nread;
  char buff[255];
  char *dev_name = "/dev/ttymxc4";//根据实际情况选择串口
  while(1) 
    {  
      fd = OpenDev(dev_name); //打开串口 

      if(fd>0) 
      set_speed(fd,9600); //设置波特率 
      else 
      { 
         printf("Can't Open Serial Port!\n"); 
         sleep(1);
        continue; 
      } 
  break;
}

if(set_Parity(fd,8,1,'N')==FALSE) //设置校验位 
{
  printf("Set Parity Error\n"); 
  exit(1);
}

while(1) 
  { 
    sleep(3); 
    nread = read(fd,buff,sizeof(buff));
    if((nread>0))
      {		
	printf("Success!\n"); 
       }
    analysis(buff);
  }
}



<think>我们正在使用C语言通过串口读取数组数据。根据引用[1],我们可以使用一个简单的读取函数来从串口读取数据。但是,用户希望逐个读取数组元素,这意味着我们需要多次调用读取函数,每次读取一个元素(例如一个字节或一个整数,取决于数组元素类型)。假设我们要读取一个整数数组(每个整数4个字节),那么我们需要读取每个整数。由于串口是流式设备,我们需要确保每次读取的数据正好对应一个数组元素。然而,串口通信中,数据是连续传输的,我们需要定义一种协议来区分每个元素。常见的方法有:1.固定长度:每个数组元素用固定字节数表示,例如每个整数4个字节。2.分隔符:使用特殊字符(如逗号、换行)分隔每个元素,但这样要求数据中不能包含分隔符。这里我们假设使用固定长度方式,即每个数组元素由固定字节数组成(比如4字节整数)。我们可以每次读取4个字节,然后将其解释为一个整数。但是,引用[1]提供的读取函数可以读取任意长度的数据,但可能一次读不到我们想要的字节数(因为串口数据可能没有完全到达)。因此,我们需要循环读取直到读满指定字节数。我们可以设计一个函数,用于读取固定长度的数据,例如:```c//从串口读取固定长度的数据int read_fixed(intport_fd, unsignedchar*buffer,int length) {inttotal_read=0;while(total_read <length){int bytes_read =read(port_fd,buffer +total_read, length- total_read);if(bytes_read <0){perror("read");return -1;//读取错误}if(bytes_read ==0) {//没有读到数据,可能是超时或文件结束,根据实际情况处理break;}total_read+= bytes_read;}returntotal_read; //返回实际读取的字节数,应该等于length,除非出错或提前结束}```然后,我们可以逐个读取数组元素。假设数组元素是int类型(4字节),我们可以这样读取一个元素:```cintread_int(intport_fd,int *value){unsigned charbuffer[4];intret =read_fixed(port_fd,buffer,4);if (ret !=4) {return-1; //读取失败}//将4个字节组合成一个整数,注意字节序(大端或小端)//这里假设是小端模式(Little-Endian)*value= buffer[0] |(buffer[1] <<8) |(buffer[2] <<16) |(buffer[3] <<24);return0;} ```然后,我们可以循环调用`read_int`来读取整个数组。但是,用户没有说明数组的长度如何确定。通常有两种方式:1.事先知道数组长度(固定长度或由其他信息得知)。2.在数据流中先发送数组长度。假设我们先从串口读取一个整数表示数组长度,然后再读取该长度的整数数组。示例代码:```cintmain(){intport_fd;//串口文件描述符,假设已经打开配置好int array_length;if(read_int(port_fd,&array_length)!=0){fprintf(stderr,"Failedto readarray length\n");return-1;}//动态分配数组int*array= (int*)malloc(array_length *sizeof(int));if (array ==NULL){perror("malloc");return -1;}for(inti =0; i< array_length;i++){if (read_int(port_fd, &array[i]) !=0){fprintf(stderr,"Failedto readelement %d\n", i);free(array);return -1;}}//使用数组...free(array);return0; }```注意:1.字节序问题:上面的`read_int`函数假设发送方是小端模式。如果发送方是大端模式,则需要调整字节组合方式。2.错误处理:需要根据实际情况处理错误(如读取超时、数据不完整等)。3.串口配置:在打开串口时,需要正确配置波特率、数据位、停止位、校验位等,这里不展开。引用[3]提到了在ubuntu下读写串口,我们可以使用类似的串口配置和打开方式。另外,引用[4]提到二进制文件的读取,但串口是字符设备,与二进制文件读取类似,我们按字节读取即可。因此,我们可以按照上述方法逐个读取数组元素。如果数组元素不是整数而是其他类型(如浮点数或结构体),则需要根据类型的大小和表示方式进行读取和解析。下面,我们生成相关问题。</think>### C语言串口通信逐个读取数组元素 在C语言中通过串口逐个读取数组元素需要结合串口通信协议和数据处理方法。以下是实现步骤和示例代码: #### 核心实现步骤 1. **打开配置串口** 使用`open()`系统调用打开串口设备,设置波特率、数据位等参数(参考引用[1][^1])。 2. **设计数据协议** - **固定长度协议**:发送方先发送数组长度,再逐个发送元素 - **分隔符协议**:使用特殊字符(如`,`)分隔元素 3. **读取单个元素** 通过循环调用`read()`函数逐个读取元素(参考引用[1][^1]封装): ```c // 串口读取封装函数 int serial_read(int fd, char *buffer, int size) { int bytes = read(fd, buffer, size); if (bytes < 0) perror("read error"); return bytes; // 返回实际读取字节数 } ``` 4. **数据解析** 将接收到的原始字节流转换为目标数据类型(参考引用[2][^2]的二进制处理)。 #### 完整示例代码 ```c #include <stdio.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> // 串口初始化 int init_serial(const char *port) { int fd = open(port, O_RDWR | O_NOCTTY); if (fd < 0) { perror("open port"); return -1; } struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); // 波特率9600 cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~PARENB; // 无校验 options.c_cflag &= ~CSTOPB; // 1位停止位 options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 8位数据 tcsetattr(fd, TCSANOW, &options); return fd; } // 逐个读取int数组 int read_int_array(int fd, int *arr, int max_size) { char header[4]; if (serial_read(fd, header, 4) != 4) return -1; // 读取数组长度 int count = *(int*)header; // 解析长度值 if (count > max_size) count = max_size; for (int i = 0; i < count; i++) { char buffer[4]; if (serial_read(fd, buffer, 4) != 4) return -1; // 读取元素 arr[i] = *(int*)buffer; // 字节转int } return count; } int main() { int fd = init_serial("/dev/ttyS0"); if (fd < 0) return 1; int array[10]; int count = read_int_array(fd, array, 10); printf("Received %d elements:\n", count); for (int i = 0; i < count; i++) { printf("[%d] %d\n", i, array[i]); } close(fd); return 0; } ``` #### 关键注意事项 1. **字节序处理** 不同系统可能有大小端差异,需使用`htonl()`/`ntohl()`转换(参考引用[2][^2])。 2. **超时控制** 添加`select()`或设置`VTIME`/`VMIN`防止永久阻塞: ```c options.c_cc[VTIME] = 1; // 0.1秒超时 options.c_cc[VMIN] = 0; // 允许返回0字节 ``` 3. **错误处理** - 校验数据完整性(如CRC校验) - 处理部分读取情况(参考引用[4][^4]) 4. **数据表示** 浮点数等特殊类型需进行二进制转换(参考引用[4][^4]的二进制处理技巧)
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值