当前位置: 首页 > news >正文

基于STM32的阿里云智能农业大棚

目录

前言:

项目效果演示:

一、简介

二、硬件需求准备

三、硬件框图

四、CubeMX配置

4.1、按键、蜂鸣器GPIO口配置

4.2、ADC输入配置

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

4.7、定时器配置——按键消抖所需

五、部分代码实现思路

5.1、菜单实现思路

5.2、OLED驱动

5.3、按键消抖

5.4、DHT11温湿度驱动

5.5、光照强度、土壤湿度ADC转换

5.6、esp8266连接阿里云

六、功能拓展


前言:

注意事项:本项目使用的是u8g2库进行显示驱动OLED,需要学会移植或者直接使用我的模板,具体可以看我的这个博文:手把手移植基于STM移植U8g2图形库教程——0.96寸OLED(附送整理资料)

买来的esp8266模可能不支持连接阿里云,需要烧写MQTT固件,具体操作可以看看我的这个博文:手把手连接阿里云教程

里面都会有所需的固件和工具和教程!

项目效果演示:

智能农业大棚

一、简介

这可以作为一个简单的课设或者用来水毕设的一个小项目,总体来说挺简单的,我做完后就打算开源出来大家一起学习一下,具体功能如下:

1、按键:

      按键一:切换菜单

      按键二:切换选项

      按键三:+-或调节风扇 | 水泵 | 灯光

      按键四:确认 | 连接阿里云平台

2、液晶屏幕显示:

     菜单1:主界面显示空气温湿度,土壤湿度,光照强度,检测是否超过或低于临界值

     菜单2:临界值调节

     菜单3:风扇手动开关

     菜单4:灯光手动开关

     菜单5:水泵手动开关

     菜单6:阿里云连接菜单界面

3、土壤湿度、空气温湿度、光照强度高于或低于临界值,蜂鸣器就会响

4、土壤湿度过低自动打开水泵

5、光照强度过低自动打开照明灯

6、空气温度过高会自动打开风扇

7、连接阿里云平台,可以在电脑上面查看各个数据

二、硬件需求准备

1、STM32F103最小核心开发板

2、0.96寸OLED屏幕

3、按键X4

4、TB6612FNG点击驱动模块

5、水泵

6、电机(带小风扇)

7、DHT11温湿度模块

8、esp8266模块

9、蜂鸣器

10、土壤湿度传感器

11、光照强度传感器

12、照明灯模块

三、硬件框图

四、CubeMX配置

这里只演示配置使用的外设配置过程!

4.1、按键、蜂鸣器GPIO口配置

按键配置为上拉模式、蜂鸣器低电平输出有效

  4.2、ADC输入配置

ADC为读取土壤湿度和光照强度的ADC数值,这里开启两个ADC分别读取

ADC1——读取土壤湿度:

ADC2——读取光照强度:

4.3、IIC——驱动OLED

4.4、DHT11温湿度读取

这个使用过程中会对弈随意变动上下拉模式,所以这里就不配置了,使用的GPIO口为PB8

4.5、PWM配置——光照灯、水泵、风扇

4.6、串口——esp8266模块

开启中断:

4.7、定时器配置——按键消抖所需

开启中断:

最后生成工程即可。

五、部分代码实现思路

5.1、菜单实现思路

最常用的就是菜单索引法还有链表法,我这里菜单结构非常简单,所以我就使用索引法了,这里简单说一下,就是每一个菜单都对应一个结构体((这个项目没有二级界面,所以用不到进入索引和返回索引)):

typedef struct
{int current_index;//当前索引int last_index;   //下一索引int enter_index;  //进入索引int back_index;   //返回索引void(*current)(u8g2_t u8g2);}Menu;

结构体成员包括以上的几个。

这个小项目有5个菜单页面:所以定义5个结构体(这个项目没有二级界面,所以用不到进入索引和返回索引):

Menu Menu_Table[30] = 
{
// 当 下 进 返{0, 1, 0, 0,(*Home_Menu)}, //主页显示界面{1, 2, 0, 0,(*Set_Menu)},  //设置临界值界面{2, 3, 0, 0,(*Fan_Menu)},  //风扇控制界面{3, 4, 0, 0,(*Light_Menu)},//灯光控制界面{4, 5, 0, 0,(*Water_Menu)},//水泵控制界面{5, 0, 0, 0,(*Wifi_Menu)},//连接阿里云控制界面};

然后定义一个当前显示菜单的索引值和当前菜单显示绘制函数:

int Current_Menu_index = 0;//当前菜单索引
void(*Current)(u8g2_t u8g2);//当前菜单索引执行绘制函数

然后初始化好按键,按下后执行跳转:

切换下一菜单使用例子(如果是其他的可以八next换成其他的结构体成员):

Current_Menu_index = Menu_Table[Current_Menu_index].last_index;//变换索引值Current = Menu_Table[Current_Menu_index].current;//函数复制
(*Current)(u8g2);//执行绘制函数

在举一个例子帮助大家理解一下,比如,我们当前程序处在索引号为2(临界值界面),就会执行Set_Menu函数。此时,如果按下next按键,程序当前索引号就会变为3,并且执行索引号为3时候的Fan_Menu函数。以此类推!

5.2、OLED驱动

这里我是使用开源的u8g2库进行开发,这个库显示效果很好,而且也很好移植!具体可以参考我的这个博文:移植u8g2库,移植成功后使用也可以看看我的另外要给博文:u8g2库函数使用

5.3、按键消抖

我这里使用的是中断消抖:

unsigned char Key_PIN_Read()
{unsigned char Temp=0;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)   Temp = 1;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET)   Temp = 2;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)   Temp = 3;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15) == GPIO_PIN_RESET)   Temp = 4;return Temp;} void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)              //中断回调函数
{Key_Slow++;if(Key_Slow == 10)  Key_Slow = 0;//按键消抖
}void Key_Pro()
{if(Key_Slow) return;//按键减速Key_Slow=1;Key_Val=Key_PIN_Read();Key_Down=Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿Key_Old=Key_Val;switch(Key_Up){case 1:break;case 2:break;case 3:break;case 4:break;}}

5.4、DHT11温湿度驱动

手动配置GPIO模式:

#define DHT_HIGHT HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8)uint8_t datas[5];//空气温湿度数据void delay_us(uint16_t cnt)
{uint8_t i;while(cnt){for (i = 0; i < 10; i++){}	cnt--;}
}void DHT_GPIO_Init(uint32_t Mode)
{GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_8;GPIO_InitStruct.Mode = Mode;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}void DHT11_Start(void)
{DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);DHT_HIGHT;DHT_LOW;HAL_Delay(30);DHT_HIGHT;DHT_GPIO_Init(GPIO_MODE_INPUT);while(DHT_VALUE);while(!DHT_VALUE);while(DHT_VALUE);
}void Read_Data_From_DHT()
{int i;//轮int j;//每一轮读多少次char tmp;char flag;DHT11_Start();DHT_GPIO_Init(GPIO_MODE_INPUT);for(i= 0;i < 5;i++){for(j=0;j<8;j++){while(!DHT_VALUE);//等待卡g点delay_us(40);if(DHT_VALUE == 1){flag = 1;while(DHT_VALUE);}else{flag = 0;}tmp = tmp << 1;tmp |= flag;}datas[i] = tmp;}
}

数据显示以及文字显示:

void Printf_DHT11(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var_buf[100];char var_buf1[100];Read_Data_From_DHT();//读取温湿度数据u8g2_DrawXBMP(&u8g2, x, y, 16, 16, kong);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, qi);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, wen);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);u8g2_DrawXBMP(&u8g2, x, y+16, 16, 16, kong);u8g2_DrawXBMP(&u8g2, x+16, y+16, 16, 16, qi);u8g2_DrawXBMP(&u8g2, x+32, y+16, 16, 16, wen);u8g2_DrawXBMP(&u8g2, x+48, y+16, 16, 16, du);sprintf(var_buf , ": %d.%d C",datas[2],datas[3]);sprintf(var_buf1, ": %d.%d",datas[0],datas[1]);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var_buf);u8g2_DrawStr(&u8g2, x+64, y+32, var_buf1);
}

5.5、光照强度、土壤湿度ADC转换

int Printf_Soil(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var[100];int value;HAL_ADC_Start(&hadc1); //启动ADC单次转换HAL_ADC_PollForConversion(&hadc1, 50); //等待ADC转换完成value = HAL_ADC_GetValue(&hadc1); //读取ADC转换数据value = 100 - value * 100 / 4096;
//	Soil  = value;u8g2_DrawXBMP(&u8g2, x, y, 16, 16, tu);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, rang);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, shi);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);sprintf(var , ": %d %%", value);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var);return value;}int Printf_Light(u8g2_t u8g2,u8g2_uint_t x, u8g2_uint_t y, const uint8_t *font)
{char var[100];int value;HAL_ADC_Start(&hadc2); //启动ADC单次转换HAL_ADC_PollForConversion(&hadc2, 50); //等待ADC转换完成value = HAL_ADC_GetValue(&hadc2); //读取ADC转换数据value = 100 - value * 100 / 4096;
//	Light = value;u8g2_DrawXBMP(&u8g2, x, y, 16, 16, guang);u8g2_DrawXBMP(&u8g2, x+16, y, 16, 16, zhao);u8g2_DrawXBMP(&u8g2, x+32, y, 16, 16, qiang);u8g2_DrawXBMP(&u8g2, x+48, y, 16, 16, du);sprintf(var , ": %d %%", value);u8g2_SetFont(&u8g2, font);u8g2_DrawStr(&u8g2, x+64, y+16, var);return value;}

5.6、esp8266连接阿里云

这里我为了保险起见就是用了很多的延迟时间(连接时间过长),你们可以自己调节时间!

#define USERNAME   "test&k28qfTAtkBg" //用户名
//                 "test&k28qfTAtkBg"
#define PASSWORD   "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39" //密码
//                 "d7c3b27a5d8ca954487de1e1946a4a08439a2c2508242268e9d90ce178178f39"
#define CLIENTID   "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|" //设备名称
//                 "k28qfTAtkBg.test|securemode=2\\,signmethod=hmacsha256\\,timestamp=1736673123047|"
#define PRODUCTID  "k28qfTAtkBg" //产品ID
//                 "k28qfTAtkBg"
#define DOMAINNAME "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com" //域名
//                 "iot-06z00fj5kcoes6j.mqtt.iothub.aliyuncs.com"
#define DEVICENAME "test"//WiFi连接函数
void Wifi_Connect()
{printf("AT\r\n");//避免报错HAL_Delay(500);printf("AT+RESTORE\r\n");//恢复出厂HAL_Delay(5000);//	printf("AT+RST\r\n");//复位
//	HAL_Delay(5000);printf("ATE0\r\n");//关闭回显HAL_Delay(5000);printf("AT+CWMODE=3\r\n");//设置双模式HAL_Delay(5000);printf("AT+CWJAP=\"USER_E191B0\",\"98599714\"\r\n");//设置WIFI密码和账号HAL_Delay(5000);printf("AT+MQTTUSERCFG=0,1,\"NULL\",\"%s\",\"%s\",0,0,\"\"\r\n",USERNAME,PASSWORD);//设置MQTT的username和passwordHAL_Delay(5000);printf("AT+MQTTCLIENTID=0,\"%s\"\r\n",CLIENTID);	//设置CLIENTIDHAL_Delay(5000);printf("AT+MQTTCONN=0,\"%s\",1883,1\r\n",DOMAINNAME);//设置域名HAL_Delay(5000);printf("AT+MQTTSUB=0,\"/%s/%s/user/get\",1\r\n",PRODUCTID,DEVICENAME);//订阅}

六、功能拓展

后续拓展:

1、电脑阿里云平台控制单片机

2、添加语音模块

。。。。。。。。。。。。其他

后续打了PCB板子后有空会实现给大家,觉得有帮助的可以点点关注!

相关文章:

基于STM32的阿里云智能农业大棚

目录 前言&#xff1a; 项目效果演示&#xff1a; 一、简介 二、硬件需求准备 三、硬件框图 四、CubeMX配置 4.1、按键、蜂鸣器GPIO口配置 4.2、ADC输入配置 4.3、IIC——驱动OLED 4.4、DHT11温湿度读取 4.5、PWM配置——光照灯、水泵、风扇 4.6、串口——esp8266模…...

80,【4】BUUCTF WEB [SUCTF 2018]MultiSQL

53&#xff0c;【3】BUUCTF WEB october 2019 Twice SQLinjection-CSDN博客 上面这个链接是我第一次接触二次注入 这道题也涉及了 对二次注入不熟悉的可以看看 BUUCTF出了点问题&#xff0c;打不开&#xff0c;以下面这两篇wp作为学习对象 [SUCTF 2018]MultiSQL-CSDN博客 …...

深入探索imi框架:PHP Swoole的高性能协程应用实践

摘要 本文将介绍 imi 框架&#xff0c;这是一个基于 PHP Swoole 的高性能协程应用开发框架。imi 支持 HttpApi、WebSocket、TCP 和 UDP 等多种服务类型&#xff0c;利用 Swoole 的优化技术&#xff0c;使得在处理请求时响应速度远超传统的 php-fpm 方式。通过丰富的代码示例&a…...

【算法篇·更新中】C++秒入门(附练习用题目)

一.二分 1.二分查找 我们来看这样一道题&#xff1a; 有一个保证有序的数组a&#xff0c;它的长度为n。现在我们需要知道这个序列是否含有x。 数据范围&#xff1a;保证n<1e9 我们看到这道题之后&#xff0c;第一时间想到的就是暴力枚举了&#xff0c;可是我们发现直接枚举…...

对神经网络基础的理解

目录 一、《python神经网络编程》 二、一些粗浅的认识 1&#xff09; 神经网络也是一种拟合 2&#xff09;神经网络不是真的大脑 3&#xff09;网络构建需要反复迭代 三、数字图像识别的实现思路 1&#xff09;建立一个神经网络类 2&#xff09;权重更新的具体实现 3&am…...

存储基础 -- SCSI命令格式与使用场景

SCSI命令格式与使用场景 1. SCSI命令描述符块&#xff08;CDB&#xff09; 1.1 CDB基本概念 SCSI命令通过**命令描述符块&#xff08;CDB, Command Descriptor Block&#xff09;**表示。 CDB长度&#xff1a;SCSI命令根据使用场景有不同长度的CDB&#xff0c;常见的有6字节…...

从崩溃难题看 C 标准库与 Rust:线程安全问题引发的深度思考

在软件开发的世界里&#xff0c;每一次技术的变革和尝试都伴随着未知的挑战。EdgeDB 团队在将部分网络 I/O 代码从 Python 迁移到 Rust 的过程中&#xff0c;就遭遇了一场棘手的问题&#xff0c;这个问题不仅暴露了 C 标准库的线程安全隐患&#xff0c;也让我们对 Rust 的 “安…...

【CSS入门学习】Flex布局设置div水平、垂直分布与居中

水平平均分布 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>…...

9. 神经网络(一.神经元模型)

首先&#xff0c;先看一个简化的生物神经元结构&#xff1a; 生物神经元有多种类型&#xff0c;内部也有复杂的结构&#xff0c;但是可以把单个神经元简化为3部分组成&#xff1a; 树突&#xff1a;一个神经元往往有多个树突&#xff0c;用于接收传入的信息。轴突&#xff1a;…...

R 语言 | future 包,非阻塞的执行耗时脚本

目的&#xff1a;有一段代码&#xff0c;后面暂时用不到&#xff0c;但是又很耗时&#xff0c;占了当前R session&#xff0c;难道只能等半个小时&#xff0c;等到它结束才能画图&#xff1f; 可以使用R多线程&#xff0c;在支线进程中执行耗时任务&#xff0c;同时不阻塞当前…...

UE学习日志#12 Niagara特效大致了解(水文,主要是花时间读了读文档和文章)

1 核心组件&#xff08;官方文档阅读&#xff09; 一些介绍主要来自官方文档Niagara概述 1.1 Systems 官方文档中的描述&#xff1a; Niagara系统是一种容器&#xff0c;可以放入你要构建该效果的所有内容。在这个系统中&#xff0c;你可以搭建不同的构建块来实现总体效果。…...

【数据结构】_链表经典算法OJ:合并两个有序数组

目录 1. 题目描述及链接 2. 解题思路 3. 程序 3.1 第一版 3.2 第二版 1. 题目描述及链接 题目链接&#xff1a;21. 合并两个有序链表 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给…...

Mongodb副本集群为什么选择3个节点不选择4个节点

一、容错能力的定义 在副本集中&#xff0c;容错能力是指系统能够容忍多少个节点故障而仍然能够保持服务可用性的能力。这通常与选举机制中的多数投票原则密切相关。 二、三节点副本集的容错能力 在三节点的副本集中&#xff0c;通常有一个主节点和两个从节点。当主节点故障…...

基于 WEB 开发的手机销售管理系统设计与实现内容

标题:基于 WEB 开发的手机销售管理系统设计与实现 内容:1.摘要 摘要&#xff1a;随着智能手机的普及和电子商务的快速发展&#xff0c;手机销售行业面临着越来越多的挑战和机遇。为了提高销售效率和管理水平&#xff0c;本文设计并实现了一个基于 WEB 的手机销售管理系统。该系…...

LeetCode - Google 大模型校招10题 第1天 Attention 汇总 (3题)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145368666 GroupQueryAttention(分组查询注意力机制) 和 KVCache(键值缓存) 是大语言模型中的常见架构&#xff0c;GroupQueryAttention 是注意力…...

Vue3 provide/inject用法总结

1. 基本概念 provide/inject 是 Vue3 中实现跨层级组件通信的方案&#xff0c;类似于 React 的 Context。它允许父组件向其所有子孙组件注入依赖&#xff0c;无论层级有多深。 1.1 基本语法 // 提供方&#xff08;父组件&#xff09; const value ref(hello) provide(key, …...

Linux——网络基础(1)

文章目录 目录 文章目录 前言 一、文件传输协议 应用层 传输层 网络层 数据链路层 数据接收与解封装 主机与网卡 数据传输过程示意 二、IP和MAC地址 定义与性质 地址格式 分配方式 作用范围 可见性与可获取性 生活例子 定义 用途 特点 联系 四、TCP和UDP协…...

【记录】日常|从零散记录到博客之星Top300的成长之路

文章目录 shandianchengzi 2024 年度盘点概述写作风格简介2024年的创作内容总结 shandianchengzi 2024 年度盘点 概述 2024年及2025年至今我创作了786即84篇文章&#xff0c;加上这篇就是85篇。 很荣幸这次居然能够入选博客之星Top300&#xff0c;这个排名在我之前的所有年份…...

【二分查找】力扣373. 查找和最小的 K 对数字

给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。 定义一对值 (u,v)&#xff0c;其中第一个元素来自 nums1&#xff0c;第二个元素来自 nums2 。 请找到和最小的 k 个数对 (u1,v1), (u2,v2) … (uk,vk) 。 示例 1: 输入: nums1 [1,7,11], nums2 …...

池化层Pooling Layer

1. 定义 池化是对特征图进行的一种压缩操作&#xff0c;通过在一个小的局部区域内进行汇总统计&#xff0c;用一个值来代表这个区域的特征信息&#xff0c;常用于卷积神经网络&#xff08;CNN&#xff09;中。 2. 作用 提取代表性信息的同时降低特征维度&#xff0c;具有平移…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...