物联网实战--入门篇之(八)嵌入式-空气净化器
目录
一、风扇调速
二、通讯协议
三、净化器运行逻辑
一、风扇调速
单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(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
相关文章:
物联网实战--入门篇之(八)嵌入式-空气净化器
目录 一、风扇调速 二、通讯协议 三、净化器运行逻辑 一、风扇调速 单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(50mA左右),他们之间正常还要有个电机驱动器,常用的有TB6612、L298和L9110等,目前项目用的这个电机它…...
macOS上QT打开麦克风和摄像头的权限问题
同样的代码在Windows上可以轻松操作麦克风和摄像头,特别是用QT这种跨平台的框架。但是对macOS这种权限要求完善的系统还需要进行一些配置,那就是增加Info.plist属性配置文件。如果是之前的早期5.x版本的QTCreator因为使用的是qmake构建系统,估…...
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题
鸿蒙手机cordova-plugin-camera不能拍照和图片不显示问题 一、运行环境 1、硬件 手机型号:NOVA 7 系统:HarmonyOS版本 4.0.0 2、软件 android SDK platforms:14.0(API Level 34)、13.0(API Level 33) SDK Build-T…...
Spring源码解析上
spring源码解析 整体架构 defaultListableBeanFactory xmlBeanDefinitionReader 创建XmlBeanFactory 对资源文件进行加载–Resource 利用LoadBeandefinitions(resource)方法加载配置中的bean loadBeandefinitions加载步骤 doLoadBeanDefinition xml配置模式 validationMode 获…...
第九题:最大间隙
题目描述 给定一个序列 a1,a2,⋯ ,an。其中 a1≤a2≤⋯≤an。 相邻两个数之间的差(后一个数减前一个数)称为它们的间隙。 请问序列中最大的间隙值是多少? 输入描述 输入的第一行包含一个整数 n,表示序列的长度。 第二行包含…...
【随笔】Git -- 高级命令(中篇)(七)
💌 所属专栏:【Git】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! 💖 欢迎大…...
可视化大屏 - 项目1
文章目录 技术栈echarts 可视化需求分析代码实现 技术栈 flexible.js rem 实现不同终端下的响应式布局,根据不同屏幕宽度,自适配布局; html中引入index.js,可以改名为flexible.js;默认划分10份,可以自己修…...
Collection与数据结构 链表与LinkedList(三):链表精选OJ例题(下)
1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…...
如何通过C++身份证实名认证接口实现实名认证功能
线上平台使用身份核验过程是验证个人身份真实性的过程,对于大多数线上平台来说,自己去开发集成身份证实名认证接口需要耗费大量的人力、物力成本,对此,为助力有需要的企业快速实现实名认证的功能,翔云平台提供了身份证…...
用html写一个爱心
<!DOCTYPE html> <html lang"zh-CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><title>爱您</title><style>* {padding: 0;margin: 0;}body {background-color: pin…...
如何看到 synchronized 背后的“monitor 锁”?
Java全能学习+面试指南:https://javaxiaobear.cn 获取和释放 monitor 锁的时机 我们都知道,最简单的同步方式就是利用 synchronized 关键字来修饰代码块或者修饰一个方法,那么这部分被保护的代码,在同一时刻就最多只有一个线程可以运行,而 synchronized 的背后正是利用 …...
如何建立一个网页模版
创建一个网页模板涉及的主要步骤如下: 基本HTML结构模板创建: 创建HTML文件: 首先,你需要创建一个新的HTML文件,并在其中编写基本的HTML结构,例如: <!DOCTYPE html> <html lang="zh"> <head><meta charset="UTF-8"...
P8783 [蓝桥杯 2022 省 B] 统计子矩阵
题目:P8783 [蓝桥杯 2022 省 B] 统计子矩阵 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 代码:(部分解析在代码中) #include<bits/stdc.h> using namespace std; long long a[1010][1010]; long long pre[1010][1010]; long long …...
【C++】list介绍
个人主页 : zxctscl 如有转载请先通知 文章目录 1. list介绍2. list的构造3. ist iterator的使用4. capacity5. element access6. modifiers7. 迭代器失效8. Operations8.1 reverse8.2 sort8.3 unique8.4 splice 1. list介绍 list是可以在常数范围内在任意位置进行插…...
【SQL Server】2. 将数据导入导出到Excel表格当中
最开始,博主介绍一下自己的环境:SQL Sever 2008 R2 SQL Sever 大致都差不多 1. 通过自带软件的方式 首先找到下载SQL Sever中提供的导入导出工具 如果开始界面没有找到自己下载的路径 C:\Program Files\Microsoft SQL Server\100\DTS\Binn下的DTSWiz…...
基于JAVA+SSM+VUE的前后端分离的大学竞赛管理系统
一、项目背景介绍: 随着互联网技术的快速发展,大学竞赛管理系统已经成为了各个高校组织和管理各类学术竞赛的重要工具。传统的大学竞赛管理系统往往采用前后端混合的开发模式,导致系统的性能和可维护性受到限制。为了提高系统的开发效率和用户…...
音频转换工具 Bigasoft FLAC Converter for Mac
Bigasoft FLAC Converter for Mac是一款专为Mac用户设计的音频转换工具,它能够将FLAC音频文件高效、高质量地转换为其他常见的音频格式,如MP3、AAC等。这款软件具有直观易用的界面,使用户能够轻松上手,无需复杂的操作步骤即可完成…...
洛谷 P4554 小明的游戏
思路:双端队列。 其实一开始你可以用BFS进行实验,由于我们需要找最小的费用,所以我们在BFS的时候可以这样想:在我们遍历到第一块板子的时候,在找周围的路时,我们可以改成这样的判断:如果周围的…...
序列化案例实操(统计每一个手机号耗费的总上行流量、总下行流量、总流量)
文章目录 序列化概述自定义bean对象实现序列化接口(Writable)案例需求编写MapReduce程序运行结果 序列化概述 序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化&…...
使用 LLMLingua-2 压缩 GPT-4 和 Claude 提示
原文地址:Compress GPT-4 and Claude prompts with LLMLingua-2 2024 年 4 月 1 日 向大型语言模型(LLM)发送的提示长度越短,推理速度就会越快,成本也会越低。因此,提示压缩已经成为LLM研究的热门领域。 …...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
