【智能家居入门1之环境信息监测】(STM32、ONENET云平台、微信小程序、HTTP协议)

作为入门本篇只实现微信小程序接收下位机上传的数据,之后会持续发布如下项目:①可以实现微信小程序控制下位机动作,真正意义上的智能家居;②将网络通讯协议换成MQTT协议再实现上述功能,此时的服务器也不再是ONENET,可以是公用的MQTT服务器也可以自己搭建或者租

    • 最终效果
    • 一、下位机模块测试与分析
      • 1、MQ系列传感器
      • 2、DHT11温湿度传感器
      • 3、Esp8266-01s
      • 4、oled液晶屏
    • 二、微信小程序
    • 三、项目获取

这个项目参考的是b站up主:彼岸有光我们有船

最终效果

实物图:
主控是STM32F103C8T6,这里arduino开发板我只是拿来给几个模块供电的,有面包板的话也可以用面包板,用到的模块有:MQ-4天然气传感器、MQ-9可燃气体传感器、0.96寸oled液晶屏、DHT11温湿度传感器、Esp8266-01s、J-Link下载器。
在这里插入图片描述
ONENET云平台:
在这里插入图片描述
微信小程序:
在这里插入图片描述

一、下位机模块测试与分析

1、MQ系列传感器

MQ气体传感器使用的气敏材料是在清洁空气中电导率较低的二氧化锡。当传感器所处环境中存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增大。使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。MQ气体传感器对甲烷的灵敏度高,对丙烷、丁烷也有较好的灵敏度。这种传感器可检测多种可燃性气体,特别是天然气。
在这里插入图片描述
关于这个传感器的详细资料可以下载阅读:我用夸克网盘分享了「MQ-2-135-3-7-9烟雾空气敏酒精氢一氧化碳可燃液化传感器模块探头.rar」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/22c08247dd8a
提取码:xLRC

在这个项目中只需要接三个引脚:VCC、GND、AO。AO输出接开发板的IO口,通过ADC将传感器的模拟输出转换成数字量。这里用到了开发板上ADC1的通道2、3,对应GPIOA-2、GPIOA-3。 关于 ADC的使用可以直接看视频:
https://www.bilibili.com/video/BV1th411z7sn/?p=21&spm_id_from=pageDriver&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a
下面是多通道ADC源码,如果想再加的话只需要在初始化gpio的时候加上需要的io口即可,但是需要对应io口与adc通道的对应关系:
在这里插入图片描述

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*设置ADC时钟*/
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
	
	/*GPIO初始化*/
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0、PA1、PA2和PA3引脚初始化为模拟输入
	
	/*不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道*/
	
	/*ADC初始化*/
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置
	ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
	ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1
	
	/*ADC使能*/
	ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

/**
  * 函    数:获取AD转换的值
  * 参    数:ADC_Channel 指定AD转换的通道,范围:ADC_Channel_x,其中x可以是0/1/2/3
  * 返 回 值:AD转换的值,范围:0~4095
  */
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	//在每次转换前,根据函数形参灵活更改规则组的通道1
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束
	return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

2、DHT11温湿度传感器

1、DHT11 采用单总线协议与单片机通信,概括起来是两个大过程:配对和数据传输,下面对两个过程进行分析:
①配对过程
(1)Data引脚在默认状态时处于高电平;
(2)在开始通信时,MCU将Data引脚拉低并保持18ms,然后再将Data引脚拉高20-40us;
(3)当DHT11收到命令后,它会主动拉低Data引脚,持续80us;
(4)DHT11再次拉高DATA引脚,80us后开始发送数据给MCU。
在这里插入图片描述
②数据传输
(1)在每次发送数据之前,DHT11会把Data引脚先拉低50us,这表示单片机要继续发送下一位数据;
(2)DHT11拉高Data引脚,如果拉高持续时间是26-28us,表示发送0;如果拉高的持续时间是116-118us,表示发送1。

在这里插入图片描述
2、驱动代码:
①c文件:

#include "dht11.h"
#include "delay.h"
      
//复位DHT11
void DHT11_Rst(void)	   
{                 
	DHT11_IO_OUT(); 	//SET OUTPUT
    DHT11_DQ_OUT=0; 	//拉低DQ
    delay_ms(20);    	//拉低至少18ms
    DHT11_DQ_OUT=1; 	//DQ=1 
	delay_us(30);     	//主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void) 	   
{   
	u8 retry=0;
	DHT11_IO_IN();//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_DQ_IN)return 1;
	else return 0;		   
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在    	 
u8 DHT11_Init(void)
{	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA端口时钟
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 //PA0端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);				 //初始化IO口
 	GPIO_SetBits(GPIOA,GPIO_Pin_8);						 //PA0 输出高
			    
	DHT11_Rst();  //复位DHT11
	return DHT11_Check();//等待DHT11的回应
} 

②头文件:

#ifndef __DHT11_H
#define __DHT11_H 
#include "sys.h"   
 
//IO方向设置
#define DHT11_IO_IN()  {GPIOA->CRH&=0XFFFFFFF0;GPIOA->CRH|=8;}
#define DHT11_IO_OUT() {GPIOA->CRH&=0XFFFFFFF0;GPIOA->CRH|=3;}
IO操作函数											   
#define	DHT11_DQ_OUT PAout(8) //数据端口	PA0出方向 
#define	DHT11_DQ_IN  PAin(8)  //数据端口	PA0入方向

u8 DHT11_Init(void);//初始化DHT11
u8 DHT11_Read_Data(u8 *temp,u8 *humi);//读取温湿度
u8 DHT11_Read_Byte(void);//读出一个字节
u8 DHT11_Read_Bit(void);//读出一个位
u8 DHT11_Check(void);//检测是否存在DHT11
void DHT11_Rst(void);//复位DHT11    
#endif

主函数中直接调用DHT11_Read_Data,定义两个变量接收即可。

3、Esp8266-01s

在使用单片机连接此模块前最好先进行测试,测试可以参考之前的一篇博客(这篇博客还有如何在ONENET云平台创建产品和设备):https://blog.csdn.net/m0_71523511/article/details/135887108
驱动代码:

#include "esp8266.h"

char *str[4] = {"POST /devices/1038xxxxxxxx/datapoints HTTP/1.1",
				"api-key:wfsF4bCGtQIQmW=xxxxxxxx",
				"Host:api.heclouds.com",
				""};
char strValue[8] = {0};

// 向onenet发送数据
u8 *esp8266_str_data(char *key, char *value)
{
	u8 i;
	u8 *back;
	char temp[512];
	char temp3[64];		// 长度
	char temp5[128];		// 发送值

	// 拼接post报文
	strcpy(temp5, "{\"datastreams\":[{\"id\":\"");
	strcat(temp5, key);
	strcat(temp5, "\",\"datapoints\":[{\"value\":");
	strcat(temp5, value);
	strcat(temp5, "}]}]}");

	strcpy(temp3, "Content-Length:");
	sprintf(temp, "%d", strlen(temp5) + 1);
	strcat(temp3, temp);

	strcpy(temp, "");
	for (i = 0; i < 3; i++)
	{
		strcat(temp, str[i]);
		strcat(temp, "\r\n");
	}
	strcat(temp, temp3);
	strcat(temp, "\r\n\r\n");
	strcat(temp, temp5);
	strcat(temp, "\r\n");

	back = esp8266_send_data((u8 *)temp, 50);
	// printf("server:%s\r\n", back);
	if (strstr((char *)back, "ERROR"))		//发送失败, 重新初始化,发送
	{
		esp8266_send_cmd("AT+RST", "OK", 50);
		esp8266_send_cmd("AT+CIPCLOSE", "OK", 50);
	
		esp8266_send_cmd("AT+CWMODE=1", "OK", 50);

		esp8266_send_cmd("AT+CWDHCP=1", "OK", 50);
		//esp8266_send_cmd("AT+CIPMUX=0", "OK", 50);
		while (esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"183.230.40.33\",80", "CONNECT", 100));
		//esp8266_send_cmd("AT+CIPMODE=1", "OK", 50);
		//esp8266_send_cmd("AT+CIPSEND", "OK", 20);
		return esp8266_send_data((u8 *)temp, 50);
	}
	return back;
}

// 向esp8266请求数据
u16 esp8266_get_data(char *vStr)
{
	u8 i;
	u16 value = 0;
	char *back;
	char temp[160] = "GET /devices/1038269453/datastreams/";

	// 拼接请求报文
	strcat(temp, vStr);
	strcat(temp, " HTTP/1.1\r\n");
	for (i = 1; i < 4; i++)
	{
		strcat(temp, str[i]);
		strcat(temp, "\r\n");
	}

	// 发送报文, 获取返回字符串
	back = (char *)esp8266_send_data((u8 *)temp, 50);
	
	// 在回送报文中截取出数值
	back = strchr(strstr(back, "\"current_value\":"), ':') + 1;
	while (*back != '}')
	{
		if(*back == '\"'){
			back++;
			continue;
		}
		value = value * 10 + (*back - '0');
		back++;
	}

	return value;
}


//ESP8266模块和PC进入透传模式
void esp8266_start_trans(void)
{
		//让Wifi模块重启的命令
	esp8266_send_cmd("AT+RST", "OK", 50);
	
	esp8266_send_cmd("AT+CIPCLOSE", "OK", 50);
	
	esp8266_send_cmd("AT+CWMODE=1", "OK", 50);

	esp8266_send_cmd("AT+CWDHCP=1", "OK", 50);

	delay_ms(1000); //延时2S等待重启成功
	delay_ms(1000);

	//让模块连接上自己的路由WIFI GOT IP
	while (esp8266_send_cmd("AT+CWJAP=\"WZQ\",\"1234567890\"", "WIFI GOT IP", 500)){
		delay_ms(1);
	};

	//建立TCP连接  这四项分别代表了 要连接的ID号0~4   连接类型  远程服务器IP地址   远程服务器端口号
	while (esp8266_send_cmd("AT+CIPSTART=\"TCP\",\"183.230.40.33\",80", "CONNECT", 200)){
		delay_ms(1);
	};
}

//ESP8266退出透传模式   返回值:0,退出成功;1,退出失败
//配置wifi模块,通过想wifi模块连续发送3个+(每个+号之间 超过10ms,这样认为是连续三次发送+)
u8 esp8266_quit_trans(void)
{
	u8 result = 1;
	u3_printf("+++");
	delay_ms(1000);							   //等待500ms太少 要1000ms才可以退出
	result = esp8266_send_cmd("AT", "OK", 20); //退出透传判断.
	if (result)
		printf("quit_trans failed!");
	else
		printf("quit_trans success!");
	return result;
}

//向ESP8266发送命令
//cmd:发送的命令字符串;ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果);1,发送失败
u8 esp8266_send_cmd(u8 *cmd, u8 *ack, u16 waittime)
{
	u8 res = 0;
	USART3_RX_STA = 0;
	u3_printf("%s\r\n", cmd); //发送命令
	delay_ms(1);
	if (ack && waittime)	  //需要等待应答
	{
		while (--waittime) //等待倒计时
		{
			delay_ms(10);
			if (USART3_RX_STA&0X8000) //接收到期待的应答结果
			{
				
				if (esp8266_check_cmd(ack))
				{
					printf("%s\r\n", (u8 *)USART3_RX_BUF);
					break; //得到有效数据
				}
				USART3_RX_STA = 0;
				//strcpy((char *)USART3_RX_BUF, "");		// 清空接收缓存区
			}
		}
		if (waittime == 0) res = 1;
	}
	return res;
}

//ESP8266发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果;其他,期待应答结果的位置(str的位置)
u8 *esp8266_check_cmd(u8 *str)
{
	char *strx = 0;
	if (USART3_RX_STA & 0X8000) //接收到一次数据了
	{
		USART3_RX_BUF[USART3_RX_STA & 0X7FFF] = 0; //添加结束符
		strx = strstr((const char *)USART3_RX_BUF, (const char *)str);
	}
	return (u8 *)strx;
}

//向ESP8266发送数据
//cmd:发送的命令字符串;waittime:等待时间(单位:10ms)
//返回值:发送数据后,服务器的返回验证码
u8 *esp8266_send_data(u8 *cmd, u16 waittime)
{
	char temp[1024];
	char *ack = temp;
	USART3_RX_STA = 0;
	u3_printf("%s", cmd); //发送命令
	delay_ms(1);
	if (waittime)		  //需要等待应答
	{
		while (--waittime) //等待倒计时
		{
			delay_ms(10);
			if (USART3_RX_STA & 0X8000) //接收到期待的应答结果
			{
				USART3_RX_BUF[USART3_RX_STA & 0X7FFF] = 0; //添加结束符
				ack = (char *)USART3_RX_BUF;
				USART3_RX_STA = 0;
				break; //得到有效数据
			}
		}
	}
	return (u8 *)ack;
}

// 将数字转为字符串
void numToString(u16 value)
{
	int k = 0, j = 0;
	int num = (int)value;
	char tem[10];
	if (value == 0)
	{
		strValue[0] = '0';
		strValue[1] = '\0';
		return;
	}
	while (num)
	{
		tem[k++] = num % 10 + '0'; //将数字加字符0就变成相应字符
		num /= 10;				   //此时的字符串为逆序
	}
	tem[k] = '\0';
	k = k - 1;
	while (k >= 0)
	{
		strValue[j++] = tem[k--]; //将逆序的字符串转为正序
	}
	strValue[j] = '\0'; //字符串结束标志
}

需要注意的是这段代码有两个地方需要修改:
在这里插入图片描述
分别换成自己云平台的设备ID和master-keyapi。

4、oled液晶屏

这是调试程序的好帮手,用的好可以很快找出程序是哪里出问题了。这个驱动代码网上都有很多封装好的,这里就不贴出来了。本项目用的是四引脚oled,使用IIC通信协议,IIC协议的原理可以看此视频:https://www.bilibili.com/video/BV1th411z7sn/?p=31&spm_id_from=pageDriver&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a
想连接oled的详细代码可以看此视频:
https://www.bilibili.com/video/BV1EN41177Pc/?spm_id_from=333.337.search-card.all.click&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a

二、微信小程序

微信小程序最关键的地方就是与云平台的数据交互,其他比如界面、功能都是在这个的基础上才有用。对微信小程序开发感兴趣的可以学一下javascript,比较简单。
下载文章末尾的开源项目压缩包,解压之后可以看到里面有一个文件夹叫:基于STM32的环境信息采集_微信小程序,打开微信开发者工具,选择导入,选择此小程序文件夹打开即可。
在这里插入图片描述
在这里插入图片描述
进入工程之后修改设备ID和master-keyapi:
在这里插入图片描述
index.js代码:

Page({
    data: {
     temp:0
    },
    // 事件处理函数
    getinfo(){
      var that = this
      wx.request({
      url: "https://api.heclouds.com/devices/1038269453/datapoints",   
      //将请求行中的数字换成自己的设备ID
      header: {
        "api-key": "wfsF4bCGtQIQmW=3wTsPnrdjuFA=" //自己的api-key
      },
      method: "GET",
      success: function (e) {
        console.log("获取成功",e)
        that.setData({
          temp:e.data.data.datastreams[2].datapoints[0].value,
          humi:e.data.data.datastreams[7].datapoints[0].value,
          gas_ch4:e.data.data.datastreams[0].datapoints[0].value,
          ranqi:e.data.data.datastreams[4].datapoints[0].value
        })
        console.log("temp==",that.data.temp),
        console.log("humi==",that.data.humi),
        console.log("gas==",that.data.gas_ch4),
        console.log("ranqi==",that.data.ranqi)
      }
     });
    },
    onLoad() {
      var that = this
      setInterval(function(){
        that.getinfo()
      },5000)
    }
  })

三、项目获取

我用夸克网盘分享了「基于STM32的环境信息采集(ONENET+HTTP).rar」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/23b7bdc7b54b
提取码:pR55

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/437645.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IPSEC VPN 网关模式实验

要求&#xff1a;FW1与FW3建立IPSEC通道&#xff0c;保证10.0.2.0/24网段能访问192.168.1.0/24网段 因为FW1与FW3都处于边界&#xff0c;所以使用网关部署模式来建立IPSEC VPN FW1 这里选择主模式跟隧道模式 FW3与FW1配置类似&#xff0c;与FW1的源目地址反过来&#xff0c;…

-bash: unzip: 未找到命令的解决方案

遇到 -bash: unzip: 未找到命令 这样的错误信息&#xff0c;表示你的系统中没有安装 unzip 工具。unzip 是一个常用的解压工具&#xff0c;用于解压缩 .zip 文件。你可以通过系统的包管理器安装它。 根据你使用的 Linux 发行版&#xff0c;安装 unzip 的命令会有所不同。下面是…

图形系统开发实战课程:进阶篇(上)——10.应用实例:交通路网

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形样式”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-10.html 第十章 应用实例&#xff1a;交通路网 \quad 在前面几…

老师如何发布已点评的学生在校表现,并让家长留言反馈?

教师想要在线上发布已点评过的成绩单&#xff0c;同时想让家长在线留言反馈&#xff0c;还要做到只能查自己孩子的成绩&#xff0c;应该如何实现&#xff1f; 可以使用易查分制作一个学生在校表现查询系统&#xff0c;家长自主查询&#xff0c;有问题可留言向班主任反馈&#x…

什么是工业协议网关?作用是什么?

在工业自动化和智能制造领域&#xff0c;数据的采集、传输和处理是实现设备监控、远程控制和优化的关键。而工业协议网关&#xff0c;作为连接工业设备与上层管理系统的桥梁&#xff0c;发挥着至关重要的作用。今天&#xff0c;我们就来深入解析一下HiWoo Box这一工业协议网关的…

银行数字化转型导师坚鹏:银行数字化转型案例研究

银行数字化转型案例研究 课程背景&#xff1a; 数字化背景下&#xff0c;很多银行存在以下问题&#xff1a; 不清楚银行科技金融数智化案例&#xff1f; 不清楚银行供应链金融数智化案例&#xff1f; 不清楚银行普惠金融数智化案例&#xff1f; 不清楚银行跨境金融数智…

ACM题解Day10|总结篇|进制转化,GCD ,LCM ,二分答案

&#x1f525;博客介绍&#xff1a; 27dCnc [Cstring中find_first_not_of()函数和find_last_not_of()函数-CSDN博客] 方差,期望 概率 今日打卡: 算法周总结 ACM题解Day3| To Crash or not To Crash,Integer Prefix ,I don’t want to pay for the Late Jar-CSDN博客 第3题:…

温室气体排放控制中的DNDC模型建模技术及双碳应用

由于全球变暖、大气中温室气体浓度逐年增加等问题的出现&#xff0c;“双碳”行动特别是碳中和已经在世界范围形成广泛影响。国家领导人在多次重要会议上讲到&#xff0c;要把“双碳”纳入经济社会发展和生态文明建设整体布局。同时&#xff0c;提到要把减污降碳协同增效作为促…

蓝牙 | 软件: Qualcomm BT Audio 问题分析(4)----检查MIPS使用情况

大家好&#xff01; 我是“声波电波还看今朝”成员的一位FAE Devin.wen&#xff0c;欢迎大家关注我们的账号。 今天给大家大概讲解“如何排查Qualcomm BT Audio”的疑难杂症&#xff08;四&#xff09;&#xff1a;MIPS检查。 如果大家还没有注册我们大大通的账号&#xff0c…

彻底理解Java并发:乐观锁、悲观锁和CAS

一、悲观锁与乐观锁 锁的一种宏观分类方式是悲观锁和乐观锁。悲观锁与乐观锁并不是特指某个锁&#xff08;Java 中没有哪个 Lock 实现类就叫 PessimisticLock 或 OptimisticLock&#xff09;&#xff0c;而是在并发情况下的两种不同策略。 1、乐观锁&#xff08;Optimistic L…

RK3568平台 USB数据包的收发格式

一.USB硬件拓扑结构 compound device &#xff1a;多个设备组合起来&#xff0c;通过HUB跟Host相连composite device &#xff1a;一个物理设备有多个逻辑设备(multiple interfaces) 在软件开发过程中&#xff0c;我们可以忽略Hub的存在&#xff0c;硬件拓扑图简化如下&#x…

git revert 撤回之前的几个指定的提交

文章目录 Intro操作命令-n 选项 参考 Intro 在开发过程中&#xff0c;有的时候一开始只是一个小需求&#xff0c;可以改着改着事情超出了控制&#xff0c;比如说我一开始只是想调整一个依赖包的版本&#xff0c;可是改到后来类库不兼容甚至导致项目无法启动。 这个时候我就想&…

(二十二)devops持续集成开发——jenkins服务代理Agent搭建

前言 在Jenkins 中&#xff0c;代理&#xff08;Agent&#xff09;是一种用于执行构建、部署和其他任务的计算节点。代理节点可以是物理机器、虚拟机或容器&#xff0c;它们负责接收 Jenkins 主控节点委派的任务并执行这些任务。通过使用代理节点&#xff0c;可以有效地分担Je…

基于WebDriverAgent代理服务,实现iOS手机app自动化测试的框架搭建

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

[数据结构初阶]队列

鼠鼠我呀&#xff0c;今天写一个基于C语言关于队列的博客&#xff0c;如果有兴趣的读者老爷可以抽空看看&#xff0c;很希望的到各位老爷观点和点评捏&#xff01; 在此今日&#xff0c;也祝各位小姐姐女生节快乐啊&#xff0c;愿笑容依旧灿烂如初阳&#xff0c;勇气与童真永不…

每日五道java面试题之springMVC篇(一)

目录&#xff1a; 第一题. 什么是Spring MVC&#xff1f;简单介绍下你对Spring MVC的理解&#xff1f;第二题. Spring MVC的优点第三题. Spring MVC的主要组件&#xff1f;第四题. 什么是DispatcherServlet?第五题. 什么是Spring MVC框架的控制器&#xff1f; 第一题. 什么是S…

JavaScript 作用域详解:如何影响变量生命周期

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Linux系统——Keepalive群集部署及认识

目录 一、Keepalive的认识 1.Keepalive基础——VRRP 2.Keepalived工具介绍 2.1Keepalived介绍 2.2Keepalived架构 2.2.1用户空间核心组件 2.2.2WatchDog&#xff1a;监控进程&#xff08;整个架构是否有问题&#xff09; 二、安装Keepalived及相关配置文件详解 1.安装…

python 输入和输出

在 Python 中&#xff0c;输入和输出是最基本的操作之一。你可以使用内置函数 input() 来获取用户输入&#xff0c;使用 print() 函数来输出信息到控制台。 输入&#xff08;Input&#xff09; input() 函数用于从用户那里获取输入。这个函数会将用户的输入作为字符串返回。 示…

【C语言】终の指针(前篇)

个人主页点这里~ 指针初阶点这里~ 指针初阶2.0点这里~ 指针进阶点这里~ 终の指针 一、回调函数二、qsort函数1、整形比较2、结构数据比较①结构体②-> 的使用③结构数据比较 一、回调函数 回调函数就是⼀个通过函数指针调用的函数。 把一个函数的指针作为参数传递给另一…