基于STM32F407ZET6的环境温湿度监控系统(粤嵌GEC-M4)

news2024/12/25 11:09:08

注意使用事项:
开发板如下
在这里插入图片描述

由于外部晶振是8M,需要修改setup和stm32f4头文件的晶振值。
操作如下:
system_stm32f4xx.c的254行

#define PLL_M      8

stm32f4xx.h的127行

  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

基于STM32F407ZET6的环境温湿度监控系统

  • 工程文件下载如下
  • 功能介绍和使用说明
  • 如下代码
    • 目录如下
    • main.c
    • system.c
    • system.h
    • KEY.c
    • KEY.h
    • LED.c
    • LED.h
    • BEEP.c
    • BEEP.h
    • UART.c
    • UART.h
    • CODED_LOCK.c
    • CODED_LOCK.h
    • TIMER.c
    • TIMER.h
    • DHT11.c
    • DHT11.h
    • ADC.c
    • ADC.h

工程文件下载如下

下载点这里

功能介绍和使用说明

下载程序后打开串口调试助手,按一下复位按键,如图。
在这里插入图片描述
通过按键输入1234进入,或者输入指令open#进入系统,密码错误会连响两下,正确会长响一下,进入之后如图。
在这里插入图片描述
到了控制界面,通过输入指令mode0或者mode1切换手动模式和自动模式,手动模式可以使用滑动变阻器控制LED1亮度,自动模式可以由光敏电阻调节灯光亮度。
温度阈值和湿度阈值是温度和湿度的临界值,当温度高于临界值,LED3亮,否则灭,当湿度高于临界值,LED2亮。
灯光亮度是滑动变阻器值,光照值是光敏电阻值。
温度阈值可以由指令txx修改,比如t20就是修改到20
湿度阈值可以由指令hxx修改,比如h20就是修改到20
最后输入off#退出系统

如下代码

目录如下

在这里插入图片描述

main.c

#include "CODED_LOCK.h"

int main(void)
{
	while(1)
	{
		CODED_LOCK_Open();
		
	}
}

system.c

#include "system.h"


void System_Init(void)
{
	LED_Init();
	KEY_Init();
	BEEP_Init();
	UART1_Init(115200);
	//TIM3_Init(10000,8400);
	//ADC1_Init();
	adc_init();
	adc3_init();
	TIM14_init();
	TIM_SetCompare1(TIM14,95);
}

//软件延时
void delay_us(uint32_t nus)
{

	SysTick->CTRL = 0; 			// Disable SysTick,关闭系统时钟后才能设置寄存器
	SysTick->LOAD = SystemCoreClock/8/1000000*nus; 		//设置计数值
	SysTick->VAL = 0; 			// Clear current value as well as count flag,清空当前值还有标志位
	SysTick->CTRL = 1; 			// Enable SysTick timer with processor clock,使能系统定时器开始计算,且使用8分频的时钟
	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set,等待计数完成
	SysTick->CTRL = 0; 			// Disable SysTick,关闭系统时钟代表说不再进行定时计数	

}

void delay_ms(uint32_t nms)
{
	while(nms --)
	{
		SysTick->CTRL = 0; 			// Disable SysTick,关闭系统时钟后才能设置寄存器
		SysTick->LOAD = SystemCoreClock/8/1000; 		// 设置计数值
		SysTick->VAL = 0; 			// Clear current value as well as count flag,清空当前值还有标志位
		SysTick->CTRL = 1; 			// Enable SysTick timer with processor clock,使能系统定时器开始计算,且使用8分频的时钟
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set,等待计数完成
		SysTick->CTRL = 0; 			// Disable SysTick,关闭系统时钟代表说不再进行定时计数	
	
	}
}

system.h

#ifndef __system_H_
#define __system_H_

#include "stm32f4xx.h"
#include "LED.h"
#include "BEEP.h"
#include "KEY.h"
#include "UART.h"
#include "TIMER.h"
#include "DHT11.h"
#include "ADC.h"
#include "string.h"


//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+\
                              ((addr & 0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))//把值类型转成地址类型
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     
 
#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 
 
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 
 
#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 
 
#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 
 
#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入
 
#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入
 
#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
 
#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入
 
#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入


void System_Init(void);
void delay_us(uint32_t nus);
void delay_ms(uint32_t nms);

#endif 

KEY.c

#include "KEY.h" 

void KEY_Init(void)
{
	GPIO_InitTypeDef gpio;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE,ENABLE);

	gpio.GPIO_Mode=GPIO_Mode_IN;	
	gpio.GPIO_PuPd=GPIO_PuPd_UP;
	
	gpio.GPIO_Pin=GPIO_Pin_0;
	GPIO_Init(GPIOA,&gpio);
	
	gpio.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;	
	GPIO_Init(GPIOE,&gpio);
}



KEY.h

#ifndef __KEY_H_
#define __KEY_H_


#include "system.h" 

#define KEY0 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define KEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define KEY3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define KEY ((KEY0)|(KEY1<<1)|(KEY2<<2)|(KEY3<<3))

void KEY_Init(void);
//unsigned char KEY_Scan(void);


#endif 

LED.c

#include "LED.h" 

void LED_Init(void)
{
	GPIO_InitTypeDef gpio;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOE,ENABLE);

	gpio.GPIO_Mode=GPIO_Mode_OUT;	
	gpio.GPIO_PuPd=GPIO_PuPd_UP;
	gpio.GPIO_Speed=GPIO_Speed_100MHz;
	gpio.GPIO_OType=GPIO_OType_PP;
	
	gpio.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
	GPIO_Init(GPIOF,&gpio);
	
	gpio.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14;	
	GPIO_Init(GPIOE,&gpio);
	GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
	GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14);
}

LED.h

#ifndef __LED_H_
#define __LED_H_


#include "system.h"
void LED_Init(void);

#endif 

BEEP.c

#include "BEEP.h" 


void BEEP_Init(void)
{
	GPIO_InitTypeDef gpio;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);

	gpio.GPIO_Mode=GPIO_Mode_OUT;	
	gpio.GPIO_PuPd=GPIO_PuPd_UP;
	gpio.GPIO_Speed=GPIO_Speed_100MHz;
	gpio.GPIO_OType=GPIO_OType_PP;
	
	gpio.GPIO_Pin=GPIO_Pin_8;
	GPIO_Init(GPIOF,&gpio);
	
	GPIO_ResetBits(GPIOF,GPIO_Pin_8);	
}


BEEP.h

#ifndef __BEEP_H_
#define __BEEP_H_


#include "system.h" 
void BEEP_Init(void);

#endif 

UART.c

#include "UART.h"

void UART1_Init(uint32_t baudrate) 
{
  GPIO_InitTypeDef GPIO_InitStruct;
  USART_InitTypeDef USART_InitStruct;
  NVIC_InitTypeDef NVIC_InitStructure;
  // 使能USART1和GPIOA的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  // 配置USART1的引脚
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // PA9(TX), PA10(RX)
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  // 将引脚复用为USART1
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); // TX
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); // RX

  // 配置USART1
  USART_InitStruct.USART_BaudRate = baudrate;
  USART_InitStruct.USART_WordLength = USART_WordLength_8b;
  USART_InitStruct.USART_StopBits = USART_StopBits_1;
  USART_InitStruct.USART_Parity = USART_Parity_No;
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_Init(USART1, &USART_InitStruct);

	/* 配置中断参数--使能中断 */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

      //设置中断条件---接收缓冲区有数据就产生中断
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

  // 使能USART1
  USART_Cmd(USART1, ENABLE);

}

int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(USART1, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}
 
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
 
		return (int)USART_ReceiveData(USART1);
}
extern uint8_t usart_recv[1024];//接受串口数据---字符串
extern int recv_i;//接收数组下标
extern int recv_end;//接收标记  0 没有完  1 完了


void USART1_IRQHandler(void)//"hello#"
{
	uint8_t d;
    //检测中断是否产生
	if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
	{
	    d =USART_ReceiveData(USART1);
		  if(recv_i < 1024&& d != '#'&& recv_end ==0)
			{
			     usart_recv[recv_i++] = d;
			}
			else
			{
			     recv_end = 1;
			}
	    
		//把接收的数据回发给发送方
		 //USART_SendData(USART1,d); //h
		 //while(USART_GetFlagStatus( USART1,USART_FLAG_TXE)==0);//等待上一个数据发送完毕
     		
	}
    //把中断标志位清空,方便接收下一次中断
	USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	
}

UART.h

#ifndef __UART_H_
#define __UART_H_

#include <stdio.h>
#include "system.h"

void UART1_Init(uint32_t baudrate) ;


#endif 

CODED_LOCK.c

#include "CODED_LOCK.h"

uint8_t pass_num[4]={1,2,3,4};
uint8_t input_num[4]={0,0,0,0};
uint8_t open=0;
uint8_t dht_data[5];
int ret = 0;
uint32_t adc_val;
int adc_vol;
uint32_t light_val;
int light_vol;

unsigned char mode=0;

uint8_t usart_recv[1024]={0};//接受串口数据---字符串
int recv_i = 0;//接收数组下标
int recv_end = 0;//接收标记  0 没有完  1 完了

int byte_light=40;
int byte_temp=40;
int byte_humi=90;
char display=1;
void CODED_LOCK_Open(void)
{
	System_Init();
	while(1)
	{
		  if(recv_end ==1)
			{
				

			      if(strncmp((char *)usart_recv,"open",6)== 0)
			      {
			         //打开D1
				       input_num[0]=1;input_num[1]=2;input_num[2]=3;input_num[3]=4;
			      }
						else if(strncmp((char *)usart_recv,"mode1",6)== 0)mode=1;
						else if(strncmp((char *)usart_recv,"mode0",6)== 0)mode=0;
						else if(strncmp((char *)usart_recv,"display",7)== 0)display=1;
						else if(strncmp((char *)usart_recv,"off",7)== 0)open=0;
						else if(usart_recv[0]==116)
						{
							//printf("recv is %d ,%d\n",usart_recv[1]-48,usart_recv[2]-48);
							byte_temp=(usart_recv[1]-48)*10+(usart_recv[2]-48);
						}
						else if(usart_recv[0]==104)
						{
							//printf("recv is %d ,%d\n",usart_recv[1]-48,usart_recv[2]-48);
							byte_humi=(usart_recv[1]-48)*10+(usart_recv[2]-48);
						}
						
						memset(usart_recv,0,1024);//清空接收缓冲区数组
						recv_end = 0;//接收标志置零,方便下一个字符串的接收
			      recv_i = 0;//下标清零
						display=1;
			}		
//		USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
//		TIM_ITConfig(TIM3,TIM_IT_Update , DISABLE);
	  ADC_SoftwareStartConv(ADC1);
		//等待转换完成
		while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)!=SET);
		//获取ADC1的转换结果
		adc_val=ADC_GetConversionValue(ADC1);
		//将结果值转换为电压值
		adc_vol=adc_val*100/4095;


		ADC_SoftwareStartConv(ADC3);
		//等待转换完成
		while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC)!=SET);
		//获取ADC1的转换结果
		light_val=ADC_GetConversionValue(ADC3);
		//将结果值转换为电压值
		light_vol=light_val*100/4095;
//		TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);
//		USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);		
		
		 if((mode==1)&&(open==1))
		 {
			TIM_SetCompare1(TIM14,90-light_vol);
		 }
		 else if((mode==0)&&(open==1))
		 {
			 TIM_SetCompare1(TIM14,110-adc_vol);
		 }			 
		
		if(open==1)
		{
			if(dht_data[0]<byte_humi)PFout(10)=1;
			else PFout(10)=0;
			if(dht_data[2]<byte_temp)PEout(13)=1;
			else PEout(13)=0;
		}
		 
		ret = Get_DHT11_Data(dht_data);
		KEY_Scan();
		if((input_num[0]!=0)&&(input_num[1]!=0)&&(input_num[2]!=0)&&(input_num[3]!=0))
		{
			if((input_num[0]==pass_num[0])&&(input_num[1]==pass_num[1])&&(input_num[2]==pass_num[2])&&(input_num[3]==pass_num[3]))
			{
				PFout(8)=1;delay_ms(1000);PFout(8)=0;
				open=1;display=1;
			}
			else
			{
				PFout(8)=1;delay_ms(500);PFout(8)=0;delay_ms(500);
				PFout(8)=1;delay_ms(500);PFout(8)=0;
				printf("密码错误,请重新输入\r\n");
				open=0;
			}
			input_num[0]=input_num[1]=input_num[2]=input_num[3]=0;
		}
		 if((open==1)&&(display==1))
		 {
			 display=0;
			 printf("/**************温湿度控制界面******************/\r\n");
			 if(mode==0)
				 printf("/*****模式:手动\r\n");
			 if(mode==1)
				 printf("/*****模式:自动\r\n");
			 printf("/*****当前湿度:%d/\r\n",dht_data[0]);
			 printf("/*****当前温度:%d/\r\n",dht_data[2]);
			 printf("/*****灯光亮度:%d/\r\n",adc_vol);
			 printf("/*****光照值:%d/\r\n",110-light_vol);
			 printf("/*****湿度阈值:%d/\r\n",byte_humi);
			 printf("/*****温度阈值:%d/\r\n",byte_temp);
			 printf("/**********************************************/\r\n");
		 }
		 if((open==0)&&(display==1))
		 {
			 display=0;
			 printf("/**************密码输入界面******************/\r\n");
			 printf("密码:%d %d %d %d\r\n",input_num[0],input_num[1],input_num[2],input_num[3]);
			 printf("/**********************************************/\r\n");
		 }		
	}
}

void Input_Data(char data)
{
	if(input_num[0]==0)
	{
		input_num[0]=data;display=1;
	}
	else if(input_num[1]==0)
	{
		input_num[1]=data;display=1;
	}
	else if(input_num[2]==0)
	{
		input_num[2]=data;display=1;
	}
	else if(input_num[3]==0)
	{
		input_num[3]=data;display=1;
	}
}


void KEY_Scan(void)
{
	static char keybyte=0;
	static char key=0x0f;
	//static char return_num=0;
	//if(KEY==0x0f)return 1;
	if((KEY!=0x0f)&&(keybyte==0))
	{
		key=0x0f;key &=KEY;keybyte=1;
	}
	if((KEY==0x0f)&&(keybyte==1))
	{
		keybyte=0;
		switch(key)
		{
			case 0x0e:Input_Data(1);break;
			case 0x0d:Input_Data(2);break;
			case 0x0b:Input_Data(3);break;
			case 0x07:Input_Data(4);break;
			//default: return 0;
		}
	}
}



CODED_LOCK.h

#ifndef __CODED_LOCK_H_
#define __CODED_LOCK_H_


#include "system.h"
void CODED_LOCK_Init(void);
void CODED_LOCK_Open(void);
void KEY_Scan(void);
void Input_Data(char data);

#endif 

TIMER.c

#include "TIMER.h"


//tim3初始化
void TIM3_Init(uint32_t period,uint32_t Prescaler)
{
	//period=5000 Prescaler=8400
	 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	 NVIC_InitTypeDef NVIC_InitStructure;
	 /* 打开TIM3时钟  */
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	 //定时器参数配置:频率  计数值 方向。。。。。中断间隔500ms  中断频率 2hz
	 TIM_TimeBaseStructure.TIM_Period = period;//计数值10000 时间就过去1s  10时间过去1ms
	 TIM_TimeBaseStructure.TIM_Prescaler = Prescaler;//设置频率  分频值  84000 000hz/8400  10000hz 1s数10000个数
	 TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
 
	 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

	 /* 配置定时器3的中断参数 */
	 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	 NVIC_Init(&NVIC_InitStructure);


		/* 设置中断条件 */
	 TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);
 
	 /*启动定时器计数*/
	 TIM_Cmd(TIM3, ENABLE);
 }

 //定时器14 通道1 初始化
void TIM14_init(void)
{
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 定时器14的时钟使能*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
	

	/*定时器的基本配置,用于配置定时器的输出脉冲的频率为200Hz */
	TIM_TimeBaseStructure.TIM_Period = 10000/200-1;					//设置定时脉冲的频率
	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;						//第一次分频,简称为预分频
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;				//第二次分频,当前实现1分频,也就是不分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);

	/* 配置PF9 引脚为复用模式 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;					//第9根引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;				//设置复用模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;				//推挽模式,增加驱动电流
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;			//设置IO的速度为100MHz,频率越高性能越好,频率越低,功耗越低
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;			//不需要上拉电阻
	GPIO_Init(GPIOF, &GPIO_InitStructure);	
	
	GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_TIM14);
	
	
	/* 让定时器14 PWM 的通道 1 工作在模式 1*/
	 //PWM 模式 1, 在递增模式下, 只要TIMx_CNT < TIMx_CCR1, 通道 1 便为有效状态(高电平), 否则为无效状态(低电平)。
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //允许输出
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//有效的时候, 输出高电平
	TIM_OC1Init(TIM14, &TIM_OCInitStructure);
	
	//TIMx_CCR1比较值的设置是由TIM_SetCompare1、TIM_SetCompare2、TIM_SetCompare3、TIM_SetCompare4来进行设置
	
	TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);  //自动重载初值, 不断输出 PWM 脉冲
	TIM_ARRPreloadConfig(TIM14, ENABLE); 				//自动重载初值使能
	
	/*  使能定时器 14 工作 */
	TIM_Cmd(TIM14, ENABLE);
}


TIMER.h

#ifndef __TIMER_H_
#define __TIMER_H_


#include "system.h"

void TIM3_Init(uint32_t period,uint32_t Prescaler);
void TIM14_init(void);

#endif 

DHT11.c

#include "DHT11.h"

//PG9输出模式
void DHT11_Out()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 打开GPIOG的时钟  */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

	/* 选择引脚编号PF9 PF10,配置为输出模式 */
	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;//9号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	GPIO_Init(GPIOG, &GPIO_InitStructure); 
	PGout(9) = 1;
}

 //PG9输入模式
void DHT11_In()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 打开GPIOG的时钟  */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;//0号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//添加上拉电阻
	GPIO_Init(GPIOG, &GPIO_InitStructure); 
}

//读取一个字节(8bit)的数据
uint8_t Read_DHT11_Byte()//1101 0000
{
		uint8_t byte = 0;//0000 0000 
		int i = 0;
		for(i = 0;i<8;i++)
		{
				 //等待低电平时隙结束
				 while(PGin(9) == 0);
				 delay_us(40);
				 if(PGin(9) == 1)
				 {
						 //当前数据就是1				       
						 byte = byte|(1<<(7-i));
						 //等待为1时70us的高电平结束
						 while(PGin(9) == 1);
				 }		
		}
		
		return byte;
}
 //获取一次温湿度数据
int Get_DHT11_Data(uint8_t *DHT11_Data)
{
	 int i = 0;
	 int t = 0;
	 //1.32芯片发送开始信号
	 //PG9输出模式
	 DHT11_Out();
	 PGout(9) = 0;
	 delay_ms(20);
	 PGout(9) = 1;
	 delay_us(30);
	 
	 //2.32芯片等待回响信号---dht11发送响应信号
		//PG9输入模式
	 DHT11_In();
	 
	 while(PGin(9) == 1)//等待响应信号到来
	 {
				delay_us(1);
				t++;
				if(t >200)
				{
					 return 1;
				}						
	 
	 }
	 t= 0;
	 while(PGin(9) == 0)//等待响应信号低电平结束
	 {
				delay_us(1);
				t++;
				if(t >200)
				{
					 return 2;
				}		
	 }
	 t = 0;
	 while(PGin(9) == 1)//等待响应信号高电平结束
	 {
				delay_us(1);
				t++;
				if(t >200)
				{
					 return 3;
				}		
	 }
	 //3.32芯片接收温湿度数据---dht11发送温湿度数据 (40bit)
	 for(i = 0;i <5; i++)
	 {
			 //获取8bit(一个字节)的数据
			 DHT11_Data[i] = Read_DHT11_Byte();
	 
	 }
	 
	//4.校验数据是否正常
	 if(DHT11_Data[0]+DHT11_Data[1]+DHT11_Data[2]+DHT11_Data[3] == DHT11_Data[4])
	 {
			 return 0;
	 }
	 
}

DHT11.h

#ifndef __DHT11_H_
#define __DHT11_H_


#include "system.h"

int Get_DHT11_Data(uint8_t *DHT11_Data);
void DHT11_Out();
void DHT11_In();
uint8_t Read_DHT11_Byte();


#endif 

ADC.c

#include "ADC.h"

 void adc_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef       ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_StructInit(&ADC_InitStructure);

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	//初始化PA5引脚为模拟模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* ADC常规的初始化*/
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;						//独立模式,只使用一个ADC硬件进行工作
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;						//ADC硬件的频率=84MHz/2=42MHz
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;			//取消DMA访问模式
	//ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;	//如果采用了多个ADC硬件对某个通道进行采样的,那么这个时间就是他们硬件工作的相隔时间
	ADC_CommonInit(&ADC_CommonInitStructure);										
	
	/* ADC1初始化*/
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;							//12bit精度,非常重要[*]
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;									//因不需要多个ADC硬件对某个通道进行采样,则不需要连续扫描
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;								//连续转换,就是ADC硬件一直进行转换输出结果,否则只得到一个结果
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;		//禁止外部脉冲触发ADC硬件工作
	//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;							//存储的结构使用右对齐的存储方式[*]
	//ADC_InitStructure.ADC_NbrOfConversion = 1;									//这个是在DMA模式生效的,转换的结果总数数量是放到内存当中	
	ADC_Init(ADC1, &ADC_InitStructure);


	/* ADC1的通道5的配置
	   指定ADC1的通道5,它的优先级为最高1(范围:1~16),采样时间为3个ADC时钟周期=3*1/f=3*(1/42MHz)
	*/
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);

	
	/* 使能ADC工作 */
	ADC_Cmd(ADC1, ENABLE);

}

void adc3_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef       ADC_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_StructInit(&ADC_InitStructure);

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);  
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);

	//初始化PA5引脚为模拟模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOF, &GPIO_InitStructure);

	/* ADC常规的初始化*/
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;						//独立模式,只使用一个ADC硬件进行工作
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;						//ADC硬件的频率=84MHz/2=42MHz
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;			//取消DMA访问模式
	//ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;	//如果采用了多个ADC硬件对某个通道进行采样的,那么这个时间就是他们硬件工作的相隔时间
	ADC_CommonInit(&ADC_CommonInitStructure);										
	
	/* ADC1初始化*/
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;							//12bit精度,非常重要[*]
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;									//因不需要多个ADC硬件对某个通道进行采样,则不需要连续扫描
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;								//连续转换,就是ADC硬件一直进行转换输出结果,否则只得到一个结果
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;		//禁止外部脉冲触发ADC硬件工作
	//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;							//存储的结构使用右对齐的存储方式[*]
	//ADC_InitStructure.ADC_NbrOfConversion = 1;									//这个是在DMA模式生效的,转换的结果总数数量是放到内存当中	
	ADC_Init(ADC3, &ADC_InitStructure);


	/* ADC1的通道5的配置
	   指定ADC1的通道5,它的优先级为最高1(范围:1~16),采样时间为3个ADC时钟周期=3*1/f=3*(1/42MHz)
	*/
	ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);

	
	/* 使能ADC工作 */
	ADC_Cmd(ADC3, ENABLE);

}

ADC.h

#ifndef __ADC_H_
#define __ADC_H_


#include "system.h" 


//void ADC1_Init(void);

 void adc_init(void);
 void adc3_init(void);
#endif 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实战SRC漏洞挖掘全过程,流程详细【网络安全】

前言 记录一次完整的某SRC漏洞挖掘实战&#xff0c;为期一个多星期。文章有点长&#xff0c;请耐心看完&#xff0c;记录了完整的SRC漏洞挖掘实战 渗透过程 因为选择的幸运儿没有对测试范围进行规划&#xff0c;所以此次范围就是没有范围。 先上主域名看一眼&#xff0c;看…

2023 Google 开发者大会 – AI 领域的技术更新

大会介绍 Google 开发者大会是 Google 面向开发者和科技爱好者展示最新产品和平台的年度盛会。2023 Google 开发者大会 (Google I/O Connect | China) 为开发者提供丰富的学习资源&#xff0c;实践操作和现场演示&#xff0c;提供与谷歌专家互动、与其他开发者交流的契机&…

贝锐蒲公英客户端6.0发布,异地组网更快、更简单

贝锐蒲公英客户端6.0全新升级&#xff0c;新版本融合了企业版、个人版和个人管理端&#xff0c;不同身份用户可以统一登录&#xff0c;快速部署&#xff0c;即装即用&#xff0c;为异地组网带来更加简单、高效的解决方案。 快速部署、即装即用&#xff0c;支持不同身份用户统一…

langchain主要模块(三):Chain

langchain2之Chain langchain1.概念2.主要模块模型输入/输出 (Model I/O)数据连接 (Data connection)链式组装 (Chains)代理 (Agents)内存 (Memory)回调 (Callbacks) 3.链• LLMChain&#xff1a;• SimpleSequentialChain• Sequential Chains:• RouterChain&#xff1a; lan…

社群团购平台方的选品,无外乎就几个方面:

社群团购平台方选品&#xff0c;无外乎几个方面&#xff1a; 1、是个主推广爆品&#xff0c;好产品&#xff08;好产品的标准&#xff1a;有卖点&#xff1a;比如&#xff1a;有 品牌力、市场需求力、诱人的性价比等&#xff09; 2、你是否跟社群团购平台方说清楚这个产品的优…

什么是云存储,从对象存储说起?

在《存储系统形态之争,从块存储到统一存储》一文中我们提到了对象存储的概念,知道目前很多企业级存储都是支持对象存储的,比如EMC、NetApp和华为等。以EMC的对象存储为例,其最早在1998年就已经具备成熟的产品了,到目前已经有二十多年的历史了。如图是关于对象存储主要产品…

科研诚信与学术规范MOOC-错题集

为了确保学术和科研诚信&#xff0c;很多大学制定了荣誉法则。大学建立荣誉制度的初衷旨在预防大学生考试作弊。“反相对论公司”是对科学的不当干预。&#xff08;√&#xff09;科学具有普遍性&#xff0c;与种族、国籍、宗教、阶级和个人品质等个人因素无关。&#xff08;不…

GpsModule 350+ 常用GPS坐标地图

背景 开源库 GpsAndMap 的 GpsModule 模块中整理集成了 350 国内常用地市的GPS坐标地址&#xff0c;对于日常使用&#xff0c;例如打些标记&#xff0c;做些PPT展示&#xff0c;是非常方便的。 引入模块 pip install GpsAndMap 打印常用地市GPS地名清单 以下代码打印了常用…

【业务功能109】微服务-springcloud-springboot-Skywalking-链路追踪-监控

Skywalking skywalking是一个apm系统&#xff0c;包含监控&#xff0c;追踪&#xff0c;并拥有故障诊断能力的 分布式系统 一、Skywalking介绍 1.什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint …

力扣 -- 1218. 最长定差子序列

参考代码&#xff1a; class Solution { public:int longestSubsequence(vector<int>& arr, int difference) {int narr.size();unordered_map<int,int> hash;//nums[i]绑定dp[i]hash[arr[0]]1;int ret1;for(int i1;i<n;i){int aarr[i];int ba-difference;…

电力系统安全问题,金融行业需警惕!

在现代金融业务的快速发展中&#xff0c;电力供应的可靠性变得愈发重要。金融交易和数据处理依赖于持续的电力供应&#xff0c;任何电力中断都可能导致严重的业务中断和损失。 为了应对这一挑战&#xff0c;金融机构广泛采用了不间断电源&#xff08;UPS&#xff09;系统&#…

QT 连接SQLServer数据库

1、安装SQLServer数据库后 在SQL Server 配置管理器中 设置后&#xff0c;需要重新启动SQL Server服务 2、重点* 配置ODBC数据源 由于没有配置ODBC&#xff0c;一直无法连接 开始——ODBC数据源管理程序(64位) 之后选择&#xff1a;使用用户输入登录ID和密码的SQL Server验…

Improving 3D Imaging with Pre-Trained Perpendicular 2D Diffusion Models

使用预先训练的垂直 2D 扩散模型改进 3D 成像 论文链接&#xff1a;https://arxiv.org/abs/2303.08440 项目链接&#xff1a;https://github.com/hyn2028/tpdm Abstract 扩散模型由于其众多的优点已经成为一种流行的图像生成和重建方法。然而&#xff0c;大多数基于扩散的逆…

只有68g的电竞鼠标,软硬件都能自定义,雷柏VT9Pro上手

最近雷柏的轻量化无线鼠标又出了一款新品VT9PRO&#xff0c;这款鼠标相比于之前的VT9升级不少&#xff0c;不仅机身更轻盈&#xff0c;而且配置更高&#xff0c;采用了原相定制3398光学引擎&#xff08;3395高定版&#xff09;&#xff0c;外加欧姆龙5000万次轻脆微动等专业级配…

Jmeter安装与测试

目录 一&#xff1a;JMeter简介&#xff1a; 二&#xff1a;JMeter安装与配置 三&#xff1a;JMeter主要原件 一&#xff1a;JMeter简介&#xff1a; JMeter&#xff0c;一个100&#xff05;的纯Java桌面应用&#xff0c;由Apache组织的开放源代码项目&#xff0c;它是功能 …

链式法则:概率论描述语言模型

目录 1.事件相互独立 2.链式法则 3.示例 4.语言模型中的链式法则 1.事件相互独立 事件相互独立就是&#xff1a;一个事件的发生与否&#xff0c;不会影响另外一个事件的发生。 当a和b两个事件互相独立时&#xff0c;有&#xff1a; P(a | b) P(a) 推广到3个事件就有下面…

windows2003 IIS6.0解析漏洞

一、漏洞说明 &#xff08;1&#xff09;当建立*.asa、.asp格式的文件夹时&#xff0c;其目录下的任意文件都将被IIS当做asp文件解析。 &#xff08;2&#xff09;当文件.asp&#xff1a;1.jpg IIS6.0同样会将文件当做asp文件解析。 二、搭建环境 Windows server2003安装iis6.0…

内网隧道代理技术(二十五)之 ICMP隧道反弹SHELL

ICMP隧道反弹SHELL ICMP隧道原理 由于ICMP报文自身可以携带数据,而且ICMP报文是由系统内核处理的,不占用任何端口,因此具有很高的隐蔽性。把数据隐藏在ICMP数据包包头的data字段中,建立隐蔽通道,可以实现绕过防火墙和入侵检测系统的阻拦。 ICMP隧道有以下的优点: ICMP…

Mybatis sql参数自动填充

问题描述 在日常开发中&#xff0c;经常会遇到Mybatis sql语句的操作问题&#xff0c;由于Mybatis实现sql的动态拼接&#xff0c;开发过程中&#xff0c;为了验证sql是否书写正确&#xff0c;通常需要获取的控制台打印的sql语句来检查是否拼接正确。如下图所示&#xff1a; 那…

ClientDataSet运行中出现“ClientDataSet:dataset not in edit or insert mode”(二)

接前期《ClientDataSet运行中出现“ClientDataSet&#xff1a;dataset not in edit or insert mode”&#xff08;一&#xff09;》中&#xff0c;提出的解决方案&#xff0c;本人作进一步探索&#xff1a; 一、编写一个返回ClientDataSet的状态函数 function Get_Client_stat…