MT7628学习笔记(23)——OpenWRT串口编程&ipk软件包编写与应用
程序员文章站
2024-02-22 10:05:05
...
src/Serial.c
#include <stdio.h> /*标准输入输出定义*/
#include <errno.h> /*错误号定义*/
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*POSIX 终端控制定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <sys/types.h>
#include <unistd.h> /*UNIX 标准函数定义*/
#include <string.h>
#define serial_device "/dev/ttyS2"
/***********************************************************
* @函数:open_port
* @功能:打开串口
* @参数:
* @作者:PJW
************************************************************/
int open_port(void)
{
int fd; //串口标识符
/*
O_RDONLY 只读打开。
O_WRONLY 只写打开。
O_RDWR 读、写打开。
O_APPEND 每次写时都加到文件的尾端。
O_CREAT 若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。
O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。
O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。
O_NOCTTY 如果 pathname 指的是终端设备,则不将此设备分配作为此进程的控制终端。
O_NDELAY 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否**或者停止)。
O_NONBLOCK 如果 pathname 指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的 I/O 操作设置非阻塞方式。
O_SYNC 使每次 write 都等到物理 I/O 操作完成
*/
fd = open(serial_device,O_RDWR | O_NOCTTY | O_NDELAY); //以读写方式、不把该文件作为终端设备、无延时模式打开串口
if(fd == -1)
{
//不能打开串口
perror("open_port: Unable to open /dev/ttyS2 -");
return(fd);
}
else
{
fcntl(fd, F_SETFL, 0); //设置文件flag为0(默认),即阻塞状态
printf("open ttyS2 .....\n");
return(fd);
}
}
#if 0
/***********************************************************
* @函数:serial_write
* @功能:串口数据发送函数
* @参数: fd:串口描述符
data:待发送数据
datalen:数据长度
* @作者:PJW
************************************************************/
int serial_write(int fd ,char *data, int datalen)
{
int len=0;
len = write(fd,data,datalen);
printf("send data OK! datalen=%d\n",len);
return len;
}
/***********************************************************
* @函数:serial_read
* @功能:串口数据接收函数
* @参数: fd:串口描述符
buff:接收的数据
datalen:数据长度
* @作者:PJW
************************************************************/
int serial_read(int fd,char buff[],int datalen)
{
int nread=0;
printf("Ready for receiving data...");
nread = read(fd,buff,datalen);
if(nread>0)
{
printf("Revlength=%d\n",nread);
buff[nread]='\0';
printf("%s\n",buff);
}
return nread;
}
#endif
/***********************************************************
* @函数:set_serial
* @功能:串口属性配置
* @参数: nSpeed:波特率
nBits: 数据位
nEvent:奇偶校验位
nStop: 停止位
* @作者:PJW
************************************************************/
int set_serial(int fd,int nSpeed,int nBits,char nEvent,int nStop)
{
struct termios newtty,oldttys;
/*保存原有串口配置*/
if(tcgetattr(fd,&oldttys)!=0)
{
perror("Setupserial 1");
return -1;
}
bzero(&newtty,sizeof(newtty));
newtty.c_cflag|=(CLOCAL|CREAD );
/*
CREAD:开启串行数据接收,保证程序可以从串口中读取数据
CLOCAL:打开本地连接模式,保证程序不占用串口
*/
newtty.c_cflag &=~CSIZE;//字符长度,设置数据位之前一定要屏掉这个位
/*数据位选择*/
switch(nBits)
{
case 7:
newtty.c_cflag |=CS7;
break;
case 8:
newtty.c_cflag |=CS8;
break;
default:
break;
}
/*设置奇偶校验位*/
switch( nEvent )
{
case '0': /*奇校验*/
newtty.c_cflag |= PARENB;/*开启奇偶校验*/
newtty.c_iflag |= (INPCK | ISTRIP);/*INPCK打开输入奇偶校验;ISTRIP去除字符的第八个比特 */
newtty.c_cflag |= PARODD;/*启用奇校验(默认为偶校验)*/
break;
case 'E': /*偶校验*/
newtty.c_cflag |= PARENB; /*开启奇偶校验 */
newtty.c_iflag |= ( INPCK | ISTRIP);/*打开输入奇偶校验并去除字符第八个比特*/
newtty.c_cflag &= ~PARODD;/*启用偶校验*/
break;
case 'N': /*无奇偶校验*/
newtty.c_cflag &= ~PARENB;
break;
default:
break;
}
/*设置波特率*/
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtty, B2400);
cfsetospeed(&newtty, B2400);
break;
case 4800:
cfsetispeed(&newtty, B4800);
cfsetospeed(&newtty, B4800);
break;
case 9600:
cfsetispeed(&newtty, B9600);
cfsetospeed(&newtty, B9600);
break;
case 115200:
cfsetispeed(&newtty, B115200);
cfsetospeed(&newtty, B115200);
break;
default:
cfsetispeed(&newtty, B9600);
cfsetospeed(&newtty, B9600);
break;
}
/*设置停止位*/
if( nStop == 1){/*设置停止位;若停止位为1,则清除CSTOPB,若停止位为2,则**CSTOPB*/
newtty.c_cflag &= ~CSTOPB; /*默认为一位停止位; */
}else if( nStop == 2){
newtty.c_cflag |= CSTOPB; /*CSTOPB表示送两位停止位*/
}
/*--------------------其他配置-----------------------*/
/*设置本地模式为原始模式*/
newtty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/*
ICANON:允许规范模式进行输入处理
ECHO:允许输入字符的本地回显
ECHOE:在接收EPASE时执行Backspace,Space,Backspace组合
ISIG:允许信号
*/
/*设置输出模式为原始输出*/
newtty.c_oflag &= ~OPOST; //OPOST:若设置则按定义的输出处理,否则所有c_oflag失效
/*发送字符0X0d的时候,往往接收端得到的字符是0X0a,原因是因为在串口设置中c_iflag和c_oflag中存在从NL-CR和CR-NL的映射,即串口能把回车和换行当成同一个字符,可以进行如下设置屏蔽之*/
newtty.c_oflag &= ~(ONLCR | OCRNL);
newtty.c_iflag &= ~(ICRNL | INLCR);
newtty.c_cflag &= ~CRTSCTS;// 不使用硬件数据流控制
newtty.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /*c_cc数组的VSTART和VSTOP元素被设定成DC1和DC3,代表ASCII标准的XON和XOFF字符,如果在传输这两个字符的时候就传不过去,需要把软件流控制屏蔽*/
/*设置最小字符数和等待时间,对于接收字符和等待时间没有特别的要求时*/
newtty.c_cc[VTIME] = 0; /*非规范模式读取时的超时时间;单位:百毫秒*/
newtty.c_cc[VMIN] = 0; /*非规范模式读取时的最小字符数*/
tcflush(fd ,TCIFLUSH); /*tcflush清空终端未完成的输入/输出请求及数据*/
/*
TCIFLUSH: 清除正收到的数据,且不会读取出来。
TCOFLUSH: 清除正写入的数据,且不会发送至终端。
TCIOFLUSH: 清除所有正在发生的I/O数据。
TCOOFF: 挂起输出
TCOON: 重启挂起的输出
TCIOFF: 发送一个停止位
TCION: 发送一个起始位
*/
/***配置使其生效*/
if((tcsetattr( fd, TCSANOW,&newtty))!=0)
{
perror("com set error");
return -1;
}
/*
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:等待所有数据传输结束,清空输入输出缓冲区才改变属性。
*/
return 0;
}
/*
test
*/
int main(void)
{
int fd;
const char message[]="Rev:";
char buffer[256]={0};
fd = open_port();
set_serial(fd,115200,8,'N',1);
while(1)
{
if(read(fd,buffer,sizeof(buffer)) > 0)
{
write(fd,message,strlen(message));
write(fd,buffer,strlen(buffer));
memset(buffer,0,strlen(buffer));
}
}
close(fd);
return 0;
}
src/Makefile
all:Serial
OBJS = Serial.o
Serial:$(OBJS)
$(CC) $(CFLAGS) -o aaa@qq.com $(OBJS) -lpthread
clean:
rm -f Serial *.o
Makefile
include $(TOPDIR)/rules.mk#将openwrt顶层目录下的rules.mk文件中的内容导入进来
PKG_NAME:=Serial#软件包名
PKG_VERSION:=1.0#软件包版本
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)#真正编译当前软件包的目录
include $(INCLUDE_DIR)/package.mk#将$(TOPDIR)/include目录下的package.mk文件中的内容导入进来
define Package/Serial
SECTION:=wrtnode#软件包类型
CATEGORY:=WRTnode#menuconfig中软件包所属的一级目录
SUBMENU :=demos#menuconfig中软件包所属的二级目录
TITLE:=Serial test#软件包标题
DEPENDS:=+libpthread#运行本软件依赖的其他包
endef
define Package/Serial/description #软件包描述
A sample for Serial test
endef
define Build/Prepare #编译之前的准备动作
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/Serial/install #软件包的安装方法,主要就是将一系列编译好的文件、启动脚本、UCI配置文件等拷贝到指定位置
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/Serial $(1)/bin/
endef
$(eval $(call BuildPackage,Serial))
二、选中软件包
三、编译软件包
进入 OpenWrt 顶层目录,使用以下命令单独编译软件包:
make package/Serial/compile V=s
四、软件包发送到开发板并安装:
scp ~/linux/MTK/MT7628/SDK/openwrt-hiwooya/bin/ramips/packages/base/Serial_1.0_ramips_24kec.ipk aaa@qq.com:/tmp
opkg install Serial_1.0_ramips_24kec.ipk
五、测试运行软件包