Linux下串口编程(二)
相关内容:
1、dev_uart.c
#include "dev_uart.h" /******************************************************************* *名称: dev_uart_open *功能: 打开串口并返回串口设备文件描述 *入口参数: fd 文件描述符 port 串口号(ttyS0,ttyS1,ttyS2) *出口参数:正确返回为1,错误返回为0 *******************************************************************/ int dev_uart_open(int fd,char *port) { fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY); if (fd<0) { printf("******Can't Open uart*****\n"); return -1; } //恢复串口为阻塞状态 if(fcntl(fd, F_SETFL, 0) < 0) { printf("******fcntl fail*****\n"); return -1; } else { printf("*****fcntl=%d******\n",fcntl(fd, F_SETFL,0)); } //测试是否为终端设备 if(0 == isatty(STDIN_FILENO)) { printf("*****standard input is not a terminal device*****\n"); return -1; } else { printf("*****isatty success!*******\n"); } printf("******fd->open=%d******\n",fd); return fd; } void dev_uart_close(int fd) { close(fd); } int dev_uart_set(int fd,int uart_speed,int flow_ctrl,int databits,int stopbits,int parity) { int i; int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300}; int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300}; struct termios options; /* tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确, 该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1. */ if( tcgetattr( fd,&options) != 0) { printf("tcgetattr err"); return -1; } //设置串口输入波特率和输出波特率 for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (uart_speed == name_arr[i]) { cfsetispeed(&options, speed_arr[i]); cfsetospeed(&options, speed_arr[i]); } } //修改控制模式,保证程序不会占用串口 options.c_cflag |= CLOCAL; //修改控制模式,使得能够从串口中读取输入数据 options.c_cflag |= CREAD; //设置数据流控制 switch(flow_ctrl) { case 0 ://不使用流控制 options.c_cflag &= ~CRTSCTS; break; case 1 ://使用硬件流控制 options.c_cflag |= CRTSCTS; break; case 2 ://使用软件流控制 options.c_cflag |= IXON | IXOFF | IXANY; break; } //设置数据位 //屏蔽其他标志位 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: printf("Unsupported data size\n"); return -1; } //设置校验位 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; break; case 'e': case 'E'://设置为偶校验 options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break; case 's': case 'S': //设置为空格 options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: printf("Unsupported parity\n"); return -1; } // 设置停止位 switch (stopbits) { case 1: options.c_cflag &= ~CSTOPB; break; case 2: options.c_cflag |= CSTOPB; break; default: printf("Unsupported stop bits\n"); return -1; } //修改输出模式,原始数据输出 options.c_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //options.c_lflag &= ~(ISIG | ICANON); //设置等待时间和最小接收字符 options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */ options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */ //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读 tcflush(fd,TCIFLUSH); //激活配置 (将修改后的termios数据设置到串口中) if (tcsetattr(fd,TCSANOW,&options) != 0) { printf("com set error!\n"); return -1; } return 1; } int dev_uart_read(int fd, char *rcv_buf,int data_len) { int len; len = read(fd,rcv_buf,data_len); return len; } int dev_uart_write(int fd, char *send_buf,int data_len) { int len = 0; len = write(fd,send_buf,data_len); return len; }
2、dev_uart.h
#ifndef _DEV_UART_H #define _DEV_UART_H //串口相关的头文件 #include<stdio.h> /*标准输入输出定义*/ #include<stdlib.h> /*标准函数库定义*/ #include<unistd.h> /*Unix 标准函数定义*/ #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> /*文件控制定义*/ #include<termios.h> /*PPSIX 终端控制定义*/ #include<errno.h> /*错误号定义*/ #include<string.h> //宏定义 int dev_uart_open(int fd,char *port); void dev_uart_close(int fd) ; int dev_uart_set(int fd,int uart_speed,int flow_ctrl,int databits,int stopbits,int parity); int dev_uart_read(int fd, char *rcv_buf,int data_len); int dev_uart_write(int fd, char *send_buf,int data_len); #endif
2、uart_test.c 串口测试代码
#include "pthread.h" #include "dev_uart.h" #define TIME_DIF 2 //2秒 #define uart_buf_SIZE 200 //接收缓冲区数据长度 char buf123[12] ={0x00,0x10,0x00,0x24,0x06,0x00,0x01,0x00,0x01,0x00,0x01,0x0D}; static char uart_buf[uart_buf_SIZE]; //接收缓冲区 static volatile char uart_cnt = 0; //接收缓冲计数 static volatile int flag = 1; static volatile int fd = -1; int uart_read_proc(char *buf,unsigned int len) { int cnt; memcpy(uart_buf+uart_cnt, buf, len); uart_cnt += len; if (uart_cnt == 100) { for(cnt = 0;cnt<uart_cnt;cnt++) { printf(" %02x",uart_buf[cnt]); if(cnt%20 == 19) printf("\n"); } printf("\n"); memset(uart_buf , 0,sizeof(uart_buf)); uart_cnt = 0; flag = 1; return 1; } } int uart_read(int fd) { char buf[200]; int iRet; unsigned int len; int i = 30; memset(uart_buf , 0,sizeof(uart_buf)); uart_cnt = 0; flag = -1; while(i > 0) { i--; if(flag == -1) { memset(buf, 0, sizeof(buf)); len = dev_uart_read(fd, buf, 30); if(len > 0) { iRet = uart_read_proc(buf,len); } return iRet; } else break; } } int uart_write(int fd) { int len = 0; len = dev_uart_write(fd,buf123, sizeof(buf123)); if(len <= 0) { printf("*******hal_uart_write err*******\n"); return -1; } return len; } /**************************************************************************** * @brief ***************************************************************************/ int main(void) { static unsigned int time_second = 0; char *dev = "/dev/ttyPS1"; int iRet = 0; printf("Line %d\n", __LINE__); fd = dev_uart_open(fd,dev); iRet = dev_uart_set(fd,115200,0,8,1,'N'); while(1) { usleep(200000);//延时200ms time_t time_now = time((time_t *)NULL); //-->定时查询串口数据 if ((time_now - time_second) >= TIME_DIF) { time_second = time_now; uart_write(fd); uart_read(fd); } } return 0; }
3、Makefile
CROSS = LIB_PWD = $(shell pwd) TARGET_BIN = test CPP = $(CROSS)g++ -std=c++11 CC = $(CROSS)gcc LD = $(CROSS)ld CFLAGS += -I$(shell pwd) CFLAGS += -Wall -g LDFLAGS += -lpthread SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) %.o: %.c $(CPP) $(CFLAGS) -o $@ -c $< all:$(OBJS) $(CPP) -o $(TARGET_BIN) $(OBJS) $(LDFLAGS) find . -name "*.o" | xargs rm -f clean: find . -name "*.o" | xargs rm -f
参考文档: POSIX操作系统的串行编程指南