嵌入式Linux串口操作接口

2019-07-12 14:26发布

摘要

鉴于串口在嵌入式系统中广泛应用于操作GPRS模块、读卡器模块和GPS北斗模块等,串口操作成为嵌入式系统开发中必备工作,但是目前web中并没有提供一个封装良好的串口初始化和读写接口函数,因此本文基于工程实践提供了操作串口的接口函数和测试程序,为嵌入式Linux的串口操作提供了较大的便利。本文中提供的串口操作接口函数并未将常用串口参数如波特率、数据位、停止位和校验方式进行参数化,因此也有待进一步封装。

背景

由于智慧泊车工程项目中开发的硬件设备需要通过串口和AT命令访问GPRS模块,自己的工作环境也从涉密事业单位变成了能够随时能够访问Internet的公司,因此打算逐步将这些操作进行抽象和封装,以备不时之需。受到开发周期的限制,目前还未来得及将常用串口参数如波特率、数据位、停止位和校验方式进行参数化,在后续工作中会逐步完善和提高,也希望从业同行能够对其中不足进行批评指正,实现共同进步。

技术方案

串口操作涉及的文件主要是termios.h头文件中的struct termios结构,该结构的定义如下: #define NCC 8 struct termio { unsigned short c_iflag; unsigned short c_oflag; unsigned short c_cflag; unsigned short c_lflag; unsigned char c_line; unsigned char c_cc[NCC]; }; 详细参数定义内核代码中有较详细的解释,后续再博客修改时会陆续加上。
串口操作接口函数头文件uart.h文件 /* *@brief:uart operation interface *@author: *@email: *@date:30th Oct 2015 */ #ifndef __UART_H__ #define __UART_H__ #include #include #include #define DATA_BUFF_SIZE 256 int open_serial(char pchSerialName[], int nSerialNameLen); int config_serial(int nFdSerial); void signal_serial_data_prepared_handler(int nFdSerial); int write_serial(int nFdSerial, char pchDataBuf[], int nDataBufLen); int close_serial(int nFdSerial); #endif 串口操作接口函数源文件uart.c文件 /* *@brief:uart operation interface *@author: *@email: *@date:30th Oct 2015 */ #include <string.h> #include "uart.h" char g_serial_data_buffer[DATA_BUFF_SIZE] = { 0 }; int open_serial(char pchSerialName[], int nSerialNameLen) { int nFdSerial; if(pchSerialName == NULL || nSerialNameLen <= 0) return -1; nFdSerial = open(pchSerialName, O_RDWR|O_NOCTTY); if(nFdSerial < 0) return -1; return nFdSerial; } /* *@brief:configure serial port as 115200bps | 8 databits | 1 stopbit | no parity check *@param: nFdSerial:handle of serial port *@return: *@author: *@date:31th Oct 2015 *@todo:parameterize uart parameters */ int config_serial(int nFdSerial) { struct termios tio; tcgetattr(nFdSerial, &tio); tcflush(nFdSerial, TCIFLUSH); cfsetispeed(&tio, B115200);//115200bps cfsetospeed(&tio, B115200); tio.c_cflag |= CS8;//8 data bits tio.c_cflag &= ~PARENB;//no parity check tio.c_oflag &= ~OPOST; tio.c_cflag &= ~CSTOPB;//1 stop bit tio.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN); tio.c_iflag &= ~(INPCK | BRKINT | ICRNL | ISTRIP | IXON); tio.c_cc[VMIN] = 64; tio.c_cc[VTIME] = 1; if(tcsetattr(nFdSerial, TCSANOW, &tio) != 0) { perror("%s,L%d,in %s, configure serial failed. ", __FILE__, __LINE__, __func__); return -1; } return 0; } void signal_serial_data_prepared_handler(int nFdSerial) { int nReadBufLen = 0; memset(g_serial_data_buffer, 0, sizeof(g_serial_data_buffer)); read(nFdSerial, g_serial_data_buffer, DATA_BUFF_SIZE); } int write_serial(int nFdSerial, char pchDataBuf[], int nDataBufLen) { int nWriteBufLen = 0; nWriteBufLen = write(nFdSerial, pchDataBuf, nDataBufLen); return nWriteBufLen; } int close_serial(int nFdSerial) { if(nFdSerial < 0) { perror("%s,L%d,in %s, close serial failed. ", __FILE__, __LINE__, __func__); return -1; } close(nFdSerial); return 0; } 串口测试主程序main.c文件如下。 #include #include #include #include #include "uart.h" #define UART_DEVICE_NAME "/dev/ttySAC0" int nFdSerial = -1; void system_exit(int nExitCode) { if(nFdSerial > 0) close(nFdSerial); exit(nExitCode); } int main(int argc, char * * argv, char * * env) { char chDataTest[16] = { 0 }; int nIndex = 0; nFdSerial = open_serial(UART_DEVICE_NAME, strlen(UART_DEVICE_NAME)); if(nFdSerial < 0) { printf("%s,L%d,in %s, open %s failed. ", __FILE__, __LINE__, __func__, UART_DEVICE_NAME); return; } config_serial(nFdSerial); signal(SIGINT, system_exit); for(nIndex = 0; nIndex < sizeof(chDataTest); nIndex++) { chDataTest[nIndex] = nIndex + 1; } while(1) { write_serial(nFdSerial, chDataTest, sizeof(chDataTest)); usleep(1000000); } return 0; } 在linux上交叉编译的Makefile文件如下。 #!/bin/sh CROSS=arm-linux- CC=$(CROSS)gcc FLAGS=-lpthread -wall objects = main.o uart.o uart_test:$(objects) $(CC) -o uart_test $(objects) cp uart_test /mnt/hgfs/vmware_shared/images clean: rm -f uart_test *.o 测试结果如下图所示。
串口测试结果图
上文中的源码链接如下:
http://www.pudn.com/downloads711/sourcecode/embedded/detail2854204.html

结语

目前提供的接口简化了串口操作,但是串口的主要参数还有待进一步参数化,另外还需要采用软中断用户自定义signal方式实现串口接收数据处理,在后续的工程开发中会进一步完善。