今天我们测试下读取温湿度传感器SHT20的传感器数值,此传感器是IIC接口的,数字输出。
我们接在板子的PB6,PB7接口上,这个有外部上拉,所以我们只需要使用两个IO即可,然后我们通过模拟IIC总线方式即可完成传感器数值获取。
之后我在原有的点灯基础上,添加4个文件,分别是IIC接口的,和传感器的。
-
-
- //硬件驱动
- #include "iic.h"
-
-
-
-
-
- IIC_INFO iicInfo;
-
-
-
- /*
- ************************************************************
- * 函数名称: IIC_SpeedCtl
- *
- * 函数功能: 软件IIC速度控制
- *
- * 入口参数: speed:延时参数
- *
- * 返回参数: 无
- *
- * 说明: 单位:微秒
- ************************************************************
- */
- void IIC_SpeedCtl(unsigned short speed)
- {
-
- iicInfo.speed = speed;
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_Init
- *
- * 函数功能: 软件IIC总线IO初始化
- *
- * 入口参数: 无
- *
- * 返回参数: 无
- *
- * 说明: 使用开漏方式,这样可以不用切换IO口的输入输出方向
- ************************************************************
- */
- void IIC_Init(void)
- {
-
- GPIO_InitTypeDef gpioInitStruct;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
-
- gpioInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //开漏,这样不用去切换输出输入方向
- gpioInitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
- gpioInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &gpioInitStruct);
-
- IIC_SpeedCtl(5);
-
- SDA_H; //拉高SDA线,处于空闲状态
- SCL_H; //拉高SCL线,处于空闲状态
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_Start
- *
- * 函数功能: 软件IIC开始信号
- *
- * 入口参数: 无
- *
- * 返回参数: 无
- *
- * 说明:
- ************************************************************
- */
- void IIC_Start(void)
- {
-
- SDA_H; //拉高SDA线
- SCL_H; //拉高SCL线
- Delay_Us(iicInfo.speed); //延时,速度控制
-
- SDA_L; //当SCL线为高时,SDA线一个下降沿代表开始信号
- Delay_Us(iicInfo.speed); //延时,速度控制
- SCL_L; //钳住SCL线,以便发送数据
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_Stop
- *
- * 函数功能: 软件IIC停止信号
- *
- * 入口参数: 无
- *
- * 返回参数: 无
- *
- * 说明:
- ************************************************************
- */
- void IIC_Stop(void)
- {
-
- SDA_L; //拉低SDA线
- SCL_L; //拉低SCL先
- Delay_Us(iicInfo.speed); //延时,速度控制
-
- SCL_H; //拉高SCL线
- SDA_H; //拉高SDA线,当SCL线为高时,SDA线一个上升沿代表停止信号
- Delay_Us(iicInfo.speed);
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_WaitAck
- *
- * 函数功能: 软件IIC等待应答
- *
- * 入口参数: timeOut:超时时间
- *
- * 返回参数: 无
- *
- * 说明: 单位:微秒
- ************************************************************
- */
- _Bool IIC_WaitAck(unsigned int timeOut)
- {
-
-
- SDA_H;Delay_Us(iicInfo.speed); //拉高SDA线
- SCL_H;Delay_Us(iicInfo.speed); //拉高SCL线
-
- while(SDA_R) //如果读到SDA线为1,则等待。应答信号应是0
- {
- if(--timeOut == 0)
- {
-
-
- IIC_Stop(); //超时未收到应答,则停止总线
-
- return IIC_Err; //返回失败
- }
-
- Delay_Us(iicInfo.speed);
- }
-
- SCL_L; //拉低SCL线,以便继续收发数据
-
- return IIC_OK; //返回成功
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_Ack
- *
- * 函数功能: 软件IIC产生一个应答
- *
- * 入口参数: 无
- *
- * 返回参数: 无
- *
- * 说明: 当SDA线为低时,SCL线一个正脉冲代表发送一个应答信号
- ************************************************************
- */
- void IIC_Ack(void)
- {
-
- SCL_L; //拉低SCL线
- SDA_L; //拉低SDA线
- Delay_Us(iicInfo.speed);
- SCL_H; //拉高SCL线
- Delay_Us(iicInfo.speed);
- SCL_L; //拉低SCL线
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_NAck
- *
- * 函数功能: 软件IIC产生一非个应答
- *
- * 入口参数: 无
- *
- * 返回参数: 无
- *
- * 说明: 当SDA线为高时,SCL线一个正脉冲代表发送一个非应答信号
- ************************************************************
- */
- void IIC_NAck(void)
- {
-
- SCL_L; //拉低SCL线
- SDA_H; //拉高SDA线
- Delay_Us(iicInfo.speed);
- SCL_H; //拉高SCL线
- Delay_Us(iicInfo.speed);
- SCL_L; //拉低SCL线
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_SendByte
- *
- * 函数功能: 软件IIC发送一个字节
- *
- * 入口参数: byte:需要发送的字节
- *
- * 返回参数: 无
- *
- * 说明:
- ************************************************************
- */
- void IIC_SendByte(unsigned char byte)
- {
-
- unsigned char count = 0;
-
- SCL_L; //拉低时钟开始数据传输
-
- for(; count < 8; count++) //循环8次,每次发送一个bit
- {
- if(byte & 0x80) //发送最高位
- SDA_H;
- else
- SDA_L;
-
- byte <<= 1; //byte左移1位
-
- Delay_Us(iicInfo.speed);
- SCL_H;
- Delay_Us(iicInfo.speed);
- SCL_L;
- }
-
- }
-
- /*
- ************************************************************
- * 函数名称: IIC_RecvByte
- *
- * 函数功能: 软件IIC接收一个字节
- *
- * 入口参数: 无
- *
- * 返回参数: 接收到的字节数据
- *
- * 说明:
- ************************************************************
- */
- unsigned char IIC_RecvByte(void)
- {
-
- unsigned char count = 0, receive = 0;
-
- SDA_H; //拉高SDA线,开漏状态下,需线拉高以便读取数据
-
- for(; count < 8; count++ ) //循环8次,每次发送一个bit
- {
- SCL_L;
- Delay_Us(iicInfo.speed);
- SCL_H;
-
- receive <<= 1; //左移一位
-
- if(SDA_R) //如果SDA线为1,则receive变量自增,每次自增都是对bit0的+1,然后下一次循环会先左移一次
- receive++;
-
- Delay_Us(iicInfo.speed);
- }
-
- return receive;
-
- }
-
- /*
- ************************************************************
- * 函数名称: I2C_WriteByte
- *
- * 函数功能: 软件IIC写一个数据
- *
- * 入口参数: slaveAddr:从机地址
- * regAddr:寄存器地址
- * byte:需要写入的数据
- *
- * 返回参数: 0-写入成功 1-写入失败
- *
- * 说明: *byte是缓存写入数据的变量的地址,因为有些寄存器只需要控制下寄存器,并不需要写入值
- ************************************************************
- */
- _Bool I2C_WriteByte(unsigned char slaveAddr, unsigned char regAddr, unsigned char *byte)
- {
-
- unsigned char addr = 0;
-
- addr = slaveAddr << 1; //IIC地址是7bit,这里需要左移1位,bit0:1-读 0-写
-
- IIC_Start(); //起始信号
-
- IIC_SendByte(addr); //发送设备地址(写)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_SendByte(regAddr); //发送寄存器地址
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- if(byte)
- {
- IIC_SendByte(*byte); //发送数据
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
- }
-
- IIC_Stop(); //停止信号
-
- return IIC_OK;
-
- }
-
- /*
- ************************************************************
- * 函数名称: I2C_ReadByte
- *
- * 函数功能: 软件IIC读取一个字节
- *
- * 入口参数: slaveAddr:从机地址
- * regAddr:寄存器地址
- * val:需要读取的数据缓存
- *
- * 返回参数: 0-成功 1-失败
- *
- * 说明: val是一个缓存变量的地址
- ************************************************************
- */
- _Bool I2C_ReadByte(unsigned char slaveAddr, unsigned char regAddr, unsigned char *val)
- {
-
- unsigned char addr = 0;
-
- addr = slaveAddr << 1; //IIC地址是7bit,这里需要左移1位,bit0:1-读 0-写
-
- IIC_Start(); //起始信号
-
- IIC_SendByte(addr); //发送设备地址(写)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_SendByte(regAddr); //发送寄存器地址
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_Start(); //重启信号
-
- IIC_SendByte(addr + 1); //发送设备地址(读)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- *val = IIC_RecvByte(); //接收
- IIC_NAck(); //产生一个非应答信号,代表读取接收
-
- IIC_Stop(); //停止信号
-
- return IIC_OK;
-
- }
-
- /*
- ************************************************************
- * 函数名称: I2C_WriteBytes
- *
- * 函数功能: 软件IIC写多个数据
- *
- * 入口参数: slaveAddr:从机地址
- * regAddr:寄存器地址
- * buf:需要写入的数据缓存
- * num:数据长度
- *
- * 返回参数: 0-写入成功 1-写入失败
- *
- * 说明: *buf是一个数组或指向一个缓存区的指针
- ************************************************************
- */
- _Bool I2C_WriteBytes(unsigned char slaveAddr, unsigned char regAddr, unsigned char *buf, unsigned char num)
- {
-
- unsigned char addr = 0;
-
- addr = slaveAddr << 1; //IIC地址是7bit,这里需要左移1位,bit0:1-读 0-写
-
- IIC_Start(); //起始信号
-
- IIC_SendByte(addr); //发送设备地址(写)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_SendByte(regAddr); //发送寄存器地址
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- while(num--) //循环写入数据
- {
- IIC_SendByte(*buf); //发送数据
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- buf++; //数据指针偏移到下一个
-
- Delay_Us(10);
- }
-
- IIC_Stop(); //停止信号
-
- return IIC_OK;
-
- }
-
- /*
- ************************************************************
- * 函数名称: I2C_ReadBytes
- *
- * 函数功能: 软件IIC读多个数据
- *
- * 入口参数: slaveAddr:从机地址
- * regAddr:寄存器地址
- * buf:需要读取的数据缓存
- * num:数据长度
- *
- * 返回参数: 0-写入成功 1-写入失败
- *
- * 说明: *buf是一个数组或指向一个缓存区的指针
- ************************************************************
- */
- _Bool I2C_ReadBytes(unsigned char slaveAddr, unsigned char regAddr, unsigned char *buf, unsigned char num)
- {
-
- unsigned short addr = 0;
-
- addr = slaveAddr << 1; //IIC地址是7bit,这里需要左移1位,bit0:1-读 0-写
-
- IIC_Start(); //起始信号
-
- IIC_SendByte(addr); //发送设备地址(写)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_SendByte(regAddr); //发送寄存器地址
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- IIC_Start(); //重启信号
-
- IIC_SendByte(addr + 1); //发送设备地址(读)
- if(IIC_WaitAck(5000)) //等待应答
- return IIC_Err;
-
- while(num--)
- {
- *buf = IIC_RecvByte();
- buf++; //偏移到下一个数据存储地址
-
- if(num == 0)
- {
- IIC_NAck(); //最后一个数据需要回NOACK
- }
- else
- {
- IIC_Ack(); //回应ACK
- }
- }
-
- IIC_Stop();
-
- return IIC_OK;
-
- }
IIC接口我们直接选择开漏模式,这样我们需要转换IO口的方向。
之后注意下其换算方式即可。套用公式就能得到最终温度。
主函数中一直打印,这里打印也有点奇怪用%f居然不显示,我强转了下,其实还有其他办法,本次测试的就这样下弄下吧。
其实还可以放在看数据,不过不知道是不是不支持全局变量自动刷新,如果我全速运行也是不显示变量的,得打上断点。不过使用下来,还是感觉方便,代码提示,报错都是比较准确的。
看下接线实物图。
搜索
复制