项目 的子部分
毕业设计
- 运行环境
- 【ESP32学习】联网模块
- 【STM32F4学习】摄像头
- STM32F4工程代码
- 【服务器】NGINX
- 【服务器】Tomcat
- 【服务器】ZLMedaikit流媒体服务器
- 【第三方库】FFmpeg媒体流转码工具
- 【深度学习】飞桨paddlepaddle实战
- 【机器学习】HMM模型(隐马尔科夫列)
- 【音视频学习】
- 【安卓APP制作】
- 硬件系统
运行环境
【ESP32学习】联网模块
ESP8266-01S上传数据到OneNet
1.进入OneNet创建产品和设备(具体步骤待补充)
2.复制产品和设备的详细信息(备份)
目的是为了方便使用AT指令以及代码编写。
设备名称(clientlD) : test
产品ID (username) : F1AVyfXw7l
password: version=2018-10-31&res=products%2FF1AVyfXw71%2Fdevices%
2Ftest&et=2810313321&method=md5&sign=EfJtPPxHwMX6iWWf3YksbA%3D%3D.urI:mqtts.heclouds.com
端口号:1883
订阅: $sys/F1AVyfXw7I/test/thing/property/post/reply发布: $sys/F1AVyfXw7l/test/thing/property/post
设备密钥: cjFZSWRwUGNrazdRR2d6eTJ4Tm9YNXN5bTNuMGpMTIE=access key: vclTl19loOn7mcfdtT39l1eRfVffM6FfH8U/U3HhUQc=
res:products/F1AVyfXw7l/devices/test
et:时间戳
收藏的一些资料
最终的操作结果
ESP32&&ESP8266-12E连接ONeNet参考资料
代码部分唯一不同的是引用的库函数不同,
ESP8266使用的是
#include <ESP8266WiFi.h>
ESP32使用的是
#include <WiFi.h>
在使用时需要注意引用的库函数,如果库函数不匹配,可能会导致编译失败,这部分的代码以放在附件中。
- ESP-12EConnectONenet是ESP8266-12E连接ONeNet的代码;
- ESP32ConnectONenet 是ESP8266-12E连接ONeNet的代码。
**注意:**我提供的代码是以onejson格式上传的,而不是数据流的格式。在云平台创建产品时需要注意这点,当然代码里博主写的就是以数据流格式上传,如果你用原来博主写的,那么创建产品时就选数据流。
上面的代码只能实现数据上传,并不能实现命令控制,下面就介绍如何实现命令控制。
主要修改的地方是callback函数,当拿到topic的时候要解析拿到一段ID,具体可以看官方的资料,里面有提到命令下发的操作。
ONeNet云平台报错: {“protocol”:“MQTT”,“offline_time”:“2024-07-15 16:01:49.977”,“offline_reason”:“CloseDueToProtoError”}怎么解决?
这个错误是协议格式不对,也就是用的topic不正确,通过下面的案例对这个作说明。
当我们在云平台下发命令的时候,在callback
函数里使用Serial.println(topic);
会打印订阅的topic,格式为:
$sys/584938/onenet_mqtt_dev1/cmd/request/c5a7e27e-05bb-41eb-972b-abce424ade8e
callback函数如下:
/********************************************************************************
函数:callback
功能:接收ONeNet传回的信息
返回值:无
参数:
topic是消息的主题,
payload是消息的有效载荷(数据部分),
length是payload的长度
*********************************************************************************/
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.println("message rev:");
Serial.println(topic); // 打印订阅的topic
const char* lastSlash = strrchr(topic, '/');
if (lastSlash != NULL) {
const char* cmdId = lastSlash + 1; // 命令ID位于最后一个'/'之后
msgid = String(cmdId); //将命令ID复制给msgid,msgid定义为全局变量
}
Serial.println(msgid); // 打印拿到的ID
if (strstr(topic, ONENET_GET_CAM_REQUEST)) //ONENET_GET_CAM_REQUEST="$sys/{产品ID}/{设备名}/cmd/request/"
{
DynamicJsonDocument doc(100);
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.println("parse json failed");
return;
}
JsonObject setAlinkMsgObj = doc.as<JsonObject>();
serializeJsonPretty(setAlinkMsgObj, Serial);
String cam = setAlinkMsgObj["cam"].as<String>();
Serial.println("@"+cam); //取出下发的命令并在前面加@
char RESPONSE_TOPIC[100];
sprintf(RESPONSE_TOPIC, "$sys/{产品ID}/{设备名}/cmd/response/%s",msgid.c_str());
client.publish(RESPONSE_TOPIC, "OK"); // 向平台响应OK
}else {
Serial.println("GET_CAM faile!");
}
}
这份代码是根据一位博主的代码改的(博主文章链接),取出后面的ID用如下代码即可
const char* lastSlash = strrchr(topic, '/');
if (lastSlash != NULL) {
const char* cmdId = lastSlash + 1; // 命令ID位于最后一个'/'之后
msgid = String(cmdId); //将命令ID复制给msgid,msgid定义为全局变量
}
Serial.println(msgid); // 打印拿到的ID
而这个时候我们需要响应这个命令用的是
$sys/584938/onenet_mqtt_dev1/cmd/response/c5a7e27e-05bb-41eb-972b-abce424ade8e
一个是request,一个是response,所以在拿到下发命令的topic后要取出后面跟着的ID,然后再重新拼接在$sys/584938/onenet_mqtt_dev1/cmd/response/
后面,然后用这个拼接的topic发送响应数据给云平台。
这个时候就能在云平台那看到类似如下信息:
一般格式错误返回的错误码是15,原因就是格式有问题。使用如下的格式上传响应都可能有问题:
1.$sys/584938/onenet_mqtt_dev1/cmd/response/
2.$sys/584938/onenet_mqtt_dev1/cmd/response/+
3.$sys/584938/onenet_mqtt_dev1/cmd/response/+/+
以上内容仅供参考,如果你有更好的方法,请在评论区告诉我。
APP连接ONeNet
- 1.内含demo
- 2.新版视频地址
- 3.json格式化网站
- 4.Android Okhttp3的使用(很全面,包含Post提交字符串、键值对、表单、上传文件、无参请求和Get有参无参请求,还有自动添加token)
- 从json中取出数据,结合第一点看
- 5.云平台调试错误码
在B站上学习OKHTTP3,我把主要的核心代码放在附件里,分别是get和post的同步和异步请求,返回的结果和视频地址2里讲的一样。
在编写HTTPS网络请求(post)时需要上传一些数据,这些数据有一定的上传格式,下面的网址汇总了上传格式content参数
2024.8.19
json数据解析步骤
方法一:
方法二:
使用第三方库Gson,在使用前需要创建一个Jsonbear,就是接收Jsons数据的格式。
总结:
在Android Studio中,如果你想要生成代码,例如getter和setter方法,可以使用快捷键Alt + Insert(Windows/Linux系统)或Command + N(Mac系统) 。这个快捷操作会引导你通过一个菜单来选择想要生成的代码类型,比如构造函数、toString方法、以及各种重写方法等。
此外,如果你需要查看某个方法的参数信息,可以使用快捷键Ctrl + P(Windows/Linux系统)或Command + P(Mac系统),这将展示出当前方法的参数列表及其类型。
STM32+电脑(模拟ESP32)+ESP8266通信
STM32————电脑:串口1(PA 9 PA10),手机连接指定热点,连接成功后等待一段时间把摄像头的网址发给单片机,单片机通过串口2发给ESP8266.ESP8266再传到OneNet上。
注意:在用ESP8266最小系统通信的时,需要给板子单独供电,否则通信可能失败,原因我想可能是因为电压不够。
设备热点配网技术——WIFIManager
这个配网技术是让开发板设置热点,然后让手机连接,连接好后配置要让开发板连接的WIFI和密码,这个技术叫设备热点技术。相比于以往的一键配网技术,我个人觉得这个设备热点配网技术成功率要要一些。
缺点是这个技术不能用AT指令来实现,所以目前AT指令在不配合其他设备的情况下,通常都使用一键配网技术。
ESP32和ESP8266使用设备热点配网技术的区别
- 区别一:使用的WiFi库不同,ESP32使用
WiFi.h
,而ESP8266使用ESP8266WiFi.h
- 区别二:使用的WiFiManager.h版本不同,ESP32使用
2.0.17
(目前这个版本是最新的),而ESP8266使用0.16或0.15
在使用ESP32时,请使用目前最新版的wifimanage库,而使用ESP8266的话请使用0.15或0.16版本的WIFIManager,如果ESP8266使用最新版的可能会报错。报什么错呢?
报错:error: ‘wifi_country_t’ does not name a type const wifi_country_t WM_COUNTRY_US{“US”,1,11,WIFI_COUNTRY_POLICY_AUTO};
完整报错如下:
d:\Program Files (x86)\arduino\libraries\WiFiManager/wm_consts_en.h:162:7: error: 'wifi_country_t' does not name a type
const wifi_country_t WM_COUNTRY_US{"US",1,11,WIFI_COUNTRY_POLICY_AUTO};
^
d:\Program Files (x86)\arduino\libraries\WiFiManager/wm_consts_en.h:163:7: error: 'wifi_country_t' does not name a type
const wifi_country_t WM_COUNTRY_CN{"CN",1,13,WIFI_COUNTRY_POLICY_AUTO};
^
d:\Program Files (x86)\arduino\libraries\WiFiManager/wm_consts_en.h:164:7: error: 'wifi_country_t' does not name a type
const wifi_country_t WM_COUNTRY_JP{"JP",1,14,WIFI_COUNTRY_POLICY_AUTO};
^
这个错误我目前没有解决,如果你解决了还请评论区或邮件(3256149770@qq.con)告诉我。
通信过程中遇到的问题
-
keil5中一点击下载就闪退或点击debug中的setting就闪退。参照文章
-
Keil5编程之warning: #223-D: function “xxx“ declared implicitly.参考链接
这一部分所用到的资料下载地址
2024.8.12(更新).
【实验】SPIFFS文件系统的使用
【实验】TCP/UDP通信实验
【STM32F4学习】摄像头
参考资料
STM32F4工程代码
使用三个ADC通道要注意按顺序去初始化,否则可能会出现问题,运营我还不知道.
【服务器】NGINX
在Linux中搭建NGINX服务器
TCP/IP协议
[知识储备]
- 可以自由选择所需的应用,生成nginx配置作为参考。
- 根据你的业务需求,自动生成复杂的nginx配置文件,提供你作为参考,非常好用
NGINX架构
NGINX中master的工作原理
nginx处理HTTP请求的过程
安装NGINX
安装路径:https://blog.csdn.net/u011715638/article/details/138670319
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
上面是配置文件的内容,下面说明一下配置时的一些注意事项:
- 把配置文件的
example.com www.example.com
换成172.0.0.1,这样方便在本地测试; - 在Ubuntu中可以下载ifconfig来查看Ubuntu的IP地址(ip addr也可以)
- 每次修改配置文件记
sudo systemctl reload nginx
【服务器】Tomcat
1.安装Tomcat要使用哪个版本的java?
使用jdk8或更高版本,详细参考官方文档
2.如何在Ubuntu安装Tomcat?
- 安装jdk8或更高版本
- 安装
【服务器】ZLMedaikit流媒体服务器
【第三方库】FFmpeg媒体流转码工具
【深度学习】飞桨paddlepaddle实战
2024.8.18
1.从入门到实际运用,请参考B站up主视频:点击链接
2.学完上面的视频后学习paddlepaddle的语音识别课程:
3.接着参考STM32cudeXM.AI的相关知识,把模型转换成onnx格式然后在但【单片机上运行:
3.1先用一个项目练练手:https://shequ.stmicroelectronics.cn/thread-632736-1-1.html
意外收获,这是一个学习论坛:https://www.waveshare.net/study/portal.php?mod=list&catid=38
2024.8.25
参考文献:
- 禹鑫鹏,贺庆,王世昕,.基于STM32CubeMX AI和NanoEdge AI的眼动信号分类效果对比研究【J】.传感器世界,2024,(04):6-10.
2024.8.26
X-CUDE—AI在线课程
相关论文参考
【机器学习】HMM模型(隐马尔科夫列)
相关论文参考
-【1.基于声学的婴儿哭声识别细分市场模型】(Baby Cry Recognition Based on Acoustic) -【2.使用隐马尔可夫模型自动分割婴儿哭闹信号】(Automatic segmentation of infant cry signals using hidden Markov models)
导入库
【音视频学习】
H.264编码
所谓视频编码就是指通过特定的压缩技术,将某个视频格式文件转换成另一种视频格式文件的方式。
视频流传输中最重要的编解码标准有国际电联(TU-T,国际电信联盟)的H.261、H.263、H.264等,运动静止图像专家组(由ISO国际标准化组织与IEC国际电子委员会于1988年联合成立)的MPEG系列标准MPEG1、MPEG2、MPEG4 AVC等。
其中ITU-TH.264/MPEG-4 AVC是ITU-T与ISO/IEC连手合作制订的新标准。ITU-T方面称之为H.264。但ISOIEC的则将这个新标准归纳于MPEG系列,称为MPEG-4 AVC。
而H.265则被视为是ITU-TH.264/MPEG-4AVC标准的继任者,又称为高效率视频编码(High Efficiency VideoCoding,简称HEVC)
安卓音视频实战编程
构建预览布局-使用SurfaceView或者TextureView
打开相机- Camera.open
设置参数- Camera.Parameters
设置预览数据回调- PreviewCallback
设置预览画布并启动- setPreviewTexture/startPreview
释放相机- stopPreview/release
YUV
YUV主要应用于优化彩色视频信号的传输,与RGB相比,YUV只需要占用极少的频宽(RGB需要三个独立的视频信号同时传输)。YUV中Y代表明亮度,也称灰阶值;U与V表示的则是色度(色调和饱和度)也可以记作:YCbCr。如果只有Y数据,那么表示的图像就是黑白的。
使用YUV的原因:
使用YUV格式才能极大地去除冗余信息,人眼对亮点信息更敏感,对色度敏感度不高。也就是说,可以压缩UV数据,而人眼难以发现。所以压缩算法的第一步,往往先把RGB数据转换成YUV数据。对Y少压缩一点,对UV多压缩一点,以平衡图像效果和压缩率。这也是为什么编码选择使用YUV而不是RGB。
YUV是一组数据的压缩格式,其下还有因为排列不同而衍生的不同格式名称
RTMP协议所在所在的网络层结构
【第三方库】LIBRTMP
【工具】类似安卓虚拟机:Total Control
采集音频数据工具
视频采集工具—MediaProjection
安卓P18
2024.8.27
方法一:
方法二:
【安卓APP制作】
1.安卓登录开发
2024.8.21
安卓的两种登录方式
登录可以进去就强登录,或进去后在某个页面触发登录。
对于第一个只需要在第一个页面做登录处理即可,而第二种需要Hook AMS + APT
框架实现,具体看这篇博文:文章连接
安卓中集成第三方库进行登录
可以使用目前比较流行的第三方库实现:
JustAuth开源组件
:JustAuth是一个整合了国内外数十家知名平台的OAuth登录的开源组件,它提供了丰富的OAuth平台支持,自定义State、自定义OAuth、自定义Http接口和自定义Scope等功能,极大地简化了开发者在第三方登录功能上的工作量。
2024.8.23
2.数据显示
安卓显示ONENet提供的可视化链接
2024.8.29
硬件系统
一、设备选型
1.空气质量模块设备选型:
电赛
以下笔记皆基于HAL库。
新建STM32CubeMX工程步骤
创建工程中如果勾选MCO表示向外部输出时钟,
输出的是哪一个引脚可以查看,如下图。
如果Application Structure设置为Basic,那么会把下面的两个文件分开放
否则项目会把两个文件放在一个文件夹里,如Core
时钟
1.初识时钟周期
4.外设时钟使能和失能
5.sys_stm32_cloc_init()函数
-
HAL_RCC_OscConfig()
- HSE高速外设振荡器
- LSE
- RC振荡器,随着电压的变化而变化,所以需要一个检验值
- PLL锁相环
6.SYSTEN文件夹
NVIC介绍
中断基本概念
中断向量表
文件里的中断在哪里呢?
在文件startup_stm32f10x_hd.s中这里列出内部中断,外部中断就在内部中断之下,这里不再列出。
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
中断寄存器
中断原理
中断优先级
中断的抢占优先级由AICR寄存器的后三位控制,而响应优先级由IPRx寄存器的后四位控制,最终分配结果参考下面的表格
中断一般只设置一次,设置多次可能会导致中断紊乱,一般以最后一次的中断设置为准,详细说明参考手册4.4.5
中断执行的顺序:抢占优先级(先执行数值小的)————响应优先级(先执行数值小的)————自然优先级(先执行数值大的)
NVIC 的使用
以下笔记皆基于标准库。
标准库中额中断
EXTI(Extern Interrupt)外部中断
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
简而言之,gpio电平发生变化时,申请外部中断。
- 支持的触发方式:上升沿/下降沿/双边沿/软件触发(引脚没有发生变化,执行一段代码就申请中断)
- 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(如PA1,PB1,PC1不能同时触发中断)
- 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
- 触发响应方式:中断响应/事件响应(事件响应不会触发中断。而是触发别的外设操作。属于外设之间的联合工作)
AFIO复用IO口
主要用于引脚复用功能的选择和重定义
在STM32中,AFIO主要完成两个任务:
EXTI实现代码
这段代码的中断端口是GPIOB_Pin14,所以需要将相关的传感器接到PB14这个端口
void CountSensor_Init(){
//配置RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//AFIO、
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//EXTI、一直打开着不用配置打开时钟
//NVIC 一直打开着不用配置打开时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
//EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line14;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
//NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI15_10_IRQHandler(void){//中断函数
if(EXTI_GetITStatus(EXTI_Line14)== SET){
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
定时器
TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
使用内部时钟源实现中断(标准库中)
在编写代码前先看看定时器的实现原理图
此处主要参考通用计时器的结构图,下面是基于内部时钟RCC的定时器。
在 stm32f103xxx_rcc.c 文件对 RCC_APB1PeriphClockCmd 这样的介绍:
/**
* @brief Enables or disables the High Speed APB (APB2) peripheral clock.
* @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
* This parameter can be any combination of the following values:
* @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA,
……
……
……+
*/
specifies the APB2 peripheral to gates its clock.即:指定APB 2外围设备到其时钟门。而这里的时钟门代码里选择了TIM2。
void Timer_Init(void){
//1.RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//2.选择时基单元时钟源,
TIM_InternalClockConfig(TIM2);
//3.时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分频,这里是1分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //计数方式
TIM_TimeBaseInitStructure.TIM_Period=10000-1; //自动重装值,计数达到这个值后触发中断,然后重新开始计数
TIM_TimeBaseInitStructure.TIM_Prescaler=7200 -1; //预分频,计数频率,
//假设计数为1s则自动重装值可设置为10000,预分频可设置为7200,公式为秒数=27MHz/PSC/ARR
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //重复计数数器高级定时器才有,这里设置为0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //时基单元设置
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//4.中断输出控制
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //抢占优先级,0-3, 响应优先级0-3,一个工程只设置一次
//5.NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
Num++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
实现输出比较
OC(Output Compare)输出比较
-
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
-
每个高级定时器和通用定时器都拥有4个输出比较通道
-
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
-
OC:输出比较
-
IC:输入比较
-
CC:输入/输出比较
PWM波形
- PWM(Pulse Width Modulation)脉冲宽度调制,广泛应用于各种电子和电气系统中,用于控制功率转换、电机速度、信号传输等
- 在具有^1中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域 ^1
- PWM参数:
在信号通过比较后输出到CC1P,然后再输出到输出使用电路,输出使用电路的OC1可以查看引脚定义表
在上图中需要注意的一些引文缩写:
- REF 是reference的缩写。意思是 参考信号
输出比较的设置
设置的函数为
PWM基本结构
配置PWM的时候可以参考下面的图,
图中的参考坐标系图红色线表示CCR的值,蓝色线表示CNT的值,黄色线表示自动重装载值即ARR。
了解了这点后我们再看看PWM的是如何计算的,如下公式
PWM频率: [ \text{Freq} = \frac{CKPSC}{(PSC + 1) \times (ARR + 1)} ] 可以看出PWM的频率等于CNT的更新频率
PWM占空比: [ \text{Duty} = \frac{CCR}{(ARR + 1)} ]
PWM分辨率: [ \text{Reso} = \frac{1}{(ARR + 1)} ]
代码编写
唛盟杯比赛详记
比赛题目
一、项目主题
知识产权流程管理系统
二、项目描述
该系统用于知识产权项目申报的全过程跟踪管理,其功能包括:
- 客户下单、
- 提交申请、
- 申请反馈、
- 订单查询、
- 订单详情、
- 文档查阅下载等六大部分。
该系统分为客户端和管理端两个子系统。客户端对客户开放,主要功能包括:
- 客户下单、
- 付款、
- 订单查询、
- 订单进度消息推送(推送到公众号、网站内部消息)、
- 文档查阅下载等。
管理端对管理人员开放,不对客户开放,负责订单管理、文档上传(批量上传)等。
三、项目需求
(一)、用户端
个人中心模块:
1、订单查询
分为我的订单(综合查询)及商标、专利、版权、科技项目四大子类查询,订单查询按全部业务下单时间顺列。
2、订单详细
可根据订单详情按钮跳转到对应的订单详情。
订单详情页展示图:
(二)、管理端
订单管理模块:
1、订单查询
查询订单,展示列表。
2、订单详细
在订单列表中点击某个订单,进入订单详情。
3、文档上传
在订单详情页,点击文档上传,选中本地文件,上传本地文件到服务器,支持批量、单文件上传。
注册唛盟账号
队长和队员注册账号
一、扫描一级部门的二维码
这一部分只建议参加了比赛的网友查看。本次是组队参加,一队3-5人,队长要在他们的官方网页端注册号团队(二级部门),方便后面的项目管理,然后再通过一级部门添加自己的团队,首先是扫描官方给的二维码,扫这个二维码后注册就会在一级部门下,这也是要注册在一级部门之下的办法,
二、授权登录成功后,跳转到提示页面,点击“首页”
三、进入低代码平台首页,按照提示,点击“账户明细”
四、按照提示,输入姓名,并提交
五、点击唛盟低代码平台官网,选择微信扫码登录
唛盟低代码平台官网:https://maimengcloud.com/lcode/m1/#/login
六、看到用户名称是自己的即报名成功
队长注册团队
1要求
1.构建每个参赛团队的独立部门
2.将参赛队员拉入部门
3.给每个参赛队员设置好岗位
2相关环境
3操作步骤
3.1 在一级部门,即总部下建立子部门
进入【部门管理】,点击【添加下级】
3.2输入部门信息
- 部门名称要求:以参赛团队名称作为部门名称
- 上级领导选:一级部门
- 部门负责人:选参赛团队组长
- 部门性质:技术部门
- 协作类型:内部组织
其它字段不填
(如果你不是第一届比赛的同学,那这个不需要关注,可能每年都不一样)
3.3保存提交
3.4把岗位挂接到部门上
【部门管理】中找到刚才建立的部门,点击【岗位】按钮弹出以下岗位选择框:
选择左边需要绑定的岗位,移动到右边,点击【提交】按钮即完成岗位绑定(如果没有显示岗位,多次刷新,或者退出重新登录,这个知识第一届遇到此问题解决的方案)
3.5把用户拉入部门
打开【用户管理】菜单,先把自己的搜索出来,如果不是通过一级部门的二维码注册的,会搜不到的哦。找到需要拉入的队友,点击【部门/岗位】
弹出以下部门岗位选择界面:
在弹出的界面中左边选中归属的部门,右边选中岗位,再【提交】即可
这部分本来也不想记了,毕竟没什么用了,可能下一届又不一样了,但想想自己记一下当作回忆也可以。
安装git和nodejs
在安装前我们通过这个链接https://gitee.com/maimengcloud/mdp-lcode-ui-web
去看看这个项目的介绍,
大概浏览一下,然后往下拉根据导航直接跳到 快速开始
这里并不是说其他的不重要,只是说对于一个项目而言如果不是涉及本地启动的话不必花费时间去纠结,等你能让项目在本地启动后再回来看看也不迟,当然这也有弊端,可能会错一些细节哈。
在快速开始的地方提到:
注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+ nodejs版本v14.16.1
所以我们安装的时候要注意版本的问题尽量不要选太高的,如果你已经安装了一部分或全部,而且版本很高或很低,这样也不必太担心(大不了删掉重新安装,哈哈),下面是我的一些经验,希望帮到你。
git的安装
这部分没有太多可讲的,网上有很多的教程,讲的也很好,这里需要你记住的一条命令是:
git clone <远程仓库地址> <本地存放目录>
这里举个例子,就比如这次比赛用到的这个项目,我们建一个文件夹装要下载的项目,比如是mdp文件夹,然后右键,win11选显示更多,在弹出的选项选择: git bash here
然后复制下面的内容回车就可以了。
git clone https://gitee.com/maimengcloud/mdp-lcode-ui-web.git mdp-lcode-ui-web/
但是有的时候也会因为网速的问题,导致无法下载,比如回车后报错,如下:
Cloning into ‘mdp-lcode-ui-web’…
fatal: unable to access ‘https://gitee.com/maimengcloud/mdp-lcode-ui-web.git/': Failed to connect to 127.0.0.1 port 26501 after 2017 ms: Couldn’t connect to server
简单翻译理解就是这个远程仓库无法访问,其实这也是使用让我比较烦恼的问题,这里的原因我可能没办法给你讲清楚(你有时间可以去琢磨哈),但有个软件可以分享给你,帮你解决这个问题,即 watt toolkit ,而且这个软件在微软软件商城就有。
下载后选github,然后点击一键加速。
然我们再回到git base here,再次输入刚才的命令回车,
发现刚才的代码仓库已经下载到本地了。
如果你使用上面的软件还是无法下载远程的仓库,那你需要根据报错信息在网上查考相关的信息,这里提供上面报错的可能解决方案,只是针对上面的问题哦!参照文章
安装node
网上可能称为nodejs都是一个工具,这个工具的简介还请参照官方,这里我们有做过多的了解哦。在安装node之前我们要先安装nvm。这是一个管理node的工具,这里安装的主要目的是 升高或降低node版本,简单就是想安装哪个版本(已发布且可下载的版本)的可以用这个工具来实现。
nvm是否要安装取决于你的情况,除了nvm,此次项目还需要安装工具node,vue,mvn。
方案一:为防止版本过高过低影响运行,以后可能还需要,最好是下载nvm管理node,然后也要了解升级或降低vue版本的方法,最后下载mvn;
方案二:自己不管安装还是没安装,直接安装node,vue,mvn,本次项目用到的node,vue,mvn都在package.json文件里定义写好了,运行后会根据里面去下载,似乎对项目没太大影响(因为我工具处于最高版本,或是相对低一点的版本,使用相同的命令,报错都是一个,基于这点你可以尝试。)
方案一
安装nvm
参照文档 关于文章的几点说明:
- 登录github的时候记得开watt toolket;
- 如果nvm下载不了要刷新或者退出重新进入,多试几次;
- 基于本次的项目我们只看文章的一——四,五往后有时间就了解一下就好了;
里面的 三、配置路径和下载源我们需要把淘宝镜像改为如下:
node_mirror: https://cdn.npmmirror.com/binaries/node/
npm_mirror: https://cdn.npmmirror.com/binaries/npm/
这是因为淘宝的镜像换了。
接着参照文章,目的是node还要做一些配置,主要node的环境变量设置,还有目录node_cache
和目录node_global
的一些设置。从文章的下图开始看,关于node的下载就不看了。
注意在设置目录node_cache
和目录node_global
时,
npm config set prefix “<自己的文件目录>\node_global” npm config set cache “<自己的文件目录>\node_cache”
这两个路径时要记得把它改成自己安装的路径:
安装指定的vue版本
情况一:你没安装过vue
首先你要先安装好node,然后用node的npm工具安装vue。
使用命令查看可安装版本:
要查看的vue版本是1.x和2.x的
npm view vue-cli versions --json
要查看的vue版本是3.x的
npm view @vue/cli versions --json
安装vue指定的版本:
安装的vue版本是1.x和2.x的
npm install -g @vue/cli@版本号
yarn global add @vue/cli@版本号
要查看的vue版本是3.x的
npm install -g vue-cli@版本号
yarn global add vue-cli@版本号
第一次安装要去配环境变量。
情况二:你安装过vue
卸载已经安装的Vue Cli
卸载 3.x 或 4.x 版本的Vue Cli
npm uninstall -g @vue/cli
yarn global remove @vue/cli
卸载 1.x 或 2.x 版本的Vue Cli
npm uninstall vue-cli -g
yarn global remove vue-cli
重复情况一的步骤,然后打开cmd,输入:
vue -V
显示安装的版本则说明安装完成。
安装mvn(Maven)工具
直接参照这个文章就好了。
方案二
安装node和vue
参照文章,同样的里面涉及到镜像文件的设置要注意换掉:
node_mirror: https://cdn.npmmirror.com/binaries/node/
npm_mirror: https://cdn.npmmirror.com/binaries/npm/
除此之外在设置目录node_cache
和目录node_global
这两个路径时要记得把它改成自己安装的路径:
npm config set prefix “<自己的文件目录>\node_global” npm config set cache “<自己的文件目录>\node_cache”
安装mvn
直接参照这个文章就好了。
至此工具就就安装完了,接着我们就要去启动项目了。
本地启动项目
本次使用的系统是win11和code应用程序,如果你用的不是这个系统和应用程序情况可能不一样哈。
根据项目的简介开始运行项目
这里我使用的是code应用程序(你如果用的是别的应用程序另说咯),点击文件夹用code打开后,根据项目文档执行命令:
npm install
结果…………………………报错啦(我就知道没这么简单)!!!错误如下:
上面的报错意思是:在尝试安装项目依赖时,npm遇到了依赖冲突问题。具体来说,babel-loader需要webpack的版本在2、3或4之间,但是你的项目中已经安装了webpack的5.90.1版本。这导致了peer依赖冲突,因为babel-loader期望的webpack版本与实际安装的版本不匹配,
解决办法如下:
1.查看自己的node版本;
```
node -v
```
2.修改"package.json",在"devDependencies"中增加"node": “^21.6.1"依赖;
```
"node":"^21.6.1",
```
3.npm install -s node-sass@4.14.1;
4.npm install –save –legacy-peer-deps;
结果……………………报错啦!!!!!
修改"package.json",原来的改为"node": "^13.14.0"依赖;
再次运行结果没报错。
5.npm install –registry=https://cdn.npmmirror.com
接着我们运行如下代码 `npm install --registry=https://cdn.npmmirror.com`
6.npm run dev
运行npm run dev,结果还是报错了……
这里的错误说vue-template-compiler的版本为2.7.16,那我们就去"package.json"找到vue,
原来的vue版本:
把上面的修改为`"vue":"^2.7.16",`
这时候要重新运行 `npm install --save --legacy-peer-deps`,然后再次运行 `npm run dev`;
结果还是报错,如下:
大概意思是没有找到ajv这个包,那么我们在"package.json"里的 **"dependencies"** 添加`"ajv": "^8.12.0",`
然后重复`npm install --save --legacy-peer-deps`, `npm run dev`操作就可以了。
显示如下:
我们再看看页面,页面如下:
到这里说明没问题了。
从上面我们可以了解到一点,自己安装的版本似乎并不会影响项目的运行,所以选择方案二来进行安装似乎更简单,但从往长远的看方案一更更好,他可以随时换版本,更为方便。