我是靠谱客的博主 舒适草莓,最近开发中收集的这篇文章主要介绍linux 串口驱动,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

struct termios 结构体

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <termios.h>

typedef struct uart_hardware_cfg{
	unsigned int baudrate;
	unsigned char dbit;
	char parity;
	unsigned char sbit;
}uart_cfg_t;

static int fd;
static struct termios old_cfg;

static int uart_init(const char *device)
{
	fd=open(device,O_RDWR|O_NOCTTY);
	if(0>fd){
	fprintf(stderr,"open error:%s:%sn",device,strerror(errno));
	return -1;
	}
	if(0>fd){
	fprintf(stderr, "open error: %s: %sn", device, strerror(errno));
	return -1;
	}
	return 0;
	
}

static int uart_cfg(const uart_cfg_t *cfg)
{
	struct termios new_cfg={0}; //定义termios类型结构体为new_cfg
	speed_t speed;
	new_cfg.c_cflag |=CREAD;
	
/* 设置通信速率大小,默认为115200*/
	switch(cfg->baudrate){
	case 1200:
		speed=B1200;
		break;
	case 1800:
		speed=B1800;
		break;
	case 2400:
		speed=B2400;
		break;
	case 4800:
		speed=B4800;
		break;	
	case 9600:
		speed=B9600;
		break;
	case 19200:
		speed = B19200;
		break;
	case 38400:
		speed = B38400;
		break;
	case 57600: 
		speed = B57600;
		break;
	case 115200:
		speed = B115200;		
		break;
	case 230400:
		speed = B230400;
		break;
	case 460800:
		speed = B460800;
		break;
	case 500000:
		speed = B500000;
		break;
	default:
	speed = B115200;	//默认配置为 115200
	printf("default baud rate:115200 n");
	break;
	}
	
	if(0 > cfsetspeed(&new_cfg,speed)){
		fprintf(stderr,"cfsetspeed error:%sn",strerror(errno));
		return -1;
	}
	
/* 设置数据为大小,默认为8位*/
	new_cfg.c_cflag &=~CSIZE;  //将数据位相关的比特位清零
	switch(cfg->dbit){
	case 5:
		new_cfg.c_cflag |= CS5;
		break;
	case 6:
		new_cfg.c_cflag |= CS6;
		break;
	case 7:
		new_cfg.c_cflag |= CS7;
		break;
	case 8:
		new_cfg.c_cflag |= CS8;
		break;
	default:
		new_cfg.c_cflag |=CS8;
		printf("defalut data bit size:8n");
		break;		
	}
	
/* 设置奇偶校验,默认为无校验*/	
switch(cfg->parity){
case 'N':	//无校验
	new_cfg.c_cflag &= ~PARENB;	//关闭奇偶校验
	new_cfg.c_iflag &= ~INPCK;	//	
	break;
case 'O':	//奇校验
	new_cfg.c_cflag |= (PARODD|PARENB);
	new_cfg.c_iflag |= INPCK;
	break;
case 'E':	//偶校验
	new_cfg.c_cflag |= PARENB;
	new_cfg.c_cflag &= ~PARODD;/* 清除PARODD标志,配置为偶校验 */
	new_cfg.c_iflag |= INPCK;
	break;
default:
	new_cfg.c_cflag &= ~PARENB;
	new_cfg.c_iflag &= ~INPCK;
	printf("default parity: N 无校验位 n");
	break;
}

/* 设置停止位 */
	switch(cfg->sbit){
	case 1:
		new_cfg.c_cflag &= ~CSTOPB;
		break;
	case 2:
		new_cfg.c_cflag |= CSTOPB;
		break;
	default:
		new_cfg.c_cflag &= ~CSTOPB;
		printf("defalut stop bit size:1 n");
		break;
}

/* 将MIN和TIME设置为0 */
	new_cfg.c_cc[VTIME]=0;
	new_cfg.c_cc[VMIN]=0;
	
/* 清空缓冲区 */
if(0>tcflush(fd,TCIOFLUSH)){
	fprintf(stderr,"tcflush error:%sn",strerror(errno));
	return -1;
	}

/* 写入配置、使配置生效 */	
if(0>tcsetattr(fd,TCSANOW,&new_cfg)){
	fprintf(stderr,"tcsetattr error:%sn",strerror(errno));
	return -1;
	}
	return 0;
}

static void show_help(const char *app)
{
	printf("Usage:%s[选项]n"
		"n 必选选项:n"
		"  --dev-DEVICE 指定串口终端设备名称,譬如--dev=/dev/ttyTHS0 n"
		"  --type=TYPE  指定操作类型,读串口还是写串口,譬如--type=read(read表示读、write表示写、其他值无效)n"
		"n 可选选项"
		" --brate=SPEED 指定串口波特率、e.g. --bitrate=115200n"
		" --dbitsize=SIZE 指定串口数据位个数,e.g. --dbit=8(可选5/6/7/8)n"
		" --parity=PARITY 指定串口奇偶校验方式 e.g. --parity=N(N 表示无校验、O表示奇校验、E表示偶校验)n"
		" --sbit-SIEZ	指定串口停止位个数,e.g. --sbit=1(可取1/2)n"
		" --help 查看本程序的使用帮助信息nn",app);
		}
		
/* 信号处理函数,当串口有数据可读时,会跳转到该函数执行 */
static void io_handler(int sig,siginfo_t *info,void *context)
{
	unsigned char buf[10]={0};
	int ret;
	int n;
	
	if(SIGRTMIN !=sig)
	return ;
	
/* 判断串口是否有数据可读 */
if(POLL_IN == info->si_code){
	ret = read(fd,buf,8);
	printf("[");
	for(n=0;n<ret;n++)
	printf("0x%hhx ",buf[n]);
	printf("]n");
	}
}

static void async_io_init(void)
{
	struct sigaction sigatn;
	int flag;
	
/* 使能异步I/O */
flag = fcntl(fd,F_GETFL); //使能串口的异步I/O功能
flag |=O_ASYNC;
fcntl(fd,F_SETFL,flag);

/* 设置异步I/O的所有者 */
fcntl(fd,F_SETOWN,getpid());

/* 指定实时信号SIGRTMIN作为异步I/O 通知信号 */
fcntl(fd,F_SETSIG,SIGRTMIN);

/* 为实时信号SIGRTMIN注册信号处理函数 */	
sigatn.sa_sigaction = io_handler; //当串口有数据可读时,会跳转到io_hander函数
sigatn.sa_flags = SA_SIGINFO;
sigemptyset(&sigatn.sa_mask);
sigaction(SIGRTMIN,&sigatn,NULL);
}

int main(int argc,char *argv[])
{
	uart_cfg_t cfg = {0};
	char *device=NULL;
	int rw_flag=-1;
	unsigned char w_buf[10]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};//通过串口发送出发的数据
	int n;
/* 解析出参数 */
/* 参考数据格式 ./demo --dev=ttyTHS0 --brate=115200 --parity=N --sbit=1 --tpye=read */
for(n=1;n<argc;n++)
{
	if(!strncmp("--dev=",argv[n],6))
		device = &argv[n][6];
	else if(!strncmp("--brate=",argv[n],8))
		cfg.baudrate = atoi(&argv[n][8]);
	else if(!strncmp("--dbit=",argv[n],7))
		cfg.dbit = atoi(&argv[n][7]);
	else if(!strncmp("--parity=",argv[n],9))
		cfg.parity = argv[n][9];
	else if(!strncmp("--sbit=",argv[n],7))
	cfg.sbit = atoi(&argv[n][7]);
	else if(!strncmp("--type=",argv[n],7)){
	if(!strcmp("read",&argv[n][7]))
	rw_flag=0; //读
	if(!strcmp("write",&argv[n][7])){
	rw_flag=1; //写
	}
}
	else if(!strcmp("--help",argv[n])){
	show_help(argv[0]);//打印帮助信息
	exit(EXIT_SUCCESS);
}

if(NULL == device || -1 ==rw_flag){
	fprintf(stderr,"Error:the device and read|write type must be set!n");
	show_help(argv[0]);
	exit(EXIT_FAILURE);
}

/* 串口初始化 */
if(uart_init(device))
	exit(EXIT_FAILURE);
	
/* 串口配置 */
if(uart_cfg(&cfg)){
	tcsetattr(fd,TCSANOW,&old_cfg);
	close(fd);
	exit(EXIT_FAILURE);
}

switch(rw_flag){
case 0: //读串口数据
	async_io_init(); //使用异步I/O方式读取串口的数据,调用函数区初始花串口的异步I/O
	for(;;)
	sleep(1);
	break;
case 1:
	for(;;){
		write(fd,w_buf,8);
		sleep(1);
	}
	break;
}
	tcsetattr(fd,TCSANOW,&old_cfg);
	close(fd);
	exit(EXIT_SUCCESS);
}
}	

最后

以上就是舒适草莓为你收集整理的linux 串口驱动的全部内容,希望文章能够帮你解决linux 串口驱动所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部