STM32_9:I2C_DHT11_OLED项目

目录

1.DHT11

1.硬件线路

2.数据格式

3.时序图

数字0信号表示方法

项目代码

软件I2C_OLED

DHT11代码

main函数

SYSTICK延时函数


1.DHT11

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用于专用数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。

传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能八位单片机相连接。采用单线制串口行接口,信号传输距离可达20M以上。

1.硬件线路

  • 供电电压:3.3 - 5.5V直流电
  • 输出为单总线数字信号
  • 温度测量范围0-50度(精度正负2度,分辨率1度)
  • 湿度测量范围为20-90%RH(精度为正负5%,分辨率1%)
  • 模块的+ 接单片机的5V
  • 模块的- 接单片机的GND
  • 模块的OUT 接单片机定义的引脚
  • vcc和gnd之间可以加一个电容,用于去耦滤波

采用单总线双向串行通信协议,每次采集都要由单片机发起开始信号,然后DHT11会向单片机发送响应并开始传输40位数据帧,高位在前。

2.数据格式

  • 第一二个字节: 8bit湿度整数数据+8bit湿度小数数据
  • 第三四个字节: 8bit温度整数数据+8bit温度小数数据
  • 第五个字节 : 8bit校验位(它是前四个数据相加后八位的数值)

温湿度小数部分默认为0,即单片机采集的数据都是整数,校验位为4个字节的数据相加取结果的低8位数据作为校验和

示例一:

0011 0101 0000 0000 0011 1000 0000 0000 0100 1101

湿度高八位 湿度低八位 温度高八位 温度低八位 检验位

计算 : 0011 0101 (相加)

0011 1000

结果: 01001101 湿度为0011 0101 = 35H = 53%RH

温度为0011 1000 = 18H = 24°

示例二:

0011 0101 0000 0000 0001 1000 0000 0000 0100 1001

湿度高八位 湿度低八位 温度高八位 温度低八位 检验位

计算 : 0011 0101 (相加)

0001 1000

结果: 0100 1101 不等于 01001001 本次接收数据不正确,重新接收数据

3.时序图

  • 总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。
  • DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号.
  • 主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
  • 总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据。
  • 每一bit数据都以50us低电平时隙开始,高电平的长短定 了数据位是0还是1.格式见下面图示.
  • 如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.
  • 当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

数字0信号表示方法

数字1信号表示方法

项目代码

软件I2C_OLED

字模库见最后

cs 复制代码
#include "stm32f10x.h"
#include "I2C_soft.h"
#include "systick.h"
#include "OLED_Codetab.h"

static void OLED_GPIO_Init(void)
{
	
	GPIO_InitTypeDef GPIO_Initstructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Initstructure);
	
	OLED_SCLK_Set();
	OLED_SDIN_Set();
	
}

static void OLED_I2C_Start(void)
{
	OLED_SCLK_Set();
	OLED_SDIN_Set();
	us_delay(1);
	
	OLED_SDIN_Clr();
	us_delay(1);
	
	OLED_SCLK_Clr();
	us_delay(1);
	
}

static void OLED_I2C_Stop(void)
{
	OLED_SDIN_Clr();
	us_delay(1);
	
	OLED_SCLK_Set();
	us_delay(1);
	
	OLED_SDIN_Set();
	us_delay(1);

}

static unsigned char I2C_Wait_Ask(void )
{
	unsigned char ask;
	
	OLED_SCLK_Clr();
	us_delay(1);
	
	OLED_SDIN_Set();
	us_delay(1);
	
	OLED_SCLK_Set();
	us_delay(1);
	
	if(OLED_READ_SDIN())
	{
		ask = OLED_NO_ASK;
	}
	else
	{
		ask = OLED_ASK;
	}
	
	OLED_SCLK_Clr();
	us_delay(1);
	
	return ask;
	
}

static void Write_I2C_Byte(unsigned char I2C_Byte)
{
	unsigned char i;
	
	for(i = 0 ;i < 8;i++)
	{
		OLED_SCLK_Clr();
		us_delay(1);
		
		if(I2C_Byte & 0x80)
			OLED_SDIN_Set();
		else
			OLED_SDIN_Clr();
		
		I2C_Byte  = I2C_Byte << 1;
		us_delay(1);
		
		OLED_SCLK_Set();
		us_delay(1);
	}
	OLED_SCLK_Clr();
	us_delay(1);
	
	I2C_Wait_Ask();
}

static void Write_I2C_Command(unsigned char I2C_Command)
{
	OLED_I2C_Start();
	Write_I2C_Byte(0x78);
	Write_I2C_Byte(0x00);
	Write_I2C_Byte(I2C_Command);
	OLED_I2C_Stop();
}

static void Write_I2C_Data(unsigned char I2C_Data)
{
	OLED_I2C_Start();
	Write_I2C_Byte(0x78);
	Write_I2C_Byte(0x40);
	Write_I2C_Byte(I2C_Data);
	OLED_I2C_Stop();
}

void Write_OLED_Byte(unsigned char data,unsigned char command)
{
	if(command)
	{
		Write_I2C_Data(data);
	}
	else
	{
		Write_I2C_Command(data);
	}
}


void OLED_SetPos(unsigned char x,unsigned char y)
{
	Write_OLED_Byte(0xb0+y,OLED_CMD);
	Write_OLED_Byte(0X00 | (x & 0X0F),OLED_CMD);
	Write_OLED_Byte(0x10 | (x & 0xF0) >> 4,OLED_CMD);
}

void OLED_Display_ON(void)
{
	Write_OLED_Byte(0X8D,OLED_CMD);
	Write_OLED_Byte(0X14,OLED_CMD);
	Write_OLED_Byte(0XAF,OLED_CMD);
}

void OLED_Display_OFF(void)
{
	Write_OLED_Byte(0X8D,OLED_CMD);
	Write_OLED_Byte(0X10,OLED_CMD);
	Write_OLED_Byte(0XAE,OLED_CMD);
}

void OLED_Clear(void)
{
	int i,j;
	
	for(j = 0;j < 8;j++)
	{
		Write_OLED_Byte(0XB0+j,OLED_CMD);
		Write_OLED_Byte(0X10,OLED_CMD);
		Write_OLED_Byte(0X00,OLED_CMD);
		
		for(i = 0;i < 128;i++)
			Write_OLED_Byte(0,OLED_DATA);
	}
}


//OELDÆÁÄ>>³õʼ>>¯
void OLED_Init(void)
{
	OLED_GPIO_Init();
	
  ms_delay(100);
	Write_I2C_Command(0xAE); //display off
	Write_I2C_Command(0x20);	//Set Memory Addressing Mode	
	Write_I2C_Command(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	Write_I2C_Command(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	Write_I2C_Command(0xc8);	//Set COM Output Scan Direction
	Write_I2C_Command(0x00); //---set low column address
	Write_I2C_Command(0x10); //---set high column address
	Write_I2C_Command(0x40); //--set start line address
	Write_I2C_Command(0x81); //--set contrast control register
	Write_I2C_Command(0xff); //ÁÁ¶Èµ÷½Ú 0x00~0xff
	Write_I2C_Command(0xa1); //--set segment re-map 0 to 127
	Write_I2C_Command(0xa6); //--set normal display
	Write_I2C_Command(0xa8); //--set multiplex ratio(1 to 64)
	Write_I2C_Command(0x3F); //
	Write_I2C_Command(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	Write_I2C_Command(0xd3); //-set display offset
	Write_I2C_Command(0x00); //-not offset
	Write_I2C_Command(0xd5); //--set display clock divide ratio/oscillator frequency
	Write_I2C_Command(0xf0); //--set divide ratio
	Write_I2C_Command(0xd9); //--set pre-charge period
	Write_I2C_Command(0x22); //
	Write_I2C_Command(0xda); //--set com pins hardware configuration
	Write_I2C_Command(0x12);
	Write_I2C_Command(0xdb); //--set vcomh
	Write_I2C_Command(0x20); //0x20,0.77xVcc
	Write_I2C_Command(0x8d); //--set DC-DC enable
	Write_I2C_Command(0x14); //
	Write_I2C_Command(0xaf); //--turn on oled panel

}

void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chara)
{
	unsigned char i = 0,ch = 0;
	
	if(x + 16 > Max_Column)
	{
		x = 0;
		y = y+2;
	}
	
	ch = chara - ' ';
	
	if(Size == 16)
	{
		OLED_SetPos(x,y);
		for(i = 0;i < 8;i++)
		{
			Write_OLED_Byte(F8X16[ch*16+i],OLED_DATA);
		}
		
		OLED_SetPos(x,y+1);
		for(i = 0;i < 8;i++)
		{
			Write_OLED_Byte(F8X16[ch*16+i+8],OLED_DATA);
		}
	}
	else
	{
		OLED_SetPos(x,y);
		for(i = 0;i < 6;i++)
		{
			Write_OLED_Byte(F6x8[ch][i],OLED_DATA);
		}
	}
	
}

void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *ch)
{
	unsigned char j = 0 ;
	
	while( ch[j] != '\0')
	{
		OLED_ShowChar(x,y,ch[j]);
		x += 8;
		
		if(x >128)
		{
			x = 0;
			y = y + 2; 
		}
		
		j++;
	}
}

unsigned int OLED_pow(unsigned int m,unsigned int n)
{
	unsigned int result = 1;
	while(n--)
		result *= m;
	
	return result;
}

void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned int len,unsigned int size)
{
	unsigned char t = 0,temp = 0;
	unsigned char enshow = 0;
	
	for(t = 0;t < len;t++)
	{
		temp = num/OLED_pow(10,len-1-t)%10;
		
		if(enshow == 0 && t < (len-1))
		{
			if(temp == 0)
			{
				OLED_ShowChar(x + t*(size/2),y,' ');
				continue;
			}
		}
		else
			enshow = 1;
		
		OLED_ShowChar(x + t*(size/2),y,temp + '0');//Êý×Ö0ת>>>>³Éasci0
	}
}


void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N)
{
	unsigned char i = 0;
	
	OLED_SetPos(x,y);
	for(i = 0;i < 16;i++)
	{
		Write_OLED_Byte(F8X16_TM[N*2][i],OLED_DATA);
	}
	
	OLED_SetPos(x,y+1);
	for(i = 0;i < 16;i++)
	{
		Write_OLED_Byte(F8X16_TM[N*2+1][i],OLED_DATA);
	}
	
}

DHT11代码

cs 复制代码
#include "stdio.h"
#include "dht11.h"
#include "stm32f10x.h"
#include "systick.h"

uint16_t RxBuf[5];

void Dht11_GPIO_Init_Ouput()
{
	GPIO_InitTypeDef GPIO_Initstructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Initstructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_11);

}

void Dht11_GPIO_Init_Input()
{
	GPIO_InitTypeDef GPIO_Initstructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Initstructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_Initstructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_11);

}

static uint8_t Dht11_Ask()
{
	uint8_t i = 200;
	
	while(read_data && i--);  //等待电平拉低
	i = 200;
	while(!read_data && i--); //等待电平拉高
	
	return 0;
}

void Dht11_Start()
{
	data0;
	ms_delay(20);  //>=18ms
	
	data1;
	us_delay(10);  //拉高等待应答
	
	Dht11_GPIO_Init_Input();//转为输入模式
	while(Dht11_Ask());
}

void Dht11_ReceptionBuf()
{
	uint8_t i = 0,j = 0;
	uint16_t rec = 0;
	
	for(i = 0;i < 5;i++)  //5组数据
	{
		rec = 0;
		
		for(j = 0;j < 8;j++)
		{
			while(read_data)//等待低电平到来
			{
			    __nop();
			 
			}
			us_delay(40);
			
			while(!read_data)//等待高电平到来
			{
			    __nop();
			 
			}

			rec  = rec << 1;
			us_delay(30);    //!!!!!!26-28us为0,70us为1
			
			if(read_data)
			{
				rec = rec | 1;
			}
			
			while(read_data);
		}
		
		RxBuf[i] = rec;
		
	}
	
}

void Dht11_UpdateData()
{
	Dht11_GPIO_Init_Ouput();
	Dht11_Start();
	Dht11_ReceptionBuf();
}
cs 复制代码
#ifndef _DHT11_H_
#define _DHT11_H_

#include "stm32f10x.h"


#define data0 GPIO_ResetBits(GPIOB,GPIO_Pin_11)
#define data1 GPIO_SetBits(GPIOB,GPIO_Pin_11)

#define read_data GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)

void Dht11_GPIO_Init_Ouput(void);
void Dht11_GPIO_Init_Input(void);
static uint8_t Dht11_Ask(void);
void Dht11_Start(void);
void Dht11_ReceptionBuf(void);
void Dht11_UpdateData(void);

#endif

main函数

cs 复制代码
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "buzzer.h"
#include "key.h"
#include "Relay.h"
#include "Shake.h"
#include "Exti.h"
#include "usart.h"
#include "stdio.h"
#include "Time.h"
#include "sg90.h"
#include "systick.h"
#include "I2C_soft.h"
#include "dht11.h"

extern uint16_t RxBuf[5];

int  main()
{
	initSysTick();
	
	OLED_Init();
	OLED_Clear();
	
	OLED_ShowCN(0,0,0);//当
	OLED_ShowCN(16,0,1);//前
	OLED_ShowCN(32,0,2);//温
	OLED_ShowCN(48,0,3);//度
	OLED_ShowCN(64,0,4);//:
	OLED_ShowCN(90,0,9);//.
	OLED_ShowCN(112,0,5);//°C
	
	OLED_ShowCN(0,2,0);
	OLED_ShowCN(16,2,1);
	OLED_ShowCN(32,2,6);//湿
	OLED_ShowCN(48,2,3);
	OLED_ShowCN(64,2,4);
	OLED_ShowCN(90,2,9);//.
	OLED_ShowCN(112,2,7);//%
	
	while(1)
	{
		uint16_t i = 0;
		
		uint8_t Humidity_H = 0;
		uint8_t Humidity_L = 0;
		uint8_t Tempurature_H = 0;
		uint8_t Tempurature_L = 0;
		
		Dht11_UpdateData();
		
		i = RxBuf[0] + RxBuf[1] + RxBuf[2] + RxBuf[3];
		if(i == RxBuf[4])
		{
			Humidity_H = RxBuf[0];
			Humidity_L = RxBuf[1];
			Tempurature_H = RxBuf[2];
			Tempurature_L = RxBuf[3];
		}
		
		OLED_ShowNum(74,0,Tempurature_H,2,16);
		OLED_ShowNum(98,0,Tempurature_L,1,16);
		OLED_ShowNum(74,2,Humidity_H,2,16);
		OLED_ShowNum(98,2,Humidity_L,1,16);
		
		ms_delay(2000);
	} 
   
}

SYSTICK延时函数

当系统时钟为 72 MHz 时:

情况1:不分频

  • SysTick 时钟 = 72 MHz
  • 1 秒 = 72,000,000 个时钟周期
  • 1 毫秒 = 72,000 个时钟周期
  • 1 微秒 = 72 个时钟周期

情况2:8分频(原代码的设置)

  • SysTick 时钟 = 72 MHz ÷ 8 = 9 MHz
  • 1 秒 = 9,000,000 个时钟周期
  • 1 毫秒 = 9,000 个时钟周期
  • 1 微秒 = 9 个时钟周期

写入 VAL 时:

  1. 计数器立即被清零
  2. COUNTFLAG 标志被清除
  3. 在下一个时钟周期,硬件自动将 LOAD 值加载到 VAL
cs 复制代码
#include "systick.h"
#include "stm32f10x.h"

/**
  * @brief  SysTick定时器初始化
  * @param  无
  * @retval 无
  */
void initSysTick(void)
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); // 设置时钟源为HCLK的8分频
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;           // 使能SysTick中断
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;            // 开启定时器
    SysTick->LOAD = 9;                                   // 设置一个初始重装载值
}

/**
  * @brief  微秒级延时函数
  * @param  xus : 延时时间(单位:微秒)
  * @retval 无
  */
void us_delay(u32 xus)
{
    SysTick->LOAD = 9 * xus;                               // 计9次为1us,xus则重装载值要*9
    SysTick->VAL = 0;                                      // 计数器归零
    while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // 等待计数完成
}

/**
  * @brief  毫秒级延时函数
  * @param  xms : 延时时间(单位:毫秒)
  * @retval 无
  */
void ms_delay(u32 xms)
{
    SysTick->LOAD = 9000;                                      // 计9次为1us,1000次为1ms
    SysTick->VAL = 0;                                          // 计数器归零
    while (xms--)
    {
        while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // 等待单次计数完成
    }
}
相关推荐
__万波__2 小时前
STM32基于HAL 库开发包创建新的工程-编译-烧录
stm32·单片机·嵌入式硬件
曾浩轩2 小时前
跟着江协科技学STM32之4-5OLED模块教程OLED显示原理
科技·stm32·单片机·嵌入式硬件·学习
BreezeJuvenile3 小时前
ADC_案例练习:独立模式多通道采集
stm32·单片机·adc·多通道采集·dma辅助
代码游侠3 小时前
学习笔记——HC-SR04 超声波测距传感器
开发语言·笔记·嵌入式硬件·学习
Joshua-a3 小时前
高云FPGA在线调试/逻辑分析仪简要使用流程
嵌入式硬件·fpga开发·高云
国科安芯3 小时前
高轨航天器抗辐照MCU选型约束分析
单片机·嵌入式硬件·性能优化·机器人·安全性测试
CS Beginner3 小时前
【单片机】嵌入式显示屏开发框架:QT、SDL、LVGL 深度解析
单片机·嵌入式硬件·qt
YouEmbedded3 小时前
解码从架构到嵌套向量中断控制器(NVIC)
stm32·软件架构·mcu中断·exti外设·启动文件分析
亿道电子Emdoor4 小时前
【Altium】原理图中网络标签作用范围的设置
单片机·嵌入式硬件