繁体   English   中英

Raspberry Pi的C串行通信

[英]Serial Communication in C for Raspberry Pi

我想使两个Raspberry Pi使用ZigBee协议互相发送消息。 我已经使用USB Explorer(CH430g)将XBee S2C(ZigBee)模块连接到Raspberry Pi。 我写了一个python脚本,可以完成所需的工作,

import serial

ser = serial.Serial('/dev/ttyUSB0', 9600)

while True:
    incoming = ser.readline().strip()
    print ('%s' %incoming.decode())
    string = input("") + '\n'
    ser.write(string.encode())

但是我需要一个C程序来做同样的事情,我查看了用于C和C ++的libserial库,发现它有错误,并且从未为我编译过。

我试过了这个线程,它工作得很好,但是在接收方,我需要保持read(fd, &buffer, sizeof(buffer)); 在一个while循环中可以连续打开以进行监听,这与C套接字程序不同,在该程序中, read()函数将暂停直到接收到数据,就像我的python脚本将在一行中等待incoming = ser.readline().strip()直到接收到一些信息。

没有使用while循环有什么解决方案吗?

编辑1:

在上述python代码中,while循环用于接收多个消息。 incoming = ser.readline().strip()incoming = ser.readline().strip()将捕获消息,对其进行处理,并等待下一条消息,因为它处于while循环中。

在C中,如果我的代码是这样的:

while(1){
    str = read();
    //some processing
    }

它会引发错误,因为read直到获得数据才停止,而只是返回读取失败。 由于读取的数据为NULL ,因此数据的后处理将引发错误。 为了使其工作,我引入了另一个while循环,如下所示:

 while(1){
    while(1){
        str = read();
        if(str!=NULL)
            break;
        }
    //some processing
    }

我想消除这个额外的循环,并使read()等待消息。 PS:我正在像这样打开串行设备: uart0_filestream = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);

从此代码中获得一些启发。 这是使用C进行的非常通用的规范串行编程。

注意:规范的输入处理还可以处理擦除,删除单词和重印字符,将CR转换为NL等。


我建议您阅读本文,以了解有关串行编程设置(不同模式)的更多信息。

HowTo串行编程。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

/* baudrate settings are defined in <asm/termbits.h>, which is
included by <termios.h> */
#define BAUDRATE B38400            
/* change this definition for the correct port */
#define SERIAL_DEVICE "/dev/ttyS1"


#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE; 

int main(void)
{
  int fd,c, res;
  struct termios oldtio,newtio;
  char buf[255];
/* 
  Open modem device for reading and writing and not as controlling tty
  because we don't want to get killed if linenoise sends CTRL-C.
*/
 fd = open(SERIAL_DEVICE, O_RDWR | O_NOCTTY ); 
 if (fd <0) {perror(SERIAL_DEVICE); exit(-1); }

 tcgetattr(fd,&oldtio); /* save current serial port settings */
 memset(&newtio, sizeof(newtio)); /* clear struct for new port settings */

/* 
  BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
  CRTSCTS : output hardware flow control (only used if the cable has
            all necessary lines. See sect. 7 of Serial-HOWTO)
  CS8     : 8n1 (8bit,no parity,1 stopbit)
  CLOCAL  : local connection, no modem contol
  CREAD   : enable receiving characters
*/
 newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

/*
  IGNPAR  : ignore bytes with parity errors
  ICRNL   : map CR to NL (otherwise a CR input on the other computer
            will not terminate input)
  otherwise make device raw (no other input processing)
*/
 newtio.c_iflag = IGNPAR | ICRNL;

/*
 Raw output.
*/
 newtio.c_oflag = 0;

/*
  ICANON  : enable canonical input
  disable all echo functionality, and don't send signals to calling program
*/
 newtio.c_lflag = ICANON;

/* 
  initialize all control characters 
  default values can be found in /usr/include/termios.h, and are given
  in the comments, but we don't need them here
*/
 newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
 newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
 newtio.c_cc[VERASE]   = 0;     /* del */
 newtio.c_cc[VKILL]    = 0;     /* @ */
 newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
 newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
 newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
 newtio.c_cc[VSWTC]    = 0;     /* '\0' */
 newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
 newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
 newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
 newtio.c_cc[VEOL]     = 0;     /* '\0' */
 newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
 newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
 newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
 newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
 newtio.c_cc[VEOL2]    = 0;     /* '\0' */

/* 
  now clean the modem line and activate the settings for the port
*/
 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);

/*
  terminal settings done, now handle input
  In this example, inputting a 'z' at the beginning of a line will 
  exit the program.
*/
 while (STOP==FALSE) {     /* loop until we have a terminating condition */
 /* read blocks program execution until a line terminating character is 
    input, even if more than 255 chars are input. If the number
    of characters read is smaller than the number of chars available,
    subsequent reads will return the remaining chars. res will be set
    to the actual number of characters actually read */
    res = read(fd,buf,255); 
    buf[res]=0;             /* set end of string, so we can printf */
    printf(":%s:%d\n", buf, res);
    if (buf[0]=='z') STOP=TRUE;
 }
 /* restore the old port settings */
 tcsetattr(fd,TCSANOW,&oldtio);
 return 0;
}

如果您不希望连接是非阻塞的,则可能要删除添加到open非阻塞的调用中的O_NDELAY选项。 像这样...

uart0_filestream = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);

同样, read不返回字符串,它返回读入的字节数,因此您的read调用应更像

bytecount = read(uart0_filestream, str, 20);
if(bytecount>0)
   {
   str[bytecount]='\0';
   }
else
   {
   // Something bad happened?
   }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM