概述
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 串口驱动所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复