基于stm32f103c8t6的智慧农业系统



前言

本次实验用到的外设有1.44寸LCD(4线spi)、DHT11温湿度传感器、HM-10(蓝牙)、继电器、L9110风扇模块、蜂鸣器、土壤湿度模块、震动传感器、水泵。

一、实验要求

1、用外部中断方式 使用按键PC8控制风扇的打开和关闭。
2、用外部中断方式 使用按键PC9控制LED灯的打开和关闭。
3、用外部中断方式 使用震动传感器控制打开和关闭蜂鸣器。
4、用外部中断方式 使用土壤温湿度控制打开和关闭水泵。
5、在主函数中优先初始化串口和延时函数,再初始化其他模块,每个模块初始化完成通过串口1发送字符串显示“XX模块初始化成功”。
6、通过发送字符’A’控制LED灯打开 ,字符’a’控制LED灯关闭 水泵 继电器 风扇 RGB灯带 也分别通过 字符B,C,D,E实现。
7、在主函数中优先初始化串口和延时函数,再初始化其他模块,每个模块初始化完成通过串口2(蓝牙模块)发送字符串显示“XX模块初始化成功”,在手机端可以查看。
8、通过蓝牙调试助手发送字符’A’控制LED灯打开 ,字符’a’控制LED灯关闭,水泵、继电器、风扇也分别通过字符B,C,D,E实现。
9、在LCD屏幕初始化之后显示一张图片,尺寸为128*128,内容:自制在显示5秒后调用LCD_Fill()函数将画面填充为白色。紧接着在图片上显示字符串。
10、循环刷新显示温湿度信息。

二、模块实现

1.要求1、2、3、4

针对要求,用到的有风扇、LED灯(stm32系统板上)、继电器(连接水泵)、震动传感器、土壤湿度模块。
首先各模块进行初始化:
#include "drive.h"

//B1------>风扇
//B0------>蜂鸣器
//B11------>继电器
void  Drive_Init(void)
{
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_11;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIOInitstruct);
}
按键初始化
#include "stm32f10x.h"
#include "key.h"
void key1_init(void)//led
{
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_8;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIOInitstruct);
}
void key2_Init(void)
{
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_8;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIOInitstruct);
}
void key3_Init(void)//k4
{
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_9;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIOInitstruct);
}
void key4_Init(void)//
{
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_IPD;
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_0;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIOInitstruct);
}
IPD对应下拉输入(io口初始为低电平),IPU对应上拉输入(初始为高电平),具体为什么这么设置可以参照stm32f103c8t6原理图。
振荡器和水泵放在中断初始化里面。
#include "exit.h"
#include "key.h"
#include "delay.h"
void exit_init(void)
{
	 EXTI_InitTypeDef EXTI_InitStructure;
	 NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIOInitstruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//时钟使能
	key1_init();
	key2_Init();		
	key3_Init();
	key4_Init();	//按键初始化
	GPIOInitstruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
	GPIOInitstruct.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_0;
	GPIOInitstruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIOInitstruct);//土壤湿度检测模块和振荡器模块初始化
	//中断映射
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource1);//振荡器映射
	 EXTI_InitStructure.EXTI_Line=EXTI_Line1;
	 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//触发中断
	 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发(发生震动时输入为高电平)
	 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	 EXTI_Init(&EXTI_InitStructure);

	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8);//按键k3映射
	 EXTI_InitStructure.EXTI_Line=EXTI_Line8;
	 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
	 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	 EXTI_Init(&EXTI_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource9);//按键K4映射
	EXTI_InitStructure.EXTI_Line=EXTI_Line9;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure); 
	
	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	 EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource0);//土壤湿度模块
	 EXTI_InitStructure.EXTI_Line=EXTI_Line0;
	 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);



	 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	 NVIC_Init(&NVIC_InitStructure); 
 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	 NVIC_Init(&NVIC_InitStructure); 
	 
	  NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	 NVIC_Init(&NVIC_InitStructure);
}
	void EXTI0_IRQHandler(void)
	{	
		 delay_ms(10); 
		if(WK_UP==1)
		{ 
		//LED0=!LED0;
		//LED1=!LED1;
		}
		if(PCin(0)==0)
		{
			PBout(11)=!PBout(11);
		}
		EXTI_ClearITPendingBit(EXTI_Line0); 
	}
	void EXTI9_5_IRQHandler(void)
	{
		delay_ms(10); 
		if(K4==0)
		{
			LED=!LED;
			EXTI_ClearITPendingBit(EXTI_Line9); 
		}
		if(K3==0)
		{
			PBout(1)=!PBout(1);
			EXTI_ClearITPendingBit(EXTI_Line8); 
		}
	}
void EXTI1_IRQHandler(void)
{
	delay_ms(10);
	if(PCin(1)==1)
	{
		PBout(0)=!PBout(0);
	}	
	EXTI_ClearITPendingBit(EXTI_Line1); 
}

中断映射完后需设置各个中断对应的优先级,及区分出谁更重要,主要是当两个事件同时发生时,告诉mpu更优先执行哪一个中断,因为是实验,所以不会让两个中断同时发生,所以设置所有中断的抢占优先级和子优先级都为3,若需要更改可参照正点原子《STM32F103RCT6数据手册》。根据实验要求,需采用中断的方式驱动各个模块,这里主要是通过中断服务函数EXTI_X_IRQHandler进行实现,例如EXTI1_IRQHandler(void)函数,一直检测PC1口电平状态,当中断发生时,mpu进入中断服务函数,实现对PB0(蜂鸣器)口的状态翻转,最后清除中断标志位,防止mpu一直执行中断服务函数。

2.要求5、7

主函数要求优先初始化延时函数和串口,这步按照要求就可以,针对后面的每个模块初始化完成后对串口1、串口2(蓝牙)发送字符串,最开始也确实是按照这个步骤写,但是运行出来会出现一些问题,主要是蓝牙发送的字符串异常,所以最后就变成好几个模块初始化完成后再向蓝牙和串口1发松字符串,大家可以试一下按步骤来,不好说这个,看主函数。

#include "delay.h"
#include "sys.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"
#include "menu.h"
#include "key.h"
#include "adc.h"
#include "usart.h"
#include "dht110.h"
#include "bluetooth.h"
#include <stdio.h>
#include "drive.h"
#include "exit.h"
#include "ws2812.h"
USART_TypeDef* DEBUG_USARTx=USART1;


//土壤湿度A0脚-----------PA1(ADC²É¼¯Òý½Å)
//土壤湿度D0脚-----------PA0(ADC²É¼¯Òý½Å)
//DHT11数据总线DAT脚------------PC14


//LCDÒ引脚定义
//              SCL   PA5
//              SDA   PA7
//              RES   PD2
//              DC    PB5
//              CS    PA4
//              BLK   PB6
//B1------>风扇
//B0------>蜂鸣器
//B11------>继电器
//PC1----->振荡器
//PA2---------USART2_TX
//PA3---------USART2_RX
uint8_t RX_Data;
uint8_t Flag;
int main(void)
{
	int adcx;
	float temp;
	u8 temperature,humi;//´óÆøÎ¶ȡ¢Êª¶È
	uart_init(9600);//´®¿ÚÒ»³õʼ»¯
	Usart2_Init(9600);//´®¿Ú2³õʼ»¯
	delay_init();	
	printf("串口初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("串口初始化成功\r\n");
	DEBUG_USARTx=USART1;
	printf("延时函数初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("延时函数初始化成功\r\n");
	DEBUG_USARTx=USART1;
	LCD_Init();//LCD³õʼ»¯
	printf("LCD初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("LCD初始化成功\r\n");
	DEBUG_USARTx=USART1;
	//LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
	adc_init();
	Drive_Init();
	printf("蜂鸣器、风扇初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("蜂鸣器、风扇初始化成功\r\n");
	DEBUG_USARTx=USART1;
	printf("水泵初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("水泵初始化成功\r\n");
	exit_init();
	DEBUG_USARTx=USART1;
	printf("中断初始化成功\r\n");
	DEBUG_USARTx=USART2;
	printf("中断初始化成功\r\n");
	DEBUG_USARTx=USART1;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组
	DEBUG_USARTx=USART2;
	DEBUG_USARTx=USART1;
	DEBUG_USARTx=USART1;
	LCD_ShowPicture(0,0,128,128,gImage_6);
	menu1();
	//DHT11_Rst();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	while(1)
	{	
//		adcx=Get_Adc_Average(ADC_Channel_1,10);
//		temp=(float)(4093-adcx)/(float)(4093-1500);
//		temp=temp*100;
		if(DHT11_Read_Data(&temperature,&humi)==1)
		{
			printf("%d",temperature);
			menu_(temp,temperature,humi);
			if(temperature>30)
			{	
				fan_on;
			}
			if(temperature<=30)
			{	
				fan_down;
			}
}
}
	}

一行一行看,除过printf,出现频率最高的应该就是DEBUG_USARTx,那为什么要设这个东西,又有什么用。先看实验要求,不仅需要对串口1发送数据,同时需要对串口2发送数据,向串口发送数据我们用的是printf函数,而printf函数是依托fputc函数发送字符串,看fputc函数。

int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//Ñ­»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
    USART1->DR = (u8) ch;      
	return ch;
}

注意这里的USART1,即fputc函数即printf函数只能向串口1发送字符串。但是本次实验又需要向串口2发送字符串,我的解决办法是在主函数外设一个全局变量DEBUG_USARTx,只需要改变变量的值为USART1/USART2即可实现向串口一发送数据后再向串口2发送数据。
应该也能看到主函数出现一个adc_init();这算是一个拓展的功能,即对土壤湿度进行量化,本次实验用不到,有需要的可以私信我。

3.要求6、8

主要是实现向串口发送数据来控制各个模块,只需打开串口1和串口2的接收中断,在中断服务函数内实现对各个模块的控制。
#include "bluetooth.h"
#include "sys.h"
#include "usart.h"
#include "drive.h"

extern uint8_t Flag;
extern uint8_t RX_Data;
//PA2---------USART2_TX
//PA3---------USART2_RX
void Usart2_Init(u32 bond)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);	//串口2,GPIOA时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//¸´ÓÃÍÆÍìÊä³ö
  GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.9
   
  //USART1_RX	  GPIOA.10³õʼ»¯
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
  GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIOA.10  

  //Usart1 NVIC ÅäÖÃ
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//ÇÀÕ¼ÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//×ÓÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
	NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
  
   //USART ³õʼ»¯ÉèÖÃ

	USART_InitStructure.USART_BaudRate = bond;//´®¿Ú²¨ÌØÂÊ
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
	USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæÅ¼Ð£Ñéλ
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//ÊÕ·¢Ä£Ê½

  USART_Init(USART2, &USART_InitStructure); //³õʼ»¯´®¿Ú2
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//¿ªÆô´®¿Ú½ÓÊÜÖжÏ
  USART_Cmd(USART2, ENABLE);                   
}

void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
	{
		RX_Data=USART_ReceiveData(USART2);
		if(RX_Data=='A')
			PAout(8)=0;
		if(RX_Data=='a')
			PAout(8)=1;
		if(RX_Data=='B')
			bee_on;
		if(RX_Data=='b')
			bee_down;
		if(RX_Data=='C')
			fan_on;
		if(RX_Data=='c')
			fan_down;
		if(RX_Data=='D')
			pump_on;
		if(RX_Data=='d')
			pump_down;
		//USART_SendData(USART1,RX_Data);
		Flag=1;
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);
	}
}
串口1配置函数可以在官方网站上找,正点原子和野火的都可以,但是需要改USART1_IRQHandler(void)和添加头文件。
void USART1_IRQHandler(void) 
{
	u8 Res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		Res =USART_ReceiveData(USART1);
		if(Res=='A')
		{
			LED=1;
		}
		if(Res=='a')
		{
			LED=0;
		}
		if(Res=='B')
		{
			pump_on;
		}
		if(Res=='b')
		{
			pump_down;;
		}
		if(Res=='C')
		{
			fan_on;
		}
		if(Res=='c')
		{
			fan_down;
		}
	}
	USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
需要额外添加的头文件有
#include "drive.h"
#include "key.h"

根据实验要求,在中断服务函数内实现对各模块的控制,.h文件中存在部分宏定义,这里也可以直接对对应IO口输出,即不需要对应的宏定义,也就不需要添加后面这两个头文件。

4.要求9、10

这两个要求主要是针对LCD,我这里直接用中景园电子的代码,可以不用了解具体原理,但需要会用,与代码对应的还有取模软件,最终取的模需要添加至字库。看实现方法
主函数上面已经展示过,这里只看9、10对应函数

#include "lcd_init.h"
#include "lcd.h"
#include "menu.h"
#include "sys.h"
#include "delay.h"
void menu_(float tmp,u8 ak,u8 ak1)
{

		LCD_ShowChinese(0,0,"温度",BLACK,WHITE,16,0);
		LCD_ShowChinese(66,0,"湿度",BLACK,WHITE,16,0);
		LCD_ShowIntNum(33,0,ak,3,BLACK,WHITE,16);
		LCD_ShowIntNum(111,0,ak1,3,BLACK,WHITE,16);
		LCD_ShowChar(0,57,"L",BLACK,WHITE,16,0);
		LCD_ShowChar(17,57,"E",BLACK,WHITE,16,0);
		LCD_ShowChar(34,57,"D",BLACK,WHITE,16,0);
}
extern const unsigned char *gImage_6;
void menu1(void)
{
	//LCD_ShowPicture(0,0,128,128,gImage_6);
delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);
	LCD_Fill(0,0,128,128,WHITE);
	LCD_ShowChinese(0,0,"综合实训项目",RED,WHITE,16,0);
	LCD_ShowChinese(0,17,"组号",GREEN,WHITE,16,0);
	LCD_ShowChinese(0,34,"组员2",BLACK,WHITE,16,0);
	LCD_ShowChinese(0,51,"组员3",BLUE,WHITE,16,0);
	LCD_ShowChinese(0,68,"组员1",LBBLUE,WHITE,16,0);
delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);delay_ms(500);
	LCD_Fill(0,0,128,128,WHITE);
}

gImage_6是在pic.h中,需要自行添加对应地址,这里是延时5秒,但是delay_ms()函数内的时间不宜过长,所以直接用10个delay_ms(500),也可以使用定时器,不会占用计算资源。主函数内需要对温度和湿度(空气湿度)不断进行采集,即对DHT11_Read_Data不断调用,然后通过menu1刷新显示。

DHT11

#include "sys.h"
#include "stm32f10x.h"
#include "dht110.h"
#include "delay.h"
void DHT11_IO_Out(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
}
void DHT11_IO_In(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
}
void DHT11_Rst(void)
{
	DHT11_IO_Out();
	PCout(14)=0;
	delay_ms(20);
	PCout(14)=1;
	delay_us(30);
}
u8 DHT11_Check(void)
{
	u8 retry=0;
	DHT11_IO_In();
	while((PCin(14)==1)&&retry<100)
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;
	else retry=0;
	while(PCin(14)==0&&retry<100)
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;
	return 0;
	
}


u8 DHT11_Init(void)
{
	int a;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	/*DHT11_Rst();
	a=DHT11_Check();*/
	return a;
}
u8 DHT11_Read_bit(void)
{
	u8 retry=0;
	while(retry<100&&PCin(14)==1)
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(retry<100&&PCin(14)==0)
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);
	if(PCin(14)==1)
		return 1;
	else
		return 0;
}
u8 DHT11_Read_Byte(void)
{
	u8 i,dat;
	dat=0;
	for(i=0;i<8;i++)
	{
		dat<<=1;
		dat|=DHT11_Read_bit();
	}
	return dat;
}
u8 DHT11_Read_Data(u8 *temp, u8 *humi1)
{
    u8 buf[5];
    u8 i;
   DHT11_Rst();						
    if(DHT11_Check() == 0)				
    {
        for(i = 0; i < 5; i++) 			
        {
            buf[i] = DHT11_Read_Byte();
        }
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])	
        {
            *humi1 = buf[0];				
            *temp = buf[2];				
        }
    }
    else return 1;
    return 0;
}

总结

因内容较多,这里只对代码略作解释,若有表述不当的地方,还望大佬们指正。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值