【训练营_进阶班】卷帘大将 - 嘉立创EDA开源硬件平台

编辑器版本 ×
标准版 Standard

1、简单易用,可快速上手

2、流畅支持300个器件或1000个焊盘以下的设计规模

3、支持简单的电路仿真

4、面向学生、老师、创客

专业版 professional

1、全新的交互和界面

2、流畅支持超过3w器件或10w焊盘的设计规模,支持面板和外壳设计

3、更严谨的设计约束,更规范的流程

4、面向企业、更专业的用户

标准版 【训练营_进阶班】卷帘大将

简介:该项目旨在开发一款电动窗帘设备。 设备使用STM32单片机做主控,通过控制编码器电机正反转实现窗帘的电动开合, 并通过EMW3080接入阿里云物联网平台,实现本地/云端控制。

开源协议: CC-BY-NC 3.0

(未经作者授权,禁止转载)

创建时间: 2020-08-08 09:39:57
更新时间: 2022-01-10 14:49:36
描述
# 卷帘大将 注: 该工程描述文件同说明文档,可下载附件“卷帘大将\_电动窗帘\_说明文档\.pdf”查看。 工程代码可下载附件 “Code_RollerBlindGeneral.zip” 查看。 配网、配网过程意外断电重启、联网控制演示视频已上传,可下拉至文档下方查看。 PDF文件内置超链接,可直接点击跳转Datasheet等文件。 作者:OpticalMoe 日期:2020/08/23 **高清靓照:** ![高清靓照](//image.lceda.cn/pullimage/tt9Gt019af0zH57yrO0ZjlQayn9U7HHcOQHQd1Fs.jpeg) ![高清靓照](//image.lceda.cn/pullimage/tB0X6Mf8gPZb8J2RTdaCO1SiJmoS9jE9GKuq7UKr.jpeg) ![高清靓照](//image.lceda.cn/pullimage/36tDIgylKyeyQr9IdaXQwdQnunZAsLQJmvqVpqEm.jpeg) - - - ## 前 言 该项目旨在开发一款电动窗帘设备。 设备使用STM32单片机做主控,通过控制编码器电机正反转实现窗帘的电动开合,并通过EMW3080接入阿里云物联网平台,实现本地/云端控制。 * 电源:采用LP6498芯片,设计输出5V@1A。LDO采用HX9193,设计输出3.3V。 * WIFI:采用EMW3080(阿里飞燕固件),可接入阿里云生活物联网平台。 * 电机驱动:配有AB相编码器接口,可实现电机的位置环、速度环PID控制;驱动芯片采用RZ7899,支持25V@3A(最大5A);另配置了一限位开关接口,防止窗帘超限位运行损坏。 * 外设:配有无源蜂鸣器,通过TIM定时器控制,可奏乐;两个LED指示灯用于指示WIFI联网状态和设备运行状态;光敏电阻和NTC热敏电阻,可反馈光照和温度;两枚按键,单键可手动控制窗帘的上下行,双键可进入配网模式。 - - - ## 使用方法 **一、配网** 1. 上电后任意时刻,同时按动两按键两秒(先后按动两按键也可识别)。 2. 设备奏乐“ Bi~~~ Pu ”,开始配网流程。蓝色、绿色指示灯快闪。 3. 手机打开“云智慧”,扫码后,按提示开始配网。(扫码可下载APP)。 4. 等待5s后设备奏乐“嘀嘀嘀”三声,设备开启AP热点。 5. 手机端输入设备将要连接的家庭路由器名称和密码,点击“开始连接”,开始配网。(低版本安卓系统可直接接入adh_xxx热点,高版本安卓需手动连接该热点,热点连接成功后会断开,返回APP界面即可)。 6. 耐心等待设备上云。若过程中设备奏乐“ 滴~~~~ ”表示出错,可以断电重启后从第2步重试。 7. 当设备配网成功后,奏乐“ 1234567 ”,蓝色、绿色指示灯慢闪。 注:在配网过程中任意时刻意外断电导致设备配网失败,下次上电自动进入配网模式。从第2步开始依次执行配网操作直至配网完成。 **二、联网控制** * 设备配网后可实现联网控制。 * 设备联网成功后奏乐“123”,蓝色指示灯开始慢闪。 * 按动上键或下键,窗帘匀速上行或下行,松手后,APP端自动刷新窗帘位置。 * APP端滑动窗帘位置滑块,窗帘运行到指定位置停止并锁定。 * 点击APP端“快捷操作”,可直接控制窗帘到达预设位置。 * 点击APP端“状态信息”,可查看设备温度、电压、光强等数据。 * 配网二维码:(未安装APP可扫码下载) ![配网二维码](//image.lceda.cn/pullimage/O4aYkeqtUe24zm9r3ofC6xUinMX86mKcFOnT0dBV.png) - - - **目 录** **一 器件选型** * 电源 * MCU * WIFI * 电机驱动 * 外设 **二 原理图设计** * 电源 * MCU * EMW3080 * 电机驱动 * 外设 **三 PCB设计** * 电源&电机驱动 * MCU * EMW3080 * 外设 **四 焊接** **五 APP设计** **六 程序调试** * 代码移植&上传数据 * ADC&DMA采样 * 蜂鸣器驱动 * PID及参数整定 * 按键控制 * 任务/消息调度器改写 * 配网模式 **结论** - - - ## 一 器件选型 本次活动要求设计一款物联网设备。为了控制成本,器件选型尽可能地选择性价比高的器件。 ### 1.电源 * **电源输入插座** 采用DC005插座,设计可承受30V@3A。 Datasheet:[DC005-30A](https://atta.szlcsc.com/upload/public/pdf/source/20181207/C111573_8ADF7A9E2DA38C4FFF507DB908EB4EB9.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=fzDLrz83vRIAgK64gTsoNgSTFnE%3D&response-content-disposition=attachment%3Bfilename%3DC111573_DC%25E8%25BF%259E%25E6%258E%25A5%25E5%2599%25A8%252FDC005-2.5MMA%25E7%25BA%25A7_2018-12-07.PDF) 商城编号:C111573 封装:DC005-T25 输入:30V(最大) 电流:3A(最大) 注意选用A级插座,并注意可承受的电压电流是否满足。 * **DCDC** 采用LP6498AB6F芯片,设计输出5.12V@1A。 Datasheet:[LP6498](https://atta.szlcsc.com/upload/public/pdf/source/20190410/C387722_5E8EF9F8DFA2C79D78906FD8B2280BF7.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=MEOCe68loWFcaP42nXQBgiJbcFQ%3D&response-content-disposition=attachment%3Bfilename%3DC387722_LP6498AB6F_2019-04-10.PDF) 商城编号:C387722 封装:SOT23-6 输入:4.5 ~ 30V 输出:4.8 ~ 12V 电流:1200mA(最大) 该芯片耐压高,输入、输出电压范围宽,电流大。体积小,外围电路简单,输出电压可调。便宜皮实,性价比高。 * **LDO** 采用HX9193-33GB,设计输出3.3V@600mA。 Datasheet:[HX9193-33GB](https://atta.szlcsc.com/upload/public/pdf/source/20181113/C296123_247B444685EF4D8999014683EA1AF591.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=XVOQdquv%2FDEuNQwCCuEmU%2F3mrlE%3D&response-content-disposition=attachment%3Bfilename%3DC296123_%25E4%25B8%2589%25E7%25AB%25AF%25E7%25A8%25B3%25E5%258E%258BICHX9193-33GB_2018-11-13.PDF) 商城编号:C296123 封装:SOT-23-5 输入:6V(最大) 输出:3.3V(固定) 电流:600mA(最大) 压降:480mV(最大) 该芯片电流大,压降小。体积小,外围电路简单。便宜皮实,性价比高。 - - - ### 2\. MCU MCU采用 **STM32F030K6** 单片机。 Datasheet:[STM32F030K6T6](https://atta.szlcsc.com/upload/public/pdf/source/20190902/C106925_4C89CDEE905DCB71B11CF5798678D860.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=xy8f9QNRqyJ5D0XPnevyawZD%2BDA%3D&response-content-disposition=attachment%3Bfilename%3DC88446_STM32F030K6T6TR_2019-09-02.PDF) 商城编号:C88446 封装:LQFP32 选用这款单片机的主要原因是 ~~便宜~~ 性价比高。同时STM32芯片可以使用 ST-Link 连接 Keil 在线DEBUG,也可以使用 **STM32CubeMonitor** 软件打印内部变量变化曲线,方便PID调试。 这款单片拥有32KB FLASH,4KB RAM,48MHz的主频,LQFP-32的封装,一个串口,5个定时器,一个10通道12bit AD,26个IO。可谓是小巧精悍,实力不凡。 > 原本计划上RTOS的,但是4KB的RAM跑OS有点勉强,稍稍加点东西就超,最后没跑上。 > 自己做的ST-Link V2-1,成本低,性能强,比某宝盗版J-Link采样频率高。 - - - ### 3\. WIFI **WIFI** 选用的是EMW3080V2(阿里云飞燕固件)。WIFI选型没有经验,全跟课程走。 - - - ### 4.电机驱动 * **电机驱动** 部分采用RZ7899驱动芯片。 Datasheet:[RZ7899](https://atta.szlcsc.com/upload/public/pdf/source/20170213/1486965283321.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=h0oQds3tRKJPlhUe0RfGmyCNW3s%3D&response-content-disposition=attachment%3Bfilename%3DC92373_RZ7899_2017-02-13.PDF) 商城编号:C92373 封装:SOP-8_150mil 输入:3 ~ 25V 电流:3A 峰值电流:5A 内建刹车功能、内置过温保护、内置短路保护、内置过流保护。 * **电流传感器** 采用CC6900SO-5A芯片。 Datasheet:[CC6900SO-5A](https://atta.szlcsc.com/upload/public/pdf/source/20181213/C350864_3935909D6FCF7E5436F1F062F69C3E0E.pdf?Expires=4070880000&OSSAccessKeyId=LTAIJDIkh7KmGS1H&Signature=YiwemN7QFvwhXSYo58SSxDWYTZg%3D&response-content-disposition=attachment%3Bfilename%3DC350864_CC6900SO-5A_2018-12-13.PDF) 商城编号:C350864 封装:SOP-8 增益:400mV/A 电流:5A - - - ### 5.外设 外设部分设计有:一个无源蜂鸣器,两个按键,两个LED指示灯。编码器接口,限位开关接口。 - - - ## 二 原理图设计 根据个人的设计习惯,原理图按功能划分,设计在5张A4图纸上。下面依次介绍。 ### 1.电源 电源部分主要分为四块。分别是:**电源输入插座、DCDC降压、LDO降压、测试点**。 **电源输入插座** 正极先通过SS54二极管,再接入设备。 **DCDC** 和 **LDO** 部分按照官方手册绘制就可。 ![原理图-电源](//image.lceda.cn/pullimage/TfS9fWFkqElvlpGMhXy1OhqRPhmQCRo8WUjirExt.png) ``` 原理图-电源 ``` - - - ### 2\. MCU MCU部分主要设计 **晶振电路,复位电路,SWD下载接口**。 **晶振** 采用SMD-3225封装的8MHz无源晶振,该封装对烙铁焊接不友好。晶振电路主要由晶振和两个22pF无极性陶瓷电容构成。 **复位电路** 由10k上拉电阻和0.1uF电容构成,主要完成上电复位功能。 **SWD接口** 用于调试和下载程序,引出了SWCLK、SWDIO、NRST,采用XH2.5-4P端子接口。引出NRST引脚,即使程序中未使能SWD调试接口仍能下载、调试程序。 ![原理图-MCU](//image.lceda.cn/pullimage/hg2rVWtJXxy3BMnuJYrH8e8REWiBzdpXBCSY49Qh.png) ``` 原理图-MCU ``` - - - ### 3\. EMW3080 EMW3080电路主要包括 **电源滤波、串口、BOOT、测试点**。 **电源滤波** 采用0.1uF和10uF组合的形式;根据手册要求,电源采用3.3V。 **串口** 通过0R电阻交叉连接到MCU串口;GPIO23根据手册要求通过10k上拉; **BOOT** 引脚预留0R电阻接地,但不焊接;EN引脚通过0R电阻连接到MCU和按键,主要完成WIFI的复位工作。 **测试点** 包括串口的TXD和RXD接口。调试时连接串口,可监视MCU和WIFI间交换的所有数据。 > 连接外部串口监视数据时,MCU串口需设置为开漏+上拉模式,否则会导致MCU与WIFI间数据乱码。 ![原理图-EMW3080](//image.lceda.cn/pullimage/lhAjgH3Gm265FYJvEWrJLNM1Yp15QaOe0paqfH6A.png) ``` 原理图-EMW3080 ``` - - - ### 4\. 电机驱动 电机驱动部分主要完成 **电流传感器电流采样、电源电压采样、电机驱动、测试点**。 **电源电压采样** 采用分压电阻结构,通过100k和10k电阻获得低的采样电压送入MCU-ADC接口。 **电流采样** 按照CC6900SO-5A官方手册绘制即可。 **电机驱动芯片** 按照官方手册绘制,注意输入和输出接口走线宽度。同时在电机接口上设计四个二极管钳位。电机采用5.0-2P接口,方便拆装。 **测试点** 主要有电流采样点、电压采样点、电机驱动正反转信号点,便于调试时确定状态。 注意功率地与信号地分开,并连接 ![原理图-电机驱动](//image.lceda.cn/pullimage/Tt0260ZeDmawoDoUiOKyoBqxZ2NyzoGOoJie5f4X.png) ``` 原理图-电机驱动 ``` - - - ### 5\. 外设 外设主要设计 **无源蜂鸣器、光敏电阻、热敏电阻、编码器接口、按键、LED指示灯、测试点、机械孔**。 **无源蜂鸣器** 需连接到TIM-PWM输出引脚,可以通过调整TIM装载值和比较值控制蜂鸣器音调和音量。 **热敏电阻** 和 **光敏电阻** 需要串联一个已知阻值的电阻接入电路,通过MCU-ADC测量中间点电压反向推算出外部温度和光强。 > 热敏电阻和光敏电阻测量精度非常有限,即使程序中加入修正,采样值仍可能和实际值偏差较大。对温度和光强精度要求高的场所慎用。 **编码器接口** 是为了电机的位置环、速度环PID设计,可连接AB相编码器。接口内已设计上拉电阻和硬件消抖电路,编码器电源通过两个0R电阻在5V和3.3V间选择,注意不可同时连接5V和3.3V电阻。 **按键** 用于控制窗帘的上拉、下拉动作,同时在必要时刻充当配网开关。 **蓝色LED指示灯** 用于指示WIFI连接状态,**绿色LED** 用于指示设备运行状态。 **测试点** 可测量光敏电阻和热敏电阻输出电压。 **机械孔** 是四个M3螺丝孔,方便设备通过螺丝安装在需要的地方。 ![原理图-外设](//image.lceda.cn/pullimage/nv3PnkDgL1C5qx8eAa93J5oJDLq2WQ0ISTHGDN2U.png) ``` 原理图-外设 ``` - - - ## 三 PCB设计 PCB设计经验不足,在此抛砖引玉。如有错误之处,还望大佬不惜赐教。 ![PCB效果图](//image.lceda.cn/pullimage/1mXDSHXZxVGB70g22QDLD4krlMLdb7WxIjbA0uFU.png) ``` PCB效果图 ``` - - - ### 1\. 电源&电机驱动 **电源** 和 **电机驱动** 主要注意走线宽度、功率地和信号地分开、端子下面挖空防止接地短路等。 ![PCB-电源&电机驱动](//image.lceda.cn/pullimage/i5HsjL5xzMk9M1YQQkGj7kFMmvywm0bXYFHKldQg.png) ``` PCB-电源&电机驱动 ``` 左侧为 **LDO**,右侧为 **DCDC**。注意电感离DCDC芯片近一些,电感下面不要走信号线。(此图为错误示范) ![PCB-DCDC&LDO](//image.lceda.cn/pullimage/wFLNddjtHocm0miJWRFr75xTnIVztfvMB2XNmxgp.png) ``` PCB-DCDC&LDO ``` - - - ### 2\. MCU MCU主要注意晶振连线短一些,滤波电容靠近MCU电源引脚。 ![PCB-MCU](//image.lceda.cn/pullimage/KZ7yxzw3HWy2zTB1yw2AGIYLiyQbY17t6xAlTv3e.png) ``` PCB-MCU ``` - - - ### 3\. EMW3080 EMW3080按照官方手册要求,1、2、24、25脚不接,天线前方、左右留16mm净空区。搜索EDA中所有的封装都不完全满足官方手册要求,我自己画了一个。 ![PCB-EMW3080](//image.lceda.cn/pullimage/qr46IvUmW0ePuPrHv7rodVwsbzogx7fcucldQrpu.png) ``` PCB-EMW3080 ``` - - - ### 4\. 外设 **热敏** 避开发热区域;**光敏** 避开LED区域;**编码器接口** 放在电机端子旁边,方便连接;**按键** 和 **LED指示灯** 放在板子下方,方便操作。 ![PCB-外设](//image.lceda.cn/pullimage/USJQhyT4ZAM4QuUusiuqtmQQ1LFPPATdZiAugjQU.png) ``` PCB-外设 ``` - - - ## 四 焊接 拿到PCB,准备焊接工具,开始焊接。 ![PCB](//image.lceda.cn/pullimage/2aQLCMKoi6bwNuJz1BouIrdH6GU0pnpuATcyA0Dr.jpeg) ``` PCB ``` 因为部分PCB中有一些封装对烙铁十分不友好。所以,上风枪。 ![工具](//image.lceda.cn/pullimage/5xdQvoVY128rhaH1TMxB917hdYvBIjiEnsmjiBld.jpeg) ``` 工具 ``` 下面简述下焊接步骤和注意事项。 * 首先,准备0.5mm左右的焊锡丝、焊锡膏、助焊剂。清理烙铁头,烙铁温度350℃。尖嘴镊子。提前释放身上静电。 * 第一步,焊接DCDC芯片及外围电路。电感封装问题,只能用风枪和焊锡膏焊。焊接完成后,焊接DC005接口。接入12V电源,使用万用表电压档测量5V测试点电压是否在5.12V左右。若电压不正确,需核对反馈电阻阻值是否正确。 * 第二步,焊接LDO电路。焊完后上电测试输出电压是否在3.3V左右。 * 第三步,电源没有问题后,焊接其他元件。顺序没有要求,一般由高度低的元件开始焊接。 单片机可以使用针管挤焊锡膏在焊盘上,摆好单片机,烙铁走一遍就能焊好,不连锡,贼好用。 电容焊盘也较短,需要焊锡膏和烙铁配合焊接。 PCB注意有几个元件不能焊接。分别是:编码器电源5V处0R电阻,EMW3080的BOOT接地电阻。 焊接完成后,效果如下。 ![实物图](//image.lceda.cn/pullimage/B5OSsPPBub4zktbGxyPzaDh9r43sl0OD4t872rkS.jpeg) ``` 实物图 ``` - - - ## 五 APP设计 APP设计采用阿里云物联网平台。具体过程可参考[B站课程回放](https://www.bilibili.com/video/BV1uC4y1t7KH) 一些属性参数如下:(部分功能未使用) ![属性参数](//image.lceda.cn/pullimage/HsWQ53XBjWaXkvRBPkdqTSpYXMl11yWYCegdqAu5.png) ``` 属性参数 ``` ![三元组信息](//image.lceda.cn/pullimage/LqkYJQjeB8uQ1TrQPcrVh11uVQeKLIEkxRAEBPew.png) ``` 三元组信息 ``` ![APP主界面](//image.lceda.cn/pullimage/PlCI7GGAFrB0f094ssI0SdaWU9XRtFGl2mOLmvpx.png) ``` APP主界面 ``` - - - ## 六 程序调试 程序调试主要按功能块调试。调试日志按以下顺序依次进行:**代码移植、上传数据、蜂鸣器驱动、ADC&DMA采样、PID&参数整定、按键控制、任务调度器改写、配网模式**。 ### 1\. 代码移植&上传数据 零妖大佬给的例程是基于51单片机。51程序和STM32不兼容,需要移植一些底层代码。代码平台 **CubeMX&HAL** 库,**MDK-ARM 5.27** 。 > 移植需要一定的软件操作基础,回忆的过程,不完整。 > 工程代码可移步附件下载查看。 移植前可通过串口先让WIFI上云,减小移植难度。 首先打开 **CubeMX** 软件,选择 **STM32F030K6T6** ,使能外部晶振,使能SWD接口。勾选必要的外设。设置时钟48MHz。填写工程名称,保存位置。选择使用的IDE为MDK-ARM 5.27,勾选“为每一个外设生成.c/.h文件”。点击“生成代码”。 ![引脚配置](//image.lceda.cn/pullimage/kjWOid8ZWm2g39pPMhvdJnmLvz2mZI7TcwZ3YqzI.png) ``` 引脚配置 ``` ![时钟树](//image.lceda.cn/pullimage/51rKAZh4WLQOONtZsItjFbR3TaWWuVq5QG4V0gmW.png) ``` 时钟树 ``` 代码生成后,点击“打开工程”,自动调用Keil软件。 首先,在keil左侧Project中添加一个文件夹,用来存放我们的.c文件。双击该文件夹,加入Code_User文件夹下所有文件。 然后,点击 **魔术棒** ,点击“C/C++”选项卡,点击“Include Paths”后面三点,添加“Code_User”文件夹路径。 编译文件,不出意外,您会收获 **error(s)** 。 下面开始解决这些错误: 1. 大多数错误是由于 **#include \** 造成的,这是51的头文件,32不使用,**删除** 所有该语句。 2. **Button.c** 文件实现按键的短按、长按识别。该设备只需识别单按键和双按键,**修改** 其中的**Button_Loop** 函数。 3. **DeviceName.c** 文件操作三元组数据。我们把三元组数据移植到 **usart.c** 文件下,**删除** 该文件。 4. **DS18B20.c** 文件用于读取温度传感器数据。我们温度采用热敏电阻配合ADC,不涉及该文件,**删除**。 5. **IAP_EEPROM.c** 文件操作 **EEPROM**。32没有,**删除** 文件。 6. **main.c** 文件是设备主逻辑实现。复制内容到CubeMX创建的 **main.c** 文件中,**删除** 该文件。 7. **Mode.c** 文件操作LED和继电器。我们没有继电器,LED灯移植到 **WIFI.c** 文件下,**删除** 该文件。 8. **Relay.c** 文件操作继电器,**删除** 。 9. **Timer0.c** 文件实现任务调度器,需要修改定时器底层。**删除** 定时器初始化结尾前代码,并添加“**HAL\_TIM\_Base\_Start\_IT\(&htim17\);**”启动定时器。 10. **Uart_1.c** 文件用于转发串口2数据到电脑。**STM32F030K6** 只有一个串口,**删除** 该文件。 11. **Uart2.c** 文件主要和WIFI交换数据。**修改** 底层代码,使用STM32的 **DMA+空闲中断** 接收不定长数据。 12. **WDT.c** 文件实现看门狗。未使用,**删除**。 其他错误可双击编译结果跳转至指定位置。具体问题自行查阅资料修改,不赘述。 首次移植可只删除和移植串口代码,其他无关紧要的稍后移植。 如果一切顺利,编译没有错误,可下载到MCU。WIFI能够上云。 ``` c int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_ADC_Init(); MX_TIM3_Init(); MX_TIM14_Init(); MX_USART1_UART_Init(); MX_TIM17_Init(); MX_TIM1_Init(); MX_TIM16_Init(); /* USER CODE BEGIN 2 */ //******** Init ***************// AdcInit(); MotorSpeedInit(); MotorPositionInit(); //******** OS Init ***************// Init_Uart2(); Timer0_Init(); Button_Init(); WIFI_Init(); //******** PID ***************// Timer_0_Add_Fun(10, MotorPositionLoop); //位置环 // Timer_0_Pas_Fun(MotorPositionLoop); //位置环 暂停 Timer_0_Add_Fun(10, MotorSpeedLoop); //速度环 Timer_0_Pause_Fun(MotorSpeedLoop); //速度环 暂停 //******** OS ***************// Timer_0_Add_Fun(50, UserButton); //按键检测底层业务 Timer_0_Add_Fun(5, Uart2_CheckMessageLoop); //帧处理函数 Timer_0_Add_Fun(500, WIFI_LED_Loop); //网络状态指示灯 1Hz Timer_0_Add_Fun(500, Mode_LED_Loop); //设备状态指示灯 1Hz Timer_0_Add_Fun(60 * 1000, WIFI_SubTemp); //上报一次 温度 信息 Timer_0_Add_Fun(61 * 1000, WIFI_SubLlluminance);//上报一次 光强 信息 Timer_0_Add_Fun(62 * 1000, WIFI_SubVoltage); //上报一次 电压 信息 // Timer_0_Add_Fun(32 * 1000, WIFI_SubMotorMode); //上报一次 电机运行模式 信息 // Timer_0_Add_Fun(33 * 1000, WIFI_SubLimitStatus);//上报一次 限位状态 信息 // Timer_0_Add_Fun(34 * 1000, WIFI_SubAction); //上报一次 电机动作 信息 // Timer_0_Add_Fun(35 * 1000, WIFI_SubMode); //上报一次 窗帘模式 信息 // Timer_0_Add_Fun(36 * 1000, WIFI_SubPosition); //上报一次 窗帘位置 信息 //******** Message ***************// Timer0_Add_MessageFun('A', DistributionNetwork); //上次AP配网不成功,开机会自动进 “配网模式” Timer0_Add_MessageFun('F', DistributionNetwork); //上下按键同时长按2S 配网 Timer0_Add_MessageFun('U', MotorUp); //上键 上行 Timer0_Add_MessageFun('D', MotorDown); //下键 下行 Timer0_Add_MessageFun('S', LetGo); //松手检测 Timer0_Add_MessageFun('S', WIFI_SubPosition); //上传位置 //******** Buzzer ***************// Timer0_Add_MessageFun('C', Buzzer_DJI); //连接网络 Timer0_Add_MessageFun('U', Buzzer_Di); //上键 上行 Timer0_Add_MessageFun('D', Buzzer_Di); //下键 下行 //******** Pause ***************// PauseUpload(); //未联网时,所有上传动作暂停 //******** ReStart ***************// Timer0_Add_MessageFun('C', ReStartUpload); //开机 连接网络成功 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Timer0_SYS_APP_LOOP(); Timer0_SYS_APP_LOOP_Message(); Timer0_SYS_APP_LOOP_Once(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } ``` 上传数据基于零妖代码结构。把所有上传项目独立,可配置不同项目不同上传频率。 ``` C //******************* 上传数据 **************************// void WIFI_SubTemp(void) { WIFI_SubStation(0); } void WIFI_SubLlluminance(void) { WIFI_SubStation(1); } void WIFI_SubMotorMode(void) { WIFI_SubStation(2); } void WIFI_SubLimitStatus(void) { WIFI_SubStation(3); } void WIFI_SubMode(void) { WIFI_SubStation(5); } void WIFI_SubPosition(void) { WIFI_SubStation(6); } void WIFI_SubVoltage(void) { WIFI_SubStation(7); } ``` - - - ### 2\. ADC&DMA采样 ADC采用DMA多通道不连续采集。使用二维数组缓存数据,每次获取ADC测量值时均采样10次求平均后上传。 ``` C //0:Current; 1:Voltage; 2:Temp; 3:Photo; 4:Vref uint16_t AdcValue[10][5]; float AdcActualValue[10][5]; uint8_t AdcValuePosition = 0; ``` ``` C void AdcInit(void) { //校准ADC HAL_ADCEx_Calibration_Start(&hadc); //开DMA AdcValuePosition = 0; // HAL_ADC_Start_DMA(&hadc, (uint32_t *)AdcValue[AdcValuePosition], 5); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) { HAL_ADC_Stop_DMA(&hadc); if(++AdcValuePosition >= 10) AdcValuePosition = 0; HAL_ADC_Start_DMA(&hadc, (uint32_t *)AdcValue[AdcValuePosition], 5); } ``` 温度和光强公式根据元件手册给出的温度-阻值、光强-阻值曲线拟合而成,辅以修正因子修正。 ``` C float AdcGetOneChannel(uint8_t channel) { uint8_t i; float AdcReturn; float PowerVoltage; //校准ADC HAL_ADCEx_Calibration_Start(&hadc); //开DMA AdcValuePosition = 0; HAL_ADC_Start_DMA(&hadc, (uint32_t *)AdcValue[AdcValuePosition], 5); HAL_Delay(1); HAL_ADC_Stop_DMA(&hadc); for(i = 0; i < 10; i++) { PowerVoltage = 1.2 * 4096 / AdcValue[i][4]; //电源电压,内部参考电压1.2V switch(channel) { case 0: //电流,中点2.5v,增益100mV/A AdcActualValue[i][0] = ( 2.5 - ( AdcValue[i][0] * PowerVoltage / 4096 )) / 0.1; break; case 1: //电压,1/11 AdcActualValue[i][1] = ( AdcValue[i][1] * PowerVoltage / 4096 ) * 11; break; case 2: //温度 //-10~50℃: y = -33.186 * x + 80.268 (R^2 = 0.998) //修正:-5 AdcActualValue[i][2] = -33.186 * ((float)AdcValue[i][2] * PowerVoltage / 4096) + 80.268 - 5; break; case 3: //光强: [400lx] y = -16691 * x + 8262.9 (R^2 = 0.9764); if(AdcValue[i][3] > (0.47 * 4096 / PowerVoltage)) AdcActualValue[i][3] = 30.24 * pow(( (float)AdcValue[i][3] * PowerVoltage / 4096 ), -3.54); else AdcActualValue[i][3] = -16691 * ((float)AdcValue[i][3] * PowerVoltage / 4096 ) + 8262.9; break; default: break; } if(i == 0) AdcReturn = AdcActualValue[i][channel]; AdcReturn += AdcActualValue[i][channel]; AdcReturn /= 2; } return AdcReturn; } ``` - - - ### 3\. 蜂鸣器驱动 蜂鸣器通过TIM14-1通道驱动。内置25个环形缓存区数组实现蜂鸣器音调、音量、延时功能。 ``` C #define BuzzerParameterMax 25 //蜂鸣器参数:频率(0-65535Hz),音量(0-100),时长(0-65535ms) uint16_t BuzzerParameter[BuzzerParameterMax][3] = {{0xFFFF, 0, 0}}; uint8_t BuzzerPositionOut = 0, BuzzerPositionIn = 0, BuzzerCount = 0; float BuzzerReload = 0.0, BuzzerTime = -1.0, BuzzerBeat = 0.0; uint8_t BuzzerWorking = 0; ``` ``` C void BuzzerInterrupt(void) //蜂鸣器中断 { if(BuzzerTime > 0) //延时中... { BuzzerTime -= BuzzerBeat; } else //切换 { if(BuzzerCount == 0) //OVER { BuzzerWorking = 0; HAL_TIM_PWM_Stop(&htim14, TIM_CHANNEL_1); HAL_TIM_Base_Stop_IT(&htim14); HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET); } else //NEXT { BuzzerReload = 1000000.0 / BuzzerParameter[BuzzerPositionOut][0]; __HAL_TIM_SET_AUTORELOAD(&htim14, (uint16_t)BuzzerReload - 1); __HAL_TIM_SET_COMPARE(&htim14, TIM_CHANNEL_1, (uint16_t)(BuzzerReload * BuzzerParameter[BuzzerPositionOut][1] * 0.01 * 0.9)); BuzzerBeat = BuzzerReload / 1000; //ms BuzzerTime = BuzzerParameter[BuzzerPositionOut][2]; HAL_TIM_PWM_Start(&htim14, TIM_CHANNEL_1); HAL_TIM_Base_Start_IT(&htim14); BuzzerPositionOut = (BuzzerPositionOut + 1) % BuzzerParameterMax; BuzzerWorking = 1; BuzzerCount--; } } } ``` ``` C uint8_t BuzzerSetParameter(uint16_t frequncy, uint8_t volume, uint16_t time) //设置蜂鸣器参数 { BuzzerParameter[BuzzerPositionIn][0] = frequncy; BuzzerParameter[BuzzerPositionIn][1] = volume; BuzzerParameter[BuzzerPositionIn][2] = time; BuzzerPositionIn = (BuzzerPositionIn + 1) % BuzzerParameterMax; if((++BuzzerCount == 1) && (!BuzzerWorking)) //从停止状态启动 { BuzzerTime = -1.0; BuzzerInterrupt(); } if(BuzzerCount == BuzzerParameterMax) return 0; else return 1; } ``` - - - ### 4\. PID及参数整定 PID使用增量式和位置式,分别用于速度环和位置环。 PID参数因电机而异,需要自行耐心调整。 ``` C void MotorIncrementPID(struct PID *pid, int16_t pidInput) {     pid->PidInput = pidInput;     //Pid     pid->PidEt = pid->PidSetPoint - pid->PidInput;     pid->PidOutput += pid->PidKp * (pid->PidEt - pid->PidLastErr) \                     + pid->PidKi * pid->PidEt \                     + pid->PidKd * (pid->PidEt - 2 * pid->PidLastErr + pid->PidLastTwoErr);     //Pid限幅     pid->PidOutput = pid->PidOutput > pid->PidLimitUp ? pid->PidLimitUp : pid->PidOutput;     pid->PidOutput = pid->PidOutput < pid->PidLimitDown ? pid->PidLimitDown : pid->PidOutput;     //覆写     pid->PidLastTwoErr = pid->PidLastErr;     pid->PidLastErr = pid->PidEt; } ``` ``` C void MotorPositionPID(struct PID *pid, int32_t pidInput) {     pid->PidInput = pidInput;     //Pid     pid->PidEt = pid->PidSetPoint - pid->PidInput;     pid->PidEtSum += pid->PidEt;     pid->PidOutput = pid->PidKp * pid->PidEt + pid->PidKi * pid->PidEtSum                     + pid->PidKd * (pid->PidEt - pid->PidLastErr);     //Pid限幅     pid->PidOutput = pid->PidOutput > pid->PidLimitUp ? pid->PidLimitUp : pid->PidOutput;     pid->PidOutput = pid->PidOutput < pid->PidLimitDown ? pid->PidLimitDown : pid->PidOutput;     //覆写     pid->PidLastErr = pid->PidEt; } ``` 因为使用的编码器电机阻尼大,大约5V电压才能启动,为了避免电机从停止状态退出过程时间过长,在PID输出和电机间添加MotorCurve函数。保证低速时呈对数变化,高速时线性变化。该函数已在我的遥控车项目验证,效果非常棒。 ``` C float MotorCurve(float inPut) {     float outPut = 0;     outPut = (inPut < 0 ? -1 : 1);     inPut = inPut > 265 ? 265 : inPut;     inPut = inPut < -265 ? -265 : inPut;     //输出曲线。类似对数曲线。     //分界点 15:266.2; 0.002425; -0.155; use     //可快速从驻车状态退出,且低速时刹车距离变短。     //f(x) = 256.7[227.6, 285.8] * exp(0.002453[0.001927, 0.002979] * x)     // + (-256.7[-297.8, -215.6]) * exp(-0.09653[-0.1635, -0.02957] * x); /*下面两行可合并为一行。此处改写是因为MarkDown不识别*/     outPut *= 266.2 * (exp(0.002425 * (inPut < 0 ? - inPut : inPut)); output -= exp(-0.155 * (inPut < 0 ? - inPut : inPut))) + 0.5;     return outPut; } ``` **速度环:** ``` C void MotorSpeedInit(void) { //PID: 5, 0.6, 1 MotorInit(&PidSpeed); MotorSetPidParameter(&PidSpeed, 5, 0.6, 1); PidSpeed.PidLimitUp = 150; PidSpeed.PidLimitDown = -150; } ``` 从速度环曲线可以看出,调整时间大约0.3s。过程存在一点超调,正常现象,可以保证更快速的调整。 ![速度环调试曲线](//image.lceda.cn/pullimage/dBaBRAFTr6VKVf6XPBawHqPaBz1T7yz9QWWycoRf.jpeg) ``` 速度环调试曲线 ``` **位置环:** ``` C void MotorPositionInit(void) { //0.6, 0, 13 MotorInit(&PidPosition); MotorSetPidParameter(&PidPosition, 0.6, 0, 13); //微调该参数 PidPosition.PidLimitUp = 200; PidPosition.PidLimitDown = -200; } ``` 位置环中间线性段受限于电机输出限幅。后段波动是施加扰动和释放扰动造成。 ![位置环曲线](//image.lceda.cn/pullimage/R9XiPLjXu4uRWKRLRwPluRuuCALuSNsQASQQDMQL.jpeg) ``` 位置环曲线 ``` - - - ### 5\. 按键控制 按键部分删除了原来的Button\_Loop实现函数。添加了User\_Button函数,用于识别单按键按下,双按键按下,按键松开等动作。并向系统发布消息。 ``` C void UserButton(void) { if( ((Button_ReadIO(0)) && (Button_ReadIO(1))) \ && (ButtonTwoTime || Button_Timer[0] || Button_Timer[1]) ) //松手检测 { Timer0_SendMessage('S'); //松手 } if((!Button_ReadIO(0)) && (!Button_ReadIO(1))) //同时按下 { ButtonTwoTime++; Button_Timer[0] = 0; Button_Timer[1] = 0; } else { ButtonTwoTime = 0; if(Button_ReadIO(0) == 0) Button_Timer[0]++; else Button_Timer[0] = 0; if(Button_ReadIO(1) == 0) Button_Timer[1]++; else Button_Timer[1] = 0; } if(ButtonTwoTime > 65500) ButtonTwoTime = 65500; if(Button_Timer[0] > 65500) Button_Timer[0] = 65500; if(Button_Timer[1] > 65500) Button_Timer[1] = 65500; if(ButtonTwoTime > Button_L_Time) { Timer0_SendMessage('F'); //恢复出场设置 return; } if(ButtonTwoTime == 0) //按键未同时按下 { if((Button_Timer[0] > Button_G_Time) && (Button_Timer[0] < Button_L_Time)) { Timer0_SendMessage('U'); //上 Button_Timer[0] = 65500; return; } if((Button_Timer[1] > Button_G_Time) && (Button_Timer[1] < Button_L_Time)) { Timer0_SendMessage('D'); //下 Button_Timer[1] = 65500; return; } } } ``` 为了实现一个消息可以对应多个功能函数,我们修改了Message循环部分代码。修改后的代码,可以实现:按下上键,电机速度环模式上行,同时蜂鸣器“滴”提示音。下键同理。 ``` C //******** Message ***************// Timer0_Add_MessageFun('A', DistributionNetwork); //上次AP配网不成功,开机会自动进 “配网模式” Timer0_Add_MessageFun('F', DistributionNetwork); //上下按键同时长按2S 配网 Timer0_Add_MessageFun('U', MotorUp); //上键 上行 Timer0_Add_MessageFun('D', MotorDown); //下键 下行 Timer0_Add_MessageFun('S', LetGo); //松手检测 Timer0_Add_MessageFun('S', WIFI_SubPosition); //上传位置 //******** Buzzer ***************// Timer0_Add_MessageFun('C', Buzzer_DJI); //连接网络 Timer0_Add_MessageFun('U', Buzzer_Di); //上键 上行 Timer0_Add_MessageFun('D', Buzzer_Di); //下键 下行 ``` ``` C //系统循环执行-邮箱处理 void Timer0_SYS_APP_LOOP_Message(void) { signed char i = 0, j = 0; if(Timer0_Handler_Flag_Message == 0) return; Timer0_Handler_Flag_Message = 0; for(i = 0; i < Timer_0_List_Count; i++) //调用消息队列中的函数 { if(Timer0_Message_Struct.MessageQueue[i]) { for(j = 0; j < Timer_0_List_Count; j++) { if(Timer0_Message_Struct.Flag[j] == 1) { if(Timer0_Message_Struct.MessageQueue[i] == Timer0_Message_Struct.MessageList[j]) { Timer0_Message_Struct.MessageFun_Point_List[j](); // j = Timer_0_List_Count + 10; //注释则可以一个消息对应多个函数 } } } Timer0_Message_Struct.MessageQueue[i] = 0; } } } ``` - - - ### 6\. 任务/消息调度器改写 为了实现一些功能,我们在零妖的任务调度器基础上进行了修改。 对Flag部分重新规划。 ``` C unsigned char Flag[Timer_0_List_Count]; //0:空;1:运行;2:暂停;10:暂停所有 ``` 修改后的任务调度器添加了:删除、暂停、恢复、暂停所有、恢复所有功能。 ``` C //************** 任务 *****************// //添加 unsigned char Timer_0_Add_Fun(unsigned long Time,void (*Fun)(void)) { signed char i = 0; for(i = 0; i < Timer_0_List_Count; i++) { if(Timer0_Struct.Flag[i] == 0) //空的 { Timer0_Struct.Flag[i] = 1; Timer0_Struct.Counter[i] = 0; Timer0_Struct.Fun_Point_List[i] = Fun; Timer0_Struct.Timer[i] = Time-1; return 1; } } return 0; } //删除 unsigned char Timer_0_Del_Fun(void (*Fun)(void)) { signed char i=0; for(i = (Timer_0_List_Count- 1); i >= 0; i--) //从后往前 { if(Fun == Timer0_Struct.Fun_Point_List[i]) { Timer0_Struct.Flag[i] = 0; Timer0_Struct.Counter[i] = 0; return 1; } } return 0; } //暂停 unsigned char Timer_0_Pause_Fun(void (*Fun)(void)) { signed char i=0; for(i = (Timer_0_List_Count- 1); i >= 0; i--) //从后往前 { if((Fun == Timer0_Struct.Fun_Point_List[i]) && (Timer0_Struct.Flag[i] == 1)) { Timer0_Struct.Flag[i] = 2; Timer0_Struct.Counter[i] = 0; } } return 0; } //恢复 unsigned char Timer_0_ReStart_Fun(void (*Fun)(void)) { signed char i=0; for(i = (Timer_0_List_Count- 1); i >= 0; i--) //从后往前 { if(Fun == Timer0_Struct.Fun_Point_List[i]) { Timer0_Struct.Flag[i] = 1; Timer0_Struct.Counter[i] = 0; } } return 0; } //暂停所有 unsigned char Timer_0_Pause_All(void) { signed char i=0; for(i = 0; i < Timer_0_List_Count; i++) { if(Timer0_Struct.Flag[i] == 1) { Timer0_Struct.Flag[i] = 10; Timer0_Struct.Counter[i] = 0; } } return 0; } //恢复 通过“暂停所有”暂停的任务 unsigned char Timer_0_ReStart_All(void) { signed char i=0; for(i = 0; i < Timer_0_List_Count; i++) { if(Timer0_Struct.Flag[i] == 10) { Timer0_Struct.Flag[i] = 1; Timer0_Struct.Counter[i] = 0; } } return 0; } ``` 为了实现一些功能,我们添加了Flag,并对其重新规划。 ``` C unsigned char Flag[Timer_0_List_Count]; //0:空;1:运行;2:暂停;10:暂停所有 ``` 修改后的消息调度器添加了:删除、暂停、恢复、暂停所有、恢复所有功能。 ``` C //************** 消息 *****************// //添加 unsigned char Timer0_Add_MessageFun(unsigned char Message,void (*Fun)(void)) { signed char i; for(i = 0; i < Timer_0_List_Count; i++) { if(Timer0_Message_Struct.Flag[i] == 0) { Timer0_Message_Struct.Flag[i] = 1; Timer0_Message_Struct.MessageList[i] = Message; Timer0_Message_Struct.MessageFun_Point_List[i] = Fun; return 1; } } return 0; } //删除 unsigned char Timer0_Del_MessageFun(void (*Fun)(void)) { signed char i; for(i = (Timer_0_List_Count - 1); i >= 0; i--) //从后往前 { if(Fun == Timer0_Message_Struct.MessageFun_Point_List[i]) { Timer0_Message_Struct.Flag[i] = 0; Timer0_Message_Struct.MessageList[i] = 0x00; return 1; } } return 0; } //暂停 unsigned char Timer0_Pause_MessageFun(void (*Fun)(void)) { signed char i; for(i = (Timer_0_List_Count - 1); i >= 0; i--) //从后往前 { if((Fun == Timer0_Message_Struct.MessageFun_Point_List[i]) && (Timer0_Message_Struct.Flag[i] == 1)) { Timer0_Message_Struct.Flag[i] = 2; return 1; } } return 0; } //恢复 unsigned char Timer0_ReStart_MessageFun(void (*Fun)(void)) { signed char i; for(i = (Timer_0_List_Count- 1); i >= 0; i--) //从后往前删 { if(Fun == Timer0_Message_Struct.MessageFun_Point_List[i]) { Timer0_Message_Struct.Flag[i] = 1; return 1; } } return 0; } //暂停 所有 unsigned char Timer0_Pause_MessageAll(void) { signed char i; for(i = (Timer_0_List_Count - 1); i >= 0; i--) //从后往前 { if(Timer0_Message_Struct.Flag[i] == 1) { Timer0_Message_Struct.Flag[i] = 10; } } return 0; } //恢复 所有 unsigned char Timer0_ReStart_MessageAll(void) { signed char i; for(i = (Timer_0_List_Count- 1); i >= 0; i--) //从后往前删 { if(Timer0_Message_Struct.Flag[i] == 10) { Timer0_Message_Struct.Flag[i] = 1; } } return 0; } ``` - - - ### 7\. 配网模式 同时长按上下两按键2S,进入AP热点配网模式。 ``` C //配网模式 void DistributionNetwork(void) { MotorPause(); Timer_0_Pause_All(); //暂停所有任务 Timer0_Pause_MessageAll(); //暂停所有消息 Buzzer_BiPu(); //奏乐 //开始配网流程 Timer_0_Add_Fun_Once(1000, WIFI_CloseRTE); //关闭回显 Timer_0_Add_Fun_Once(1500, WIFI_ResetAuthor);//解除绑定关系, Timer_0_Add_Fun_Once(2000, WIFI_SendAT); //AT Timer_0_Add_Fun_Once(2500, WIFI_SetILOP); //设置三元组 Timer_0_Add_Fun_Once(3000, WIFI_StartILOP); //开启ILOP // Timer_0_Add_Fun_Once(5000, WIFI_StartAWS); //路由器配网 Timer_0_Add_Fun_Once(5000, WIFI_StartAP); //热点配网 //其他操作 Timer_0_Add_Fun(100, WIFI_LED_Loop); //WIFI指示灯快闪 5Hz Timer_0_Add_Fun(100, Mode_LED_Loop); //快闪 5Hz Timer_0_ReStart_Fun(Uart2_CheckMessageLoop); //帧处理函数 // Timer0_Add_MessageFun('C', WIFI_SubPosition); //连接成功 主动上报一次位置 Timer0_Add_MessageFun('C', NetworkConnected); //连接成功 Timer0_Add_MessageFun('E', Buzzer_DiLong); //Error Timer0_Add_MessageFun('A', Buzzer_DiDiDi); //AP已开启 } ``` 配网成功,则执行NetworkConnected函数。删除配网过程创建的任务和消息,启用电机,恢复配网前所有任务和消息。最后奏乐,返回原来任务。无需重启设备,节省了重启&联网时间。 这点和**零妖**代码有较大区别。宋工实现过程是:进入配网过程,重新初始化所有任务、消息。创建配网需要的任务和消息,配网成功后调用软件重启指令,重新进入正常工作模式。这样会多一次重启WIFI上云过程。 ``` C //配网成功 已连接 void NetworkConnected(void) { //删除 配网 过程创建的所有任务 Timer_0_Del_Fun(WIFI_LED_Loop); //WIFI指示灯 Timer_0_Del_Fun(Mode_LED_Loop); // Timer0_Del_MessageFun(NetworkConnected); //连接成功 Timer0_Del_MessageFun(Buzzer_DiLong); //Error Timer0_Del_MessageFun(Buzzer_DiDiDi); //AP已开启 MotorReStart(); Timer_0_ReStart_All(); //恢复 配网前所有任务 Timer0_ReStart_MessageAll(); //恢复 配网前所有消息 Buzzer_DoToXi(); //奏乐 } ``` - - - ## 结论 该项目参考**零妖**代码框架,删除了一些未使用的功能,修改了一些底层功能,增加了一些定制化功能。 设备基本实现了电动窗帘的本地/云端控制功能,能够按一定频率上传设备运行状态。当设备发生故障时,具有一定的处理能力。有着较为友好的交互方式。成本控制得当。 程序设计采用任务/消息调度器模式,可方便地添加、删减功能而不影响其他功能运行。 由于时间、精力、能力有限,设备还存在着诸多问题待修复,已知问题罗列如下,如您有时间、有精力、有能力,可尝试修复。 1. 软硬限位未实现,窗帘存在超限位运行损坏风险。窗帘超限位后APP无法显示实际位置; 2. PID参数设定需要手动完成。 3. 当外接电源为开关电源时,电机反转会触发开关电源过压保护。加入SS54二极管防倒灌可解决。但电机反转时设备电压会被拉高,当使用24V电源时可能会导致电机驱动芯片过压保护. 4. 光敏电阻和热敏电阻测量数值不准确。 - - - ## 致 谢 感谢立创EDA开设活动,提供一个 ~~白嫖~~ 学习的机会。 感谢**零妖**源码,学习了任务/消息调度器、环形缓存区、JSON字符串比较等知识,受益匪浅。 感谢客编:481978A大佬上传的文件,解决了令人头秃的配网流程。
设计图
PCB
1 /
未生成预览图,请在编辑器重新保存一次
ID Name Designator Footprint Quantity
1 LED-0603_R LED1,LED2 LED0603_RED 2
2 8MHz X1 OSC-SMD_4P-L3.2-W2.5-BL 1
3 0R R1,R5,R6,R7,R13,R12,R14,R11,R25,R26 R0603 10
4 10k R2,R10,R16,R29,R30,R31,R33,R20,R32 R0603 9
5 1.5k R3,R4 R0603 2
6 SWD CN1 CONN-TH_4P-P2.50_XH-4A 1
7 22pF C1,C2 C0603 2
8 0.1u C4,C3,C10,C9,C12,C13,C19,C17,C16,C18,C15,C23,C24,C22,C21,C20,C25,C26 C0603 18
9 STM32F030K6T6TR U8 TQFP-32_L7.0-W7.0-P0.50-BL 1
10 22uF C6,C7 CAP-D5.0×H5.5 2
11 Supply TP2 PAD.03X.04 1
12 +5V TP3 PAD.03X.04 1
13 GND TP1,TP5 PAD.03X.04 2
14 3.3v TP4 PAD.03X.04 1
15 10uF C8,C11,C14 C1206 3
16 470uF C5 CAP-SMD_BD10.0-L10.3-W10.3-FD 1
17 LP6498AB6F U2 SOT-23-6_L2.9-W1.6-P0.95-LS2.8-BL 1
18 16.2k R8 R0603 1
19 3k R9 R0603 1
20 SS54 D6 SMB_L4.6-W3.6-LS5.3-R-RD 1
21 HX9193-33GB U3 SOT-23-5_L3.0-W1.7-P0.95-LS2.8-BR 1
22 DC-005-2.5A-2.5 DC1 CONN-TH_DC-005-2.5A-2.0 1
23 15uH L1 IND-SMD_L5.0-W5.0_SWPA5040S 1
24 K2-3.6×6.1_SMD KEY1,KEY3,KEY2 KEY-SMD_2P-L6.2-W3.6-LS8.0 3
25 EMW_RXD TP7 PAD.03X.04 1
26 EMW_TXD TP6 PAD.03X.04 1
27 EMW3080 U4 EMW3080 1
28 SS32F D4,D3,D1,D2 SMAF_L3.5-W2.6-LS4.7-RD 4
29 DB128L-5.08-2P U7 CONN-TH_2P-P5.08_DB128L-5.08-2P 1
30 M_F TP11 PAD.03X.04 1
31 Voltage TP8 PAD.03X.04 1
32 M_B TP10 PAD.03X.04 1
33 Current TP9 PAD.03X.04 1
34 10R R17,R18,R24,R21 R0603 4
35 100k R15,R19 R0603 2
36 rz7899 U6 SOP-8_L4.9-W3.9-P1.27-LS6.0-BL 1
37 CC6900SO-5A U5 SOP-8_L4.9-W3.9-P1.27-LS6.0-BL 1
38 X8821WR-05S-N0SN CN3 CONN-TH_5P-P2.50_X8821WR-05S-N0SN 1
39 MLT-7525 BUZZER1 BUZ-SMD_4P-L7.5-W7.5-P7.59-BR 1
40 Buzzer TP12 PAD.03X.04 1
41 Photoresistance TP13 PAD.03X.04 1
42 GL5516 R22 RES-TH_L5.1-W4.3-P3.40-D0.5 1
43 M3 H1,H2,H4,H3 MOUNTINGHOLE_3.2MM_M3_PAD_VIA 4
44 LED-0603_B LED3 LED0603_BLUE 1
45 SI2306 Q1 SOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR 1
46 1k R27,R28 R0603 2
47 NTC R23 R0603 1
48 1N4007W D5 SOD-123FL_L2.7-W1.8-LS3.8-RD 1
49 LED-0603_G LED4 LED0603_GREEN 1

展开

工程成员
侵权投诉
相关工程
换一批
加载中...
添加到专辑 ×

加载中...

温馨提示 ×

是否需要添加此工程到专辑?

温馨提示
动态内容涉嫌违规
内容:
  • 153 6159 2675

服务时间

周一至周五 9:00~18:00
  • 技术支持

support
  • 开源平台公众号

MP