I2C总线通信(温湿度实验)

1.使能GPIOF时钟

2.将PF14设置为输出,PF15也可以先设置为输出

3.设置输出速度最高档位速度

4.SI7006的初始化

5.读取温度、湿度

6.将读取到的温度湿度数据通过计算公式进行转换

7.将结果输出 

main.c

#include "si7006.h"

extern void printf(const char *fmt,...);

void delay(int ms)

{

  int i,j;

  for(i=0;i<ms;i++)

  {
      for(j=0;j<2000;j++);
  }

}

int main()

{

    unsigned short tem;//用于保存 温度数据和湿度数据

    unsigned short hum;

    //进行SI7e06的初始化

    si7006_init();

    while(1)

    {

        //读取温度

        tem=si7006_read_data( 0x40,0XE0);

        hum=si7006_read_data(0x40,0XE5);//读取湿度

         //数据转换

        tem=tem*175.72/65536-46.85;

        hum=hum*125/65536-6;

        //数据输出

        printf("tem:%d\n",tem);

        printf("hum:%d\n",hum);

        delay(1000);

    }

    return 0;

}

iic.c

#include "iic.h"

extern void printf(const char* fmt, ...);
/*
 * 函数名 : delay_us
 * 函数功能:延时函数
 * 函数参数:无
 * 函数返回值:无
 * */
void delay_us(void)
{
	unsigned int i = 2000;
	while(i--);
}
/*
 * 函数名 : i2c_init
 * 函数功能: i2C总线引脚的初始化, 通用输出,推挽输出,输出速度,
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_init(void)
{
 	// 使能GPIOF端口的时钟
	RCC->MP_AHB4ENSETR |= (0x1 << 5);
	// 设置PF14,PF15引脚为通用的输出功能
	GPIOF->MODER &= (~(0xF << 28));
	GPIOF->MODER |= (0x5 << 28);
	// 设置PF14, PF15引脚为推挽输出
	GPIOF->OTYPER &= (~(0x3 << 14));
	// 设置PF14, PF15引脚为高速输出
	GPIOF->OSPEEDR |= (0xF << 28);
	// 设置PF14, PF15引脚的禁止上拉和下拉
	GPIOF->PUPDR &= (~(0xF << 28));
	// 空闲状态SDA和SCL拉高 
	I2C_SCL_H;
	I2C_SDA_H;
}



/*
 * 函数名:i2c_start
 * 函数功能:模拟i2c开始信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_start(void)
{
	/*
	 * 开始信号:时钟在高电平期间,数据线从高到低的变化
	 *     --------
	 * SCL         \
	 *              --------
	 *     ----
	 * SDA     \
	 *          --------
	 * */	
	//保证数据线PF15是输出
	SET_SDA_OUT;
	//空闲状态时钟线和数据线拉高
	I2C_SCL_H;
	I2C_SDA_H;
	delay_us();
	I2C_SDA_L;//数据线拉低
	delay_us();
	I2C_SCL_L;//时钟线拉低,此时I2C总线处于占用状态
}

/*
 * 函数名:i2c_stop
 * 函数功能:模拟i2c停止信号的时序
 * 函数参数:无
 * 函数返回值:无
 * */

void i2c_stop(void)
{
	/*
	 * 停止信号 : 时钟在高电平期间,数据线从低到高的变化 
	 *             ----------
	 * SCL        /
	 *    --------
	 *    ---         -------
	 * SDA   X       /
	 *    --- -------
	 * */
    //可能为高电平也可能是低电平(应答或非应答)
	SET_SDA_OUT;
	I2C_SCL_L;//方便讲数据线电频拉低
	delay_us();
	I2C_SDA_L;
	delay_us();
	I2C_SCL_H;
	delay_us();
	I2C_SDA_H;


}

/*
 * 函数名: i2c_write_byte
 * 函数功能:主机向i2c总线上的从设备写8bits数据
 * 函数参数:dat : 等待发送的字节数据
 * 函数返回值: 无
 * */

void i2c_write_byte(unsigned char dat)
{
	/*
	 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
	 * 			时钟在高电平期间,接收器从数据线上读取数据 
	 *      ----          --------
	 * 	SCL     \        /        \
	 *           --------          --------
	 *      -------- ------------------ ---
	 * 	SDA         X                  X
	 *      -------- ------------------ ---
	 *
	 *      先发送高位在发送低位 
	 * */
	//确保SDA是输出状态 PF15输出
    SET_SDA_OUT;
    unsigned int i;
    for(i=0;i<8;i++)
    {
        //时钟线拉低
         I2C_SCL_L;
         delay_us();//延时
         //0X3A->0011 1010   0X80->10000000
         if(dat&0X80)//最高位为1
         {
            //发送1
            I2C_SDA_H;
         }
         else  //最高位为0
         {
            I2C_SDA_L;//发送0
         }
         delay_us();//延时
         //时钟线拉高,接收器接收
         I2C_SCL_H;
        delay_us();//延时,用于等待接收器接收数据
        delay_us();//延时
        //将数据左移一位,让原来第6位变为第7位
        dat = dat<<1;

    }



}

/*
 * 函数名:i2c_read_byte
 * 函数功能: 主机从i2c总线上的从设备读8bits数据, 
 *          主机发送一个应答或者非应答信号
 * 函数参数: 0 : 应答信号   1 : 非应答信号
 * 函数返回值:读到的有效数据
 *
 * */
unsigned char i2c_read_byte(unsigned char ack)
{
	/*
	 * 数据信号:时钟在低电平期间,发送器向数据线上写入数据
	 * 			时钟在高电平期间,接收器从数据线上读取数据 
	 *      ----          --------
	 * 	SCL     \        /        \
	 *           --------          --------
	 *      -------- ------------------ ---
	 * 	SDA         X                  X
	 *      -------- ------------------ ---
	 *
	 *      先接收高位, 在接收低位 
	 * */
	unsigned int i;
    unsigned char dat;//保存接受的数据
    //将数据线设置为输入
    SET_SDA_IN;
    for(i=0;i<8;i++)
    {
        //先把时钟线拉低,等一段时间,保证发送器发送完毕数据
        I2C_SCL_L;
        delay_us();
        delay_us();//保证发送器发送完数据
        //时钟线拉高,读取数据
        I2C_SCL_H;       
        delay_us();
        dat=dat<<1;//数值左移  0000 0000
        if(I2C_SDA_READ)//pf15管脚得到了一个高电平输入
        {
            dat |=1; //0000 0110
        }
        else
        {
            dat &=(~0X1);
        }
         delay_us();
    }
        if(ack)
        {
            i2c_nack();//发送非应答信号,不再接收下一次数据
        }
        else
        {
           i2c_ack();//发送应答信号 
        }
    return dat;
}
/*
 * 函数名: i2c_wait_ack
 * 函数功能: 主机作为发送器时,等待接收器返回的应答信号
 * 函数参数:无
 * 函数返回值:
 *					0:接收到的应答信号
 *                  1:接收到的非应答信号
 * */
unsigned char i2c_wait_ack(void)
{
	/*
	 * 主机发送一个字节之后,从机给主机返回一个应答信号
	 *
	 *                   -----------
	 * SCL              /   M:读    \
	 *     -------------             --------
	 *     --- ---- --------------------
	 * SDA    X    X
	 *     ---      --------------------
	 *     主  释   从机    主机
	 *     机  放   向数据  读数据线
	 *         总   线写    上的数据
	 *         线   数据
	 * */	
	//时钟线拉低,接收器可以发送信号
    I2C_SCL_L;
    I2C_SDA_H;//先把数据线拉高,当接收器回应应答信号时,数据线会拉低
    delay_us();
    SET_SDA_IN;//设置数据线为输入
    delay_us();//等待接收方向数据线写入
    delay_us();
    I2C_SCL_H;//用于读取数据线数据
    if(I2C_SDA_READ)//PF15得到一个高电平输入,收到非应答信号
        return 1;//应答信号
    I2C_SCL_L;//时钟线拉低,让数据线处于占用状态
    return 0;//非应答信号
} 
/*
 * 函数名: iic_ack
 * 函数功能: 主机作为接收器时,给发送器发送应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_ack(void)
{
	/*            --------
	 * SCL       /        \
	 *    -------          ------
	 *    ---
	 * SDA   X 
	 *    --- -------------
	 * */
	//保证数据线是输出
    SET_SDA_OUT;
    I2C_SCL_L;//拉低时钟线
    delay_us();
    I2C_SDA_L;//数据线拉低,表示应答信号
    delay_us();
    I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号
    delay_us();
    delay_us();
    I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据
}
/*
 * 函数名: iic_nack
 * 函数功能: 主机作为接收器时,给发送器发送非应答信号
 * 函数参数:无
 * 函数返回值:无
 * */
void i2c_nack(void)
{
	/*            --------
	 * SCL       /        \
	 *    -------          ------
	 *    --- ---------------
	 * SDA   X 
	 *    --- 
	 * */
	//保证数据线是输出
    SET_SDA_OUT;
    I2C_SCL_L;//拉低时钟线
    delay_us();
    I2C_SDA_H;//数据线拉高,表示非应答信号
    delay_us();
    I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号
    delay_us();
    delay_us();
    I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据	
}


si7006.c

#include "iic.h"
#include "si7006.h"
extern void delay(unsigned int ms);
/*
 * 函数名:si7006_init
 * 函数功能:SI7006芯片的初始化
 * 函数参数:无
 * 函数返回值:无
*/
void si7006_init(void)
{
	i2c_init();
	i2c_start();
	i2c_write_byte(SI7006_SLAVE << 1);
	i2c_wait_ack();
	i2c_write_byte(0xE6);
	i2c_wait_ack();
    //芯片初始化
	i2c_write_byte(0x3A);
	i2c_wait_ack();
	i2c_stop();

}
/*
 * 函数名:si7006_read_data
 * 函数功能:读取SI7006的转换结果
 * 函数参数:
 *     slave_addr : 从机地址
 *     reg_addr : 寄存器地址
 * 函数返回值:无
*/
short si7006_read_data(unsigned char slave_addr, 
		unsigned char reg_addr)
{
	short dat;
	unsigned char dat_h, dat_l;
	i2c_start();
    //写
	i2c_write_byte(slave_addr << 1);
	i2c_wait_ack();
	i2c_write_byte(reg_addr);
	i2c_wait_ack();
	i2c_start();
    //读
	i2c_write_byte((slave_addr << 1) | 1);
	i2c_wait_ack();
	delay(10);  // 等待转换结束
	dat_h = i2c_read_byte(0);//读取高八位数据,响应一个应答信号
	dat_l = i2c_read_byte(1);
	i2c_stop();
	dat = dat_h;
	dat <<= 8;
	dat |= dat_l;

	return dat;
}

iic.h

#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
#include "gpio.h"
/* 通过程序模拟实现I2C总线的时序和协议
 * GPIOF ---> AHB4
 * I2C1_SCL ---> PF14
 * I2C1_SDA ---> PF15
 *
 * */

#define SET_SDA_OUT     do{GPIOF->MODER &= (~(0x3 << 30)); \
							GPIOF->MODER |= (0x1 << 30);}while(0)
#define SET_SDA_IN      do{GPIOF->MODER &= (~(0x3 << 30));}while(0)

#define I2C_SCL_H       do{GPIOF->BSRR |= (0x1 << 14);}while(0)
#define I2C_SCL_L       do{GPIOF->BRR |= (0x1 << 14);}while(0)

#define I2C_SDA_H       do{GPIOF->BSRR |= (0x1 << 15);}while(0)
#define I2C_SDA_L       do{GPIOF->BRR |= (0x1 << 15);}while(0)

#define I2C_SDA_READ    (GPIOF->IDR & (0x1 << 15))

void delay_us(void);
void i2c_init(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(unsigned char  dat);
unsigned char i2c_read_byte(unsigned char ack);
unsigned char i2c_wait_ack(void);       
void i2c_ack(void);
void i2c_nack(void);

#endif 

si7006.h

#ifndef __SI7006_H__
#define __SI7006_H__

#include "iic.h"
#define        SI7006_SLAVE      0x40

void si7006_init(void);

short si7006_read_data(unsigned char slave_addr, unsigned char reg_addr);


#endif //__SI7006_H__

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python笔记】requests模块基础总结

前言 菜某笔记总结&#xff0c;如有错误请指正。&#xff08;抱歉可能我用渗透的靶场做的功能演示&#xff0c;让单纯想看爬虫整理的朋友不好理解&#xff0c;主要看一下requests库的写法吧&#xff0c;关于sql靶场&#xff0c;文件上传靶场什么的都当做网站的名字吧&#xff…

YashanDB携手深智城集团联合发布智慧城市解决方案

近日&#xff0c;在YashanDB 2023年度发布会上&#xff0c;深圳计算科学研究院携手深圳市智慧城市科技发展集团有限公司&#xff08;简称“深智城集团”&#xff09;重磅推出基于崖山数据库YashanDB的智慧城市解决方案&#xff0c;该联合解决方案高效支撑了深圳市CIM平台的建设…

020 OpenCV 轮廓、外接圆、外接矩形

一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、原理 2.1 函数接口 OpenCV中的findContours函数用于检测图像中的轮廓。轮廓是图像中连续的点集&#xff0c;它们通常表示物体的边缘或形状。在计算机视觉和图像处理中&#xff0c;…

PyCharm控制台堆栈乱码问题解决

目录 1、问题描述2、问题原因3、问题解决 1、问题描述 PyCharm环境都已经配置成了UTF-8编码&#xff0c;控制台打印中文也不会出现乱码&#xff0c;但报错堆栈信息中如果有中文会出现中文乱码&#xff1a; 这种该怎么解决呢&#xff1f; 2、问题原因 未将PyCharm编码环境与项目…

大数据机器学习与深度学习—— 生成对抗网络(GAN)

GAN概述 在讲GAN之前&#xff0c;先讲一个小趣事&#xff0c;你知道GAN是怎么被发明的吗&#xff1f;据Ian Goodfellow自己说&#xff1a; 之前他一直在研究生成模型&#xff0c;可能是一时兴起&#xff0c;有一天他在酒吧喝酒时&#xff0c;在酒吧里跟朋友讨论起生成模型。然…

Mapreduce小试牛刀(1)

1.与hdfs一样&#xff0c;mapreduce基于hadoop框架&#xff0c;所以我们首先要启动hadoop服务器 --------------------------------------------------------------------------------------------------------------------------------- 2.修改hadoop-env.sh位置JAVA_HOME配…

Android codec2 视频框架之编码输出内存管理

文章目录 pool的创建pool 中申请内存buffer 从service传递到clientC2buffer转换为MediaCodecBuffer编码 输出C2buffer的生命周期 buffer在框架中的流动流程&#xff0c;从buffer的申请、填充数据到binder中传递、转换为应用层数据、从应用层释放。 围绕以下的方面&#xff1a;…

(开源)2023工训大赛智能垃圾分类项目(可循环播放视频,显示垃圾分类信息,拍照识别,垃圾分类,满载报警,压缩)

省赛:由于这个比赛是两年一届&#xff0c;并未做足充分的准备&#xff0c;但是通过一定的单片机基础&#xff0c;加上速成能力&#xff0c;也就是熬夜学&#xff0c;通过疯狂的网络搜索&#xff0c;在省赛第5 入选国赛 下面来简单介绍一下我们作品&#xff1a; 主控&#xff1…

搜维尔科技:第九届元宇宙数字人设计大赛校园行讲演活动正式启动—中国戏曲学院站!

由全国高等院校计算机基础教育研究会指导&#xff0c;利亚德集团和爱迪斯通科技发起的数字人设计大赛正在火热进行中&#xff0c;同时进行的元宇宙数字人设计大赛校园行活动也正式拉开序幕&#xff0c;12月13日校园行活动—中国戏曲学院开讲。划重点&#xff1a;此次大赛已成为…

SSL证书过期怎么更新?

一、概述 SSL证书是用于加密网站和客户端之间通信的一种数字证书&#xff0c;可以确保数据传输的安全性和保密性。然而&#xff0c;SSL证书是有有效期的&#xff0c;一旦过期就需要及时更新。本文将介绍如何更新SSL证书&#xff0c;以确保网站的安全性和正常运行。 二、SSL证…

小程序开发实战案例四 | 小程序标题栏如何设置

上一期我们了解了 小程序底部导航栏 的实现效果&#xff0c;今天一起来了解下如何设置小程序标题栏&#xff5e; 基础标题栏 小程序标题栏主要包含返回、标题、收藏、菜单、收起 5 个模块&#xff0c;其中能够调整的部分只有标题和背景色。 另外 IDE上无法展示收藏按钮&#…

智慧路灯杆如何实现雪天道路安全监测

随着北方区域连续发生暴雪、寒潮、大风等气象变化&#xff0c;北方多地产生暴雪和低温雨雪冰冻灾害风险&#xff0c;冬季雨雪天气深度影响人们出行生活&#xff0c;也持续增加道路交通风险。 智慧路灯杆是现代城市不可或缺的智能基础设施&#xff0c;凭借搭载智慧照明、环境监测…

深入解析Freemarker模板引擎及其在Spring Boot中的高级整合

目录 引言1. Freemarker1.1.什么是Freemarker1.2 Freemarker模板组成部分1.3.优点 2. Spring Boot整合Freemarker2.1 配置2.2 数据类型 3. 案例总结 引言 Freemarker作为一款强大的模板引擎&#xff0c;与Spring Boot的整合能够极大地提升Web应用的开发效率和灵活性。本篇博客…

Ubuntu22.04_修改用户名_添加用户_修改电脑名

概要&#xff1a; 本篇所讲述的操作都是在图形化界面中进行。点击顶部栏右侧&#xff0c;展开系统菜单&#xff0c;打开设置 一、修改自己的用户名 1、修改之前查看信息 cat /etc/passwd 2、修改 输入完成&#xff0c;回车即可 3、修改之后查看信息 cat /etc/passwd 4、解…

一分钟解决:vscode卡在“设置SSH主机:VS Code-正在本地下载 VS Code 服务器”

问题&#xff1a;vscode之前可正常使用&#xff0c;更新之后&#xff0c;连接服务器卡住了。 解决&#xff1a;从CMD或者你的终端连接服务器&#xff0c;进入vscode-server目录下&#xff0c;删除一些文件夹就行&#xff0c;然后使用vscode重新链接&#xff0c;它会自动下载新…

Linux访问MySQL数据库(包含实验案例)

1、访问MySQL数据库。 1.1、登录到MySQL服务器 经过安装后的初始化过程&#xff0c;MySQL数据库的默认管理员用户名为"root"&#xff0c;密码为空。 [rootyang ~]# mysql -u root //"-u"选项用于指定认证用户有密码的情况下&#xff0c;使用"-p&qu…

用23种设计模式打造一个cocos creator的游戏框架----(十五)策略模式

1、模式标准 模式名称&#xff1a;策略模式 模式分类&#xff1a;行为型 模式意图&#xff1a;定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化 结构图&#xff1a; 适用于&#xff1…

【期末复习向】常见的激活函数

激活函数是非线性的函数&#xff0c;使用它的原因就是因为线性函数无论叠加多少层&#xff0c;最终带来的变化都是线性的组合&#xff0c;一般也只能用于线性分类&#xff0c;如经典的多层感知机。但是如果加上非线性的变换&#xff0c;根据通用近似定理&#xff0c;就可使得神…

持续集成交付CICD:Jenkins使用GitLab共享库实现自动上传前后端项目Nexus制品

目录 一、实验 1.GitLab本地导入前后端项目 2.Jenkins新建前后端项目流水线 3.Sonarqube录入质量阈与质量配置 4.修改GitLab共享库代码 5.Jenkins手动构建前后端项目流水线 6.Nexus查看制品上传情况 7.优化代码获取RELEASE分支 8.优化Jenkins流水线项目名称 一、实验 …

Linux环境下maven的安装

到官网下载maven 步入下面的地址选择合适的maven版本 https://dlcdn.apache.org/maven/ 以笔者为例&#xff0c;选择了3.5.4这个版本 将maven上传到Linux服务器并解压 tar -zxvf apache-maven-3.5.4-bin.tar.gz配置环境变量 我们使用vim编辑profile vim /etc/profile环境…