物联网实战--入门篇之(八)嵌入式-空气净化器
目录
一、风扇调速
二、通讯协议
三、净化器运行逻辑
一、风扇调速
单片机是不能直接驱动电机的,因为主芯片的驱动电流比较小(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研究的热门领域。 …...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
