【ARM】Day9 cortex-A7核I2C实验(采集温湿度)

 1. 2、编写IIC协议,采集温湿度值

iic.h

#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
#include "led.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      0x40void si7006_init(void);
short si7006_read_data(unsigned char slave_addr, unsigned char reg_addr);#endif //__SI7006_H__

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     \*          --------* */	SET_SDA_OUT;  	//1.设置数据线为输出模式I2C_SCL_H; 		//2.SCL为高电平delay_us(); 	I2C_SDA_H; 		//3.SDA为高电平delay_us();I2C_SDA_L; 		//4.SDA拉低I2C_SCL_L; 		//5.SCL拉低,起始信号产生之后,总线处于占用状态
}/** 函数名:i2c_stop* 函数功能:模拟i2c停止信号的时序* 函数参数:无* 函数返回值:无* */void i2c_stop(void)
{/** 停止信号 : 时钟在高电平期间,数据线从低到高的变化 *             ----------* SCL        /*    --------*    ---         -------* SDA   X       /*    --- -------* */SET_SDA_OUT;  	//1.设置数据线为输出模式I2C_SCL_L; 		//2.设置SCL为低电平delay_us();I2C_SDA_L; 		//3.设置SDA为低电平delay_us();I2C_SCL_H; 		//4.SCL拉高I2C_SDA_H; 		//5.SDA拉高
}/** 函数名: i2c_write_byte* 函数功能:主机向i2c总线上的从设备写8bits数据* 函数参数:dat : 等待发送的字节数据* 函数返回值: 无* */void i2c_write_byte(unsigned char dat)
{/** 数据信号:时钟在低电平期间,发送器向数据线上写入数据* 			时钟在高电平期间,接收器从数据线上读取数据 *      ----          --------* 	SCL     \        /        \*           --------          --------*      -------- ------------------ ---* 	SDA         X                  X*      -------- ------------------ ---**      先发送高位在发送低位 * */SET_SDA_OUT;  	//1.设置数据线为输出模式//2. for循环, 条件, 实现SCL先发高位,再发低位for(int i=0;i<8;i++){I2C_SCL_L; 		//2.时钟线拉低,可以向数据线上写入数据delay_us();if(dat & 0x80)  //  先发高位,再发低位I2C_SDA_H; 	//3.向数据线上写入高电平elseI2C_SDA_L; 	//4.向数据线上写入低电平delay_us();I2C_SCL_H; 		//5.等待从机从数据线上读取数据delay_us();delay_us();dat <<= 1;  	//6.先发高位,数据左移}
}/** 函数名:i2c_read_byte* 函数功能: 主机从i2c总线上的从设备读8bits数据, *          主机发送一个应答或者非应答信号* 函数参数: 0 : 应答信号   1 : 非应答信号* 函数返回值:读到的有效数据** */
unsigned char i2c_read_byte(unsigned char ack)
{/** 数据信号:时钟在低电平期间,发送器向数据线上写入数据* 			时钟在高电平期间,接收器从数据线上读取数据 *      ----          --------* 	SCL     \        /        \*           --------          --------*      -------- ------------------ ---* 	SDA         X                  X*      -------- ------------------ ---**      先接收高位, 在接收低位 *      ACK=0,应答信号*      ACK=1,非应答信号* */unsigned int dat;SET_SDA_IN;  		//1.设置数据线为输入模式for(int i=0;i<8;i++){I2C_SCL_L; 		//2.保证发送器,向数据线上写入数据完成delay_us();delay_us();I2C_SCL_H; 		//3.时钟线为高电平时,从数据线上读取数据delay_us();dat <<= 1; 		//4.移位if(I2C_SDA_READ)dat |= 1;  	//5.读取数据为1else dat |= 0; 	//6.读取为0delay_us();}if(!ack)i2c_ack();  //7.应答信号elsei2c_nack(); //8.非应答信号return dat;
}/** 函数名: i2c_wait_ack* 函数功能: 主机作为发送器时,等待接收器返回的应答信号* 函数参数:无* 函数返回值:*					0:接收到的应答信号*                  1:接收到的非应答信号* */
unsigned char i2c_wait_ack(void)
{/** 主机发送一个字节之后,从机给主机返回一个应答信号*t                   -----------* SCL              /   M:读    \*     -------------             --------*     --- ---- --------------------* SDA    X    X*     ---      --------------------*     主  释   从机    主机*     机  放   向数据  读数据线*         总   线写    上的数据*         线   数据* */	I2C_SCL_L; 		//1.时钟线为低电平delay_us();I2C_SDA_H;		//2.数据线为高电平,释放总线delay_us();SET_SDA_IN;		//3.设置数据线为输入模式delay_us();I2C_SCL_H;		//4.时钟为高电平期间delay_us();if(I2C_SDA_READ)//5.从数据线上读取数据return 1; 	//6.读1,非应答信号I2C_SCL_L; 		//时钟线为低电平,总线处于占用状态return 0;  		//读0,应答信号	
} /** 函数名: iic_ack* 函数功能: 主机作为接收器时,给发送器发送应答信号* 函数参数:无* 函数返回值:无* */
void i2c_ack(void)
{/*            --------* SCL       /        \*    -------          ------*    ---* SDA   X *    --- -------------* */SET_SDA_OUT;  	//1.设置数据线为输出模式I2C_SCL_L;		//2.时钟线为低电平时,改变数据线上的数据delay_us(); I2C_SDA_L; 		//3.应答信号 ===> 0delay_us();I2C_SCL_H; 		//4.等待从机读取应答信号delay_us();delay_us();I2C_SCL_L; 		//5.总线处于占用状态
}/** 函数名: iic_nack* 函数功能: 主机作为接收器时,给发送器发送非应答信号* 函数参数:无* 函数返回值:无* */
void i2c_nack(void)
{/*            --------* SCL       /        \*    -------          ------*    --- ---------------* SDA   X *    --- * */SET_SDA_OUT;  	//1.设置数据线为输出模式I2C_SCL_L;		//2.时钟线为低电平时,改变数据线上的数据delay_us(); I2C_SDA_H; 		//3.非应答信号 ===> 0delay_us();I2C_SCL_H; 		//4.等待从机读取应答信号delay_us();delay_us();I2C_SCL_L; 		//5.总线处于占用状态	
}

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 | 0);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;short dat1,dat2;i2c_start();		//起始信号i2c_write_byte(slave_addr<<1 | 0);//从机地址+写i2c_wait_ack();		//acki2c_write_byte(reg_addr);	//命令码i2c_wait_ack();i2c_start();		//起始信号i2c_write_byte(slave_addr<<1 | 1);//从机地址+读i2c_wait_ack();delay_ms(100);	//测量时间dat1 = i2c_read_byte(0);dat2 = i2c_read_byte(1);  //NACKi2c_stop();//停止信号dat = (dat1 << 8) | dat2;	return dat;
}

main.c

#include "iic.h"
#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++);
}#define Measure_RH_cmd   0xE5   //测量湿度cmd
#define Measure_Temp_cmd 0xE3   //测量温度cmdint main()
{short temp;unsigned short hum;si7006_init();while(1){	hum = si7006_read_data(SI7006_SLAVE , Measure_RH_cmd);	//测量湿度hum = (125*hum)/65536 - 6;printf("hum = %d\n",hum);delay_ms(1000);temp = si7006_read_data(SI7006_SLAVE , Measure_Temp_cmd);  //测量温度temp = (175.72*temp)/65536 - 46.85;printf("temp = %d\n",temp);delay_ms(1000);}return 0;
}

运行结果:

2.思维导图

 

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

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

相关文章

Baidu World 2023,定了!

1. 定了&#xff0c;Baidu World 2023 终于定了&#xff0c;今年的 Baidu World 将会于 2023-10-17 日在北京首钢园正式召开&#xff0c;主题为『生成未来 / PROMPT THE WORLD』&#xff0c;这也是近4年来 Baidu World 再次恢复线下举行。 有些小伙伴们如果还不知道什么是 Baid…

tda4 videnc-test-app: CONTINUOUS and STEPWISE FRAMEINTERVALS not supported

/* videnc-test-app */ https://git.ti.com/cgit/jacinto7_multimedia/ git clone https://git.ti.com/git/jacinto7_multimedia/videnc-test-app.git // 编译 ./autogen.sh ./configure --enable-maintainer-mode --buildi386-linux --hostaarch64-none-linux CC/home/share…

GMS基本模块TIN、Solids、Modflow2000/2005、MT3DMS、MODPATH。及其在地下水流动、溶质运移、粒子追踪方面的应用

解决地下水数值模拟技术实施过程中遇到的困难&#xff0c;从而提出切实可行的环境保护措施&#xff0c;达到有效保护环境、防治地下水污染&#xff0c;推动经济社会可持续发展的目的。 &#xff08;1&#xff09;水文地质学&#xff0c;地下水数值模拟基础理论&#xff1b;&am…

Kotlin 中的 协程 基础篇

一、什么叫协程 协程可以称为轻量级线程&#xff0c;线程代码块&#xff1b; 二、GlobalScope 协程 CoroutineScope (协程作用域) 的上下文中通过 launch、async 等构造器来启动。GlobalScope ,即全局作用域内启动了一个新的协程&#xff0c;这意味这该协程的生命周期只受整…

CSDN编程题-每日一练(2023-08-23)

CSDN编程题-每日一练(2023-08-23) 一、题目名称:圆小艺二、题目名称:连续子数组的最大和三、题目名称:投篮一、题目名称:圆小艺 时间限制:1000ms内存限制:256M 题目描述: 最近小艺酱渐渐变成了一个圆滑的形状-球!! 小艺酱开始变得喜欢上球! 小艺酱得到n个同心圆。 …

构建智慧停车场:4G DTU实现无线数据高速传输

物联网技术的快速发展使得各种设备能够实现互联互通&#xff0c;无线网络技术给我们的日常生活带来了极大的便利。其中的网络技术如无线WiFi及4G网络已经成为了物联网应用中不可或缺的组成部分。而在工业领域中对4G无线路由器的应用是非常广泛的&#xff0c;人们通过4G工业路由…

意外发现Cortex-M内核带的64bit时间戳,比32bit的DWT时钟周期计数器更方便,再也不用担心溢出问题了

视频&#xff1a; https://www.bilibili.com/video/BV1Bw411D7F5 意外发现Cortex-M内核带的64bit时间戳&#xff0c;比32bit的DWT时钟周期计数器更方便&#xff0c;再也不用担心溢出问题了 介绍&#xff1a; 看参数手册的Debug章节&#xff0c;System ROM Table里面带Timestam…

【Java】基础练习(十)

1.判断邮箱 输入一个电子邮箱&#xff0c;判断是否是正确电子邮箱地址。 正确的邮箱地址&#xff1a; 必须包含 字符&#xff0c;不能是开头或结尾必须以 .com结尾和.com之间必须有其他字符 (1) Email类&#xff1a; package swp.kaifamiao.codes.Java.d0823; /** 输入一个…

Android——基本控件下(十七)

1. 文本切换&#xff1a;TextSwitcher 1.1 知识点 &#xff08;1&#xff09;理解TextSwitcher和ViewFactory的使用。 1.2 具体内容 范例&#xff1a;切换显示当前时间 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools&…

docker安装redis

docker安装redis 一、基本介绍二、前期准备三、docker安装redis3.1 redis镜像拉取3.2 Docker挂载redis配置文件3.3 启动redis容器3.4 验证Redis容器是否正常运行 四、Docker删除Redis容器五、Docker删除Redis镜像 一、基本介绍 Docker 是一个开源的应用容器引擎,参考链接&…

探索最短路径问题:寻找优化路线的算法解决方案

1. 前言&#xff1a;最短路径问题的背景与重要性 在现实生活中&#xff0c;我们常常面临需要找到最短路径的情况&#xff0c;如地图导航、网络路由等。最短路径问题是一个关键的优化问题&#xff0c;涉及在图中寻找两个顶点之间的最短路径&#xff0c;以便在有限时间或资源内找…

时间复杂度与空间复杂度

时间复杂度 时间复杂度是衡量算法运行速度的指标。 常数阶 O(1) 不论算法代码有多少行&#xff0c;只要其中没有循环、递归&#xff0c;按前文所介绍计算方法&#xff0c;其时间复杂度都是Ο(1)。 func calculate(_ num1: Int, _ num2: Int) -> Int {let sum num1 num…

AUTOSAR规范与ECU软件开发(实践篇)5.5 基于ISOLAR-A的系统级设计与配置方法(上)

目录 前言 1 系统配置输入文件创建与导入 2、 Composition SWC建立 前言 如前所述, AUTOSAR支持整车级别的软件架构设计, 开发人员可以进行整车级别的软件组件定义, 再将这些软件组件分配到各个ECU中, 这就是AUTOSAR系统级设计需要完成的主要任务。 下面结合AUTOSAR方法论…

【管理运筹学】第 5 章 | 整数规划 (2,割平面法及 0-1 变量的特性)

文章目录 引言三、割平面法四、0-1 型整数规划4.1 0-1 变量的特性4.1.1 投资问题4.1.2 约束条件满足个数问题 写在最后 引言 前文我们介绍了整数规划的一种求解方法——分支定界法&#xff0c;可以求解纯整数和混合整数规划问题。现在我们来学习另一种整数规划求解方法——割平…

Java 中使用 ES 高级客户端库 RestHighLevelClient 清理百万级规模历史数据

&#x1f389;工作中遇到这样一个需求场景&#xff1a;由于ES数据库中历史数据过多&#xff0c;占用太多的磁盘空间&#xff0c;需要定期地进行清理&#xff0c;在一定程度上可以释放磁盘空间&#xff0c;减轻磁盘空间压力。 &#x1f388;在经过调研之后发现&#xff0c;某服务…

[Ubuntu 20.04 PC] 安装C-Kermit:一个开源串口通信软件

在计算机科学领域,串口通信一直是非常重要的一环。而C-Kermit作为一款强大而灵活的开源串口通信软件,广泛应用于UNIX、Linux和Windows等操作系统中。本文将介绍C-Kermit的基本原理、特点以及如何使用它进行串口通信。 一、C-Kermit的基本原理 C-Kermit是由C语言实现的,旨在…

MyBatid动态语句且模糊查询

目录 什么是MyBtais动态语句&#xff1f;&#xff1f;&#xff1f; MyBatis常用的动态标签和表达式 if标签 Choose标签 where标签 MyBatis模糊查询 #与$的区别 ​编辑 MyBatis映射 resultType resultMap 什么是MyBtais动态语句&#xff1f;&#xff1f;&#xff1f;…

TensorFlow 介绍

TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google 开发。它支持多种机器学习和深度学习算法&#xff0c;包括神经网络、卷积神经网络、循环神经网络等。TensorFlow 利用数据流图的形式来表达计算&#xff0c;将输入数据和计算操作表示为节点&#xff0c;建立 TensorF…

2023-08-23力扣每日一题

链接&#xff1a; 1782. 统计点对的数目 题意&#xff1a; 给n个点和m条无向边&#xff08;可重复&#xff09;&#xff0c;q个查询 定义edge[a]为一个点是a的边数量&#xff0c;定义ret[a,b]是edge[a]edge[b]-&#xff08;a与b的边&#xff09; q个查询q个答案&#xff0…

视频转音频mp3怎么弄?

视频转音频mp3怎么弄&#xff1f;在很多人看来&#xff0c;音频就是视频中的一部分&#xff0c;其实这时是一定道理的&#xff0c;视频是一种包含图像和有声音的多媒体文件&#xff0c;没有声音的视频是不完美的。时代发展到现在&#xff0c;短视频已经融入了我们生活的方方面面…