我正在尝试通过RS232连接进行连接。
通讯参数:
*传输速率:1200波特
*字符编码:8位ASCII
*奇偶校验:无
*停止位:1
命令由两个字节代码组成,格式如下
传输格式
CODE +“FFh”
Hex code
接收格式
CODE +“FFh”
Hex code
我尝试了各种初始化,但我仍然无法从端口读取任何内容,以下代码就是其中之一:
//RS232test.c
//Transmission rate: 1200 Baud
//8 bit, no parity 1 stop bits.
//Transmit format: CODE + "FFh"
//Receive format: CODE + "FFh"
//Last edited: 23/08/2014
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#define BAUDRATE B1200
#define MULTI "/dev/ttyS0"
//#define MULTI "/dev/ttyUSB0"
int open_port(struct termios *,struct termios *);
int setDtrRts(int, int);
void close_port(int, struct termios *);
int open_port(struct termios *tty, struct termios *tty_old)
//This opens the tty port for linux saves old port setting
//and saves the new ones
{
int fd; //file descriptor
fd = open(MULTI, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror(MULTI);
printf("failed to open port\n");
exit(-1);
}
//get previous port settings so it can be restored on exit
tcgetattr(fd,tty_old);
//get port settings so they can be set
tcgetattr(fd,tty);
//Set baud rates to 1200
cfsetispeed(tty, BAUDRATE);
cfsetospeed(tty, BAUDRATE);
//ICANON -choosing canonical input.
tty->c_lflag |= (ICANON);
//tty->c_lflag &= ~(ISIG);
//unselecting echo
tty->c_lflag &= ~(ECHO | ECHOE);
//CLOCAL - setting local mode, CREAD - enabling receiver
tty->c_cflag |= (CLOCAL | CREAD);
//close doesn't change signals
tty->c_cflag &= ~HUPCL;
//8N1 no parity 1 stop bit
tty->c_cflag |= CS8;
//tty->c_cflag &= ~(PARENB | CSTOPB | CSIZE);
tty->c_cflag &= ~(PARENB | PARODD /**/| CSIZE);
tty->c_cflag &= ~CSTOPB;
//Raw output mode
tty->c_oflag &= ~OPOST;
//Enable hardware handshaking
//tty->c_cflag &= ~CRTSCTS;
//tty->c_iflag &= ~(IXON | IXOFF | IXANY); //*
//Flushing communication buffer and changing port setting
//tcflush(fd, TCIFLUSH);
//tcsetattr(fd, TCSANOW, tty);
tcsetattr(fd, TCSAFLUSH, tty);
setDtrRts(fd,1);
return fd;
}
int setDtrRts(int fd, int set)
//sets or clears the dtr and rts
//the needs both set during operation
//otherwise it switches off after approx. 20 seconds
{
int setbits;
setbits |= (TIOCM_DTR | TIOCM_RTS);
if(set)
return(ioctl(fd, TIOCMBIC, &setbits));
else
return(ioctl(fd, TIOCMBIS, &setbits));
}
void close_port(int fd, struct termios *tty_old)
//closing port
{
//reset to old options
//tcsetattrb(fd, TCSANOW, tty_old);
setDtrRts(fd,0);
close(fd);
}
int main(void)
{
int fd=0; //system file number
int buff_size; //no of characters in buffer
int bytes; //no of bytes in buffer
int ctr=0; //general counter
char in_buffer[] = "F3\xFF";
char out_buffer[255]; //serial character buffer
//new port setting and a structure to keep the old ones
struct termios tty,tty_old;
//checking if root
if (getuid()){
printf("You must be root to use this program.\n");
exit(-4);
}
printf("fd = %d\n",fd);
//opening port for reading and writing
fd = open_port(&tty,&tty_old);
printf("fd = %d\n",fd);
//flushing
tcflush(fd,TCIOFLUSH);
//sending command to serial port
//strcpy(in_buffer, "F3\xFF"); //placing a command in the buffer
printf("%s",in_buffer);
if((buff_size = write(fd, in_buffer, strlen(in_buffer))) < 0){
printf("Error while sending message\nBuffer contents:\t%s\n",in_buffer);
return -2;
}
usleep(50000); //delay for 50ms
out_buffer[0] = '\0';
ioctl(fd,FIONREAD,&bytes);
printf("\nThere are %d bytes in the buffer\n",bytes);
if(bytes > 0) {
//reading response from serial port
if((buff_size = read(fd, out_buffer,sizeof(out_buffer))) < 0){
printf("Error while reading message\n");
return -3;
}
//printing the decimal ASCII values of the response
printf("Multimeter response:\t");
while(out_buffer[ctr] != '\0')
{
printf("%i ",out_buffer[ctr]);
ctr++;
}
printf("\n%s\n",out_buffer);
} else printf("Buffer Empty\n");
//wrap things up
close_port(fd, &tty_old);
exit(0);
}
节目输出如下:
fd = 0
fd = 3
F3H
缓冲区中有0个字节
缓冲空
在之前的帖子中提出了一些建议,但没有成功。
答案 0 :(得分:3)
您描述的协议不是面向行的,因此使用规范输入模式是错误的。您应该使用良好的旧原始模式,定义为:
tty->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
tty->c_oflag &= ~OPOST;
tty->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty->c_cflag &= ~(CSIZE | PARENB);
tty->c_cflag |= CS8;
在规范模式下,只有在收到eOL后才允许读取字符以允许行编辑,这是不您想要的内容。 (参考:man termios)
答案 1 :(得分:-1)
以下代码由我自己编写,并且它一直在我的嵌入式系统上运行。
int wrap_uart_init(char *port, int baudrate, int datab, int parity, int stopb){
int fd=open_and_init_tty(port);
if (fd==-1) {
perror("cannot open device");
return fd;
}
set_baudrate(fd,baudrate);
set_dataformat(fd,datab,parity,stopb);
swflow_ctrl(fd);
return fd;
}
像这样调用这个函数:
int fd = wrap_uart_init("/dev/ttyUSB0", 1200, 8, 'N', 1);
超级好用。只要Linux将设备屏蔽到tty文件中,物理层协议就变得非常重要。
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
static struct termios origin_attrs;
static struct termios old_attrs;
int open_tty(const char *dev){
int fd=open(dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
if (fd==-1)
perror(FILE_OPEN_ERROR);
if (fcntl(fd, F_SETFL, 0)<0){
perror("fcntl error!");
close(fd);
fd=-1;
}
if (!isatty(STDIN_FILENO)){
perror("standard input error! ");
close(fd);
fd=-1;
}
return fd;
}
void close_tty(int fd){
if (tcsetattr(fd,TCSANOW,&old_attrs)) {
perror(GET_ATTR_ERROR);
}
close(fd);
}
int open_and_init_tty(const char *dev){
int fd=open_tty(dev);
if (fd==-1){
perror(FILE_OPEN_ERROR);
return -1;
}
if (tcgetattr(fd,&old_attrs)) {
perror(GET_ATTR_ERROR);
return -1;
}
struct termios opt;
int br=B9600;
cfsetispeed(&opt, br);
cfsetospeed(&opt, br);
opt.c_cflag = (CS8 | CLOCAL | CREAD);
opt.c_iflag = (IGNPAR | IXON | IXOFF | IXANY);
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 30;
opt.c_cc[VMIN] = 5;
tcflush(fd, TCIOFLUSH);
if (tcsetattr(fd,TCSANOW,&opt) != 0) {
perror(SET_ATTR_ERROR);
return -1;
}
return fd;
}
int set_baudrate(int fd, int baud){
int br;
int status;
struct termios opt;
if (tcgetattr(fd, &opt)) {
perror(GET_ATTR_ERROR);
return -1;
}
switch (baud) {
case 115200: br=B115200;break;
// case 76800: br=B76800; break;
case 57600: br=B57600; break;
case 38400: br=B38400; break;
case 19200: br=B19200; break;
case 9600: br=B9600; break;
case 4800: br=B4800; break;
case 2400: br=B2400; break;
case 1200: br=B1200; break;
case 600: br=B600; break;
case 300: br=B300; break;
default: perror("Wrong Baud rate!");
return -1;
}
tcflush(fd, TCIOFLUSH);
cfsetispeed(&opt, br);
cfsetospeed(&opt, br);
status = tcsetattr(fd, TCSANOW, &opt);
if (status) {
perror(BAUD_RATE_ERROR);
return -2;
}
tcflush(fd,TCIOFLUSH);
return 0;
}
int set_dataformat(int fd,int databits,int parity,int stopbits){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (databits) {
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
perror("Unsupported data size");
return -2;
}
switch (parity) {
case 'n': //no parity check
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o': //odd check
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= (INPCK | ISTRIP);
break;
case 'e': //even check
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
default:
perror("Unsupported parity");
return -3;
}
switch (stopbits) {
case 1: //1 stop bit
options.c_cflag &= ~CSTOPB;
break;
case 2: //2 stop bits
options.c_cflag |= CSTOPB;
break;
default:
perror("Unsupported stop bits");
return -4;
}
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 50;
options.c_cc[VMIN] = 1;
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -1;
}
return 0;
}
int set_databit(int fd, int databits){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (databits) {
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
perror("Unsupported data size");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int set_parity(int fd, int parity) {
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (parity) {
case 'n': //no parity check
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o': //odd check
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= (INPCK | ISTRIP);
break;
case 'e': //even check
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
default:
perror("Unsupported parity");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int set_stopbit(int fd, int stopbits) {
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (stopbits) {
case 1: //1 stop bit
options.c_cflag &= ~CSTOPB;
break;
case 2: //2 stop bits
options.c_cflag |= CSTOPB;
break;
default:
perror("Unsupported stop bits");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int hwflow_ctrl(int fd){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag |= CRTSCTS;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int swflow_ctrl(int fd){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CRTSCTS;
options.c_iflag |= (IXON | IXOFF | IXANY);
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int store_termios(int fd){
if (tcgetattr( fd,&origin_attrs)) {
perror(GET_ATTR_ERROR);
return -1;
}
return 0;
}
int recover_termios(int fd){
tcflush(fd, TCIOFLUSH);
if (tcsetattr(fd,TCSANOW,&origin_attrs)) {
perror(SET_ATTR_ERROR);
return -1;
}
tcflush(fd, TCIOFLUSH);
return 0;
}