基于STM32的温湿度传感器(DHT11)+OLED屏显示(超详细)

本文主要说明温湿度传感器(DHT11)在STM32下如何使用,并且结合OLED屏来达到显示的效果。喜欢的话可以点个赞和收藏噢!!以下内容均为查询相关资料撰写而成,如有侵权,请联系作者。


一、前期准备

(一)软件环境准备

编译工具为Keil5,对应芯片为:STM32F103C8

(二)硬件准备

1. STM32模块

2. OLED显示屏

3. 温湿度传感器(DHT11)

4. ST-Link V2(USB口)仿真器

5. 适量杜邦线

大约11根母对母杜邦线


二、接线图表

STM32 ST-LinkOLED屏DHT11
3V33.3V
SWOSWDIO
SWCLKSWCLK
GNDGND
PB9SDA
PB8SCL
3.3VCC
GGND
3.3+
PB11out
G-

三、温湿度传感器(DHT11)驱动

(一)原理

        DHT11工作原理是基于内部的湿度传感器和温度传感器,通过检测这两个传感器的信号变化,将湿度和温度转换为数字信号输出。它采用简单的串行通信协议(后面补充)与外部设备通信,发送包含温湿度数据的数据帧,用户则获取数据帧进行相关的处理使用。

      经典应用电路图如图1所示

 图1

        DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:
        一次完整的数据传输为40bit,高位先出。
        数据格式:
                8bit湿度整数数据+8bit湿度小数数据
                +8bi温度整数数据+8bit温度小数数据
                +8bit校验和数据传送正确时校验和
        数据等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据” 所得结果的末8位。用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。
      通讯过程如图2所示

图2  

        总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号。主机发送开始信号结束后,延时等待20-40us后,读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。

图3 

        总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1。格式见下面图示。如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

      数字0信号表示方法如图4所示

图4 

      数字1信号表示方法.如图5所示

图5 

补充内容:

        串行通信协议是一种在数据传输中将信息逐位发送的通信方式。对于DHT11传感器而言,它使用的是一种简单的串行通信协议,通常是通过单个数据线与外部设备进行通信。具体来说,DHT11使用串行通信协议与外部设备通信的过程包括以下几个步骤:
        启动信号: 外部设备发送一个启动信号给DHT11传感器,以指示开始通信的准备阶段。
        数据传输: DHT11传感器根据约定的协议,将温湿度数据以串行的形式发送给外部设备。这些数据以特定的格式组织,例如先发送湿度值,然后发送温度值,或者相反。
        校验: 在数据传输完成后,外部设备可能会对接收到的数据进行校验,以确保数据的完整性和准确性。通常使用校验和或循环冗余校验(CRC)等技术来实现校验。
        应答: 在数据传输完成后,DHT11可能会发送一个应答信号给外部设备,以表示数据传输的成功或失败状态。

(二)代码解析

1. void DHT_Init_InPut(void)函数

函数介绍:

这个函数用于将连接到DHT11传感器的GPIO引脚配置为浮空输入模式。
使用了STM32的GPIO初始化结构体(GPIO_InitStructure)来配置GPIO的模式、引脚、速度等参数。

代码:

void DHT_Init_InPut(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

2. void DHT_Init_OutPut(void)函数

函数介绍:

这个函数将连接到DHT11传感器的GPIO引脚配置为推挽输出模式。
同样使用了GPIO初始化结构体进行配置。

代码:

void DHT_Init_OutPut(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	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);
}

3. void DHT_Start(void)函数

函数介绍:

这个函数用于启动与DHT11传感器的通信。
首先调用了DHT_Init_OutPut()将引脚配置为输出模式,然后拉低总线一段时间(19ms),再拉高总线(20us),最后将引脚配置为输入模式。

代码:

void DHT_Start(void)
{
	DHT_Init_OutPut();
	GPIO_ResetBits(GPIOB, GPIO_Pin_11); // 拉低总线
	Delay_us(19000);
	GPIO_SetBits(GPIOB, GPIO_Pin_11); // 拉高总线
	Delay_us(20);
	DHT_Init_InPut();
}

4. uint16_t DHT_Scan(void)函数

函数介绍:

这个函数用于读取连接到DHT11传感器的GPIO引脚的当前状态,即读取传感器的响应状态。

代码:

uint16_t DHT_Scan(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); // 返回读取数据
}

5. uint16_t DHT_ReadBit(void)函数

函数介绍:

这个函数用于从DHT11传感器读取单个位。
它会等待传感器将数据线拉高,然后延时一段时间后再读取数据线的状态,以确定位值。

代码:

uint16_t DHT_ReadBit(void)
{
	while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == RESET);
	Delay_us(40);
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == SET)
	{
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == SET);
		return 1;
	}
	else
	{
		return 0;
	}
}

6. uint16_t DHT_ReadByte(void)函数

函数介绍:

这个函数用于从DHT11传感器读取一个字节(8位)的数据。
它通过调用DHT_ReadBit()函数8次,将每一位数据组装成一个完整的字节。

代码:

uint16_t DHT_ReadByte(void)
{
	uint16_t i, data = 0;
	for(i = 0; i < 8; i++)
	{
		data <<= 1; // 向左进一位
		data |= DHT_ReadBit();
	}
	return data;
}

7. uint16_t DHT_ReadData(uint8_t buffer[5])函数

函数介绍:

这个函数用于从DHT11传感器读取5个字节的数据,并进行校验。
它首先调用DHT_Start()启动通信,然后读取传感器发送的数据,并对数据进行校验,确保数据的准确性。

代码:

uint16_t DHT_ReadData(uint8_t buffer[5])
{
	uint16_t i =0;
	
	DHT_Start();
	if(DHT_Scan() == RESET)
	{
		while(DHT_Scan() == RESET);
		while(DHT_Scan() == SET);
		for(i = 0; i < 5; i++)
		{
			buffer[i] = DHT_ReadByte();
		}
		// DHT11输出的40位数据
		while(DHT_Scan() == RESET);
		DHT_Init_OutPut();
		GPIO_SetBits(GPIOB, GPIO_Pin_11);
		
		uint8_t check = buffer[0] + buffer[1] + buffer[2] + buffer[3];
		if(check != buffer[4])
		{
			return 1; // 数据出错
		}
	}
	return  0;
}

四、OLED显示屏驱动(主要函数、I2C协议)

1. OLED_ShowChar函数

函数介绍:

功能:在指定的行和列位置显示一个字符。
参数:

        Line:行位置,范围为1到4。
        Column:列位置,范围为1到16。
        Char:要显示的字符,范围为ASCII可见字符。
这个函数首先根据行和列位置设置光标的位置,然后根据字符的ASCII码在字库中查找对应的字形数据,并将上半部分和下半部分的数据分别写入OLED屏幕的两个页面,以完成字符的显示。

 代码:

void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

2. OLED_ShowString函数

函数介绍:

功能:在指定的行和列位置显示一个字符串。
参数:

        Line:起始行位置,范围为1到4。
        Column:起始列位置,范围为1到16。
        String:要显示的字符串,范围为ASCII可见字符。

这个函数通过循环调用OLED_ShowChar()函数,逐个显示字符串中的字符。

代码:

void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

3. OLED_Pow函数

函数介绍:

功能:计算X的Y次方。
返回值:返回值等于X的Y次方。

这个函数实现了简单的幂函数计算,用于数字显示的处理。

 代码:

void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

4. OLED_ShowNum函数

函数介绍:

功能:在指定的行和列位置显示一个十进制的正整数。
参数:

        Line:起始行位置,范围为1到4。
        Column:起始列位置,范围为1到16。
        Number:要显示的数字,范围为0到4294967295。
        Length:要显示数字的长度,范围为1到10。

这个函数将数字按位数拆分,并逐个调用OLED_ShowChar()函数来显示每一位数字。

代码:  

void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

5. OLED_ShowFNum函数

函数介绍:

功能:在指定的行和列位置显示一个带小数点的十进制数。
参数:

        Line:起始行位置,范围为1到4。
        Column:起始列位置,范围为1到16。
        Number:要显示的数字。
        Length:要显示数字的长度,范围为1到10。
        FLength:要显示的小数点后几位。
这个函数首先判断数字的正负,然后将数字分为整数部分和小数部分,并调用OLED_ShowChar()函数逐个显示每一位数字。

 代码: 

void OLED_ShowFNum(uint8_t Line, uint8_t Column, float Number, uint8_t Length, uint8_t FLength)
{
	uint8_t i;
	uint8_t flag = 1; // 标志是否为小数部分
	float Number1;
	uint32_t Number2;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	Number2 = (int)(Number1*OLED_Pow(10, FLength)); // 小数转换成整数
	for(i = Length; i > 0; i--)
	{
		if(i == Length - FLength)
		{
			OLED_ShowChar(Line, Column + i + flag, '.');
			flag = 0;
		}
		OLED_ShowChar(Line, Column + i + flag, Number2/OLED_Pow(10, Length-i)%10+'0');
	}
}

6. OLED_ShowCC_F16x16函数

函数介绍:

功能:在指定的行和列位置显示一个汉字(16x16像素)。
参数:

        Line:行位置,范围为1到4。
        Column:列位置,范围为1到16。
        num:要显示的汉字在字库中的索引。
这个函数类似于OLED_ShowChar(),但是专门用于显示汉字,字库中每个汉字占16个字节,前8个字节表示汉字的上半部分,后8个字节表示下半部分。

代码: 

void OLED_ShowCC_F16x16(uint8_t Line, uint8_t Column, uint8_t num)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(CC_F16x16[num*2][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(CC_F16x16[num*2][i + 16]);		//显示下半部分内容
	}
}

五、效果展示

基于STM32的温湿度传感器+OLED屏显示的测试视频(有杂音,耳机党请注意)


六、总结 

本文章主要讲的是通过使用STM32实现了对DHT11温湿度传感器的数据采集和显示。通过对GPIO的配置和延时函数的使用,我们成功地与DHT11传感器进行了通信,并读取了温度和湿度数据。在软件开发方面,我们编写了针对DHT11传感器的初始化、数据读取和校验的函数,并成功地将获取到的数据显示在OLED屏幕上,使用户能够直观地了解当前环境的温度和湿度情况。


七、完整代码

压缩包连接:https://download.csdn.net/download/D102428/89078308

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "DHT11.h"

int main()
{
	OLED_Init();
	
	uint8_t buffer[5];
	float h, t;
	              
	OLED_ShowCC_F16x16(2, 1, 2); // 温
	OLED_ShowCC_F16x16(2, 3, 4); // 度
	OLED_ShowChar(2, 5, ':');
	
	OLED_ShowCC_F16x16(3, 1, 3); // 湿
	OLED_ShowCC_F16x16(3, 3, 4); // 度
	OLED_ShowChar(3, 5, ':');
	
	while(1)
	{
		if(DHT_ReadData(buffer) == 0)
		{
			h = buffer[0] + buffer[1] / 10.0;
			t = buffer[2] + buffer[3] / 10.0;

			OLED_ShowFNum(2, 6, t, 3, 1);
			OLED_ShowCC_F16x16(2, 11, 0); // ℃

			OLED_ShowFNum(3, 6, h, 3, 1);
			OLED_ShowCC_F16x16(3, 11, 1); // %
		}
		else
		{
			OLED_Clear();
			OLED_ShowString(2, 6, "ERROR");
		}
	}
}

 DHT11.h

#ifndef _DHT11_H
#define _DHT11_H

void DHT_Init_InPut(void);
void DHT_Init_OutPut(void);
void DHT_Start(void);
uint16_t DHT_Scan(void);
uint16_t DHT_ReadBit(void);
uint16_t DHT_ReadByte(void);
uint16_t DHT_ReadData(uint8_t buffer[5]);

#endif

DHT11.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void DHT_Init_InPut(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void DHT_Init_OutPut(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	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);
}

void DHT_Start(void)
{
	DHT_Init_OutPut();
	GPIO_ResetBits(GPIOB, GPIO_Pin_11); // 拉低总线
	Delay_us(19000);
	GPIO_SetBits(GPIOB, GPIO_Pin_11); // 拉高总线
	Delay_us(20);
	DHT_Init_InPut();
}

uint16_t DHT_Scan(void)
{
	return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11); // 返回读取数据
}

uint16_t DHT_ReadBit(void)
{
	while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == RESET);
	Delay_us(40);
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == SET)
	{
		while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == SET);
		return 1;
	}
	else
	{
		return 0;
	}
}

uint16_t DHT_ReadByte(void)
{
	uint16_t i, data = 0;
	for(i = 0; i < 8; i++)
	{
		data <<= 1; // 向左进一位
		data |= DHT_ReadBit();
	}
	return data;
}

uint16_t DHT_ReadData(uint8_t buffer[5])
{
	uint16_t i =0;
	
	DHT_Start();
	if(DHT_Scan() == RESET)
	{
		while(DHT_Scan() == RESET);
		while(DHT_Scan() == SET);
		for(i = 0; i < 5; i++)
		{
			buffer[i] = DHT_ReadByte();
		}
		// DHT11输出的40位数据
		while(DHT_Scan() == RESET);
		DHT_Init_OutPut();
		GPIO_SetBits(GPIOB, GPIO_Pin_11);
		
		uint8_t check = buffer[0] + buffer[1] + buffer[2] + buffer[3];
		if(check != buffer[4])
		{
			return 1; // 数据出错
		}
	}
	return  0;
}

OLED_Font.h 

#ifndef __OLED_FONT_H
#define __OLED_FONT_H

/*OLED字模库,宽8像素,高16像素*/
const uint8_t OLED_F8x16[][16]=
{
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
	
	0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
	
	0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
	
	0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
	0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
	
	0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
	0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
	
	0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
	0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
	
	0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
	0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
	
	0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
	
	0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
	0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
	
	0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
	0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
	
	0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
	0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
	
	0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
	0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
	
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
	
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
	
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
	
	0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
	0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
	
	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
	0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
	
	0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
	
	0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
	0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
	
	0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
	0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
	
	0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
	0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
	
	0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
	0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
	
	0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
	0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
	
	0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
	0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
	
	0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
	0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
	
	0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
	0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
	
	0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
	0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
	
	0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
	0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
	
	0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
	0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
	
	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
	0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
	
	0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
	0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
	
	0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
	0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
	
	0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
	0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
	
	0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
	0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
	
	0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
	
	0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
	0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
	
	0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
	
	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
	0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
	
	0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
	0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
	
	0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
	0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
	
	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
	0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
	
	0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
	
	0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
	0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
	
	0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
	0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
	
	0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
	0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
	
	0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
	0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
	
	0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
	0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
	
	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
	
	0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
	0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
	
	0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
	0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
	
	0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
	0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
	
	0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
	0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
	
	0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
	
	0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
	
	0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
	0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
	
	0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
	0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
	
	0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
	0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
	
	0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
	0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
	
	0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
	0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
	
	0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
	0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
	
	0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
	
	0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
	0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
	
	0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
	
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
	
	0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
	
	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
	0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
	
	0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
	0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
	
	0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
	0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
	
	0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
	0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
	
	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
	0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
	
	0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
	
	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
	0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
	
	0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
	
	0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
	
	0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
	0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
	
	0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
	0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
	
	0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
	0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
	
	0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
	0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
	
	0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
	0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
	
	0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
	0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
	
	0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
	0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
	
	0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
	0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
	
	0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
	0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
	
	0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
	0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
	
	0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
	0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
	
	0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
	0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
	
	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
	0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
	
	0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
	0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
	
	0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
	0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
	
	0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
	0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
	
	0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
	0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
	
	0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
	0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
	
	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
	
	0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
	0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
	
	0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};

const uint8_t CC_F16x16[][16] = { // Custom Characters 自定义字符
	0x06,0x09,0x09,0xE6,0xF8,0x0C,0x04,0x02,0x02,0x02,0x02,0x02,0x04,0x1E,0x00,0x00,
	0x00,0x00,0x00,0x07,0x1F,0x30,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x10,0x00,0x00,/* "℃",0 */
	
	0x60,0xF0,0x08,0x08,0x08,0xF8,0xF0,0x00,0x80,0x40,0x30,0x08,0x00,0x00,0x00,0x00,
	0x00,0x00,0x01,0x21,0x11,0x0C,0x02,0x01,0x00,0x1E,0x21,0x21,0x21,0x33,0x1E,0x00,/* " %",1 */ 
	
	0x10,0x60,0x02,0x8C,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,
	0x04,0x04,0x7E,0x01,0x40,0x7E,0x42,0x42,0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00,/* "温",2 */

	0x10,0x60,0x02,0x8C,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,
	0x04,0x04,0x7E,0x01,0x44,0x48,0x50,0x7F,0x40,0x40,0x7F,0x50,0x48,0x44,0x40,0x00,/* "湿",3 */

	0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00,
	0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00,/* "度",4 */
	
	0x00,0x00,0x40,0x40,0x40,0x40,0x40,0xFF,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,
	0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,/* "土",5 */
	
	0x10,0x10,0xFF,0x10,0x00,0x82,0xBA,0xEA,0xBA,0x83,0xBA,0xEA,0xBA,0x82,0x00,0x00,
	0x08,0x18,0x0F,0x04,0x48,0x4A,0x2A,0xFF,0x8A,0x4A,0x1A,0x2F,0x5A,0x8A,0x88,0x00,/* "壤",6 */

};

#endif

OLED.h

#ifndef __OLED_H
#define __OLED_H

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowFNum(uint8_t Line, uint8_t Column, float Number, uint8_t Length, uint8_t FLength);
void OLED_ShowCC_F16x16(uint8_t Line, uint8_t Column, uint8_t num);

#endif

OLED.c

#include "stm32f10x.h"
#include "OLED_Font.h"

/*引脚配置*/
#define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))

/*引脚初始化*/
void OLED_I2C_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SCL(1);	//额外的一个时钟,不处理应答信号
	OLED_W_SCL(0);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x00);		//写命令
	OLED_I2C_SendByte(Command); 
	OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78);		//从机地址
	OLED_I2C_SendByte(0x40);		//写数据
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);					//设置Y位置
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));	//设置X位置高4位
	OLED_WriteCommand(0x00 | (X & 0x0F));			//设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for(i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)							
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)							
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**
  * @brief  OLED显示小数(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字
  * @param  Length 要显示数字的长度,范围:1~10
  * @param  FLength 要显示的小数点后几位
  * @retval 无
  */
void OLED_ShowFNum(uint8_t Line, uint8_t Column, float Number, uint8_t Length, uint8_t FLength)
{
	uint8_t i;
	uint8_t flag = 1; // 标志是否为小数部分
	float Number1;
	uint32_t Number2;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	Number2 = (int)(Number1*OLED_Pow(10, FLength)); // 小数转换成整数
	for(i = Length; i > 0; i--)
	{
		if(i == Length - FLength)
		{
			OLED_ShowChar(Line, Column + i + flag, '.');
			flag = 0;
		}
		OLED_ShowChar(Line, Column + i + flag, Number2/OLED_Pow(10, Length-i)%10+'0');
	}
}

void OLED_ShowCC_F16x16(uint8_t Line, uint8_t Column, uint8_t num)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);		//设置光标位置在上半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(CC_F16x16[num*2][i]);			//显示上半部分内容
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//设置光标位置在下半部分
	for (i = 0; i < 16; i++)
	{
		OLED_WriteData(CC_F16x16[num*2][i + 16]);		//显示下半部分内容
	}
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
	uint32_t i, j;
	
	for (i = 0; i < 1000; i++)			//上电延时
	{
		for (j = 0; j < 1000; j++);
	}
	
	OLED_I2C_Init();			//端口初始化
	
	OLED_WriteCommand(0xAE);	//关闭显示
	
	OLED_WriteCommand(0xD5);	//设置显示时钟分频比/振荡器频率
	OLED_WriteCommand(0x80);
	
	OLED_WriteCommand(0xA8);	//设置多路复用率
	OLED_WriteCommand(0x3F);
	
	OLED_WriteCommand(0xD3);	//设置显示偏移
	OLED_WriteCommand(0x00);
	
	OLED_WriteCommand(0x40);	//设置显示开始行
	
	OLED_WriteCommand(0xA1);	//设置左右方向,0xA1正常 0xA0左右反置
	
	OLED_WriteCommand(0xC8);	//设置上下方向,0xC8正常 0xC0上下反置

	OLED_WriteCommand(0xDA);	//设置COM引脚硬件配置
	OLED_WriteCommand(0x12);
	
	OLED_WriteCommand(0x81);	//设置对比度控制
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9);	//设置预充电周期
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);	//设置VCOMH取消选择级别
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);	//设置整个显示打开/关闭

	OLED_WriteCommand(0xA6);	//设置正常/倒转显示

	OLED_WriteCommand(0x8D);	//设置充电泵
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);	//开启显示
		
	OLED_Clear();				//OLED清屏
}
### 回答1: 要用STM32C8T6和DHT11度、湿度显示OLED幕上,我们需要编写一些程序代码。下面是可能的代码示例: ``` #include <DHT11.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); DHT11 dht11(D1); void setup() { display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.display(); } void loop() { int chk = dht11.read(DHT11_PIN); if (chk == DHT11_OK) { display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(10,10); display.print("Temperature: "); display.print(dht11.temperature); display.print("C"); display.setCursor(10,20); display.print("Humidity: "); display.print(dht11.humidity); display.print("%"); display.display(); } delay(2000); } ``` 在这个程序中,我们首先定义了OLED显示器的宽度和高度,然后初始化了显示器。在循环中,我们读取DHT11传感器的度和湿度值,将它们显示显示器上。显示文本的位置可以调整,以适应您的OLED尺寸。我们还包括一个2秒的延迟,以避免在显示上刷新文本太快。 请注意,此代码示例使用了DHT11OLED库。库应该先下载并在代码中导入,否则编译时会出现错误。 ### 回答2: 首先,需要准备好以下材料: 1. STM32C8T6主控板 2. DHT11湿度传感器 3. OLED显示 4. 接线材料 在开始编写源代码之前,需要将上述材料进行连接。具体的连接方式如下: DHT11的接线方式如下: 1. VCC接STM32C8T6板的5V电源端口 2. GND接STM32C8T6板的GND电源端口 3. DATA接STM32C8T6的GPIO口 OLED显示的接线方式如下: 1. VCC接STM32C8T6的5V电源端口 2. GND接STM32C8T6的GND电源端口 3. SCL接STM32C8T6的GPIO端口 4. SDA接STM32C8T6的GPIO端口 5. RES接STM32C8T6的GPIO端口 6. DC接STM32C8T6的GPIO端口 7. CS接STM32C8T6的GPIO端口 接线完成后,可以开始编写源代码。以下是参考代码,可以根据实际情况进行修改: #include "stm32f10x.h" #include "oled.h" #include "dht11.h" int main(void) { //初始化OLED显示 OLED_Init(); //初始化DHT11传感器 DHT11_Init(); //定义变量,保存度和湿度的值 int temperature, humidity; while(1) { //获取度和湿度的值 DHT11_Read_Data(&temperature, &humidity); //将获取到的度和湿度值进行显示 OLED_ShowNum(0, 0, temperature, 2, 16); OLED_ShowString(2 * 8, 0, "℃", 16); OLED_ShowNum(0, 2 * 8, humidity, 2, 16); OLED_ShowString(2 * 8, 2 * 8, "%", 16); //延时一段时间,避免数据频繁更新 delay_ms(2000); } } 在此代码中,首先进行OLED显示DHT11湿度传感器的初始化。然后,定义变量保存度和湿度的值。使用DHT11_Read_Data函数获取度和湿度的值,并且将获取到的度和湿度值进行显示。最后,通过delay_ms函数延时一段时间,避免数据频繁更新导致幕闪烁。 需要注意的是,以上代码仅为参考,具体情况可能需要根据实际情况进行修改。例如,具体的GPIO口需要根据实际的连接情况进行选择。同时,需要根据实际需求自行调整显示内容的位置、大小等参数。 ### 回答3: STM32C8T6是一款高性能的32位单片机DHT11是一个数字湿度度传感器,OLED是一种小型的有机发光显示器。将这三个设备结合起来,可以制作一个简单的湿度显示器。 以下是基于STM32C8T6、DHT11OLED湿度显示源代码: 首先,我们需要引用必要的库头文件: #include "stm32f10x.h" #include "dht11.h" #include "oled.h" 然后,我们需要定义一些常量和变量来初始化设备和存储输出结果: #define DHT11_DATA_PIN GPIO_Pin_0 #define DHT11_DATA_PORT GPIOA #define OLED_WIDTH 128 #define OLED_HEIGHT 64 uint8_t humi_int, humi_deci, temp_int, temp_deci; char text[20]; 接下来,我们需要实现初始化函数来初始化STM32C8T6和OLED: void init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); DHT11_Init(DHT11_DATA_PORT, DHT11_DATA_PIN); OLED_Init(); } 然后,我们可以实现主函数,以读取湿度传感器并在OLED显示结果: int main(void) { init(); while (1) { // 读取湿度 if (DHT11_Read_Pin(DHT11_DATA_PORT, DHT11_DATA_PIN) == 1) { DHT11_Read_Data(&humi_int, &humi_deci, &temp_int, &temp_deci); } // 渲染湿度到幕 sprintf(text, "Temp: %d.%dC", temp_int, temp_deci); OLED_Clear(); OLED_ShowString(0, 0, text, 1); sprintf(text, "Humi: %d.%d%%", humi_int, humi_deci); OLED_ShowString(0, 20, text, 1); OLED_Refresh(); // 等待1s for (volatile int i = 0; i < 1000000; i++); } } 以上就是基于STM32C8T6、DHT11OLED湿度显示代码。需要注意的一些细节是: - 在渲染文本字符串之前,我们需要先清除OLED幕上的所有内容。 - 在渲染文本字符串之后,我们需要调用OLED_Refresh()函数才能将结果渲染到实际幕上。 - 我们使用sprintf()函数来将湿度转换为文本字符串。这个函数可以将格式化的字符串输出到一个字符数组中。
评论 95
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YdaMooc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值