STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块

今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。

文章提供源码、测试工程下载、测试效果图。

目录

AHT10温湿度传感器:

特性:

连接方式:

适用场所范围:

程序设计:

设计目标:

 程序设计注意点:

AHT10代码:

 主函数代码:

测试效果:

 完整工程下载:


AHT10温湿度传感器:

下图为AHT温湿度传感器模块,它长这样,这里的介绍不重要,了解就行,快速浏览即可

AHT10,新一代温湿度传感器在尺寸与智能方面建立了新的标准:

它嵌入了适于回流焊的双列扁平无引脚SMD封装,底面4x5mm,高度1.6mm。

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

特性:

1.模块尺寸:    16*11mm
2.接口类型:    I2C
3.工作电压:    1.8-6.0V
4.接口尺寸:    4*2.54mm间距
5.湿度精度:    典型 士 2%
6.湿度分辨率:0.024%
7.温度精度:    典型 土 0.3C
8.温度分辨率:典型0.01C
9.工作温度:    -40°C--85C 

连接方式:

适用场所范围:

  • 暖通空调 、除湿器
  • 检测设备
  • 自动控制、数据记录器
  • 气象站、家电
  • 医疗及其他相关湿度检测控制。

程序设计:

设计目标:

1.使用IIC通信初始化和读取AHT10传感器的温湿度信息,并通过OLED打印

2.IIC通信引脚:PB3(SCL)   PB4(SDA)

3.使用定时器2,周期性读取AHT10的温湿度信息(300ms为周期)

 程序设计注意点:

1.上电启动传感器,启动后需要先等待40ms(设备才开始正常工作),然后发送0x71 来获取状态字节

2.获取到校准使能位后,查看其是否已校准,若已校准则跳过当前步骤;若未校准则发送0xe1,进行初始化,然后发送0x080x00

3.接着开始触发测量,测量先发送0xac,然后发送0x330x00

 4.测量命令发送完成后,需要等待80ms,用于温湿度的测量;之后再发送命令0x71,以读取状态寄存器是否处于空闲状态(bit7 => idle);若是空闲状态,可以直接读取之后六个字节的温湿度数值;

 

5.相对湿度和温度转换公式:

 接受的处理是使用char类型的数组 去接受每个读取到的八位数据,然后根据运算公式计算:(1024*1024=2^20 )  ,( int )强制类型转换为int是为了不丢符号:

 最后还有俩个函数,一个是检查,一个是复位的:

 

AHT10代码:

#include "AHT10.h"
/**
brief AHT10初始化函数
param NONE
return NONE
*/
void AHT10Init()
{//IIC_Init();GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3|GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOBA	GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);				 //PA4 输出高delay_ms(50);//延时50ms让传感器稳定I2C_Start();I2C_Send_Byte(AHT10_ADDRESS);  //获取状态//初始化校准I2C_Send_Byte(0xe1);	I2C_Send_Byte(0x08);I2C_Send_Byte(0x00);I2C_Stop();	delay_ms(50);//延时50ms让传感器稳定
}/**
brief 检查AHT10是否存在
param NONE
return 0存在  1不存在
*/
u8 AHT10Check(void)
{u8 ack=0;I2C_Start();I2C_Send_Byte(AHT10_ADDRESS);ack=I2C_Wait_Ack();I2C_Stop();	return ack;
}/**
brief AHT10软复位
param NONE
return NONE
*/
void AHT10Reset(void)
{I2C_Start();I2C_Send_Byte(AHT10_WRITE);I2C_Wait_Ack();I2C_Send_Byte(0xba);I2C_Wait_Ack();I2C_Stop();	
}/**
brief 检查AHT10读温湿度数据
param *temperature:需要读出的温度数据,float指针类型,精度范围+-0.3C
param *humidity:需要读出的湿度数据,u8指针类型,精度范围+-2RH
return 0 读数据正常 1读数据失败
*/
u8 AHT10ReadData(float *temperature,u8 *humidity)
{u8 ack;u32 SRH=0,ST=0;u8 databuff[6];I2C_Start();I2C_Send_Byte(AHT10_WRITE);I2C_Wait_Ack();I2C_Send_Byte(0xac);I2C_Wait_Ack();I2C_Send_Byte(0x33);I2C_Wait_Ack();I2C_Send_Byte(0x00);I2C_Wait_Ack();I2C_Stop();	  delay_ms(80);//延时一会等待数据读出I2C_Start();I2C_Send_Byte(AHT10_READ);I2C_Wait_Ack();ack=I22C_Read_Byte(1);if((ack&0x40)==0){databuff[0]=I22C_Read_Byte(1);databuff[1]=I22C_Read_Byte(1);databuff[2]=I22C_Read_Byte(1);databuff[3]=I22C_Read_Byte(1);databuff[4]=I22C_Read_Byte(0);I2C_Stop();SRH=(databuff[0]<<12)+(databuff[1]<<4)+(databuff[2]>>4);ST=((databuff[2]&0X0f)<<16)+(databuff[3]<<8)+(databuff[4]);*humidity=(int)(SRH*100.0/1024/1024+0.5);*temperature=((int)(ST*2000.0/1024/1024+0.5))/10.0-50;return 0;}I2C_Stop();	return 1;
}//初始化IIC
void I22C_Init(void)
{					     GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4); 	//PB6,PB7 输出高
}
//产生IIC起始信号
void I2C_Start(void)
{SDA_OUT();     //sda线输出IIC_SDA=1;	  	  IIC_SCL=1;delay_us(4);IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4);IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void I2C_Stop(void)
{SDA_OUT();//sda线输出IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(4);IIC_SCL=1; IIC_SDA=1;//发送I2C总线结束信号delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 I2C_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();      //SDA设置为输入  IIC_SDA=1;delay_us(1);	   IIC_SCL=1;delay_us(1);	 while(READ_SDA){ucErrTime++;if(ucErrTime>250){I2C_Stop();return 1;}}IIC_SCL=0;//时钟输出0 	   return 0;  
} 
//产生ACK应答
void I2C_Ack(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}
//不产生ACK应答		    
void I2C_NAck(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void I2C_Send_Byte(u8 txd)
{                        u8 t;   SDA_OUT(); 	    IIC_SCL=0;//拉低时钟开始数据传输for(t=0;t<8;t++){              //IIC_SDA=(txd&0x80)>>7;if((txd&0x80)>>7)IIC_SDA=1;elseIIC_SDA=0;txd<<=1; 	  delay_us(2);   //对TEA5767这三个延时都是必须的IIC_SCL=1;delay_us(2); IIC_SCL=0;	delay_us(2);}	 
} 	    //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 I22C_Read_Byte(unsigned char ack)
{unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA)receive++;   delay_us(1); }					 if (!ack)I2C_NAck();//发送nACKelseI2C_Ack(); //发送ACK   return receive;
}
#ifndef _AHT10_h_
#define _AHT10_h_#include "headfire.h"
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
//输出寄存器
#define GPIOA_ODR_Addr (GPIOA_BASE+12)//0x4001280C
#define GPIOB_ODR_Addr (GPIOB_BASE+12)//0x40010C0C
//输入寄存器
#define GPIOA_IDR_Addr (GPIOA_BASE+8)//0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8)//0x40010C08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)	BIT_ADDR(GPIOA_ODR_Addr,n)//输出
#define PAin(n) 	BIT_ADDR (GPIOA_IDR_Addr,n)//输入#define PBout(n) 	BIT_ADDR(GPIOB_ODR_Addr,n)//输出
#define PBin(n) 	BIT_ADDR(GPIOB_IDR_Addr,n)//输入#define SDA_IN()  {GPIOB->CRL&=0XFFF0FFFF;GPIOB->CRL|=(u32)8<<16;}
#define SDA_OUT() {GPIOB->CRL&=0XFFF0FFFF;GPIOB->CRL|=(u32)3<<16;}//IO操作函数	 
#define IIC_SCL    PBout(3) //SCL
#define IIC_SDA    PBout(4) //SDA	 
#define READ_SDA   PBin(4)  //输入SDA #define AHT10_ADDRESS 0x70
#define AHT10_WRITE 0x70
#define AHT10_READ 0x71/*****************函数声明******************/
extern void AHT10Init(void);
extern u8 AHT10Check(void);
extern void AHT10Reset(void);
extern u8 AHT10ReadData(float *temperature,u8 *humidity);//IIC所有操作函数
void I22C_Init(void);                //初始化IIC的IO口				 
void I2C_Start(void);				//发送IIC开始信号
void I2C_Stop(void);	  			//发送IIC停止信号
void I2C_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 I2C_Wait_Ack(void); 				//IIC等待ACK信号
void I2C_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号void I2C_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 I2C_Read_One_Byte(u8 daddr,u8 addr);	  
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 I22C_Read_Byte(unsigned char ack);#endif

 主函数代码:

#include "main.h"float temp;
u8 hum;
int humm,temper;
uint16_t AHT10_cnt,AHT10_flag;
char buf[30];int main(void)
{	init_ALL();     //初始化所有函数while(1){	if(AHT10_flag==1){AHT10_flag=0;AHT10ReadData(&temp,&hum);temper=temp*10;humm=hum;OLED_ShowCHinese(0,0,0);  //打印中文“温”OLED_ShowCHinese(16,0,2);  //打印中文“度”sprintf(buf,": %d.%d",temper/10,temper%10);		OLED_ShowString(32,0,(u8 *)buf,16);	   OLED_ShowCHinese(0,2,1);  //打印中文“湿”OLED_ShowCHinese(16,2,2);  //打印中文“度”sprintf(buf,": %d ",humm);		OLED_ShowString(32,2,(u8 *)buf,16);	      			}}
}//初始化所有函数:
void init_ALL(void)
{SysTick_Init(72);         //初始化滴答计时器Timer2_Init();						//初始化定时器2i2c_GPIO_Config();	      //IIC初始化OLED_Init();              //初始化OLED屏幕OLED_Clear();             //清空屏幕数据AHT10Init();              //初始化温湿度传感器}//定时器2中断服务函数
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){		if(++AHT10_cnt==30)         //每300ms刷新一次温湿度数据{AHT10_cnt=0;AHT10_flag=1;}TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断}
}

测试效果:

 完整工程下载:

https://download.csdn.net/download/qq_64257614/88248711?spm=1001.2014.3001.5503

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/56492.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨专业申请成功|金融公司经理赴美国密苏里大学访学交流

J经理所学专业与从事工作不符&#xff0c;尽管如此&#xff0c;我们还是为其成功申请到美国密苏里大学经济学专业的访问学者职位&#xff0c;全家顺利过签出国。 J经理背景&#xff1a; 申请类型&#xff1a; 自费访问学者 工作背景&#xff1a; 某金融公司经理 教育背景&am…

(视频教程)单细胞转录组多组差异基因分析及可视化函数

很久以前&#xff0c;我们发布过一个单细胞多组差异基因可视化的方法。跟着Cell学单细胞转录组分析(八):单细胞转录组差异基因分析及多组结果可视化。主要复现参考的是这篇发表在《Cell》上的文章。可以将多个组的差异结果展示出来。 &#xff08;reference&#xff1a;A Spati…

在VScode中执行npm、yarn命令报错解

在VScode中执行npm、yarn命令报错解 我使用的是vnm安装好npm&#xff0c;在WindowsR 界面是可以运行查看出版本的&#xff1b;但是在VScode中报错。 查了很多资料&#xff0c;我这种情况的原因是在VScode中默认使用的终端是Powershell&#xff0c;然后我切换到系统的cmd则可以…

原生微信小程序使用 wxs;微信小程序使用 vant-weapp组件

1.原生微信小程序使用 wxs 1.内嵌 WXS 脚本 2. 定义外链 wxs 3. 使用外连wxs 在这里插入图片描述 2. 微信小程序使用 vant weapp 1.安装步骤 2. 安装包管理(package.json)文件的方法 操作顺序 &#xff1a;文档地址 如果使用 typescript 需要操作步骤3&#xff0c;否则不…

使用 wxPython 和 pymupdf进行 PDF 加密

PDF 文件是一种常见的文档格式&#xff0c;但有时候我们希望对敏感信息进行保护&#xff0c;以防止未经授权的访问。在本文中&#xff0c;我们将使用 Python 和 wxPython 库创建一个简单的图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;用于对 PDF 文件进行加密…

自动化运维:Ansible基础与命令行模块操作

目录 一、理论 1. Ansible 2.部署Ansible自动化运维工具 3.Ansible常用模块 4.hostsinverntory主机清单 二、实验 1.部署Ansible自动化运维工具 2.ansible 命令行模块 3.hostsinverntory主机清单 三、问题 1. ansible远程shell失败 2.组变量查看webservers内主机ip报…

基于Java+SpringBoot+Vue前后端分离美食推荐商城设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

时间和日期--Python

1. 时间&#xff1a;time模块 总结&#xff1a;2. datetime模块 相比与time模块&#xff0c;datetime模块的接口更直观、更容易调用 2.1 datetime模块定义的类 &#xff08;1&#xff09;datetime.date:表示日期的类。常用的属性有&#xff1a;year、month、day; &#xff…

vue中form、table和input标签过长

form标签过长 效果&#xff1a; 代码&#xff1a; <el-form-item v-for"(item,index) in ticketEditTable1" :label"item.fieldNameCn" :propitem.fieldName :key"item.fieldNameCn" overflow"":rules"form[item.fieldName…

Android中使用JT808协议进行车载终端通信的实现和优化

JT808是一种在中国广泛应用的车载终端通信协议&#xff0c;用于车辆与监控中心之间的数据通信。下面是关于Android平台上使用JT808协议进行通信的一般步骤和注意事项&#xff1a; 协议了解&#xff1a;首先&#xff0c;您需要详细了解JT808协议的规范和定义。该协议包含了通信消…

【halcon深度学习】图像分割数据集格式的转换

前言 目前用于**图像分割的**数据集&#xff0c;我目前接触到的用的比较多的有&#xff1a; 1 PASCAL VOC 2 COCO 3 YOLO 4 Halcon自己的格式&#xff08;其实就是Halcon字典类型&#xff09;当前我涉及到计算机视觉中的数据集格式有&#xff0c;PASCAL VOC、COCO 和 YOLO 用于…

软件设计师学习笔记3-CPU组成

目录 1.计算机结构 1.1计算机的外设与主机 1.2计算机各部分之间的联系(了解一下即可) 2.CPU结构 1.计算机结构 1.1计算机的外设与主机 1.2计算机各部分之间的联系(了解一下即可) 该图片来自希赛软考 注&#xff1a;黄色的是传递数据的数据总线&#xff0c;白色的是传递控…

表和Json的相互操作

目录 一、表转Json 1.使用 for json path 2.如何返回单个Json 3.如何给返回的Json增加一个根节点呢 4.如何给返回的Json增加上一个节点 二、对Json基本操作 1.判断给的字符串是否是Json格式 2.从 JSON 字符串中提取标量值 3. 从 JSON 字符串中提取对象或数组 4. 更…

【Linux】进程概念,轻松入门【下篇】

目录 1. 基本概念 2. 常见环境变量 常见环境变量指令 &#xff08;1. PATH &#xff08;2. HOME &#xff08;3. SHELL 3.环境变量的组织形式 &#xff08;1&#xff09;通过代码如何获取环境变量 &#xff08;2&#xff09;普通变量与环境变量的区别 &#xff08;3&…

206.Flink(一):flink概述,flink集群搭建,flink中执行任务,单节点、yarn运行模式,三种部署模式的具体实现

一、Flink概述 1.基本描述 Flink官网地址:Apache Flink — Stateful Computations over Data Streams | Apache Flink Flink是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。 2.有界流和无界流 无界流(流): 有定义流的开始,没有定义结束。会无休止…

[当前就业]2023年8月25日-计算机视觉就业现状分析

计算机视觉就业现状分析 前言&#xff1a;超越YOLO&#xff1a;计算机视觉市场蓬勃发展 如今&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;新版本的发布周期很快&#xff0c;每次迭代的性能都优于其前身。每 3 到 4 个月就会推出一个升级版 YOLO 变体&#xf…

数据通信——RIP协议

一&#xff0c;实验背景 你们公司又订购了一批设备&#xff0c;你以为还要为新员工设计静态路由&#xff0c;结果领导说&#xff0c;不是有动态路由吗&#xff1f;用动态路由&#xff0c;就用什么R的那个。“垃圾RIP&#xff0c;用RIP还不如静态&#xff0c;RIP缺点太多&#x…

25-非父子通信 - event bus 事件总线

作用:非父子组件之间&#xff0c;进行简易消息传递。(复杂场景 -> Vuex) 1.创建一个都能访问到的事件总线(空 Vue 实例) -> utils/EventBus.js import Vue from vue const Bus new Vue() export default Bus 2. A组件(接收方),监听 Bus实例 的事件(支持多个组件同时监…

SSL核心概念 SSL类型级别

SSL&#xff1a;SSL&#xff08;Secure Sockets Layer&#xff09;即安全套接层&#xff0c;及其继任者传输层安全&#xff08;Transport Layer Security&#xff0c;TLS&#xff09;是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。 H…

探索内网穿透工具:实现局域网SQL Server数据库的公网远程访问方法

文章目录 1.前言2.本地安装和设置SQL Server2.1 SQL Server下载2.2 SQL Server本地连接测试2.3 Cpolar内网穿透的下载和安装2.3 Cpolar内网穿透的注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据库的重要性相信大家都有所了解&…