STM32MP157实现串口接收数据上云-MP157连接4G模块和电脑


前言

本篇分享:

这次将会用几篇博客分享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发送数据,进而实现数据上云已实现。

五.源码(转载请注明出处)

在这里插入图片描述


结语

以上就是全部内容,如有错误请批评指正。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AゞOctopus๊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值