【stm32简单外设篇】- 土壤湿度传感器

一、适用场景

适用场景:室内植物/花圃自动浇水控制、温室环境监测、农业物联网原型、灌溉系统阈值报警、嵌入式入门 ADC 与传感器校准实验。

二、器材清单

土壤湿度传感器模块(常见两类:廉价电阻式探针模块带 AO/DO,或更可靠的电容式传感器,这里用电阻式的) ×1

stm32f103(或其它 STM32)开发板 ×1

若干杜邦线(公对母)×1组

5V/3.3V 稳压电源(按模块规格) ×1

三、工作原理(要点)

电阻式探针:两个金属探针插入土壤,土壤中水份改变电导率,从而改变探针两端电阻(或电压分压)。注意长期会电化学腐蚀,受盐分影响大,稳定性差。

电容式传感器:测量电容随含水量变化(介电常数变化)来推断湿度。优点:抗腐蚀、耐久、稳定;缺点:相对贵一些,需要适配板子/驱动电路。

四、接线示意

VCC → +5V

GND → GND

标准库

PC5 →AO

PA0 →DO

HAL库

PA0 →AO

PA0 →DO

五、示例代码
标准库-DO

cpp 复制代码
void gpio_init()
{
	GPIO_InitTypeDef PA;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	
	PA.GPIO_Pin = GPIO_Pin_0;
	PA.GPIO_Mode = GPIO_Mode_IPU;
	PA.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&PA);
}


int main()
{
	USART_Config();
	SysTick_Init();
	gpio_init();
	while(1)
	{
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) == SET)
		{
			Usart_SendString(USART1,"no\n");
		}else
		{
			Usart_SendString(USART1,"water\n");
		}
		Delay_us(1000000);
	}
//	return 0;
}

标准库-AO

cpp 复制代码
int main()
{
	SysTick_Init();
	TIM3_Init();
	USART_Config();
	adctime_Init();
	while(1)
	{
//		sprintf(showlight,"light:%d\n",adc_light);
//		Usart_SendString(USART1,showlight);
//		Delay_us(1000000);
	}
//	return 0;
}
#include "adc_time.h"
#include "stm32f10x.h"

volatile uint16_t adc_light;

void adcgpio_init()
{
	GPIO_InitTypeDef PC;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

	
	PC.GPIO_Pin = GPIO_Pin_5;
	PC.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOC,&PC);
}

void adcmode_init()
{
	ADC_InitTypeDef adc;
	NVIC_InitTypeDef nvic;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,ENABLE);
	
  adc.ADC_Mode=ADC_Mode_Independent;
	adc.ADC_ScanConvMode = DISABLE;
	adc.ADC_ContinuousConvMode = ENABLE;
	adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	adc.ADC_DataAlign = ADC_DataAlign_Right;
	adc.ADC_NbrOfChannel = 1;
	
	ADC_Init(ADC2,&adc);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	ADC_RegularChannelConfig(ADC2,ADC_Channel_11,1,ADC_SampleTime_55Cycles5);
	ADC_ITConfig(ADC2,ADC_IT_EOC,ENABLE);

	ADC_Cmd(ADC2,ENABLE);
	
	ADC_ResetCalibration(ADC2);
	while(ADC_GetResetCalibrationStatus(ADC2));
	
	ADC_StartCalibration(ADC2);
	while(ADC_GetCalibrationStatus(ADC2));
	
	ADC_SoftwareStartConvCmd(ADC2,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
  nvic.NVIC_IRQChannel = ADC1_2_IRQn;
	nvic.NVIC_IRQChannelPreemptionPriority = 3;
	nvic.NVIC_IRQChannelSubPriority = 0;
	nvic.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic);

	
}

void adctime_Init()
{
	adcgpio_init();
	adcmode_init();
}

void ADC1_2_IRQHandler(void)
{
	if(ADC_GetITStatus(ADC2,ADC_IT_EOC) == SET)
	{
		adc_light = ADC_GetConversionValue(ADC2);
	}
	ADC_ClearITPendingBit(ADC2,ADC_IT_EOC);
}
#include "breathing.h"
#include "stm32f10x.h"
#include "stdio.h"
#include "bsp_usart.h"

char showlight[20];
extern volatile uint16_t adc_light;
uint16_t num_final=10;

uint16_t adc_indexlight[] = {
1024,901,792,697,613,
539,474,417,367,323,
284,250,219,193,170,
149,131,116,102,89,
79,69,61,53,47,
41,36,32,28,25,
22,19,17,15,13,
11,10,9,8,7,
6,5,5,4,4,
3,3,2,2,2,
2,1,1,1,1,
0,0,0,0
};

void GPIO_twoInit()
{
	GPIO_InitTypeDef PD;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
	
	PD.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
	PD.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOD,&PD);
	
}

void TIM_GPIO_Init()
{
	GPIO_InitTypeDef PB;
	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
	
	PB.GPIO_Pin = GPIO_Pin_5;
	PB.GPIO_Speed = GPIO_Speed_50MHz;
	PB.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOB,&PB);
}

void TIM_PWM_Init()
{
	TIM_TimeBaseInitTypeDef TIM;
	TIM_OCInitTypeDef TIM_OC;
	NVIC_InitTypeDef nvic;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	TIM.TIM_Prescaler = (1024-1);  										//配置预装载值
	TIM.TIM_Period = (200-1);													//配置预分频值
	TIM.TIM_ClockDivision = TIM_CKD_DIV1;  						//设置时钟分频系数为不分频
	TIM.TIM_CounterMode = TIM_CounterMode_Up;					//设置向上计数
	TIM_TimeBaseInit(TIM3,&TIM);
	
	TIM_OC.TIM_OCMode = TIM_OCMode_PWM1;							//选择工作模式为PWM
	TIM_OC.TIM_OutputState = TIM_OutputState_Enable;  //使能PWM的输出
	TIM_OC.TIM_Pulse = 0;															//配置脉冲宽度为0
	TIM_OC.TIM_OCPolarity = TIM_OCPolarity_Low;     	//小于脉冲宽度时为低电平
	TIM_OC2Init(TIM3,&TIM_OC);
	
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);	//使能定时器通道2预装载
	
	TIM_ARRPreloadConfig(TIM3,ENABLE);								//使能重装载寄存器
	
	TIM_Cmd(TIM3,ENABLE);															//使能定时器3
	
  TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
  nvic.NVIC_IRQChannel = TIM3_IRQn;
	nvic.NVIC_IRQChannelPreemptionPriority = 4;
	nvic.NVIC_IRQChannelSubPriority = 0;
	nvic.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic);
	
} 



void TIM3_Init()
{
	TIM_GPIO_Init();
	TIM_PWM_Init();
}	


void TIM3_IRQHandler(void)
{
	uint16_t value;
	static uint16_t num_cnt = 0;
	
	value = (adc_light)/74;
	
	
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
	{
		num_cnt++;
		if(num_cnt > num_final)
		{
			
			TIM_SetCompare2(TIM3,adc_indexlight[value]);
			sprintf(showlight,"light:%d,value:%d\n",adc_light,value);
			Usart_SendString(USART1,showlight);
			num_cnt=0;
		}
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}

HAL库-DO

cpp 复制代码
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 1)
			HAL_UART_Transmit(&huart1,"土壤湿度正常\r\n", strlen("土壤湿度正常\r\n"), HAL_MAX_DELAY);
		else
			HAL_UART_Transmit(&huart1,"土壤湿度过高\r\n", strlen("土壤湿度过高\r\n"), HAL_MAX_DELAY);
		HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

HAL库-AO

cpp 复制代码
int main(void)
{
 
  /* USER CODE BEGIN 1 */
  char show[20]={0};
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//#1。启动常规序列
		HAL_ADC_Start(&hadc1);
		//#2.等待转换完成
		HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);
		//#3。获取结果
		uint32_t dr = HAL_ADC_GetValue(&hadc1);
		//#4.把结果转换成电压
		float voltage = dr *(3.3f-0.0f)/4095.0f;
		sprintf(show,"adc:%d,%.2f\n",dr,voltage);
		HAL_UART_Transmit(&huart1,show,strlen(show),HAL_MAX_DELAY);
		HAL_Delay(500);
//		if(voltage>1.5f)//光线暗
//			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_13,GPIO_PIN_SET);// 灭灯
//		else//光线亮
//			HAL_GPIO_WritePin(GPIOA,GPIO_PIN_13,GPIO_PIN_RESET); // 亮灯
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
​

六、讲解视频

https://www.bilibili.com/video/BV19xsmzTE8h/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV19WsmzBE2u/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

https://www.bilibili.com/video/BV1ZjsmzVEDJ/?spm_id_from=333.1387.upload.video_card.click&vd_source=f7dfe1b14f260b9cc3a146d2dbfd0719

相关推荐
序属秋秋秋16 小时前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程
雲烟16 小时前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞16 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
Yue丶越16 小时前
【C语言】数据在内存中的存储
c语言·开发语言·网络
田甲16 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up17 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
Yue丶越1 天前
【C语言】字符函数和字符串函数
c语言·开发语言·算法
纳祥科技1 天前
Switch快充方案,内置GaN,集成了多个独立芯片
单片机
蓝牙先生1 天前
简易TCP C/S通信
c语言·tcp/ip·算法
单片机日志1 天前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息