物联网实战--入门篇之(八)嵌入式-空气净化器

目录

一、风扇调速

二、通讯协议

三、净化器运行逻辑


一、风扇调速

        单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(50mA左右),他们之间正常还要有个电机驱动器,常用的有TB6612、L298和L9110等,目前项目用的这个电机它是内置了驱动器的,什么型号不清楚,作为应用层只要给个PWM信号就行了。

        PWM基本原理就是通过控制开关的时长进行调速,STM32通过定时器发生器,可以把开关周期控制在毫秒以内,这样我们宏观上就不会有卡顿的感觉了。

        下面是具体的代码,这些代码都比较常规,要注意的是PWM输出要手动开启TIM_CtrlPWMOutputs(TIM1, ENABLE),可能是PA8引脚与串口1的初始化有冲突了。

/*		
================================================================================
描述 : 风扇电机初始化
输入 : 
输出 : 
================================================================================
*/
void app_motor_init(void)
{
// 使能TIM1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 设置GPIOA_8为复用功能推挽输出GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化TIM1 PWM模式TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_Period = PWMPeriodValue-1; // 周期为10kTIM_TimeBaseStructure.TIM_Prescaler = 720 - 1; // 预分频器设置为7199,确保计数器的频率为1MHzTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性选择TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能TIM_OC1Init(TIM1, &TIM_OCInitStructure);//初始化 TIM1 OC1TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);//使能CCR1自动重装TIM_ARRPreloadConfig(TIM1,ENABLE);//开启预装载  TIM_CtrlPWMOutputs(TIM1, ENABLE);//手动开启,防止与串口1冲突后不启动// 使能TIM1的输出比较预装载寄存器TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);// 使能TIM1TIM_Cmd(TIM1, ENABLE);  printf("app_motor_init ok!\n");
}

        在使用上就很简单了,就是不断改变PWM值就行了,如下所示。这里还有个系数0.6主要是为了防止电流过大,影响主控设备稳定。

/*		
================================================================================
描述 : 设置速度
输入 : speed 0~255,速度分为256级
输出 : 
================================================================================
*/
void app_motor_set_speed(u8 speed)
{g_sAirWork.fan_speed=speed;u16 value=speed*PWMPeriodValue/255*0.6;//系数主要是防止电机电流过大影响设备稳定printf("pwm val=%d\n", value);TIM_SetCompare1(TIM1, value);
}

二、通讯协议

        这里的通讯协议是指在MQTT之上的应用层通讯协议,属于我们自定义的内容,由此我们也可以知道,协议也是一层一层堆起来的,每个场景有各自适合的协议。通讯协议在物联网系统里是最重要的,如果交流语言都不通了,还谈什么联网。

        自定义协议满足自己的要求即可,但是我们的要求也不能太低,至少要满足以下几个要求:

1、二进制传输,比较高效、省流量,这在使用4G流量卡的时候就很关键了;

2、易检索,可以在一堆数据包里找到明显特征并解析,可以解决粘包问题;

3、正确性,要有校验码,确保数据正确;

4、方便代码书写,这样可以在各类系统中使用;

5、没有网络大小端问题,这是早期很多人用结构体传输时候经常碰到的问题。

        上图是基本的协议框架,包含了帧头、数据长度、设备码、命令和校验码等关键通用的信息,需要注意的是,这里整形数据都采用高字节先传输的原则,比如数据总长Len,先传输Len的高8位,再传输低8位,具体的整合代码如下:

        这里面有个入口参数cmd_type,根据这个项目的定义如下。

        在实际使用的时候举例如下,把自己应用层的数据按你自己的顺序要求打包好发送就行了。

        细心的同学会发现,上图中在传输温度数据时候比较特别,先把数值乘以10再加1000,为什么要这么操作?主要是为了保证传输的数据都是正整数,避免了网络大小端的问题,这里的乘以10是保留小数点后一位,传感器返回的数据最小是-45.0,乘以10就是-450,再加上1000就可以保证这个数值是正整数,最后再把这个正整数高8位、低8位依次存进数组内。对于接收端,解析就是一个逆向过程了,具体如下图所示,获取到原始数据后先减1000再除以10.0,这里要记得是10.0而不是10,这样才能保持小数。

        对于接收端,就是按照协议一步步解析即可,代码很简洁、模式很固定的,具体的可以工程项目打开来看看。


/*		
================================================================================
描述 : 设备解析服务器下发的数据
输入 : 
输出 : 
================================================================================
*/
void app_air_recv_parse(u8 *buff, u16 len)
{u8 head[2]={0xAA, 0x55};u8 *pData=memstr(buff, len, head, 2);if(pData!=NULL){u16 total_len=pData[2]<<8 | pData[3];u16 crcValue=pData[total_len]<<8 | pData[total_len+1];if(crcValue==drv_crc16(pData, total_len)){pData+=4;u32 device_sn=pData[0]<<24|pData[1]<<16|pData[2]<<8|pData[3];pData+=4;if(device_sn!=g_sAirWork.device_sn)//识别码确认return;u8 cmd_type=pData[0];pData++;switch(cmd_type){case AIR_CMD_HEART://心跳包{break;}case AIR_CMD_DATA://数据包{break;}case AIR_CMD_SET_SPEED://设置风速{u8 speed=pData[0];pData+=1;app_motor_set_speed(speed);break;}        case AIR_CMD_SET_SWITCH://设置开关{u8 state=pData[0];pData+=1;g_sAirWork.switch_state=state;if(state>0){app_motor_set_speed(100);//启动风扇}else{app_motor_set_speed(0);//停止风扇}app_air_send_status();break;}}}}
}

三、净化器运行逻辑

        到目前为止,嵌入式端的各个模块基本上讲解完成了,剩下的就是如何把他们整合起来的问题了。从任务上来讲就三个部分:一是通讯连接,二是传感数据采集和发送,三是风速和开关控制。这里面任务最繁忙的要数通讯连接了,要驱动WiFi连接以及MQTT的运行,比较庞大,理论上要用RT-Thread单独为它创建个任务,但是这里由于传感数据采集内容较为简单,这里就不那么麻烦了,直接放一起就好了。对于风扇和开关控制属于被动的,其实已经在数据解析里完成了,即跟MQTT主程序同一个任务。总的来讲,就是下图这个任务了,对照着注释看,很简单。

        这样,整个项目的嵌入式部分就讲解完成了,接下来继续讲解的是手机端开发的内容了。

        

   本项目的交流QQ群:701889554

   写于2024-4-1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/585601.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis基础数据结构

文章目录 前言字符串常见命令内部编码使用场景1、缓存&#xff08;Cache&#xff09;功能2、计数3、共享Session4、限速 哈希命令内部编码使用场景存储结构化数据 列表命令内部编码使用场景1.阻塞消息队列模型2.文章列表3.微博 Timeline 集合命令内部编码使用场景1.给用户增加标…

Pytorch数据结构:Tensor

文章目录 Tensor基础1.1、Tensor的维度&#xff08;Dimensions&#xff09;1.1.1、举例说明1.1.2、高维Tensor 1.2、.dim()和.size()方法1.2.1、.dim()方法1.2.2、.size()方法1.2.3、.shape属性1.2.3、示例代码1.2.3.1、一维Tensor1.2.3.2、二维Tensor1.2.3.3、三维Tensor 1.3、…

PTA_语法入门赛

文章目录 7-1 格式化数字的显示-简单版7-2 三角形判定7-3 表面积和体积7-4 特殊数列求和7-5 矩阵中的鞍点7-6 反素数7-7 ISBN转换 题源&#xff1a;https://pintia.cn/problem-sets/1768428576024760320/overview 7-1 格式化数字的显示-简单版 在金融领域对金额之类的数字&am…

主流公链 - Fantom

Fantom&#xff1a;高性能的区块链协议 Fantom是一种开创性的区块链协议&#xff0c;旨在革新去中心化应用和数字金融领域 技术特点 共识机制 Lachesis协议&#xff1a;Fantom使用了Lachesis协议作为其共识算法。Lachesis是一种 异步拜占庭容错&#xff08;ABFT&#xff09;共…

java数据结构与算法刷题-----LeetCode200. 岛屿数量

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 深度优先遍历 深度优先遍历 解题思路&#xff1a;时间复杂度O( …

Reversing Linked List

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K3, then you must output 3→2→1→6→5→4; if K4, you must output 4→3→2→1→5→6. Input Specifi…

软考 系统架构设计师系列知识点之云原生架构设计理论与实践(13)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之云原生架构设计理论与实践&#xff08;12&#xff09; 所属章节&#xff1a; 第14章. 云原生架构设计理论与实践 第3节 云原生架构相关技术 14.3.2 云原生微服务 1. 微服务发展背景 过去开发一个后端应用最为直接的方…

2023年第十四届蓝桥杯 - 省赛 - Python研究生组 - A.工作时长

题目 数据文件&#xff1a;https://labfile.oss.aliyuncs.com/courses/21074/records.txt Idea 直接通过 datetime 模块加载时间字符串进行格式化&#xff0c;然后对时间列表进行排序&#xff0c;最后两两计算时间差。 Code Python from datetime import datetimetime_lis…

在js中本地存储的数组如何转成对象

一、此方法仅适用一维数组&#xff1b; 二、效果图 使用后 三、js代码。 function gong(s){console.log(s);let data;let kk1;// 检查ask_id是否不为空 if (s.ask_id null ) { kk1}else{kk2let dd;dds.data;sessionStorage.setItem(wenda,JSON.stringify(dd[0]))window.l…

【Frida】【Android】08_爬虫之网络通信库okhttp3

&#x1f6eb; 系列文章导航 【Frida】【Android】01_手把手教你环境搭建 https://blog.csdn.net/kinghzking/article/details/136986950【Frida】【Android】02_JAVA层HOOK https://blog.csdn.net/kinghzking/article/details/137008446【Frida】【Android】03_RPC https://bl…

基于深度学习的停车场车辆检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 上图测试结果如下图所示&#xff1a; 2.算法运行软件版本 matlab2022a 3.部分核心程序 image imread(image_test\test.jpg); image2 image;%图…

HUAWEI 华为交换机 配置 Eth-Trunk 接口流量本地优先转发示例(堆叠)

组网需求 说明 S5720I-10X-PWH-SI-AC 和 S5720I-6X-PWH-SI-AC 不支持此配置。 如 图 3-23 所示&#xff0c;为了增加设备的容量采用设备堆叠技术&#xff0c;将 Switch3 和 Switch4通过专用的堆叠电缆链接起来&#xff0c;对外呈现为一台逻辑交换机。为了实现设备间的备份、…