前言
本篇分享:
这次将会用几篇博客分享STM32MP157实现串口接收数据上云的一个基础功能,实现STM32MP157的串口在接收到数据时能上传至服务器,让用户可以随时随地查看一个设备的实时信息。
在上一篇博客中我们已经使用minicom测试过STM32MP157的串口功能,本篇将分享如何使用电脑串口调试助手向MP157发送数据,进而实现数据上云。
知识点:
串口初始化;串口数据处理;AT指令;文件IO;多线程;MQTT协议
使用代码实现步骤:
本代码中串口通信主要分为四个步骤:
1.打开串口设备文件,获取设备句柄fd
2.配置串口的参数
3.利用select函数检测串口设备可进行读写
4.应用read、write函数实现串口读写操作
一.打开设备文件
在Linux中,设备文件一般都位于/dev下,其中连接4G模块的为STM32MP157上的串口7,设备文件为/dev/ttySTM3
首先,打开串口,得到串口设备的文件描述符,代码如下所示,这里将open函数返回的文件描述符用serportfd_PC保存
这里代码中没有直接将设备文件地址写入,而是选择在执行程序时自行传入参数,写死直接将argc[1]改为“/dev/ttySTM3”即可
open函数这里用到了三个标志,其中
O_RDWR作用为使以可读可写方式打开;
O_NOCTTY为使打开的文件不会成为该进程的控制终端。如果没有指定这个标志,那么任何一个输入都将会影响用户的进程;
O_NDELAY作用为在读取不到数据或是写入缓冲区已满会马上返回,而不会阻塞等待。
serportfd_PC = open(argv[1],O_RDWR|O_NOCTTY|O_NDELAY);
if(serportfd_PC < 0){
printf("%s open faild\r\n",argv[1]);
return -1;
}
二.串口初始化
使用STM32MP157上的串口,还需要对串口进行初始化。
在STM32库函数中对串口初始化时有USART_InitStruct串口初始化结构体,在Linux下串口驱动头文件termios.h中也有类似的结构体termios_t。
在结构体中主要对c_cflag进行配置,其中主要有波特率和数据帧格式包括数据位个数、停止位,校验位等,配置的方式多为或和与操作,具体代码如下所示:
/*头文件*/
#include <termios.h>
/*串口配置*/
bzero(ter_s,sizeof(*ter_s));//清空ter_s字符串
ter_s->c_cflag |= CLOCAL | CREAD; //激活本地连接与接受使能
ter_s->c_cflag &= ~CSIZE;//失能数据位屏蔽
/*数据帧格式设置*/
ter_s->c_cflag |= CS8;//8位数据位
ter_s->c_cflag &= ~CSTOPB;//1位停止位
ter_s->c_cflag &= ~PARENB;//无校验位
/*VTIME和VMIN都取0,即使串口读不到任何数据,函数read也会立即返回*/
ter_s->c_cc[VTIME] = 0;//设置等待时间
ter_s->c_cc[VMIN] = 0;//设置最小接收字符长度
/*波特率设置*/
cfsetispeed(ter_s,B115200);//设置输入波特率
cfsetospeed(ter_s,B115200);//设置输出波特率
/*清除串口数据*/
tcflush(serportfd_PC,TCIOFLUSH) ;//清除串口所有缓存数据
/*使串口配置生效*/
if(tcsetattr(serportfd_PC,TCSANOW,ter_s) != 0){
printf("com set error!\r\n");
return -1;
}
/*提示串口配置完成信息*/
printf("serial-PC is ready!\n");
return 0;
三.多线程
代码main函数的主循环作用是在接收到外部传输的数据使能将其通过4G模块上传至云端,代码如下:
/*主循环 处理外部设备传输的数据 并通过MQTT协议传输至云端*/
while (1)
{
/*检测到外部设备传输数据*/
if(rece_byte_flag == 1)
{
/*标志位清零*/
rece_byte_flag = 0;
printf("Successfully received data!\n");
/*数据提取*/
sscanf(rece_data,"%d",&CurrentVoltage);
/*判断数据是否有误 再决定是否上传至云端*/
send=1;
if(CurrentVoltage < 0)
{
printf("data error\n");
send=0;
}
/*数据无误*/
if(send==1)
{
/*生成AT指令*/
sprintf(send_data,"AT+MPUB=\"/sys/a1cdS8zCRA0/863488054279453/thing/event/property/post\",1,0,\"{\\22id\\22:1661139282955,\\22params\\22:{\\22CurrentVoltage\\22:%d},\\22version\\22:\\221.0\\22,\\22method\\22:\\22thing.event.property.post\\22}\"\r",CurrentVoltage);
/*向4G模块发送AT指令*/
write(serportfd_4G,send_data,strlen(send_data));
}
memset(rece_data,0,sizeof(rece_data));//清空rece_data
}
}
为了能让STM32MP157向4G模块发送AT指令时能看见其中通讯的过程,在向4G模块发送指令的同时里还需要一个循环来不断输出4G模块返回的数据。
这里增加一个线程以实现该功能。
/*头文件*/
#include <pthread.h>
/*创建线程*/
pthread_t id;
pthread_create(&id,NULL,serial_lsd,&serportfd_4G);//创建线程
/*接受串口7返回数据线程代码*/
void *serial_lsd(void *d)//接受串口7返回数据线程
{
int tfd=*(int *)d;
char rec_data[256];
fd_set rd;
while (1)
{
/*检查设备(文件描述符tfd)是否可读*/
FD_ZERO(&rd);//清空rd
FD_SET(tfd,&rd);//将tfd添加进rd中
if(select(tfd+1,&rd,NULL,NULL,NULL)<0)//检查设备是否可读
perror("select");
/*如果tfd可读 执行select后rd中tfd仍为1 FD_ISSET(tfd,&rd)成立 则读取并打印数据*/
if(FD_ISSET(tfd,&rd))//如果可读则读取并打印数据
{
while(read(tfd,rec_data,1)>0)
{
strcat(rece_data,rec_data);
}
rece_byte_flag = 1;//接收到数据标志位
}
}
}
select函数解析:
函数原型:
int select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
参数:
nfds -- 要监视的文件描述符个数
readfds -- 监视文件描述符集合中是否有可读的文件描述符 即读取是不是不阻塞了
writefds -- 监视文件描述符集合中是否有可写的文件描述符 即写入是不是不阻塞了
exceptfds -- 监视文件描述符集合中是否有出错的文件描述符
timeout -- 监视时长,NULL为无期限等待
作用:
select()函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种。
以下解释转自:https://blog.csdn.net/zujipi8736/article/details/86606093
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
执行fd_set set;FD_ZERO(&set);则set用位表示是0000,0000。
若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
若再加入fd=2,fd=1,则set变为0001,0011
执行select(6,&set,0,0,0)阻塞等待
若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
四.程序的移植和执行
将代码写好后使用交叉编译工具对.c文件进行编译(要链接pthread库),得到STM3232MP157能执行的ARM类型的可执行文件。
再利用WinSCP这样的工具将可执行文件发送至开发板,步骤为:
a.开发板连接上网络后ifconfig查看当前ip地址
b.在Ubuntu输入scp 文件名 用户名@开发板ip:保存文件路径即可
如:scp uart root@15.7.22.196:/home/root
接着,在终端输入chmod 777 uart更改文件的权限。
最后传参执行即可,第一个参数是和电脑连接的串口设备文件,第二个是和4G模块连接的串口设备文件。
使用任意的串口调试助手向STM32MP157发送数据。
进而通过4G模块传输至云平台。
登录云平台,发现设备在线并已成功接收数据。
至此,使用电脑串口调试助手向MP157发送数据,进而实现数据上云已实现。
五.源码(转载请注明出处)
结语
以上就是全部内容,如有错误请批评指正。