前言
本次实验用到的外设有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;
}
总结
因内容较多,这里只对代码略作解释,若有表述不当的地方,还望大佬们指正。