收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
一、确认基本参数
传感器资料网上可以找到,实在不行可以去电子商城下载,比如某商城:
1.1 根据产品特征整体认识产品
那么其实接触一个新的传感器,在传感器文档开头部分,都会有一个 Features ,说明了产品的特征,比如 BH1750 的 Features 如下图:
上面特征我虽然全部看了,但是我画出了两条,第一条可以得知传感器的通讯方式为 I2C,第二条 具备低功耗的能力可以判断传感器是否符合我们的应用。 当然,其他的特征也得过一遍,看看是否能满足自己的应用场合。
1.2 根据工作条件确定产品的供电方式
继续往下看,我们能看到 Absolute Maximum Ratings 这个电气绝对参数,这个是规定的传感器的耐压等数据,这里了解一下即可,我们更加需要关系的是下面这个图:
通过上图我们可以直接确定传感器的供电电压。
当然还有一个重要的点就是他的 I2C 参考电压可以达到 Vcc ,这说明在我们常用的 3.3V 供电的 MCU 系统上使用这个传感器不需要做电平转换,可以直接与 MCU 的 I2C 接口连接。
再往下的一些电气参数 Electrical Characteristics 其实过一遍了解一下即可,不仔细也没有太大关系。
1.3 根据推荐电路图确定 PCB 设计
上面我们已经知道了传感器供电电压,那么如果是自己设计 硬件电路的话,那么需要了解:
各个引脚的功能定义
参考产品手册上的推荐电路图
这个在资料往下翻一大段。
引脚的定义如下:
这里加一个判别传感器1引脚的方法:
上图中,传感器中间有一个品字形状,我们拿到传感器仔细看,也能看到品字形状,根据这个形状判断 引脚即可。
在文档后面有引脚的定义:
我这里自己写一个表格做简要说明:
名称 | 功能 |
---|---|
VCC | 电源 |
ADDR | 传感器地址引脚,ADDR 高低电平传感器地址不一样 ,高电平:0x5C 低电平: 0x23 |
GND | GND |
SDA | I2C 数据线 |
DVI | SDA和 SCL 的参考电压,内部寄存器的异步重置端口,在供电以后需要保持低电平,在内部通过 150k 的电阻下拉到地 |
SCL | I2C 时钟线 |
当 ADDR 为高电平的时候,传感器地址为 1011100
:0x5C;
当 ADDR 为低电平的时候,传感器地址为 0100011
:0x23;
接下来我们来看看推荐电路图 ,注意手册中的说明:
图中 SDA 和 SCL 以及省略了,还得注意一下 ADDR 的高低电平,因为决定了传感器的地址。
在手册中推荐了 4 种电路图,我这里推荐的是使用第四种(需要知道一下这种无法满足内部寄存器重置的操作):
如果使用这种方式,那么我们接下来操作传感器的地址就是:0x23。
对于硬件相关的东西我们确定好了以后,我们可以自己画 PCB ,要记住 I2C 通讯是需要上拉电阻的。当然如果是采购的现成的传感器模块可以省略。
采购的传感器模块一般都只需要连接 4个引脚,就是标准的 I2C 通讯的 :SCL、 SDA、VCC、GND 。
博主本次采用的传感器其实也是采购的成品小板子,但是正真的最后还是会自己画的,到时候有机会也来记录一下自己画的用作低功耗的小板子:
二、工作流程及指令
我们完成硬件的基本了解,可以了解一下传感器的工作流程级操作指令。
2.1 工作流程分析
在资料手册中,列出了 Measurement Procedure 部分,如下图:
对于低功耗的产品,我们都会使用单次测量模式,可以最大限度的控制功耗。
我们可以直接总结出来,我们如果使用单次测量命令的话,我们在初始化传感器的时候就可以使用指令让模块进入单次测量模式:
初始化:
模块上电 ——> 发送指令使模块进入单次测量模式
正常工作流程:
发送指令使模块进入上电模式 ——> 发送测量命令 ——> 模块测量完成会会自动进入掉电模式(单次测量模式)
2.2 操作命令
在手册中给出了操作命令,但是根据我们前面的分析,我们需要用到的指令并不多,在图中我圈出了我们可能需要用到的指令:
其中我们只需要记住单次测量的命令就可以了,使用什么分辨率根据自己的情况而定。
2.3 单次测量示例解析
为了更好的说明命令怎么用,在手册中也已经举了例子,我给他加上了中文注释说明测量流程:
传感器手册读到这里,基本上已经满足我们的开发需求,我们下面就开始根据上面所分析的资料进行程序设计。
三、程序设计
本次的测试基于 STM32L051 ,但是其实在驱动程序中体现不出来,因为用的软件 I2C ,驱动基本上可以移植到各种单片机平台。
在我们使用 i2c 传感器的时候,一般都是有一个通用驱动文件,然后还有一个传感器的驱动文件,如下图(d6t44l 是一个 I2C 传感器):
对于 I2C 的基础知识,本文不做过多讨论,大家应该比较熟悉,不熟悉的可以复习一下基础知识。
3.1 I2C 通用驱动
通用驱动就包括了 ,I2C 启动,结束,发送等待 ACK ,发送不等待 ACK ,读取,等待 ACK 等等这些函数,这个其实在很多开源的项目中找一个就可以了。
我们这里先确定一下 i2c.h 文件,针对自己的设备连接的 IO 口进行定义:
这里因为大家都很方便的可以找到开源的驱动,唯独需要注意上图中的定义,改成自己测试的 IO 口,所以这里就不过多解释,直接把通用驱动放上 :
i2c.h:
#ifndef \_I2C\_H\_INCLUDED
#define \_I2C\_H\_INCLUDED
#include "main.h"
#include "Datadef.h"
#define MYIIC\_CLK\_HIGH HAL\_GPIO\_WritePin(SCL\_GPIO\_Port,SCL\_Pin,GPIO\_PIN\_SET)
#define MYIIC\_CLK\_LOW HAL\_GPIO\_WritePin(SCL\_GPIO\_Port,SCL\_Pin,GPIO\_PIN\_RESET)
#define MYIIC\_DATA\_HIGH HAL\_GPIO\_WritePin(SDA\_GPIO\_Port,SDA\_Pin,GPIO\_PIN\_SET)
#define MYIIC\_DATA\_LOW HAL\_GPIO\_WritePin(SDA\_GPIO\_Port,SDA\_Pin,GPIO\_PIN\_RESET)
#define MYIIC\_DATA\_STATE HAL\_GPIO\_ReadPin(SDA\_GPIO\_Port,SDA\_Pin)
// ------------------------
#define DONOTHING() {;}
// ------------------------
// command's
#define I2C\_WRITE 0
#define I2C\_READ 1
#define I2C\_ACK 0
#define I2C\_NACK 1
void MYIIC\_Start(void);
void MYIIC\_Stop(void);
u8 MYIIC\_Wait\_Ack(void);
void IIC\_NAck(void);
void IIC\_Ack(void);
void IIC\_Send\_Byte(u8 txd);
u8 IIC\_Read\_Byte(unsigned char ack);
#endif
i2c.c:
#include "i2c.h"
void MYIIC\_Start(void)
{
MYIIC_DATA_HIGH;
delay\_us(5);
MYIIC_CLK_HIGH;
delay\_us(10);
MYIIC_DATA_LOW;
delay\_us(10);
MYIIC_CLK_LOW; //使SCL置低,准备发送或者接受数据
delay\_us(10);
}
void MYIIC\_Stop(void)
{
MYIIC_DATA_LOW;
delay\_us(5);
MYIIC_CLK_LOW;
delay\_us(10);
MYIIC_CLK_HIGH;
delay\_us(5);
MYIIC_DATA_HIGH;
delay\_us(10);
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC\_Read\_Byte(unsigned char ack)
{
unsigned char i,receive=0;
// MYSDA\_IN;//SDA设置为输入
for(i=0;i<8;i++ )
{
MYIIC_CLK_LOW; //SCL为由低变高,在SCL高的时候去读 SDA的数据
delay\_us(10);
MYIIC_CLK_HIGH;
receive<<=1; //第一次这里还是0,第二次开始每次接收的数据做移动一位,从高位开始接收
if(MYIIC_DATA_STATE)receive++; //如果数据为1,++以后就是1,数据为0,不执行就是0;
delay\_us(10);
}
if (!ack)
IIC\_NAck();//发送nACK
else
IIC\_Ack(); //发送ACK
return receive;
}
u8 MYIIC\_Wait\_Ack(void)
{
u8 ucErrTime=0;
delay\_us(5);
MYIIC_DATA_HIGH;delay\_us(5); //MCU DATA 置高,外面高就是高,外面低就是低
MYIIC_CLK_HIGH; delay\_us(5); //CLK 高电平期间数据有效
while(MYIIC_DATA_STATE) //低电平为有应答,高电平无应答
{
ucErrTime++;
if(ucErrTime>250)
{
MYIIC\_Stop();
return 1;
}
}
delay\_us(10);
MYIIC_CLK_LOW;
return 0;
}
void IIC\_Ack(void)
{
MYIIC_CLK_LOW; //SCL为低,SDA为低,SCL为高,SDA为低,应答低电平有效,SCL为低,产生应答信号
// MYSDA\_OUT;
MYIIC_DATA_LOW;
delay\_us(10);
MYIIC_CLK_HIGH;
delay\_us(10);
MYIIC_CLK_LOW;
delay\_us(10);
MYIIC_DATA_HIGH;
}
void IIC\_NAck(void)
{
MYIIC_CLK_LOW; //SCL为低,SDA为高,SCL为高,SCL为低
// MYSDA\_OUT;
MYIIC_DATA_HIGH;
delay\_us(10);
MYIIC_CLK_HIGH;
delay\_us(10);
MYIIC_CLK_LOW;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC\_Send\_Byte(u8 txd)
{
u8 t;
// MYSDA\_OUT;
MYIIC_CLK_LOW; //拉低时钟开始数据传输 ,SCL为低,SDA变高或者变低(数据位),SCL变高,SCL变低,期间SDA为1既1,为0既0
for(t=0;t<8;t++) //一个字节8位,一位一位发送
{
MYIIC_CLK_LOW;
if((txd&0x80)>>7) //从最高位开始发送,如果是1,发送高电平
MYIIC_DATA_HIGH;
else
MYIIC_DATA_LOW;
txd<<=1; //SDA处理完毕,此时可以将SCL拉高接受数据,拉高以后延时拉低
delay\_us(10); //
MYIIC_CLK_HIGH;
delay\_us(10);
MYIIC_CLK_LOW;
delay\_us(5);
}
}
3.2 BH1750 驱动
完成了通用驱动,我们现在就可以完全根据前面的分析流传进行 BH1750 的驱动设计。
我们新建一个 bh1750.c
和 bh1750.h
文件,在头文件中进行一些必要的宏定义:
把可能需要用到的都给他定义一遍,后面需要改正再说。
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
9fe33b4a4c882ae8de3ae4ce15.png)
把可能需要用到的都给他定义一遍,后面需要改正再说。
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-aHNv0A1W-1715764708588)]
[外链图片转存中…(img-82mCg59J-1715764708588)]
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!