STM32单片机+雨滴传感器+OLED屏幕+蜂鸣器报警+雨滴数据发送到串口调试助手+源代码

目录

一、雨滴传感器介绍

二、雨滴传感器接线说明

三、测试说明、雨滴传感器驱动代码

四、串口调试助手把采集的雨滴数据发送出来 

五、串口调试助手软件下载 

六、源代码

七、雨滴传感器原理图资料


一、雨滴传感器介绍

        为确保自适应天气控制策略执行的准确性,加设雨滴传感器来辅助判断天气情况。该传感器用于雨雪天气状况的监测,可转成数字信号或模拟信号输出。传感器采用高品质FR-04双面材料,采用镀镍处理表面,具有对抗氧化,导电性,及寿命方面更优越的性能。如图所示。    

        该传感器具有数字开关量输出(0和1)和模拟量AO电压输出两种输出形式。     接上5V电源,电源灯亮,感应板上没有水滴时,DO输出为高电平,开关指示灯灭;滴上一滴水,DO输出为低电平,开关指示灯亮;刷掉上面的水滴后又恢复,输出高电平状态。AO模拟输出,可以连接单片机的AD口检测滴在上面的雨量大小。DO TTL数字输出也可以连接单片机检测是否有雨。

        雨滴传感器基本上是一块板,上面以线形形式涂覆镍。它基于抵抗原理。雨水传感器模块允许通过模拟输出引脚测量湿度,当湿度阈值超过时,它可以提供数字输出。

        该模块基于LM393运算放大器。它包括电子模块和“收集”雨滴的印刷电路板。当雨滴积聚在电路板上时,它们会形成并联电阻路径,该路径可通过运算放大器进行测量。

        传感器是一个电阻偶极子,在潮湿时显示较小的电阻,而在干燥时显示较大的电阻。当船上没有雨滴时,它会增加电阻,因此我们根据V = IR获得高电压。当出现雨滴时,它会降低电阻,因为水是电的导体,并且水的存在使镍线并联连接,因此降低了电阻并降低了其两端的电压降。

二、雨滴传感器接线说明

VCC(+):电源正极接口,外接电源3 ~ 5V电源正极,接单片机的5v或者3v引脚

GND(-):电源负极接口,外接电源负极或地线GND,接单片机的GND

   AO         :模拟信号输出口,接单片机的PA1采集引脚

三、测试说明、雨滴传感器驱动代码

编译环境:keil5

测试单片机: STM32F103C8T6

功能:功能1:设定雨滴阈值,超过阈值触发蜂鸣器报警

           功能2:发送雨滴数据串到口调试助手上进行显示

RAINDROP.c文件编写雨滴传感器驱动代码如下:

#include "RAINDROP.h"
#include "Delay.h"	
 //初始化ADC															   
void  RAINDROP_Adc_Init(void)
{ 	
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );	  //使能ADC1通道时钟
 

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

	//PA0 作为模拟通道输入引脚                         
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
	GPIO_Init(GPIOA, &GPIO_InitStructure);	

	ADC_DeInit(ADC1);  //复位ADC1 

	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束
	
	ADC_StartCalibration(ADC1);	 //开启AD校准
 
	while(ADC_GetCalibrationStatus(ADC1));	 //等待校准结束
 
//	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能

}				  
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道,采样时间为239.5周期	  			    
  
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		Delay_ms(5);
	}
	return temp_val/times;
} 

RAINDROP.h文件,对驱动函数经行了声明:  

#ifndef __RAINDROP_H
#define __RAINDROP_H	

#include "sys.h"
#include "math.h"



void RAINDROP_Adc_Init(void);
u16  Get_Adc(u8 ch); 
u16 Get_Adc_Average(u8 ch,u8 times); 

#endif 

四、串口调试助手把采集的雨滴数据发送出来 

printf("雨滴 = %d ",RAINDROP_Value);

五、串口调试助手软件下载 

串口调试助手-keil5调试工具资源-CSDN文库

六、源代码

《STM32单片机+雨滴传感器+OLED屏幕+蜂鸣器报警+雨滴数据发送到串口调试助手》源代码资源-CSDN文库

七、雨滴传感器原理图资料

雨滴传感器原理图、模块资料资源-CSDN文库

<think>嗯,用户想了解哈希表的相关知识,我需要详细讲解。首先,我得从哈希表的基本概念开始介绍,说明它是什么以及它的作用。然后,可能需要解释哈希函数,这是哈希表的核心部分,不同的哈希函数有什么特点,比如直接定址法、除留余数法、平方取中法之类的。接下来要讲哈希表的构造过程,包括如何处理冲突,比如开放地址法和链地址法。开放地址法里又有线性探测、二次探测和双重哈希这些方法,得分别解释它们的原理和优缺点。链地址法的话,需要说明如何用链表解决冲突,可能还要比较两种方法的效率。 然后,用户可能想知道哈希表的性能,比如时间复杂度,最好情况和最坏情况下的区别,这里涉及到装填因子和扩容机制。需要解释为什么装填因子过高会导致性能下降,以及如何动态调整哈希表的大小,比如重新哈希的过程。可能还要提到哈希表在现实中的应用,比如数据库索引、缓存系统等,让用户明白它的实际用途。 另外,用户可能对哈希表的优缺点感兴趣,比如高效的查找、插入和删除,但同时也存在哈希冲突影响性能的问题。需要提醒设计哈希表时需要注意选择合适的哈希函数和冲突解决方法。还有可能涉及常见的哈希函数示例,比如MD5、SHA系列,但这里可能主要聚焦在数据结构中的哈希函数,而不是加密领域的。 用户可能没有明确说明他们的背景,但如果是计算机专业的学生,可能需要更技术性的细节,比如具体的时间复杂度计算,或者如何实现一个简单的哈希表。如果是非技术背景,可能需要用更通俗的例子,比如图书馆书籍存放的类比,来解释哈希表的工作原理。 需要检查是否有遗漏的重要概念,比如哈希表的负载因子、再哈希的过程,或者如何处理哈希碰撞的不同策略的比较。同时,要确保用中文表达清晰,结构层次分明,使用适当的数学公式,比如用$符号包裹的行内公式和独立公式,符合之前的系统指令要求。 可能还需要注意避免术语混淆,比如哈希表和哈希映射是否指同一结构,可能需要统一术语。另外,举例说明不同冲突解决方法的具体步骤,帮助用户理解。例如,线性探测时,如果位置被占用,就顺序查找下一个空位,而二次探测则是按平方数跳跃查找,减少聚集现象。 最后,总结哈希表的适用场景和最佳实践,让用户知道在什么情况下使用哈希表最合适,以及设计时需要考虑的因素。确保回答结构清晰,分点讲解,逐步深入,同时保持语言简洁易懂,符合用户的需求。</think>好的,我将以清晰的结构为您讲解哈希表的核心知识,包含原理、实现和应用。以下分步骤说明: --- ### 一、哈希表基本概念 **定义**:哈希表(Hash Table)是一种通过**键值对(Key-Value)**存储数据数据结构,能在平均**$O(1)$时间复杂度**下完成数据的插入、查找和删除。 **核心思想**: 1. 通过**哈希函数**将键(Key)映射到数组的特定位置 2. 若发生冲突(不同键映射到同一位置),使用**冲突解决方法**处理 --- ### 二、哈希函数设计 哈希函数需满足**均匀性**和**高效性**。常见方法包括: 1. **直接定址法** $$ \text{hash}(key) = a \times key + b $$ 适合键值分布连续的场景 2. **除留余数法**(最常用) $$ \text{hash}(key) = key \mod p $$ $p$通常选择质数以减少冲突 3. **平方取中法** 对键平方后取中间几位作为哈希值 4. **字符串哈希**(如BKDRHash) $$ \text{hash}(str) = \sum_{i=0}^{n-1} str[i] \times seed^{n-1-i} $$ --- ### 三、冲突解决方法 #### 1. 开放定址法 - **线性探测**: 若位置$i$冲突,依次尝试$i+1, i+2, \dots$ $$ \text{hash}'(key) = (\text{hash}(key) + j) \mod m \quad (j=1,2,3,\dots) $$ - **二次探测**: 按平方序列探测,减少聚集现象 $$ \text{hash}'(key) = (\text{hash}(key) + j^2) \mod m $$ - **双重哈希**: 使用第二个哈希函数计算步长 $$ \text{hash}'(key) = (\text{hash}_1(key) + j \times \text{hash}_2(key)) \mod m $$ #### 2. 链地址法(拉链法) - 每个数组位置维护一个链表 - 冲突元素直接追加到链表尾部 - 时间复杂度取决于链表长度(理想情况下为$O(1)$) --- ### 四、性能优化 #### 关键指标:装填因子(Load Factor) $$ \alpha = \frac{\text{已存储元素数}}{\text{哈希表容量}} $$ 当$\alpha > 0.7$时建议扩容(例如Java HashMap默认阈值为0.75) #### 扩容机制 1. 创建新数组(通常容量翻倍) 2. 重新计算所有元素的哈希值(称为**重哈希**) 3. 迁移数据到新数组 --- ### 五、时间复杂度分析 | 操作 | 平均情况 | 最坏情况 | |------------|----------|----------| | 插入/删除 | $O(1)$ | $O(n)$ | | 查找 | $O(1)$ | $O(n)$ | > **注意**:最坏情况发生在所有键都冲突时,但通过良好设计的哈希函数和扩容策略可避免 --- ### 六、典型应用场景 1. 数据库索引(如MySQL的哈希索引) 2. 缓存系统(如Redis键值存储) 3. 唯一性检查(如检测重复元素) 4. 编译器符号表管理 5. 密码学(如MD5/SHA哈希函数) --- ### 七、优缺点总结 **优点**: - 接近常数时间的操作效率 - 适合快速查找和去重需求 **缺点**: - 哈希函数设计不当会导致严重冲突 - 遍历元素时效率低于数组/链表 - 内存消耗较高(需预分配空间) --- ### 八、代码示例(简化版Java实现) ```java class HashMap<K, V> { private Node<K,V>[] table; private int capacity = 16; private double loadFactor = 0.75; // 哈希函数 private int hash(K key) { return key.hashCode() % capacity; } // 插入操作 public void put(K key, V value) { int index = hash(key); if (table[index] == null) { table[index] = new Node<>(key, value); } else { // 处理冲突(此处简化为链表法) Node<K,V> current = table[index]; while (current.next != null) { current = current.next; } current.next = new Node<>(key, value); } // 检查扩容... } } ``` --- 如有具体问题(如哈希函数选择、扩容策略优化等),欢迎进一步提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式Dora

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值