参考——温湿度传感器DHT11驱动_STM32
设备:stm32f407ZGT6
环境:FreeRTOS HAL
到网上找DHT11的驱动,但是都无法使用。原因是RTOS环境中,由于多线程,使用循环计数阻塞式的delay_us延时函数就没那么准,且不同设备中delay_us的计数值不一样。而DHT11对时序要求得又十分严格,这就会导致读取数据异常,甚至无法读取。
虽然考虑过使用其他方法达成更精准的微秒级延时,但是对于单总线传输终归小题大做了。于是下面就简单的使用计数值来模拟延时,不需要考虑延时多少微秒,只需要比较高电平持续时间的相对长短。
/**********************************************************************************************************
函数名称:us延时函数,最小延时为1us
输入参数:时间
输出参数:无
**********************************************************************************************************/
void delay_us(unsigned int time)
{unsigned short i = 0;while (time--){i = 8;while (i--);}
}
需要注意的是,下面代码使用的是C++,如果你使用的是C,那么用相应功能的代码替换掉即可。bool类型需要包含stdbool头文件
DHT11.h
头文件里未被注释的接口,决定了哪些函数需要重点关注
#ifndef DHT11_H
#define DHT11_Hvoid DHT11_Init();
//bool DHT11_Read_Data(float &temp,float &humi);
bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi);//自定义的快速读取函数
#endif//DHT11_H
DHT11.cpp
里面的这个std_delay_us是用于调试中用的,在void DHT11_Rst()函数里,你把延时换成你自带的即可,这个不需要多精准。
下面的函数是与时序图直接对应的,连续读取温度时,最好间隔1s以上
同时说明一下,下面将作为反面例子!!,找了许久才发现是数组越界引发的硬件中断,下面代码忘了对timeBufIndex清零。后面我会发一个简化版
#include "DHT11.h"
#include "cmsis_os2.h"
#include "stm32f4xx_hal.h"#define DHT11_Pin GPIO_PIN_6
#define DHT11_GPIO_Port GPIOE
#define DHT11_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()#define DHT11_Read() (DHT11_GPIO_Port->IDR & DHT11_Pin) /*HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin)*/
#define DHT11_Write(x) HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, (GPIO_PinState) (x))#define DHT11_High() HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET)
#define DHT11_Low() HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET)static GPIO_InitTypeDef GPIO_InitStruct = {0};
static uint16_t std_delay_80us=875;//事先测试过
static uint16_t std_delay_50us=566;
static uint16_t time_count;/**动态计算延时,以确保任何情况下都可以得到较为准确的延时*/
void std_delay_us(uint8_t us)
{// uint16_t count = std_delay_80us * us / 80;//测试得到的uint16_t count =11 * us ;for (uint16_t i = 0; i < count; ++i);
}/**函数*/
void DHT11_Input();
void DHT11_Output();
void DHT11_Rst();void DHT11_Init()
{DHT11_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin = DHT11_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;// GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);DHT11_High();
}void DHT11_Input()
{GPIO_InitStruct.Mode = GPIO_MODE_INPUT;HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
}void DHT11_Output()
{GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);
}void DHT11_Rst()
{DHT11_Output();DHT11_Low();osDelay(25);//根据时序图可知,需要至少拉低18msDHT11_High();std_delay_us(20);//20-40us
}void DHT11_Check()
{DHT11_Input();for (time_count =0;DHT11_Read();++time_count);/* 等待DHT11数据线拉低 */for (time_count =0;!DHT11_Read();++time_count); /* 等待DHT11数据线拉高 *///持续80usstd_delay_80us = time_count;//获取80us需要的计数值
}//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit()
{for (time_count =0;DHT11_Read();++time_count);//等待低电平//变低了说明上一次数据位读取结束for (time_count =0;!DHT11_Read();++time_count); //等待变高电平// std_delay_50us = time_count;//测试用的//变高了说明数据位读取开始/**开始读数据*///低电平:26-28us//高电平:70usstd_delay_us(40);// 等待40us,如果延时准确的话if (DHT11_Read())return 1;elsereturn 0;
}//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte()
{uint8_t dat = 0;for (uint8_t i = 0; i < 8; i++){dat <<= 1;dat |= DHT11_Read_Bit();}return dat;
}//uint16_t timeBuf[40];
//uint8_t timeBufIndex=0;
//uint16_t timeMax=0;
//uint16_t timeMin=10000;
//uint8_t DHT11_Read_Byte_Fast()
//{
// uint8_t dat=0;
// for (uint8_t i = 0; i < 8; i++)
// {
// for (time_count =0;DHT11_Read();++time_count);//等待低电平
// //变低了说明上一次数据位读取结束
//
// for (time_count =0;!DHT11_Read();++time_count); //等待变高电平
// // std_delay_50us = time_count;//测试用的
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平:26-28us 高电平:70us
// for (time_count =0;DHT11_Read();++time_count);//等待低电平
// timeBuf[timeBufIndex++]=time_count;
// // std_delay_us(30);// 等待40us,如果延时准确的话
// dat <<= 1;
// dat |= DHT11_Read();
// }
// return dat;
//}uint16_t timeBuf[40];//存储计数值
uint8_t timeBufIndex=0;//存储计数值索引
uint16_t timeMax=0;
uint16_t timeMin=0xFFFF;
void DHT11_Read_Byte_Fast_Pro()
{for (uint8_t i = 0; i < 8; i++){for (time_count =0;DHT11_Read();++time_count);//等待低电平//变低了说明上一次数据位读取结束for (time_count =0;!DHT11_Read();++time_count); //等待变高电平//变高了说明数据位读取开始/**开始读数据*///低电平:26-28us 高电平:70usfor (time_count =0;DHT11_Read();++time_count);//等待低电平timeBuf[timeBufIndex++]=time_count;//存储计数值}
}bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi)
{uint8_t buf[5];DHT11_Rst();DHT11_Check();for (unsigned char & i : buf)//读取40位数据{DHT11_Read_Byte_Fast_Pro();}for (unsigned short i : timeBuf){if(i>timeMax){timeMax=i;}else if(i<timeMin){timeMin=i;}}/**把计数值转为二进制数据*/uint16_t timeMed=(timeMax+timeMin)>>1;//整除2,取中位数uint8_t data;//临时数据bool tempBin;//临时二进制数据for (int i = 0; i < 5; ++i){data=0;//重置for (int j = 0; j < 8; ++j){data<<=1;//比较计数值,读取二进制数据if(timeBuf[i*8+j]>timeMed){tempBin= true;}else{tempBin= false;}data|=tempBin;}buf[i]=data;//存储数据}/**检验**/if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]){humi = (float) (buf[0] + buf[1] * 0.1);temp = (float) (buf[2] + buf[3] * 0.1);return true;}else{return false;}
}//bool DHT11_Read_Data(float &temp, float &humi)
//{
// uint8_t buf[5];
// DHT11_Rst();
// DHT11_Check();
// for (unsigned char & i : buf)//读取40位数据
// {
// i = DHT11_Read_Byte_Fast();
// }
//
// for (unsigned short i : timeBuf)
// {
// if(i>timeMax)
// {
// timeMax=i;
// }
// else if(i<timeMin)
// {
// timeMin=i;
// }
// }
//
// uint16_t timeMed=(timeMax+timeMin)>>1;
// uint8_t data;
// uint8_t tempBin;
// uint8_t tempBuf[5];
// for (int i = 0; i < 5; ++i)
// {
// data=0;
// for (int j = 0; j < 8; ++j)
// {
// data<<=1;
// if(timeBuf[i*8+j]>timeMed)
// {
// tempBin=1;
// }
// else
// {
// tempBin=0;
// }
// data|=tempBin;
// }
// tempBuf[i]=data;
// }
//
// //检验
// if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
// {
// humi = (float) (buf[0] + buf[1] * 0.1);
// temp = (float) (buf[2] + buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}
修正版。里面有三个版本,没被注释的是特化版本,其下愈为通用
#include "DHT11.h"
#include "cmsis_os2.h"
#include "delay.h"
#include "stm32f4xx_hal.h"#define DHT11_Pin GPIO_PIN_6
#define DHT11_Pin_Location 6
#define DHT11_GPIO_Port GPIOE
#define DHT11_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
#define DHT11_MAX_DELAY_COUNT 7000//防止卡死#define DHT11_Read() (DHT11_GPIO_Port->IDR & DHT11_Pin) /*HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin)*/#define DHT11_High() DHT11_GPIO_Port->ODR |= (0x01 << DHT11_Pin_Location)
#define DHT11_Low() DHT11_GPIO_Port->ODR &= ~(0x01 << DHT11_Pin_Location) /*HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET)*/#define DHT11_IN() \{ \DHT11_GPIO_Port->MODER &= ~(3 << (2 * DHT11_Pin_Location)); \DHT11_GPIO_Port->MODER |= 0 << 2 * DHT11_Pin_Location; \}
#define DHT11_OUT() \{ \DHT11_GPIO_Port->MODER &= ~(3 << (2 * DHT11_Pin_Location)); \DHT11_GPIO_Port->MODER |= 1 << 2 * DHT11_Pin_Location; \}//static uint16_t std_delay_80us = 875;//事先测试过
//static uint16_t std_delay_50us = 566;/**动态计算延时,以确保任何情况下都可以得到较为准确的延时*/
//void std_delay_us(uint8_t us)
//{
// // uint16_t count = std_delay_80us * us / 80;//测试得到的
// uint16_t count = 11 * us;
// for (uint16_t i = 0; i < count; ++i)
// ;
//}
inline void std_delay_25us()
{for (uint16_t i = 0; i < 273; ++i);
}/**函数*/
inline void DHT11_Rst();void DHT11_Init()
{GPIO_InitTypeDef GPIO_InitStruct = {0};DHT11_GPIO_CLK_ENABLE();GPIO_InitStruct.Pin = DHT11_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;HAL_GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStruct);DHT11_High();
}inline void DHT11_Rst()
{DHT11_OUT();DHT11_Low();osDelay(30);//根据时序图可知,需要至少拉低18msDHT11_High();std_delay_25us();//20-40us
}inline void DHT11_Check()
{DHT11_IN();while (DHT11_Read());while (!DHT11_Read());
}bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi)
{static uint8_t buf[5];DHT11_Rst(); // 设置输出模式DHT11_Check();// 设置输入模式for (unsigned char & i : buf)// 读取40位数据{uint8_t data=0;for (uint8_t j = 0; j < 8; j++){data<<=1;while (DHT11_Read()) {} // 等待低电平while (!DHT11_Read()) {}// 等待变高电平// 开始读数据uint16_t time_count;for (time_count = 0; DHT11_Read(); ++time_count) {}data|=time_count>>10;// 由于事先已经知道一个为1194,一个为406左右}i = data;// 存储数据}if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]){humi = (buf[0]*10 + buf[1]) / 10.0f;temp = (buf[2]*10 + buf[3] ) / 10.0f;return true;}else{return false;}
}/********************下面为次优级优化********************/全局变量
//static uint8_t timeBuf[40];// 存储计数值
//static uint8_t timeBufIndex = 0;
//
//void DHT11_Read_Byte_Fast_Pro()
//{
// for (uint8_t i = 0; i < 8; i++)
// {
// while (DHT11_Read()) {} // 等待低电平
// while (!DHT11_Read()) {}// 等待变高电平
//
// // 开始读数据
// uint16_t time_count;
// for (time_count = 0; DHT11_Read(); ++time_count) {}
// timeBuf[timeBufIndex++] = time_count>>4;// 存储计数值,由于事先已经知道一个为875,一个为275左右,所以除以16
// }
//}
//
//bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi)
//{
// static uint8_t buf[5];
//
// DHT11_Rst(); // 设置输出模式
// DHT11_Check();// 设置输入模式
//
// timeBufIndex = 0; // 重置计数值索引
// for (unsigned char &i: buf)// 读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// uint16_t timeMax = 0;
// uint16_t timeMin = 0xFFFF;
// for (unsigned short i: timeBuf)
// {
// if (i > timeMax) timeMax = i;
// if (i < timeMin) timeMin = i;
// }
//
// uint16_t timeMed = (timeMax + timeMin) >> 1;// 取中位数
// for (uint8_t i = 0; i < 5; ++i)
// {
// uint8_t data = 0;
// for (uint8_t j = 0; j < 8; j++)
// {
// data <<= 1;
// data |= (timeBuf[i * 8 + j] > timeMed);
// }
// buf[i] = data;// 存储数据
// }
//
// if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
// {
// humi = (buf[0]*10 + buf[1]) / 10.0f;
// temp = (buf[2]*10 + buf[3] ) / 10.0f;
// return true;
// }
// else
// {
// return false;
// }
//}//
//static uint16_t timeBuf[40];//存储计数值
//static uint8_t timeBufIndex = 0;
//void DHT11_Read_Byte_Fast_Pro()
//{
// for (uint8_t i = 0; i < 8; i++)
// {
// while (DHT11_Read())
// ;//等待低电平
// //变低了说明上一次数据位读取结束
//
// while (!DHT11_Read())
// ;//等待变高电平
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平:26-28us 高电平:70us
// uint16_t time_count;
// for (time_count = 0; DHT11_Read(); ++time_count)
// ; //等待低电平
// timeBuf[timeBufIndex++] = time_count;//存储计数值//存储计数值
// }
//}
//
//
//bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi)
//{
// static uint8_t buf[5];
//
// DHT11_Rst(); //在里面设置了输出模式
// DHT11_Check(); //在里面设置了输入模式
// // return false;//如果超时,则退出
// timeBufIndex = 0; //存储计数值索引
// for (unsigned char &i: buf)//读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// uint16_t timeMax = 0;
// uint16_t timeMin = 0xFFFF;
// for (unsigned short i: timeBuf)
// {
// if (i > timeMax)
// {
// timeMax = i;
// }
// else if(i<timeMin)
// {
// timeMin = i;
// }
// }
//
// /**把计数值转为二进制数据*/
// uint8_t data; //临时数据
// uint16_t timeMed = (timeMax + timeMin) >> 1;//整除2,取中位数
// bool tempBin;
// for (uint8_t i = 0; i < 5; ++i)
// {
// data = 0;
// for (uint8_t j = 0; j < 8; j++)
// {
// data <<= 1;
// //比较计数值,读取二进制数据
// if (timeBuf[i * 8 + j] > timeMed)
// {
// tempBin = true;
// }
// else
// {
// tempBin = false;
// }
// data |= tempBin;
// }
// buf[i] = data;//存储数据
// }
//
// /**检验**/
// if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
// {
// humi = (float) (buf[0] + buf[1] * 0.1);
// temp = (float) (buf[2] + buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}/********************下面为原版优化********************/
//static uint16_t timeBuf[40];//存储计数值
//
//void DHT11_Read_Byte_Fast_Pro()
//{
// static uint8_t timeBufIndex = 0;//存储计数值索引
// for (uint8_t i = 0; i < 8; i++)
// {
// while (DHT11_Read())
// ;//等待低电平
// //变低了说明上一次数据位读取结束
//
// while (!DHT11_Read())
// ;//等待变高电平
// //变高了说明数据位读取开始
//
// /**开始读数据*/
// //低电平:26-28us 高电平:70us
// uint16_t time_count;
// for (time_count = 0; DHT11_Read(); ++time_count)
// ; //等待低电平
// timeBuf[timeBufIndex++] = time_count;//存储计数值
// }
//}
//
//
//bool DHT11_Read_Data_Fast_Pro(float &temp, float &humi)
//{
// static uint8_t buf[5];
// static uint16_t timeMax = 0;
// static uint16_t timeMin = 0xFFFF;
//
// DHT11_Rst(); //在里面设置了输出模式
// DHT11_Check(); //在里面设置了输入模式
// // return false;//如果超时,则退出
// for (unsigned char &i: buf)//读取40位数据
// {
// DHT11_Read_Byte_Fast_Pro();
// }
//
// for (unsigned short i: timeBuf)
// {
// if (i > timeMax)
// {
// timeMax = i;
// }
// else
// {
// timeMin = i;
// }
// }
// std_delay_25us();
// std_delay_25us();
// DHT11_OUT();
// DHT11_High();
//
//
// /**把计数值转为二进制数据*/
// uint16_t timeMed = (timeMax + timeMin) >> 1;//整除2,取中位数
// uint8_t data; //临时数据
// bool tempBin; //临时二进制数据
// for (int i = 0; i < 5; ++i)
// {
// data = 0;//重置
// for (int j = 0; j < 8; ++j)
// {
// data <<= 1;
// //比较计数值,读取二进制数据
// if (timeBuf[i * 8 + j] > timeMed)
// {
// tempBin = true;
// }
// else
// {
// tempBin = false;
// }
// data |= tempBin;
// }
// buf[i] = data;//存储数据
// }
//
// /**检验**/
// if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
// {
// humi = (float) (buf[0] + buf[1] * 0.1);
// temp = (float) (buf[2] + buf[3] * 0.1);
// return true;
// }
// else
// {
// return false;
// }
//}
相关文章:
参考——温湿度传感器DHT11驱动_STM32
设备:stm32f407ZGT6 环境:FreeRTOS HAL 到网上找DHT11的驱动,但是都无法使用。原因是RTOS环境中,由于多线程,使用循环计数阻塞式的delay_us延时函数就没那么准,且不同设备中delay_us的计数值不一样…...
架构每日一学 14:架构师如何进行可行性探索?
架构活动中,如果不进行可行性探索可能会导致重大失误,为企业发展带来风险。 可行性探索是架构活动的最后一个节点,在这之后的架构活动就像是离弦之箭,即便发现重大风险也很难再回头了。 互联网公司之间的竞争非常激烈࿰…...
多线程知识-13
为什么应该在循环中检查等待条件 为了实现多线程的同步和协调,通常使用等待和唤醒机制。在等待和唤醒机制中,等待条件是指一个线程等待某个条件的满足,当条件满足时,线程被唤醒继续执行。 在循环中检查等待条件的目的是为了避免虚…...
vue3+cli-service配置代理,跨域请求
一、配置代理端口和代理转发 在vue.config.js文件中 const {defineConfig} require(vue/cli-service)module.exports defineConfig({devServer: {host: 0.0.0.0,port: 8088, // 启动端口号proxy: {/api: { // 请求接口中要替换的标识target: , // 代理地址,后…...
git介绍、安装、配置
文章目录 1. GIT介绍2. 使用GIT的好处3. GIT 安装4. GIT 配置4.1 GIT 初始化设置、命令别名设置4.2 如果终端安装了oh-my-zsh,会带一堆git命令别名4.3 GIT配置文件介绍4.3.1 Linux、Mac OS系统4.3.2 windows系统 5. git设置远程仓库账号密码(拉取、上传代码不用输入…...
打开flutter调试
debugPaintSizeEnabled true; debugPaintBaselinesEnabled true;...

【前端 - Vue】Vuex基础入门,创建仓库的详细步骤
🚀 个人简介:6年开发经验,现任职某国企前端负责人,分享前端相关技术与工作常见问题~ 💟 作 者:前端菜鸟的自我修养❣️ 📝 专 栏:vue从基础到起飞 🌈 若有帮助&…...

#01 Stable Diffusion基础入门:了解AI图像生成
文章目录 前言什么是Stable Diffusion?Stable Diffusion的工作原理如何使用Stable Diffusion?Stable Diffusion的应用场景结论 前言 在当今迅速发展的人工智能领域,AI图像生成技术以其独特的魅力吸引了广泛的关注。Stable Diffusion作为其中的一项前沿技术&#…...

Knife4j使用
Knife4j使用 文章目录 Knife4j使用1、Knife4j介绍2、SpringBoot集成Knife4j3、基本使用 1、Knife4j介绍 Knife4j是一个用于生成和展示API文档的工具,同时它还提供了在线调试的功能,可以看作是Swagger的升级版,界面也比Swagger更好看…...
一文读懂银行承兑汇票:从申请到使用全攻略
银行承兑汇票(Banks Acceptance Bill,BA)是商业汇票的一种。它是由在承兑银行开立存款账户的存款人出票,向开户银行申请并经银行审查同意承兑的,保证在指定日期无条件支付确定的金额给收款人或持票人的票据。银行承兑汇…...

唯众智联网(AIoT)应用开发教学实训解决方案
一、引言 随着信息技术的飞速发展,物联网(IoT)和人工智能(AI)技术逐渐融合,形成了智联网(AIoT)这一新兴领域。智联网通过智能化设备、传感器、云计算等技术手段,实现了数…...
归纳跨域几种解决方案
什么是跨域? **说起跨域,就要知道什么是浏览器同源策略 **浏览器同源策略:必须是协议、域名、端口完全一致的才符合同源策略 **如果以上三项,有一项不同都涉及到跨域问题 为什么浏览器要设置同源策略呢? 没有同源策…...
LeetCode刷题第3题(C#)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串的长度。 法一: 这道题用到的其实是滑动窗口。 滑动窗口算法是在特定窗口大小的数组或字符串上执行要求的操作。它可以将一部分问题中的嵌套循环转变为一个单循环,以此减少时间复…...

了解一下Ubuntu Linux
1.3.1 什么是Ubuntu Ubuntu这个名字非常神奇,它取自非洲南部祖鲁语的ubuntu,是一个哲学名称,其意思为“人性”或者“我的存在是因为大家的存在”。对于中国人来说,一般称呼它为乌班图。 Ubuntu是在Debian的基础上开发出来的&am…...

单一原则+干湿分离,让你的架构能力起飞
# 概念 软件单一原则(Single Responsibility Principle,SRP)是面向对象编程中五大基本设计原则之一。它指每个软件模块或类都应该只负责一个单一的功能或责任。 高内聚低耦合 实现代码可维护性 干湿分离是一种建筑设计和室内装修的方法,主…...

如何恢复永久删除的照片?
“嗨,我永久删除了电脑上的很多照片。回收站被清空,照片会永久丢失吗?有什么方法可以恢复这些已删除的照片吗? 我们所有人都经历过同样的事情:我们的硬盘上存储了文件、视频或照片,但不小心删除了它。这个…...

一文看懂llama2(原理模型训练)
自从Transformer架构问世以来,大型语言模型(Large Language Models, LLMs)以及AIGC技术的发展速度惊人,它们不仅在技术层面取得了重大突破,还在商业应用、社会影响等多个层面展现出巨大潜力。随着ChatGPT的推出&#x…...

Sui基金会公布2024年3–4月资助项目名单
Sui基金会宣布3月和4月的资助项目名单,在这两个月中,共有10个项目获得了资助,以加速Sui的整合和发展。其中有八个项目专注于为开发者创造更好的体验,从开发强大的集成开发环境(IDE)到使用零知识证明保护用户…...

Spring Security3.0.1版本
前言: 抽象Spring Security3.0上一篇 在上一篇中,我们完成了对Security导入,快速入门,和对自动配置的简单验证 对登录流程的分析和Security基本原理 补充: 先解决上一篇留下的问题,端口和端点的区别 端…...

网络报文协议头学习
vxlan:就是通过Vxlan_header头在原始报文前面套了一层UDPIP(4/6)Eth_hdr 需求背景:VXLAN:简述VXLAN的概念,网络模型及报文格式_vxlan报文格式-CSDN博客 如果服务器作为VTEP,那从服务器发送到接…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...

Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...