linux与开发板串口通信
研究了一天的linux串口,结果改了树莓派的系统配置文件config.txt给改了导致系统崩溃。。。。其实我感觉网上的大多数方法都是不符合新版本树莓派的,网上的方法是通过修改系统配置文件后安装minicom进行串口的调试。为什么需要修改配置文件?因为树莓派升级后tx与rx引脚是复用的,需要用于串口的话就需要修改配置,让系统把io口让给串口。
这种方法比较麻烦,我采用的是利用两个usb转串口,互相连接好了,就可以直接通过linux下的串口通信函数来实现通信了。需要注意的是两个usb转串口相互连接时不仅仅要将RXD、TXD相互反接,还需要将GND连接在一起。
下面讲解下具体方法
(1)不同系统的串口名称是不一样的,如下图。
(2)设置
最基本的设置串口包括波特率设置,效验位和停止位设置.
很多系统都支持POSIX终端(串口)接口.程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等.要使用这个端口的话,你必须将<termios.h>头文件包含到你的程序中.这个头文件中定义了终端控制结构体和POSIX控制函数.
与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3).顾名思义,这两个函数分别用来取得设设置终端的属性.调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体,串口的设置主要是设置struct termios结构体的各成员值.
通过termio结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制,下面这张表列出了所有可以使用的常数
进行设置时千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志.不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性.
1.1波特率设置
不同的操作系统会将波特率存储在不同的位置.旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值.
程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口.下面的代码是个非常典型的设置波特率的例子.
struct termios options;
tcgetattr(fd,&option); //获取端口的当前状态
cfsetispeed(&options,B19200);//设置波特率为19200
options.c_cflags | =(CLOCK | CREAD);//将设置的参数传入
tcsetattr(fd,TCSANOW.&options);
函数tcgetattr( )会将当前串口配置回填到termio结构体option中.然后,程序设置了输入输出的波特率并且将本地模式(CLOCAL)和串行数据接收(CREAD)设置为有效,接着将新的配置作为参数传递给函数tcsetattr( ).常量TCSANOW标志所有改变必须立刻生效而不用等到数据传输结束.其他另一些常数可以保证等待数据结束或者刷新输入输出之后再生效.
1.2 设置字符大小,设置字符大小的时候,没有像设置波特率那么方便的函数.所以,程序中需要一些位掩码运算来把事情搞定.字符大小以比特为单位指定:
options.c_flag &= ~CSIZE; /* Mask the character size bits */
options.c_flag |= CS8; /* Select 8 data bits */
1.3 与上同理,通过位掩码来设置校验位与停止位
无奇偶校验( no parity)
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
偶校验(even parity)
options.c_cflag |= PARENB
options.c_cflag &= ~PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
奇校验(odd parity)
options.c_cflag |= PARENB
options.c_cflag |= PARODD
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
设置奇偶校验函数
/**
*@brief 设置串口数据位,停止位和效验位
*@param fd 类型 int 打开的串口文件句柄
*@param databits 类型 int 数据位 取值 为 7 或者8
*@param stopbits 类型 int 停止位 取值为 1 或者2
*@param parity 类型 int 效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
struct termios options;
if ( tcgetattr( fd,&options) != ) {
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE;
switch (databits) /*设置数据位数*/
{
case :
options.c_cflag |= CS7;
break;
case :
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n"); return (FALSE);
}
switch (parity)
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;break;
default:
fprintf(stderr,"Unsupported parity\n");
return (FALSE);
}
/* 设置停止位*/
switch (stopbits)
{
case :
options.c_cflag &= ~CSTOPB;
break;
case :
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return (FALSE);
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = ; /* 设置超时15 seconds*/
options.c_cc[VMIN] = ; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&options) != )
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}
1.4 本地设置,本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符.通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。
1.4.1 选择经典模式,经典输入是以面向行设计的.在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符.选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项: options.c_lflag |= (ICANON | ECHO | ECHOE);
1.4.2 选择原始输入,原始输入根本不会被处理.输入字符只是被原封不动的接收.一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
(2)读写串口,unix将串口当做文件来处理,直接读取串口即可,write函数也会返回发送数据的字节数或者在发生错误的时候返回-1.通常,发送数据最常见的错误就是EIO,当调制解调器或者数据链路将Data Carrier Detect(DCD)信号线弄掉了,就会发生这个错误.而且,直至关闭端口这个情况会一直持续.
char buffer[];int Length;int nByte;nByte = write(fd, buffer ,Length)
读取数据:使用文件操作read函数读取,如果设置为原始数据模式(Raw Date Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数,也就是返回从串口输入缓冲区中实际得到的字符的个数.在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生.
char buff[];int Len;int readByte = read(fd,buff,Len);
如果需要read(2)函数迅速返回的话,可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作: fcntl(fd, F_SETFL, FNDELAY);标志FNDELAY可以保证read()函数在端口上读不到字符的时候返回0.需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl()函数:
(3)函数编程,需要的头文件如下
#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> /*错误号定义*/
一个树莓派发送数据数据给电脑串口的程序如下:需要根据具体的情况修改USB口
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h> //serial port set function
void setTermios(struct termios *pNewtio, unsigned short uBaudRate)
{
bzero(pNewtio,sizeof(struct termios));
pNewtio->c_cflag = uBaudRate|CS8|CREAD|CLOCAL;
pNewtio->c_iflag = IGNPAR;
pNewtio->c_oflag = ;
pNewtio->c_lflag = ;
pNewtio->c_cc[VINTR] = ;
pNewtio->c_cc[VQUIT] = ;
pNewtio->c_cc[VERASE] = ;
pNewtio->c_cc[VKILL] = ;
pNewtio->c_cc[VEOF] = ;
pNewtio->c_cc[VTIME] = ;
pNewtio->c_cc[VMIN] = ;
pNewtio->c_cc[VSWTC] = ;
pNewtio->c_cc[VSTART] = ;
pNewtio->c_cc[VSTOP] = ;
pNewtio->c_cc[VSUSP] = ;
pNewtio->c_cc[VEOL] = ;
pNewtio->c_cc[VREPRINT] = ;
pNewtio->c_cc[VDISCARD] = ;
pNewtio->c_cc[VWERASE] = ;
pNewtio->c_cc[VLNEXT] = ;
pNewtio->c_cc[VEOL2] = ;
}
int main(int argc,char **argv)
{
int fd;
int nCount,nTotal;
int i,j,m;
int ReadByte = ; int Buffer[];
struct termios oldtio,newtio;
char *dev = "/dev/tq2440_serial0"; if((argc!=)||(sscanf(argv[],"%d",&nTotal)!=))
{
printf("Usage:COMSend count datat! ");
return -;
} if((fd=open(dev,O_RDWR|O_NOCTTY|O_NDELAY))<) //open serial COM2
{
printf("Can't open serial port! ");
return -;
}
tcgetattr(fd,&oldtio);
setTermios(&newtio,B9600);
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio); //Send data
for(i=;i<nTotal;i++)
{
nCount = write(fd,argv[],strlen(argv[]));
printf("send data OK!count=%d ",nCount);
sleep();
} //receive data
for(j=;j<;j++)
{
ReadByte = read(fd,Buffer,);
if(ReadByte>)
{
printf("readlength=%d ",ReadByte);
Buffer[ReadByte]='\0';
printf("%s ",Buffer);
sleep();
}
else printf("Read data failure times=%d ",j);
}
printf("Receive data finished! ");
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
return ;
}
参考文章:http://blog.sina.com.cn/s/blog_644949120100sc8n.html
http://www.cnblogs.com/jason-lu/articles/3173988.html
linux与开发板串口通信的更多相关文章
- linux下的qt串口通信
1.linux下的qt串口通信跟windows唯一的差别就是端口号的名字,windows下面是COM,而linux是ttyUSB0的路径 2.一般情况下linux插上USB转串口线就可以在/dev/目 ...
- linux下开发板网络速度测试记录
由于做的项目对于网络和USB的读写速度有很高的要求,因此新拿回来的板子要测试网络和usb的最佳传输速度.要考虑不少因素,先把我能想到的记录下来. 测试的环境是开发板和ubuntu虚拟机 ...
- iTOP-4412开发板-串口转接小板的使用文档
本文档介绍如何使用 迅为iTOP-4412 精英版如何使用串口转接板,串口小板如下所示.和串口转接板模块相关的资料如下:“iTOP-4412-Android-串口测试文档(升级版)_V2.X.zip” ...
- 迅为iTOP-4418开发板串口虚拟控制台配置为普通串口
如何将 iTOP-4418 的串口控制台配置为普通串口.在最终的产品中,如果需要额外的串口,可以将调试用的控制台串口作为普通串口使用,因为交付给最终用户手中的产品,一般不需要调试串口.屏蔽串口控制台需 ...
- 漫谈LiteOS之开发板-串口(基于GD32450i-EVAL)
[摘要] 主要讲解物联网的技术积累,本期我们先带领大家学习漫谈LiteOS之漫谈开发板第一集-串口,本文基于GD32450i-EVAL对串口以及其通信做了一个简要的分析,以及开发过程中遇到的一些技术 ...
- 如何在嵌入式Linux上开发一个语音通信解决方案
开发一个语音通信解决方案是一个软件项目.既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去做,这些工程师在这一领域的经验如何,是否需要培训,要多长时间做完,中间有几个主要的milest ...
- SecureCRT连接开发板 串口传输、tftp传输
1.串口传输 使用命令:rx r是service, x是X-model模式 ①.rx 文件名 再按Enter键 ②.将需要传到板子上的文件 拖到SecureCRT里面,选择发送X-model选项 注 ...
- 创龙TMS320C6748开发板串口和中断学习笔记
1. 硬件上,底板有2个串口,UART1和UART2(使用了MAX3232电平转换芯片),其中UART2也可以转RS485的. 2. 看下数据手册部分,不过一直不理解过采样的意思,16字节的FIFO ...
- 如何选安卓android|linux系统开发板,简化学习难度,缩短开发进程
平台一:iTOP-4412精英版 系统支持:Android 4.0.3系统 / Android 4.4系统 / Linux + Qt系统 / Ubuntu12.04系统 开发板特点:Cortex-A ...
随机推荐
- Python模块学习:glob 文件路径查找
glob模块是最简单的模块之一,内容非常少. 用它可以查找符合特定规则的文件路径名.跟使用windows下的文件搜索差不多. 查找文件只用到三个匹配符:”*”, “?”, “[]”. ”*”匹配0个或 ...
- 函数名后加const
通过把类成员函数声明为const 以表明它们不修改类对象. 任何不会修改数据成员的函数都应该声明为const类型.如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员 ...
- es6记录
3.5? 一.const 1.冻结对象 const foo = Object.freeze({}); // 常规模式时,下面一行不起作用: // 严格模式时,该行会报错 foo.prop = ; 2. ...
- 如何配置openjdk的 java home
https://blog.csdn.net/redmoon729/article/details/51671354
- [BZOJ2815][ZJOI2012]灾难 灭绝树+拓扑排序+lca
灾难 [问题描述] 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那 么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的 生态灾难. 学过 ...
- EntityFramework之多对多关系(四)
上篇介绍了一对多关系,下面介绍下多对多关系代码编写. 1.新建model实体,User是用户类,Role是角色类,由于是多对多关系,必须得有一个中间类,所以产生了UserRole类 public cl ...
- Ubunntu kylin下安装VmWare Tools(简洁方法)
1.在VM菜单栏单击虚拟机,选择安装Vmware tools(或者是重装Vmware Tools) 2.会弹出一个界面,就是光盘加载的那个界面,里面有个.******.gz文件 3.复制到桌面(你喜欢 ...
- 小白书 黑白图像【DFS/Flood Fill】
http://blog.csdn.net/u010470972/article/details/33415617 Description 输入一个n×n的黑白图像(1表示黑色,0表示白色),任务是统计 ...
- Python的程序结构[3] -> 变量/Variable[0] -> 变量类型
变量类型 / Variable Type 在 Python 中,变量主要有以下几种,即全局变量,局部变量和内建变量, 全局变量 / Global Variable 通常定义于模块内部,大写变量名形式存 ...
- [USACO17DEC] Barn Painting
题目描述 Farmer John has a large farm with NN barns (1 \le N \le 10^51≤N≤105 ), some of which are alread ...