一、串口程序需要的头文件
#include <stdio.h> //标准输入输出定义
#include <stdlib.h> //标准函数库定义
#include <unistd.h> //Unix标准函数定义
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //文件控制定义
#include <termios.h> //POSIX中断控制定义
#include <errno.h> //错误号定义
二、打开串口
串口位于/dev中,可作为标准文件的形式打开,其中:
串口1 /dev/ttyS0
串口2 /dev/ttyS1
int open_com(char *device_name)
{
int fd = 0;
/*O_RDWR以读写的方式打开,O_NOCTTY是通知Linux系统这个程序不会成为这个端口的控制终端*/
if (0 > (fd = open(device_name, O_RDWR|O_NOCTTY)))
{
perror("Open Comport Fail:");
return 0;
}
return fd;
}/* ----- End of open_com() ----- */
三、串口的基本设置
最基本的串口设置包括波特率、校验位和停止位设置,且串口设置主要使用termios.h头文件中定义的termios结构,如下:
struct termios
{
tcflag_t c_iflag; //输入模式标志
tcflag_t c_oflag; //输出模式标志
tcflag_t c_cflag; //控制模式标志
tcflag_t c_lflag; //本地模式标志
cc_t c_line; //line discipline
cc_t c_cc[NCC]; //control characters
}
该结构中c_cflag最为重要,可设置波特率、数据位、校验位、停止位。
/**************************************************************************************
* Description:设置波特率,数据位,校验位,停止位
* Input Args:
* Output Args:
* Return Value:
*************************************************************************************/
int set_com_opt(int fd, int nSpeed, int nBits, unsigned char nEvent, int nStop)
{
struct termios opt, oldopt;
tcgetattr(fd, &oldopt); //保存原先串口配置
tcgetattr(fd, &opt);
switch (nSpeed)
{
case 2400:
cfsetispeed(&opt, B2400);//输入波特率
cfsetospeed(&opt, B2400);//输出波特率
break;
case 4800:
cfsetispeed(&opt, B4800);
cfsetospeed(&opt, B4800);
break;
case 9600:
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
break;
case 57600:
cfsetispeed(&opt, B57600);
cfsetospeed(&opt, B57600);
break;
case 115200:
cfsetispeed(&opt, B115200);
cfsetospeed(&opt, B115200);
break;
default:
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
break;
}
/*设置校验位*/
switch (nEvent)
{
/*奇校验*/
case 'O':
opt.c_cflag |= PARENB; //enable parity
opt.c_cflag |= PARODD;
opt.c_cflag |= (INPCK | ISTRIP);
break;
/*偶校验*/
case 'E':
opt.c_cflag |= (INPCK | ISTRIP);
opt.c_cflag |= PARENB;
opt.c_cflag &= ~PARODD;
break;
/*无校验*/
case 'N':
opt.c_cflag &= ~PARENB; //清除校验位
opt.c_cflag &= ~INPCK; //disable pairty checking
break;
}
/*停止位设置*/
if (nStop == 1)
{
opt.c_cflag &= ~CSTOPB;
opt.c_cflag &= ~CSIZE;
}
else if (nStop == 2)
{
opt.c_cflag |= CSTOPB;
opt.c_cflag &= CSIZE;
}
/*数据位设置*/
switch (nBits)
{
case 7:
opt.c_cflag |= CS7;
break;
case 8:
opt.c_cflag |= CS8;
break;
}
/*软件流控制屏蔽*/
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
/*设置最少字符和等待时间*/
opt.c_cc[VTIME] = 0;
opt.c_cc[VMIN] = 0;
/*转换到行方式输入*/
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //Input
opt.c_oflag &= ~OPOST; //Output
tcflush(fd, TCIOFLUSH);//刷清输入输出队列
tcsetattr(fd, TCSANOW, &opt);//立即激活配置
return 0;
} /* ----- End of set_com_opt() ----- */
四、初始化串口
int init_comport (char * dev_name,int nSpeed )
{
int fd = 0;
if(0 == (fd = open_com(dev_name)))
{
printf("Open device %s fail!\n",dev_name);
return -1;
}
set_com_opt(fd,nSpeed,8,'N',1);//设置数据位为八位,无校验位,停止位为1位
printf("Initialize device [%s] :%d,S8N1\n",dev_name,nSpeed);
return fd;
} /* ----- End of init_comport() ----- */
五、主函数实现
主函数通过两个进程分别负责接收数据和发送数据。
int main(int argc, char **argv)
{
/* declare variant */
int fd = 0;
struct timeval timeout;
unsigned char buff[BUFF_SIZE];
int read_size = 0;
pid_t pid;
if (argc != 3)
{
printf("Usage:%s [Device] [Baud Rate]\n", argv[0]);
exit(0);
}
/*初始化com口*/
fd = init_comport(argv[1], atoi(argv[2]));
if (fd == -1)
{
printf("Initialize UART Fail!\n");
exit(1);
}
/*子进程执行写操作*/
if (0 == (pid = fork()))
{
char w_buff[BUFF_SIZE];
while (1)
{
scanf("%s",w_buff);
if (0 > write(fd, w_buff, strlen(w_buff)))
{
perror("Write Serial Fail:");
exit(-1);
}
memset(w_buff, 0x00, BUFF_SIZE);
}
}
timeout.tv_sec = 0;
timeout.tv_usec = 50; //wait for 50ms
/*父进程执行读操作*/
while (1)
{
memset(buff, 0x00, sizeof(buff));
if (0 > (read_size = read(fd, buff, BUFF_SIZE)))
{
perror("Read Serial Fail:");
exit(-1);
}
if (read_size > 0)
printf("%s", buff);
fflush(stdout);
}
close(fd);
return 0;
} /* ----- End of main() ----- */
六、编译执行
编译:
通过tftp下载到开发板内存中