0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

英创信息技术嵌入式Linux串口通讯的C++设计概述

英创信息技术 来源:英创信息技术 作者:英创信息技术 2019-11-18 09:32 次阅读

嵌入式Linux主板EM9160提供了6个标准异步串口:ttyS1——ttyS6,其中ttyS4、ttyS5、ttyS6和GPIO的管脚复用,每个串口都有独立的中断模式,使得多个串口能够同时实时进行数据收发。各个串口的驱动均已经包含在嵌入式Linux操作系统的内核中,EM9160在嵌入式Linux系统启动完成时,各个串口已作为字符设备完成了注册加载,用户的应用程序可以以操作文件的方式对串口进行读写,从而实现数据收发的功能。

串口编程接口函数

在嵌入式Linux系统下,所有的设备文件都位于“/dev”目录下,EM9160上6个串口所对应的设备名依次为“/dev/ttyS1”——“/dev/ttyS6”。

嵌入式Linux下操作设备的方式和操作文件的方式是一样的:调用open( )打开设备文件,再调用read( )、write( )对串口进行数据读写操作。这里需要注意的是打开串口除了设置普通的读写之外,还需要设置O_NOCTTY和O_NDLEAY,以避免该串口成为一个控制终端,因为如果作为一个终端有可能会影响到用户的进程。打开的方式如下:

sprintf( portname, ‘/dev/ttyS%d’, PortNo ); //PortNo为串口端口号,从1开始

m_fd = open( portname,O_RDWR | O_NOCTTY | O_NONBLOCK);

作为串口通讯还需要一些通讯参数的配置,包括波特率、数据位、停止位、校验位等参数。在实际的操作中,主要是通过设置struct termios结构体的各个成员值来实现,一般会用到的函数包括:

tcgetattr( ) ;

tcflush( );

cfsetispeed( );

cfsetospeed( );

tcsetattr( );

其中各个函数的具体使用方法这里就不一一介绍了,用户可以参考嵌入式Linux应用程序开发的相关书籍,也可参看Step2_SerialTest中Serial.cpp模块中set_port( )函数代码。

串口应用的C++设计

Step2 _SerialTest是一个支持异步串口数据通讯的示例,该例程采用了面向对象的C++编程,把串口数据通讯作为一个对象进行封装,用户调用该对象提供的接口函数即可方便地完成串口通讯的操作。

CSerial类介绍

利用上一小节中介绍的串口API函数,封装了一个支持异步读写的串口类CSerial,CSerial类中提供了4个公共函数、一个串口数据接收线程以及数据接收用到的数据Buffer。

class CSerial

{

private:

//通讯线程标识符ID

pthread_t m_thread;

// 串口数据接收线程

static int ReceiveThreadFunc( void* lparam );

public:

CSerial();

virtual ~CSerial();

int m_fd; // 已打开的串口文件描述符

int m_DatLen;

char DatBuf[1500];

int m_ExitThreadFlag;

// 按照指定的串口参数打开串口,并创建串口接收线程

int OpenPort( int PortNo, int baudrate, char databits, char stopbits, char parity );

// 关闭串口并释放相关资源

int ClosePort( );

// 向串口写数据

int WritePort( char* Buf, int len );

// 接收串口数据处理函数

virtual int PackagePro( char* Buf, int len );

};

OpenPort函数用于根据输入串口参数打开串口,并创建串口数据接收线程。在嵌入式Linux环境中是通过函数pthread_create( )创建线程,通过函数pthread_exit( )退出线程。嵌入式Linux线程属性存在有非分离(缺省)和分离两种,在非分离情况下,当一个线程结束时,它所占用的系统资源并没有被释放,也就是没有真正的终止;只有调用pthread_join( )函数返回时,创建的线程才能释放自己占有的资源。在分离属性下,一个线程结束时立即释放所占用的系统资源。基于这个原因,在我们提供的例程中通过相关函数将数据接收线程的属性设置为分离属性。如:

// 设置线程绑定属性

res = pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM );

// 设置线程分离属性

res += pthread_attr_setdetachstate( &attr, THREAD_CREATE_DETACHED );

ReceiveThreadFunc函数是串口数据接收和处理的主要核心代码,在该函数中调用select( ),阻塞等待串口数据的到来。对于接收到的数据处理也是在该函数中实现,在本例程中处理为简单的数据回发,用户可结合实际的应用修改此处代码,修改PackagePro( )函数即可。流程如下:

int CSerial::ReceiveThreadFunc(void* lparam)

{

CSerial *pSer = (CSerial*)lparam;

//定义读事件集合

fd_set fdRead;

int ret;

struct timeval aTime;

while( 1 )

{

//收到退出事件,结束线程

if( pSer-》m_ExitThreadFlag )

{

break;

}

FD_ZERO(&fdRead);

FD_SET(pSer-》m_fd,&fdRead);

aTime.tv_sec = 0;

aTime.tv_usec = 300000;

ret = select( pSer-》m_fd+1,&fdRead,NULL,NULL,&aTime );

if (ret 《 0 )

{

//关闭串口

pSer-》ClosePort( );

break;

}

if (ret 》 0)

{

//判断是否读事件

if (FD_ISSET(pSer-》m_fd,&fdRead))

{

//data available, so get it!

pSer-》m_DatLen = read( pSer-》m_fd, pSer-》DatBuf, 1500 );

// 对接收的数据进行处理,这里为简单的数据回发

if( pSer-》m_DatLen 》 0 )

{

pSer-》PackagePro( pSer-》DatBuf, pSer-》m_DatLen);

}

// 处理完毕

}

}

}

printf( ‘ReceiveThreadFunc finished\n’);

pthread_exit( NULL );

return 0;

}

需要注意的是,select( )函数中的时间参数在嵌入式Linux中每次都需要重新赋值,否则会自动归0。

CSerial类的实现代码请参见Serial.CPP文件。

CSerial类的调用

CSerial类的具体使用也比较简单,主要是对于类中定义的4个公共函数的调用,以下为 Step2_SerialTest.cpp中相关代码。

class CSerial m_Serial;

int main( int argc,char* argv[] )

{

int i1;

int portno, baudRate;

char cmdline[256];

printf( ‘Step2_SerialTest V1.0\n’ );

// 解析命令行参数:串口号 波特率

if( argc 》 1 ) strcpy( cmdline, argv[1] );

else portno = 1;

if( argc 》 2 )

{

strcat( cmdline, ‘ ’ );

strcat( cmdline, argv[2] );

scanf( cmdline, ‘%d %d’, &portno, &baudRate );

}

else

{

baudRate = 115200;

}

printf( ‘port:%d baudrate:%d\n’, portno, baudRate);

//打开串口相应地启动了串口数据接收线程

i1 = m_Serial.OpenPort( portno, baudRate, ‘8’, ‘1’, ‘N’);

if( i1《0 )

{

printf( ‘serial open fail\n’);

return -1;

}

//进入主循环,这里每隔1s输出一个提示信息

for( i1=0; i1《10000;i1++)

{

sleep(1);

printf( ‘%d \n’, i1+1);

}

m_Serial.ClosePort( );

return 0;

}

从上面的代码可以看出,程序的主循环只需要实现一些管理性的功能,在本例程中仅仅是每隔1s输出一个提示信息,在实际的应用中,可以把一些定时查询状态的操作、看门狗的喂狗等操作放在主循环中,这样充分利用了嵌入式Linux多任务的编程优势,利用内核的任务调度机制,将各个应用功能模块化,以便于程序的设计和管理。这里顺便再提一下,在进行多个串口编程时,也可以利用本例程中的CSerial类为基类,根据应用需求派生多个CSerial派生类实例,每一个派生类只是重新实现虚函数PackagePro(…),这样每个串口都具有一个独立的串口数据处理线程,利用Linux内核的任务调度机制以实现多串口通讯功能。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11342

    浏览量

    210318
  • 嵌入式主板
    +关注

    关注

    7

    文章

    6086

    浏览量

    35587
收藏 人收藏

    相关推荐

    嵌入式主板的无线通讯解决方案

    WiFi模块。ETA6210模块继续保持了PPP拨号模式,使得无论是Linux平台的主板还是CE平台的主板,都能方便的使用。  下表列出了当前嵌入式主板支持的无线模块。模块型号模
    发表于 03-24 14:00

    嵌入式linux培训教程 嵌入式linux学习方法步骤

      嵌入式开发技术入门易,精通难。当然,如果相对于其他的开发技术来说,嵌入式学习门槛相对较高。但嵌入式如今的发展前景也要高于其他开发
    发表于 07-03 18:25

    嵌入式Linux C概述

    嵌入式Linux C概述嵌入式系统是现在最热门的计算机应用领域之一,嵌入式
    发表于 12-15 08:32

    信息技术WinCE系统多串口扩展方案简介

     异步串行通讯口(UART)是在工业自动化中应用最为广泛的通讯接口之一,其接口形式包括RS232C、RS485、RS422。作为以网络通讯为特色的
    的头像 发表于 10-31 15:15 1706次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b>WinCE系统多<b class='flag-5'>串口</b>扩展方案简介

    信息技术C#使用COM组件接口进行串口操作介绍

    嵌入式主板采用WinCE操作系统,很多客户都选择了界面友好、开发便利的C#语言(使用Visual Studio 2005.NET集成开发环境);在VS2005中,微软提供了一个标准的串口
    的头像 发表于 11-14 09:37 2407次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b><b class='flag-5'>C</b>#使用COM组件接口进行<b class='flag-5'>串口</b>操作介绍

    信息技术嵌入式系统设备驱动接口的C#编程

    ARM9系列嵌入式主板,均预装了WinCE 5.0、WinCE 6.0操作系统,用户可使用标准的C/C++
    的头像 发表于 01-15 11:29 1345次阅读

    信息技术嵌入式系统通讯线程的C#编程方法

    在使用ARM9系列嵌入式主板的COM口,CAN口,网口时,一般会使用到timer或线程来实现数据的接收。使用timer控件较为方便,通过InterVal值来设定调用间隔,但是灵活性不如线程。并且
    的头像 发表于 01-15 11:25 1328次阅读

    信息技术嵌入式Linux主板Qt串口应用程序简介

    串口和其他设备一样,在Linux系统中都是以设备文件的形式存在的,在公司提供的Linux主板配套光盘中,已经提供了基于
    的头像 发表于 01-17 09:41 1891次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b><b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>主板Qt<b class='flag-5'>串口</b>应用程序简介

    信息技术Linux嵌入式工控板支持电容屏介绍

    随着嵌入式应用对GUI图形界面需求的增加,Qt在Linux嵌入式设备中的使用越来越广泛,许多应用也都对人机交互界面有一定的要求。因此触摸屏、鼠标等设备等支持也变得重要起来,
    的头像 发表于 02-03 09:37 6783次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b><b class='flag-5'>Linux</b><b class='flag-5'>嵌入式</b>工控板支持电容屏介绍

    信息技术嵌入式主板的无线通讯解决方案

    无线通讯是指利用公共2G / 3G / 4G网络进行的无线数据通讯,以及利用无线局域网WiFi的数据通讯。在当前嵌入式领域,无线通讯单元的主
    的头像 发表于 02-05 11:03 1488次阅读

    信息技术JAVA操作主板SPI接口简介

    2017年9月,Linux的文件系统中移植了针对嵌入式Linux的JRE(Java Runtime Environment),能够支持
    的头像 发表于 02-06 11:09 1981次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b>JAVA操作<b class='flag-5'>英</b><b class='flag-5'>创</b>主板SPI接口简介

    信息技术JAVA操作主板I2C接口简介

    2017年9月,Linux的文件系统中移植了针对嵌入式Linux的JRE(Java Runtime Environment),能够支持
    的头像 发表于 02-06 11:06 1731次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b>JAVA操作<b class='flag-5'>英</b><b class='flag-5'>创</b>主板I2<b class='flag-5'>C</b>接口简介

    信息技术Linux双进程应用示例

    控制流程,应用程序采用C/C++语言来编写。图1表现了典型工控设备的组成关系。 典型工控设备框图 工控设备的另一个特点是鉴于设备大多是24小时连续运行,且无人值守,所以基本的工控设备是无显示的。
    的头像 发表于 02-06 11:34 1152次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b><b class='flag-5'>Linux</b>双进程应用示例

    信息技术嵌入式Linux主板多网口多路由方案

    主流的嵌入式主板均支持双网络接口,其中支持ISA扩展总线的主板型号,如:EM335x、ESM335x、ESM6802、ESM6800V等,还可以通过ISA总线外接ETA728模块,再扩展两路独立
    的头像 发表于 02-07 10:48 1875次阅读
    <b class='flag-5'>英</b><b class='flag-5'>创</b><b class='flag-5'>信息技术</b><b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>主板多网口多路由方案

    嵌入式Linux UART

    文章目录前言串口连接串口测试C代码微信公众号前言这是前篇:嵌入式Linux i.MX开发板嵌入式
    发表于 11-01 16:26 8次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b> UART