1.14 IIC总线实验

news2025/1/17 0:25:57

一.IIC总线:

1.同步半双工串行总线,用于同一个开发板两个芯片之间的通信

2.有两根信号线,一根SDA,一根SCL

3.IIC总线需要外接两个上拉电阻,使空闲状态保持高电平

4.IIC总线支持多主机多从机模式,一般采用单主机多从机模式

5.每个从机都有自己的7位从机地址

6.主动发送数据的叫主机,被动接收数据的叫从机

7.发送数据的叫发送器,接收数据的叫接收器

8.时钟信号只能由主机产生

二.IIC总线时序

1.起始信号

 

2.停止信号

 

3.数据传输信号

 

4.应答和非应答信号

 8位数据位+1位应答位     在第九个时钟周期,接收器在SDA上写数据(应答或非应答),
发送器在SDA商都数据。高电平:非应答信号  低电平:应答信号

5.寻址

 7位从机地址+1位读写位         0--主机写   1---主机读

三.IIC协议

1.主机给从机发送一个字节

 

2.主机给从机发送多个字节

 

3.主机从从机接收一个字节

 

4.主机从从机接收多个字节

 四.分析SI7006芯片

(1)从机地址
(2)命令码
(3)数字量转模拟量
(4) 协议

五.代码

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);

//unsigned short si7006_read_hum_data(unsigned char slave_addr, unsigned char reg_addr);

#endif //__SI7006_H__

si7006.c (组协议)

#include "iic.h"
#include "si7006.h"
extern void delay_ms(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_temp_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_ms(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"



#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 

iic.c

#include "iic.h"

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

void delay_us(void)
{
	unsigned int i = 2000;
	while(i--);
}

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;
}


void i2c_start(void)
{

	//1.设置SDA为输出模式
	SET_SDA_OUT;
	//2.SCL拉高
	I2C_SCL_H;
	//3.延时函数
	delay_us();
	//4.SDA拉高
	I2C_SDA_H;
	//5.延时函数
	delay_us();
	//6.SDA拉低
	I2C_SDA_L;
	//7.scl拉低,起始信号产生之后,总线处于占用状态
	I2C_SCL_L;
}



void i2c_stop(void)
{

	SET_SDA_OUT;//1.设置SDA为输出模式
	I2C_SCL_L;//2.SCL拉低
	delay_us();
	I2C_SDA_L;//3.SDA拉低
	delay_us();
	I2C_SCL_H; //4.SCL拉高 
	delay_us();
	I2C_SDA_H; //5.SDA拉高 
	delay_us();
}



void i2c_write_byte(unsigned char dat)
{

	unsigned int i;
	SET_SDA_OUT;//1.设置SDA为输出模式
	for(i=0;i<8;i++) //2.for循环 一位一位进行发送
	{
		I2C_SCL_L; //3.scl拉低 
		delay_us();
		if(dat & 0x80) //4.先发送高位在发送低位
			I2C_SDA_H; //5.向数据线上写高电平
		else
			I2C_SDA_L;//6.向数据线上写低电平
		delay_us();
		I2C_SCL_H; //7.SCL拉高等待从机从数据线上读取数据
		delay_us();
		delay_us();	
		dat <<= 1;
	}
}


unsigned char i2c_read_byte(unsigned char ack)
{

	unsigned int i;
	unsigned char dat;
	SET_SDA_IN;//1.设置SDA为输入模式
	for(i=0;i<8;i++)
	{
		I2C_SCL_L;//2.等待从机向数据线上写入数据
		delay_us();
		delay_us();
		I2C_SCL_H; //3.SCL拉高
		delay_us();
		dat <<= 1; //备注:需要自己推算
		if(I2C_SDA_READ) //从数据线上读取数据
			dat |= 1; //4.向数据线上写入高电平
		else
			dat |= 0; //5.向数据线上写入低电平
		delay_us();
	}
	if(!ack)
		i2c_ack(); //6.主机给从机发送应答信号
	else
		i2c_nack(); //7.主机给从机发送非应答信号
	return dat;
}

unsigned char i2c_wait_ack(void)
{
   线   数据
	 * */	
	I2C_SCL_L;//1.SCL拉低
	delay_us();
	I2C_SDA_H;//2.主机需要释放总线
	delay_us();
	SET_SDA_IN;//3.变换总线方向
	delay_us();
	I2C_SCL_H;//4.SCL拉高
	delay_us(); //5.主机读取数据线上的数据
	if(I2C_SDA_READ)
		return 1; //6.发送器从总线上读取到非应答信号
	I2C_SCL_L; //7.总线处于占用状态
	return 0;//8.发送器从总线上读取到应答信号
} 

void i2c_ack(void)
{
 
	SET_SDA_OUT;//1.设置SDA为输出模式
	I2C_SCL_L;//2.SCL拉低
	delay_us();
	I2C_SDA_L;//3.SDA拉低,应答信号
	delay_us();
	I2C_SCL_H; //4.SCL拉高
	delay_us();
	delay_us();
	I2C_SCL_L; //5.SCL拉低,总线处于占用状态
}

void i2c_nack(void)
{
		
	SET_SDA_OUT;//1.设置SDA为输出模式
	I2C_SCL_L;//2.SCL拉低
	delay_us();
	I2C_SDA_H;//3.SDA拉高,非应答信号
	delay_us();
	I2C_SCL_H; //4.SCL拉高
	delay_us();
	delay_us();
	I2C_SCL_L; //5.SCL拉低,总线处于占用状态

}

main.c

#include "si7006.h"
extern void printf(const char *fmt, ...);
void delay_ms(int ms)
{
	int i,j;
	for(i = 0; i < ms;i++)
		for (j = 0; j < 1800; j++);
}

int main()
{
	short temp;
	unsigned short hum;
	si7006_init();
	while(1)
	{
		hum = si7006_read_data(SI7006_SLAVE,0xE5);
		temp = si7006_read_data(SI7006_SLAVE,0xE0);
		printf("hum = %d\n",125 * hum / 65536 - 6);
		printf("temp = %d\n",176 * temp / 65536 - 47);
	}
	return 0;
}


 

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

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

相关文章

STM32外部中断解析

文章目录前言一、外部中断是什么二、STM32F103的外部中断三、外部中断的中断号四、HAL库的外部中断初始化流程总结前言 本篇文章将带大家了解STM32F103的外部中断。 一、外部中断是什么 外部中断是单片机实时地处理外部事件的一种内部机制。当某种外部事件发生时&#xff0c…

数组名的意义

数组名只有单独放在sizeof内部以及放在&后才代表整个数组的地址。其余情况数组名都表示数组首元素地址。 之前我们说过用sizeof(a)计算的是整个数组的大小&#xff0c;现在我们知道其中的原因了。由于sizeof里的数组名a表示整个数组的地址&#xff0c;故sizeof(a)求的是整…

Android10以上系统Audio音频遇到播放无声时的分析方法

​商务合作 2023年招聘 2023年逆向分析资料汇总 推荐阅读 Android Audio音频系统 Android Audio音频系统之深入浅出 Android Framework/驱动/内核中高级工程师 ​Android10以上系统Audio音频遇到播放视频无声时的分析方法 干货|Android APP应用工程师转Framework工程师(…

51单片机存储结构

之前概要介绍了8151微控制器的结构&#xff08;也就是51单片机&#xff09;。相比微处理器&#xff0c;微控制器的区别之一是在一个芯片上有程序存储器(RAM)和数据存储器(RAM)。存储区是微控制器非常重要的内容。 本文就介绍一下8051的存储结构。包括存储器的组织、处理器对存储…

VTK-Tessellator Subdivision

前言&#xff1a;本博文主要研究Tessellator 的Subdivision&#xff0c;对vtk中的所有相关接口进行研究&#xff0c;并找出最优的解决方法。 GeometricObjects中vtkTessellatorFilter的应用实例 待研究对当前的Subdivision进行优化。 vtkTessellatorFilter 位置&#xff1a;…

Docker容器数据卷与数据卷容器

文章目录什么是容器数据卷使用数据卷使用 docker 安装 mysql匿名和具名挂载数据卷容器什么是容器数据卷 Docker理念回顾 将应用和运行的环境打包形成容器运行&#xff0c;运行可以伴随着容器&#xff0c;但是我们对于数据的要求&#xff0c;是希望能够 持久化的&#xff01; 就…

【寒假每日一题】DAY.6 有序序列的合并

牛客网例题&#xff1a;点我做题 描述 输入两个升序排列的序列&#xff0c;将两个序列合并为一个有序序列并输出。数据范围&#xff1a; 1 ≤ n&#xff0c;m ≤ 1000&#xff0c;序列中的值满足0≤val≤30000输入描述&#xff1a; 输入包含三行&#xff0c;第一行包含两个正整…

微信小程序开发起步

一、小程序与普通网页开发的区别 1&#xff09;运行环境不同。网页运行在浏览器环境中&#xff0c;小程序运行在微信环境中。 2&#xff09;API不同。由于运行环境不同&#xff0c;所以小程序中无法调用DOM和BOM的API&#xff0c;但是小程序可以调用微信环境提供的各种API&am…

zabbix的安装部署,一看就会

目录 1、系统组成 2、采集模式 3、监控类型 4、相关术语 5、安装部署 1、系统组成 2、采集模式 监控系统数据采集的工作模式可以分为 被动模式&#xff08;从服务器端到客户端采集数据&#xff0c;对应的英文单词是pull&#xff09; 主动模式 &#xff08;客户端主动上报…

java基于springboot的新生报到系统app新生报到安卓app新生入学报到小程序加论文

简介 本项目主要是新生报到系统&#xff0c;包含的新生入学流程的功能&#xff1a;新生可以在app里提交预报到日期确认报到&#xff0c;查看自己的学费缴费记录&#xff0c;更改自己的银行卡号&#xff0c;查看课表&#xff0c;查看寝室&#xff0c;查看自己的专业班级等个人信…

CubeMX配置:定时器中断及串口配置

本文通过CubeMX配置F103RCT6的定时器中断和串口。 文章目录1 引入2 配置过程2.1 配置时钟过程2.2 配置串口过程2.3 定时器中断配置3 生成工程代码4 测试串口及定时器中断周期5 总结1 引入 拿到一个STM32控制器&#xff0c;在啥也没有的情况下从零开始写软件&#xff0c;博主习…

Java K 个一组翻转链表

K 个一组翻转链表困难给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。你不能只是单纯的…

电视为何降价至200元依然没人买?爱奇艺给出了答案

近日爱奇艺提高降低会员的服务内容&#xff0c;消费者要享受到将内容投放到电视就要买更贵的会员服务&#xff0c;引发热议&#xff0c;此举或许能解释国内消费者为何如今不买电视了。2022年电视行业可谓是一个相当惨淡的行业&#xff0c;量价齐跌&#xff0c;随着2022年底的到…

计算机视觉OpenCv学习系列:第二部分、图像操作

第二部分、图像操作第一节、图像读取与显示1.图像理解2.图像读取与显示3.代码练习与测试第二节、图像色彩空间转换1.图像色彩空间2.函数说明与解释3.代码练习与测试第三节、图像对象的创建与赋值1.图像对象属性2.图像对象创建与赋值3.代码练习与测试第四节、图像像素的读写操作…

SpringBoot——关于controller参数校验

参数校验主要使用两个标签Validated和Valid&#xff1b; Valid是Hibernate的注解校验&#xff0c;Validated是spring的&#xff0c;是Valid的增强&#xff1b;这两个标签也有一些不同之处&#xff0c;Valid可以标注在成员属性上也可以嵌套校验&#xff0c;而Validated不行&…

Node.js 操作MySQL数据库

在讲Node.js中引入mysql模块之前先讲一下关于MySQL数据库&#xff0c;首先是关于MySQL数据库的安装和mysql服务以及对mysql命令和可视化工具的一个基本使用&#xff1b;那么在这里已经准备好了关于MySQL数据库的内容了&#xff1a; MySQL 数据库安装详细 &#xff1a; MySQL数…

redis主从复制,一主多仆启动流程

文章目录一、安装redis二、复制修改配置文件三、添加conf配置文件四、开启主从复制五、薪火相传六、反客为主7、哨兵模式一、安装redis redis安装笔记 https://blog.csdn.net/G_GUi/article/details/128361131 二、复制修改配置文件 把redis.conf复制到一个新建文件夹里面&a…

安卓手机还有这么多神仙玩法,关键只有少数人知道

随着“智能手机”的快速更新迭代&#xff0c;手机系统逐渐融入了许多实用功能&#xff1b;今年Android手机市场竞争相当激烈&#xff0c;各大手机品牌都争先恐后地向消费者展示自己的新机型。今天我就来给大家分享几个只有安卓手机才有的隐藏黑科技功能&#xff0c;每个功能都非…

cocos creator新手教程:第003节3D模型的基本概念

3.1 计算机如何制作一个3D模型 讲述这个问题之前&#xff0c;我们先来看下现实生活中我们要做一个模型&#xff0c;应该如何做呢&#xff1f;首先我们要把模型的形状给雕刻构建出来&#xff0c;现实生活中的物体都是由分子组成的连续的表面&#xff0c;计算机是离散的无法做到这…

【jQuery】常用API——尺寸、位置操作

一、jQuery 尺寸 以上参数为空&#xff0c;则是获取相应值&#xff0c;返回的是数字型。如果参数为数字&#xff0c;则是修改相应值。参数可以不必写单位。 <style>div {width: 200px;height: 200px;background-color: pink;padding: 10px;border: 15px solid red;margin…