【嵌入式学习】ARM day04.17

server/2024/9/20 7:27:56/ 标签: 学习, arm开发, 单片机

一、主要逻辑

写入数据:

  • 主机发送起始信号
  • 主机发送8bit从机地址+1bit写标志(0)
  • 从机回应应答信号
  • 主机发送8bit从机的寄存器地址
  • 从机回应应答信号
  • 主机发送8bit数据
  • 从机回应应答
  • 主机发送8bit数据
  • 从机回应应答
  • 主机发起终止信号

读取数据:

  • 主机发起起始信号
  • 主机发送7bit从机地址+1bit写标志
  • 从机回应应答信号
  • 主机发起一个重复的起始信号
  • 主机发送7bit从机地址+1bit读标志
  • 从机回应应答信号
  • 从机发送8bit数据
  • 主机回应应答信号
  • 从机发送8bit数据
  • 主机回应非应答信号
  • 主机发起终止信号

二、实现温湿度传感器代码

main.c

#include "si7006.h"int main(){//si7006初始化i2c_init();si7006_init();unsigned short hum;short tem;while(1){//读取温度和湿度hum=si7006_read_hum();tem=si7006_read_tem();//计算温湿度数据hum=(hum*125)/65536-6;tem=(tem*175.72)/65536-46.85;printf("hum:%d\n",hum);printf("tem:%d\n",tem);delay_ms(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     \*          --------* */   //确保SDA是输出状态 PF15输出SET_SDA_OUT;// 空闲状态SDA和SCL拉高 I2C_SCL_H;I2C_SDA_H;delay_us();//延时等待一段时间I2C_SDA_L;//数据线拉低delay_us();//延时等待一段时间I2C_SCL_L;//时钟线拉低,让总线处于占用状态
}/** 函数名:i2c_stop* 函数功能:模拟i2c停止信号的时序* 函数参数:无* 函数返回值:无* */void i2c_stop(void)
{/** 停止信号 : 时钟在高电平期间,数据线从低到高的变化 *             ----------* SCL        /*    --------*    ---         -------* SDA   X       /*    --- -------* *///确保SDA是输出状态 PF15输出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->10000000if(dat&0X80)//最高位为1{//发送1I2C_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;//数值左移 一定要先左移在赋值,不然数据会溢出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;//数据线处于占用状态,发送器发送下一次数据
}

iic.h

#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.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 delay(int ms);
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.c

#include "si7006.h"//手动封装延时函数
void delay_ms(int ms)
{int i,j;for(i=0;i<ms;i++){for(j=0;j<2000;j++){} }
}void si7006_init()
{//1.发起起始信号i2c_start();//2.发送7bit从机地址和写标志位   0X80i2c_write_byte(0x80);//3.等待从机应答if(i2c_wait_ack()!=0){return;}//4.发送寄存器地址 0XE6i2c_write_byte(0xE6);//5.等待从机应答if(i2c_wait_ack()!=0){return;}//6.向从机发送数据  0X3Ai2c_write_byte(0x3A);//7.等待从机应答if(i2c_wait_ack()!=0){return;}//8.发送终止信号i2c_stop();
}unsigned short si7006_read_hum()
{unsigned char hum_l,hum_h;unsigned short hum;//1.主机发起起始信号i2c_start();//2.发送7bit从机地址和写标志位   0X80i2c_write_byte(0x80);//3.等待从机应答if(i2c_wait_ack()!=0){return 0;}//4.发送寄存器地址 0XE5 //湿度寄存器i2c_write_byte(0xE5);//5.等待从机应答if(i2c_wait_ack()!=0){return 0;}//6.主机发起重复起始信号i2c_start();//7.主机发送7bit从机地址+1bit 读  0X81i2c_write_byte(0x81);//8.等待从机应答if(i2c_wait_ack()!=0){return 0;}//9.延时等待从机测量数据delay_ms(10);//10.读取湿度的高8bit数据  hum_h// 11.发送应答信号hum_h= i2c_read_byte(0);// 12.读取湿度的低8位数据  hum_l//  13.发送非应答信号hum_l= i2c_read_byte(1);//   14.发起终止信号i2c_stop();//   15.将读取到的数据的低8位和高8bit合成一个完整的数据hum=hum_h<<8|hum_l;return hum;
}short si7006_read_tem()
{char tem_l,tem_h;short tem;//1.主机发起起始信号i2c_start();//2.发送7bit从机地址和写标志位   0X80i2c_write_byte(0x80);//3.等待从机应答if(i2c_wait_ack()!=0){return 0;}//4.发送寄存器地址 0XE3 //温度寄存器i2c_write_byte(0xE3);//5.等待从机应答if(i2c_wait_ack()!=0){return 0;}//6.主机发起重复起始信号i2c_start();//7.主机发送7bit从机地址+1bit 读  0X81i2c_write_byte(0x81);//8.等待从机应答if(i2c_wait_ack()!=0){return 0;}//9.延时等待从机测量数据delay_ms(10);//10.读取湿度的高8bit数据  hum_h// 11.发送应答信号tem_h= i2c_read_byte(0);// 12.读取湿度的低8位数据  hum_l//  13.发送非应答信号tem_l= i2c_read_byte(1);//   14.发起终止信号i2c_stop();//   15.将读取到的数据的低8位和高8bit合成一个完整的数据tem=tem_h<<8|tem_l;return tem;
}

si7006.h

#ifndef __SI7006_H__
#define  __SI7006_H__#include "iic.h"
void delay_ms(int ms);
void si7006_init();
unsigned short si7006_read_hum();
short si7006_read_tem();#endif

 

 


http://www.ppmy.cn/server/6750.html

相关文章

原生实现ajax

1 什么是ajax AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网…

数码摄影色彩构成,数码相机色彩管理

一、资料描述 本套摄影色彩资料&#xff0c;大小58.54M&#xff0c;共有6个文件。 二、资料目录 《抽象彩色摄影集》.阿瑟.pdf 《色彩构成》.pdf 《色彩学》.星云.扫描版.pdf 《摄影色彩构成》.pdf 《数码相机色彩管理》.pdf 数码摄影进阶之4《色彩篇》.pdf 三、资料下…

大坝安全监测GNSS接收机:保障水库安全

大坝安全一直是社会关注的焦点之一。为了及时监测大坝的变形和位移情况&#xff0c;以预防可能发生的危险事故&#xff0c;GNSS接收机成为了不可或缺的仪器之一。本文将详细介绍GNSS接收机在大坝安全监测中的应用及其重要性。 一、GNSS接收机是什么 GNSS全球导航卫星系统&…

Gradle 进阶学习之 文件操作

1、本地文件 在 Gradle 中&#xff0c;Project.file(java.lang.Object) 方法是一个非常有用的工具&#xff0c;它允许你以一种类型安全的方式引用文件。这个方法可以接收一个字符串路径&#xff0c;返回一个 File 对象&#xff0c;这个对象代表的是一个相对于当前项目目录&…

生成对抗网络GAN的扩展应用理解

注&#xff1a;本文仅个人学习理解&#xff0c;如需详细内容请看原论文&#xff01; 一、cycleGAN 1.整体架构&#xff1a; 将图片A通过生成器生成图片B&#xff0c;然后通过判别器判别图片B的真假&#xff1b;并且图片B通过另一个生成器生成A‘&#xff0c;让A和A’近似。 2…

小红书电商运营实战课,从0打造全程实操(65节视频课)

课程内容&#xff1a; 1.小红书的电商介绍 .mp4 2.小红书的开店流程,mp4 3.小红书店铺基础设置介绍 ,mp4 4.小红书店铺产品上架流程 .mp4 5.客服的聊天过程和子账号建立 .mp4 6.店铺营销工具使用和后台活动参加 .mp4 7.小红书产品上架以及拍单教程,mp4 8.小红书如何选品…

自定义类似微信效果Preference

1. 为自定义Preference 添加背景&#xff1a;custom_preference_background.xml <?xml version"1.0" encoding"utf-8"?> <selector xmlns:android"http://schemas.android.com/apk/res/android"><item><shape android:s…

TCP/IP协议—HTTP

TCP/IP协议—HTTP HTTP协议HTTP通讯特点HTTP通讯流程 HTTP请求报文请求方法 HTTP应答报文状态码 HTTP协议 超文本传输协议&#xff08;Hypertext Transfer Protocol&#xff0c;HTTP&#xff09;是一种请求-响应的协议&#xff0c;用户可以通过HTTP向服务器上传、下载数据。HT…

04—常用方法和正则表达式

一、字符串 1.length 属性返回字符串的长度(字符数)。 2.在字符串中查找字符串 indexOf() 字符串使用 indexOf() 来定位字符串中某一个指定的字符首次出现的位置 如果没找到对应的字符函数返回-1 lastIndexOf() 方法在字符串末尾开始查找字符串出现的位置。 3.replace() 方…

C#创建磁性窗体的方法:创建特殊窗体

目录 一、磁性窗体 二、磁性窗体的实现方法 (1)无标题窗体的移动 (2)Left属性 (3)Top属性 二、设计一个磁性窗体的实例 &#xff08;1&#xff09;资源管理器Resources.Designer.cs设计 &#xff08;2&#xff09;公共类Frm_Play.cs &#xff08;3&#xff09;主窗体 …

使用WebSocket实现答题积分排名实时更新的功能

需求分析 接到一个需求&#xff0c;是一个答题积分小程序&#xff0c;其中有一个功能需求是需要实时更新答题积分排名的。之前通常比较常见的需求&#xff0c;都是指定某个时间点才更新答题排行榜的数据的。 经过技术调研&#xff0c;要实现答题积分排名实时更新的功能&#…

docker 安装geoipupdate

前提是docker已安装 一&#xff1a;执行命令&#xff1a; docker run --env-file /usr/local/etc/GeoIP.conf -v /usr/local/GeoIP2:/usr/share/GeoIP ghcr.io/maxmind/geoipupdate /usr/local/etc/GeoIP.conf &#xff1a;本地配置的账号&#xff0c;秘钥 GEOIPUPDATE_AC…

k8s安装记录

k8s安装记录 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#xff01;&#xff01;&#xff01; 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#xff01;&#xff01;&#xff01; 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#…

iOS知识点---Runloop

iOS 中的 Runloop 机制是一种事件驱动模型&#xff0c;用于管理和调度线程上的事件&#xff0c;确保线程在有工作要做时保持活跃&#xff0c;无事可做时进入休眠状态以节省系统资源。以下是 Runloop 机制的关键组成部分及其工作原理&#xff1a; 关键组成部分与原理&#xff1…

4 种策略让 MySQL 和 Redis 数据保持一致

先阐明一下 MySQL 和 Redis 的关系&#xff1a;MySQL 是数据库&#xff0c;用来持久化数据&#xff0c;一定程度上保证数据的可靠性&#xff1b;Redis 是用来当缓存&#xff0c;用来提升数据访问的性能。 关于如何保证 MySQL 和 Redis 中的数据一致&#xff08;即缓存一致性问…

过拟合与欠拟合

过拟合与欠拟合 过拟合有较为明显的对比可以判断&#xff0c;但欠拟合却是不容易判断的。 训练集效果很好&#xff0c;测试集效果变差&#xff0c;在保证训练集与测试集样本分布一致的情况下&#xff0c;很容易得出过拟合的结论。 欠拟合不太容易通过这种直接的对比来判断。 …

深入解读:BIO、NIO与IO多路复用——理解现代网络编程基石

在现代软件开发中&#xff0c;高效的数据交换是构建高性能网络应用的核心要素。深入理解输入输出&#xff08;Input/Output,简称IO&#xff09;模型的底层原理与工作机制&#xff0c;对于设计和实现高并发、低延迟的网络服务至关重要。本文将深度剖析阻塞式I/O&#xff08;BIO&…

OpenHarmony轻量系统开发【5】驱动之GPIO点灯

5.1点灯例程源码 先看最简单得LED灯闪烁操作 源码结构如下&#xff1a; 第一个BUILD.gn文件内容&#xff1a; static_library("led_demo") {sources ["led_demo.c"]include_dirs ["//utils/native/lite/include","//kernel/liteos_m/c…

Oracle解析exp、imp及常见的问题

前言 在工作中经常需要不同数据库的导入和导出。exp和imp可以实现数据的迁移。 exo会转储产生对应的二进制文件,里面包括数据的定义信息、数据内容等,即为dump文件。 下面是使用exp和imp的一些场景 exp和imp主要有4中模式: 1)数据库模式 数据库模式也就是我们说的全备…

Windows 安装 A UDP/TCP Assistant 网络调试助手

Windows 安装 A UDP/TCP Assistant 网络调试助手 0. 引言1. 下载地址2. 安装和使用 0. 引言 需要调试一个实时在线聊天程序&#xff0c;安装一个UDP/TCP Assistant 网络调试助手&#xff0c;方便调试。 1. 下载地址 https://github.com/busyluo/NetAssistant/releases 2. 安…