Linux下编程的过程有些固定,很多都是比如打开、配置、关闭等等
串口通信流程:打开串口ttySn--->初始化串口--->读写(read、write)--->关闭串口
串口设置
最基本的设置串口包括波特率设置,效验位和停止位设置。
串口的设置主要是设置 struct termios 结构体的各成员值。
struct termio
{ unsigned short c_iflag; /* 输入模式标志 */
unsigned short c_oflag; /* 输出模式标志 */
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
串口控制函数
tcgetattr 取属性(termios结构)
tcsetattr 设置属性(termios结构)
cfgetispeed 得到输入速度
cfgetospeed 得到输出速度
cfsetispeed 设置输入速度
cfsetospeed 设置输出速度
tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷清未决输入和/或输出
tcsendbreak 送BREAK字符
tcgetpgrp 得到前台进程组ID
tcsetpgrp 设置前台进程组ID
串口.h文件 usart.h
/*********************************************************************************
* Copyright: (C) 2018 Yujie
* All rights reserved.
*
* Filename: usart.h
* Description: 串口配置
*
* Version: 1.0.0(08/27/2018)
* Author: yanhuan <yanhuanmini@foxmail.com>
* ChangeLog: 1, Release initial version on "08/23/2018 17:28:51 PM"
*
********************************************************************************/
#ifndef _USART_H
#define _USART_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>
//宏定义
#define FALSE -1
#define TRUE 0
int UART0_Open(int fd,char*port);
void UART0_Close(int fd) ;
int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity);
int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity) ;
int UART0_Recv(int fd, char *rcv_buf,int data_len);
int UART0_Send(int fd, char *send_buf,int data_len);
#endif
串口测试函数 usart_test.c
/*********************************************************************************
* Copyright: (C) 2018 Yujie
* All rights reserved.
*
* Filename: usart_test.c
* Description: 串口测试
*
* Version: 1.0.0(08/27/2018)
* Author: yanhuan <yanhuanmini@foxmail.com>
* ChangeLog: 1, Release initial version on "08/23/2018 17:28:51 PM"
*
********************************************************************************/
#include "usart.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 main(int argc, char **argv)
{
int fd = -1; //文件描述符,先定义一个与程序无关的值,防止fd为任意值导致程序出bug
int err; //返回调用函数的状态
int len;
int i;
char rcv_buf[256];
char send_buf[256];
if(argc != 3)
{
printf("Usage: %s /dev/ttySn 0 #(send data)\n",argv[0]);
printf("Usage: %s /dev/ttySn 1 #1(receive data)\n",argv[0]);
printf("open failure : %s\n", strerror(errno));
return FALSE;
}
fd = UART0_Open(fd,argv[1]); //打开串口,返回文件描述符
// fd=open("dev/ttyS1", O_RDWR);
//printf("fd= \n",fd);
do
{
err = UART0_Init(fd,115200,0,8,1,'N');
printf("Set Port Exactly!\n");
sleep(1);
}while(FALSE == err || FALSE == fd);
if(0 == strcmp(argv[2],"0")) //开发板向pc发送数据的模式
{
fgets(send_buf,256,stdin); //输入内容,最大不超过40字节,fgets能吸收回车符,这样pc收到的数据就能自动换行
for(i = 0;i < 10;i++)
{
len = UART0_Send(fd,send_buf,40);
if(len > 0)
printf(" %d time send %d data successful\n",i,len);
else
printf("send data failed!\n");
sleep(1);
}
UART0_Close(fd);
}
else //开发板收到pc发送的数据的模式
{
while (1) //循环读取数据
{
len = UART0_Recv(fd, rcv_buf,sizeof(rcv_buf));
if(len > 0)
{
rcv_buf[len] = '\0';
printf("receive data is %s\n",rcv_buf);
}
else
{
printf("cannot receive data\n");
}
sleep(1);
}
UART0_Close(fd);
}
}
串口编译 makefile
CC=arm-linux-gcc
all:
CC *.c -o usart
clear:
rm usart
程序在开发板上运行,打开对应的串口;另一端接在串口调试助手,打开串口调试助手。
程序可以改进很多,同时读写、select设置非阻塞、数据结构优化等等,等有时间会改进。
对于两块开发板之间的通信,可以把程序修改成select同时读写,注意是用pc上的gcc还是arm上的交叉编译,还要注意串口线的RX和TX接线。