STM32使用硬件IIC读取AHT10温湿度传感器的数据并显示在0.96寸OLED屏上。

我用的单片机是STM32F103C8T6,程序用的是ST标准库写的。

STM32使用硬件I2C读取SHTC3温湿度传感器:https://blog.zeruns.tech/archives/692.html

实现效果图


I2C协议简介

I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备(那些电平转化芯片),现在被广泛地使用在系统内多个集成电路(IC)间的通讯。

I2C只有一跟数据总线 SDA(Serial Data Line),串行数据总线,只能一位一位的发送数据,属于串行通信,采用半双工通信

半双工通信:可以实现双向的通信,但不能在两个方向上同时进行,必须轮流交替进行,其实也可以理解成一种可以切换方向的单工通信,同一时刻必须只能一个方向传输,只需一根数据线.
对于I2C通讯协议把它分为物理层和协议层物理层规定通讯系统中具有机械、电子功能部分的特性(硬件部分),确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准(软件层面)。

I2C物理层

I2C 通讯设备之间的常用连接方式

(1) 它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。

(2) 一个 I2C 总线只使用两条总线线路,一条双向串行数据线SDA(Serial Data Line ),一条串行时钟线SCL(Serial Data Line )。数据线即用来表示数据,时钟线用于数据收发同步

(3) 总线通过上拉电阻接到电源。当 I2C 设备空闲时会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平

I2C通信时单片机GPIO口必须设置为开漏输出,否则可能会造成短路。

关于更多STM32的I2C相关信息和使用方法可以看这篇文章:https://url.zeruns.tech/JC0Ah

我这里就不详细讲解了。

AHT10温湿度传感器

介绍

AHT10是一款国产的温湿度传感器芯片,价格便宜,精度还高,体积也小。

AHT10配有一个全新设计的ASIC专用芯片、一个经过改进的MEMS半导体电容式湿度传感元件和一个标准的片上温度传感元件,其性能已经大大提升甚至超出了前一代传感器的可靠性水平,新一代温湿度传感器,经过改进使其在恶劣环境下的性能更稳定。

AHT10数据手册下载地址:https://url.zeruns.tech/EDEwF


浏览数据手册可以得到一个大概信息:

  • 温度范围:-40℃~85℃
  • 温度误差:±0.3℃
  • 湿度范围:0%~100%
  • 湿度误差:±2%
  • 工作电压:1.8v~3.6v
  • 通讯方式:I2C
  • 时钟频率:100kHz和400kHz

找到如下几个关键信息

温湿度设备地址和读写命令

在实际的使用过程中,AHT10的设备地址需要与读写数据/命令方向位组成一个字节同时发送,字节的最低位为读写数据/命令方向位,高7位是AHT10的设备地址。

如果要通过I2C写数据或命令给AHT10,在I2C起始信号之后,需要发送“0111 0000”,即0x70给AHT10,除了通过高7位“0111 000”的设备地址寻址还通过最低位“0”通知AHT10接下来是写数据或命令操作。

如果要通过I2C读取AHT10中的数据,在I2C起始信号之后,需要发送“0111 0001”,即0x71给AHT10,除了通过高7位“0111 000”的设备地址寻址还通过最低位“1”通知AHT10接下来是读取数据的操作。
简单来说就是,0x70表示写数据,0x71表示读数据。不过使用STM32硬件I2C时只需要输入0x70就行,最低位标准库会处理的。

读取温湿度数据


从数据手册可知,一个测量周期包概括三个步骤:

  1. 发送测量命令
  2. 等待测量完成
  3. 读取测量后的数据

总结如下:

  1. 发送测量命令:先发送写入指令(0x70),再发送触发测量指令(0xAC),再发送命令参数(0x33和0x00)。
  2. 等待测量完成:数据手册上写的75ms,等待的时间大于这个就行了。
  3. 接收数据:发送读取指令(0x71),连续接收6个字节数据。接收到的第一个字节是状态字,检查状态字第3位校准使能位是否为1,不为1就发送初始化命令,检查第7位忙闲指示,如果是0为测量完成,进行下一步。
  4. 对接收到的数据进行转换处理。

数据的计算

由AHT10数据手册可知

例如:采集到的湿度数值是0x0C6501,换算成十进制是812289。
则:湿度 = 812289 * 100 / 1048576 = 77.46 (单位:%)
采集到的温度数值是0x056A00,换算成十进制是354816。
则:温度 = ( 354816 * 200 / 1048576 ) - 50= 17.67 (单位:℃)

需要用的元件

STM32最小系统板:https://s.click.taobao.com/bqMwZRu
AHT10模块:https://s.click.taobao.com/gIF09Ru
OLED模块:https://s.click.taobao.com/aNlvZRu
杜邦线:https://s.click.taobao.com/xAkAJRu
面包板:https://s.click.taobao.com/ShJAJRu
ST-LINK V2:https://s.click.taobao.com/C8ftZRu

程序

这里就放出main.c、AHT10.c和OLED.c这三个主要的代码,其他的请下载下面链接的压缩包。

完整工程文件:https://url.zeruns.tech/AHT10

AHT10和OLED模块的 SCL接PB6,SDA接PB7。

使用VSCode代替Keil实现STM32和51单片机的开发:https://blog.zeruns.tech/archives/690.html

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "IWDG.h"
#include "AHT10.h"uint16_t numlen(uint16_t num);int main(void)
{IWDG_Configuration();  //初始化看门狗OLED_Init();            //初始化OLED屏AHT10_Init();         //初始化AHT10OLED_ShowString(1, 1, "T:");OLED_ShowString(2, 1, "H:");uint32_t a=0;uint16_t err_count=0;while (1){a++;OLED_ShowNum(3, 1, a, 9);//计数显示,方便观察程序是否正常运行if(a==999999999)a=0;float Temp,Hum;         //声明变量存放温湿度数据/*https://blog.zeruns.tech*/if(ReadAHT10(&Hum,&Temp))  //读取温湿度数据{if(Temp>=0){char String[10];sprintf(String, "+%.2fC", Temp);//格式化字符串输出到字符串变量OLED_ShowString(1, 3, String); //显示温度sprintf(String, " %.2f%%", Hum);//格式化字符串输出到字符串变量OLED_ShowString(2, 3, String);  //显示湿度}else{char String[10];sprintf(String, "-%.2fC", Temp);//格式化字符串输出到字符串变量OLED_ShowString(1, 3, String);    //显示温度sprintf(String, " %.2f%%", Hum);//格式化字符串输出到字符串变量OLED_ShowString(2, 3, String);  //显示湿度}}else{err_count++;OLED_ShowNum(4,1, err_count, 5); //显示错误次数计数}Delay_ms(100);   //延时100毫秒IWDG_FeedDog();    //喂狗(看门狗,超过1秒没有执行喂狗则自动复位)}
}

AHT10.c

#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"/*AHT10地址*/
#define AHT10_ADDRESS 0x38<<1 //从机地址是7位,最后一位是传输方向位,所以左移一位/*设置使用哪一个I2C*/
#define I2Cx I2C1/*
https://blog.zeruns.tech
*//*发送起始信号*/
void AHT10_I2C_START(){while( I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));//等待总线空闲I2C_GenerateSTART(I2Cx, ENABLE);//发送起始信号while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);//检测EV5事件
}/*发送停止信号*/
void AHT10_I2C_STOP(){I2C_GenerateSTOP(I2Cx, ENABLE);//发送停止信号
}/*** @brief  发送3个字节数据* @param  cmd 命令字节* @param  DATA0 第0个参数* @param  DATA1 第1个参数* @retval 无*/
void AHT10_WriteByte(uint8_t cmd, uint8_t DATA0, uint8_t DATA1)
{AHT10_I2C_START();  //发送起始信号I2C_Send7bitAddress(I2Cx, AHT10_ADDRESS, I2C_Direction_Transmitter);    //发送设备写地址while(I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //检测EV6事件I2C_SendData(I2Cx, cmd);//发送命令while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检测EV8事件I2C_SendData(I2Cx, DATA0);//发送命令参数高8位数据while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检测EV8事件I2C_SendData(I2Cx, DATA1);//发送命令参数低8位数据while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检测EV8事件I2C_GenerateSTOP(I2Cx, ENABLE);//发送停止信号
}/*** @brief  发送命令读取AHT10的状态* @retval 读取到的状态字节*/
/*uint8_t AHT10_ReadStatus(void){AHT10_I2C_START();//发送起始信号  I2C_Send7bitAddress(I2Cx,AHT10_ADDRESS,I2C_Direction_Receiver);//发送设备读地址while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//检测EV6事件while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//检测EV7事件I2C_AcknowledgeConfig(I2Cx, DISABLE); //关闭应答信号uint8_t status = I2C_ReceiveData(I2Cx);//读取数据并返回AHT10_I2C_STOP();   //发送停止信号I2C_AcknowledgeConfig(I2Cx,ENABLE);//重新开启应答信号return status;
}*//*** @brief  读取数据* @retval 读取到的字节数据*/
uint8_t AHT10_ReadData(void)
{while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//检测EV7事件return I2C_ReceiveData(I2Cx);//读取数据并返回
}/*软件复位AHT10*/
void AHT10_SoftReset(void)
{AHT10_I2C_START();  //发送起始信号I2C_Send7bitAddress(I2Cx, AHT10_ADDRESS, I2C_Direction_Transmitter);    //发送设备写地址while(I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //检测EV6事件I2C_SendData(I2Cx, 0xBA);//发送软复位命令while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检测EV8事件I2C_GenerateSTOP(I2Cx, ENABLE);//发送停止信号Delay_ms(20);
}/*引脚初始化*/
void AHT10_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);    //使能I2C1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟/*STM32F103芯片的硬件I2C1: PB6 -- SCL; PB7 -- SDA */GPIO_InitTypeDef  GPIO_InitStructure;               //定义结构体配置GPIOGPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;      //设置输出模式为开漏输出,需接上拉电阻GPIO_Init(GPIOB, &GPIO_InitStructure);              //初始化GPIOI2C_DeInit(I2Cx);   //将外设I2C寄存器重设为缺省值I2C_InitTypeDef  I2C_InitStructure;                 //定义结构体配置I2CI2C_InitStructure.I2C_Mode = I2C_Mode_I2C;            //工作模式I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;   //时钟占空比,Tlow/Thigh = 2I2C_InitStructure.I2C_OwnAddress1 = 0x88;    //主机的I2C地址,用不到则随便写,无影响I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;   //使能应答位I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//设置地址长度7位I2C_InitStructure.I2C_ClockSpeed = 400000;  //I2C传输速度,400K,根据自己所用芯片手册查看支持的速度。 I2C_Init(I2Cx, &I2C_InitStructure);         //初始化I2CI2C_Cmd(I2Cx, ENABLE);  //启用I2CDelay_ms(20);//上电延时AHT10_WriteByte(0XE1,0X08,0x00);//发送指令初始化Delay_ms(20);}/*** @brief  读取AHT10数据* @param  *Hum 湿度* @param  *Temp 温度* @retval 1 - 读取成功;0 - 读取失败*/
uint8_t ReadAHT10(float *Hum,float *Temp)
{uint8_t Data[5];//声明变量存放读取的数据AHT10_WriteByte(0XAC,0X33,0x00);//发送指令触发测量Delay_ms(70);   //延时70毫秒等待测量完成AHT10_I2C_START();//发送起始信号  I2C_Send7bitAddress(I2Cx,AHT10_ADDRESS,I2C_Direction_Receiver);//发送设备读地址while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//检测EV6事件uint8_t i;for(i=0;i<6;i++)//循环6次读取6个字节数据{if (i == 5)  //读取最后1个字节时关闭应答信号{I2C_AcknowledgeConfig(I2Cx, DISABLE); //关闭应答信号}Data[i] = AHT10_ReadData();   //读取数据if (i == 5)I2C_GenerateSTOP(I2Cx, ENABLE); //发送停止信号}I2C_AcknowledgeConfig(I2Cx,ENABLE);//重新开启应答信号if( (Data[0]&0x08) == 0 )//0x08(00001000)检查状态字节第3位(校准使能位)是否为0{AHT10_WriteByte(0XE1,0X08,0x00);   //发送指令初始化Delay_ms(20);return 0;}else if( (Data[0]&0x80) == 0 )//0x80(10000000)检查状态字节第7位(忙闲指示)是否为0{uint32_t SRH = (Data[1]<<12) | (Data[2]<<4) | (Data[3]>>4);  //湿度数据处理uint32_t ST = ((Data[3]&0x0f)<<16) | (Data[4]<<8) | Data[5];//温度数据处理*Hum = (SRH * 100.0) / 1024.0 / 1024;    //根据手册给的公式转换湿度数据*Temp = (ST * 200.0) / 1024.0 / 1024 - 50; //根据手册给的公式转换温度数据return 1;}I2C_GenerateSTOP(I2Cx, ENABLE);//发送停止信号return 0;   }/*
https://blog.zeruns.tech
*/

OLED.c

#include "stm32f10x.h"
#include "OLED_Font.h"/*OLED屏地址*/
#define OLED_ADDRESS 0x78/*设置哪一个使用I2C*/
#define I2Cx I2C1/*
https://blog.zeruns.tech
*//*引脚初始化*/
void OLED_I2C_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);    //使能I2C1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟/*STM32F103芯片的硬件I2C: PB6 -- SCL; PB7 -- SDA */GPIO_InitTypeDef  GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;      //设置输出模式为开漏输出,需接上拉电阻GPIO_Init(GPIOB, &GPIO_InitStructure);I2C_DeInit(I2Cx);  //将外设I2C寄存器重设为缺省值I2C_InitTypeDef  I2C_InitStructure;I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;         //工作模式I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;   //时钟占空比,Tlow/Thigh = 2I2C_InitStructure.I2C_OwnAddress1 = 0x88;    //主机的I2C地址,用不到则随便写,无影响I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;   //使能应答位I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//设置地址长度7位I2C_InitStructure.I2C_ClockSpeed = 400000;  //I2C传输速度,400K,根据自己所用芯片手册查看支持的速度。 I2C_Init(I2Cx, &I2C_InitStructure);I2C_Cmd(I2Cx, ENABLE);
}void I2C_WriteByte(uint8_t addr,uint8_t data)
{while( I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));//发送起始信号I2C_GenerateSTART(I2Cx, ENABLE);//检测EV5事件while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);//发送设备写地址I2C_Send7bitAddress(I2Cx, OLED_ADDRESS, I2C_Direction_Transmitter);//检测EV6事件while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);//发送要操作设备内部的地址I2C_SendData(I2Cx, addr);//检测EV8_2事件while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));I2C_SendData(I2Cx, data);//发送数据while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//发送停止信号I2C_GenerateSTOP(I2Cx, ENABLE);
}/*** @brief  OLED写命令* @param  Command 要写入的命令* @retval 无*/
void OLED_WriteCommand(unsigned char Command)//写命令
{I2C_WriteByte(0x00, Command);
}/*** @brief  OLED写数据* @param  Data 要写入的数据* @retval 无
*/
void OLED_WriteData(unsigned char Data)//写数据
{I2C_WriteByte(0x40, Data);
}/*** @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  start 列开始位置,范围:1~16* @param  end 列开始位置,范围:1~16* @retval 无*/
void OLED_Clear_Part(uint8_t Line, uint8_t start, uint8_t end)
{  uint8_t i,Column;for(Column = start; Column <= end; Column++){OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);       //设置光标位置在上半部分for (i = 0; i < 8; i++){OLED_WriteData(0x00);            //显示上半部分内容}OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);   //设置光标位置在下半部分for (i = 0; i < 8; 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  无* @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清屏
}

推荐阅读

  • 高性价比和便宜的VPS/云服务器推荐: https://www.awsl9527.cn/archives/41.html
  • 使用NPS搭建内网穿透服务器,带Web面板:https://www.awsl9527.cn/archives/748.html
  • Linux搭建网站教程,建站教程:https://www.awsl9527.cn/archives/1094.html
  • 我的世界服务器搭建教程:https://www.awsl9527.cn/archives/tag/minecraft
  • 基于STM32和HC-SR04模块实现超声波测距功能:https://blog.zeruns.tech/archives/680.html
  • ESP8266开发环境搭建及项目演示:https://blog.zeruns.tech/archives/526.html

STM32单片机硬件I2C读取AHT10温湿度传感器数据相关推荐

  1. FPGA实验记录五:I2C读取AHT10温湿度传感器

    FPGA实验记录五:I2C读取AHT10温湿度传感器 一.AHT10温湿度传感器 1. 简介 AHT10,新一代温湿度传感器在尺寸与智能方面建立了新的标准:它嵌入了始于回流焊的双列扁平无引脚SMD封装 ...

  2. MicroPython ESP32 读取DHT11温湿度传感器数据

    MicroPython ESP32 读取DHT11温湿度传感器数据 DHT11温湿度传感器 接线说明 ESP32 ----- DHT11 3.3V ----- VCC GND ----- GND GP ...

  3. 模拟IIC读取SHT30温湿度传感器数据

    文章目录 1 i2c.c 2 i2c.h 3 crc.c 4 crc.h 1 i2c.c /*** @brief SHT30温湿度传感器相关,使用模拟IIC进行数据的读取*/#include < ...

  4. STM32单片机硬件I2C驱动程序(查询方式)

    本文章原始地址:http://feotech.com/?p=69 本程序主要用于驱动STM32单片机芯片的硬件I2C寄存器,实现通过使用芯片自带的I2C寄存器进行数据的发送与接收. 本例程中采用I2C ...

  5. STM32单片机硬件I2C驱动程序(软件轮询方式)---摘自:FeoTech

    感谢原作者:FeoTech   原文网址:http://feotech.com/?p=69 本程序主要用于驱动STM32单片机芯片的硬件I2C寄存器,实现通过使用芯片自带的I2C寄存器进行数据的发送与 ...

  6. STM32F103C6T6 | 模拟IIC主机读取AHT20温湿度传感器数据

    关于STM32的IIC 一开始是用硬件内置的IIC来读取数据的,没有什么问题,但是不知道为什么后续断电上电之后一直没有数据,仿真看的话发现卡死在这些循环里面,我才反应过来网上一直说的硬件IIC有问题是 ...

  7. 基于I2C硬件协议的AH20温湿度传感器的数据采集

    目录 I2C 温湿度传感器数据采集 实验准备 实验步骤: 实验结果: I2C I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实 ...

  8. STM32F 单片机硬件I2C Busy标志导致的I2C卡死的处理办法

    STM32F 单片机硬件I2C Busy标志导致的I2C卡死的处理办法 在调试多用户表的时候,发现如果人为短接I2C的SDA或SLK脚后,I2C的SR2的Busy标志将会置1,并且试了很多种办法也无法 ...

  9. vb6编写dll读取dat文件_【STM32Cube_15】使用硬件I2C读取温湿度传感器数据(SHT30)...

    寻求更好的阅读体验,请移步Mculover666的个人博客: [STM32Cube_15]使用硬件I2C读取温湿度传感器数据(SHT30)​www.mculover666.cn 本篇详细的记录了如何使 ...

最新文章

  1. inodesusedpercent_Linux运维监控基础采集项
  2. QT的QGradient类的使用
  3. Chrome 调试技巧
  4. php 自带 web server 如何重写 rewrite .htaccess
  5. 解读边缘计算在7大领域的研究趋势和最新进展
  6. spring 线程安全
  7. SQL语句学习之路7
  8. 学习matlab(十八)——小波分析
  9. (半)自动化爬虫系统该包含的功能点及相关介绍
  10. 高分meta分析质量评价方法
  11. centos 7 DVD版设置基础软件仓库出错(error setting up base repository)
  12. 史上最好听的十首纯音乐推荐
  13. [zz]u盘做系统启动盘后容量变小的解决方法 8GU盘变成2G 或 xG变成2G
  14. 自己动手该 博客 百度给的模板不好看,有没个性
  15. 嵌入式主板上使用的插针式加密锁
  16. pythonocc常见问题集锦
  17. PHP-Swoole+tp3+websocket+redis,利用接口制作客服实时对话聊天服务器
  18. FLINK 基于1.15.2的Java开发-Watermark是怎么解决延迟数据唯一正确的生产级解决方案-目前市面上的例子都有问题
  19. 关于昨晚昨晚的银河护卫队2
  20. 阿宽食品冲刺深交所:年销售11亿 高瓴与茅台建信是股东

热门文章

  1. Linux磁盘与分区命名:sda, sdb, sdc, sda1, sda2
  2. 计算机程序是通过专利保护,《专利审查指南》修改后计算机程序的专利保护研究.doc...
  3. Spring整合Quartz集群部署
  4. 如何创建自己的云盘-私有云盘
  5. 2020老年产业过去|现在|未来:疫情促进“线上化”,各分支加速融合创新
  6. 20160411_使用老毛桃破解电脑密码
  7. 2018最新手机cpu排行
  8. 【笔记】编程的原则:改善代码质量的101个方法
  9. 51单片机——存储器
  10. python中的内置高阶函数