STM32CubeMX学习笔记13 ---IIC总线

news2024/11/20 4:52:08

1、IIC 简介

        IIC(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 

在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。

PS: 这里要注意IIC是为了与低速设备通信而发明的,所以IIC的传输速率比不上SPI


IIC的物理层
IIC一共有只有两个总线: 一条是双向的数据线SDA,一条是串行时钟线SCL,所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每一个设备都对应一个唯一的地址。

关于IIC的讲解,已经单独整理了一篇文章:

《IIC原理超详细讲解---值得一看-CSDN博客》。
如果对IIC还不是太了解的朋友请移步到这篇文章中

IIC起始信号和终止信号:

起始信号:SCL保持高电平,SDA由高电平变为低电平后,延时(>4.7us),SCL变为低电平。
停止信号:SCL保持高电平。SDA由低电平变为高电平。


数据有效性
IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。

也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输

应答信号
每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,

应答信号:主机SCL拉高,读取从机SDA的电平,为低电平表示产生应答

应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。


每发送一个字节(8个bit)在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。

应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答,

 

1.2 AT24C02芯片介绍

AT24C02是一个2K位串行CMOS,内部含有256个字节,此芯片具有I2C通讯接口,芯片内保存的数据在掉电的情况下不丢失(EEPROM),常用于存放比较重要的数据。本实验使用的是SOP-8封装的AT24C02芯片,其引脚说明见下图

AT24C02芯片的器件地址为7位,高4位固定为1010,低3位有上表中的A0/A1/A2引脚的电平决定,还有一位(最低位R/W)用来选择读写方向。本实验中A0/A1/A2引脚接在GND上了,因此器件地址为1010000;加上最低位的读写方向位后,写器件地址为10100000(0xA0),读器件地址为10100001(0xA1)

下图为AT24C02的总线时序图和时间参数

2、硬件设计

LED2指示灯用来提示系统运行状态,s1按键用来控制24C02的数据写入,S2按键用来控制24C02的数据读取,数据的写入与读取信息通过串口1打印出来

  • LED2指示灯
  • S1和S2按键
  • USART1
  • AT24C02

 

3、STM32CubeMX设置

  • RCC设置外接HSE,时钟设置为72M
  • PE5设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
  • PE3,PE4设置为GPIO输入模式、上拉模式
  • 激活I2C2,选择标准传输模式,选择7位寻址地址,其余默认设置

  • 输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

 

 4、程序编程

  • 在i2c.c文件中可以看到IIC初始化函数。在stm32f1xx_hal_i2c.h头文件中可以看到I2C的操作函数。分别对应轮询,中断和DMA三种控制方式

  • 上面的函数看起来多,但是只是发送和接收的方式改变了,函数的参数和本质功能并没有改变
    比方说IIC发送函数 还是发送函数,只不过有普通发送,DMA传输,中断 的几种发送模式

        这里我们仅介绍下普通发送,其他的只是改下函数名即可 

IIC写函数(单个字节写入)

 HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

功能:IIC写一个字节数据
参数:

  • *hi2c 设置使用的是那个IIC 例:&hi2c2
  • DevAddress 写入的地址 设置写入数据的地址 例 0xA0
  • *pData 需要写入的数据
  • Size 要发送的字节数
  • Timeout 最大传输时间,超过传输时间将自动退出传输函数

 举例:

HAL_I2C_Master_Transmit(&hi2c1,0xA0,(uint8_t*)TxData,2,1000) ;//发送两个字节数据

IIC读函数(单个字节读取)

HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);


功能:IIC读一个字节数据
参数:

  • *hi2c: 设置使用的是那个IIC 例:&hi2c2
  • DevAddress: 写入的地址 设置写入数据的地址 例 0xA0
  • *pDat:a 存储读取到的数据
  • Size: 发送的字节数
  • Timeout: 最大读取时间,超过时间将自动退出读取函数

举例:

HAL_I2C_Master_Receive(&hi2c1,0xA1,(uint8_t*)TxData,2,1000) ;//读取两个字节数据

IIC写数据函数(多字节写入)


HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/* 第1个参数为I2C操作句柄
   第2个参数为从机设备地址
   第3个参数为从机寄存器地址
   第4个参数为从机寄存器地址长度
   第5个参数为发送的数据的起始地址
   第6个参数为传输数据的大小
   第7个参数为操作超时时间   */

 

功能: IIC写多个数据 该函数适用于IIC外设里面还有子地址寄存器的设备,比方说E2PROM,除了设备地址,每个存储字节都有其对应的地址

参数:

  • *hi2c: I2C设备号指针,设置使用的是那个IIC 例:&hi2c2
  • DevAddress: 从设备地址 从设备的IIC地址 例E2PROM的设备地址 0xA0
  • MemAddress: 从机寄存器地址 ,每写入一个字节数据,地址就会自动+1
  • MemAddSize: 从机寄存器地址字节长度 8位或16位

写入数据的字节类型 8位还是16位
I2C_MEMADD_SIZE_8BIT
I2C_MEMADD_SIZE_16BIT
在stm32f1xx_hal_i2c.h中有定义

  • *pData: 需要写入的的数据的起始地址
  • Size: 传输数据的大小 多少个字节
  • Timeout: 最大读取时间,超过时间将自动退出函数

使用HAL_I2C_Mem_Write等于先使用HAL_I2C_Master_Transmit传输第一个寄存器地址,再用HAL_I2C_Master_Transmit传输写入第一个寄存器的数据。可以传输多个数据

在传输过程,寄存器地址和源数据地址是会自加的。

至于读函数也是如此,因此用HAL_I2C_Mem_Write和HAL_I2C_Mem_Read,来写读指定设备的指定寄存器数据是十分方便的,让设计过程省了好多步骤。

举例:

8位:

HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);

HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000);

16位:

HAL_I2C_Mem_Write(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);

HAL_I2C_Mem_Read(&hi2c2, ADDR, i, I2C_MEMADD_SIZE_16BIT,&(I2C_Buffer_Write[i]),8, 1000);
  • 添加key.h和key.c文件,具体可看STM32CubeMX学习笔记2-按键检测_uint8_t key_scan(uint8_t mode)-CSDN博客
  • 添加AT24C02驱动文件24cxx.c和24cxx.h
#ifndef __24cxx_h__
#define  __24cxx_h__


#include "usart.h"

//AT24C02 写地址和读地址
#define ADDR_24CXX_WRITE 0XA0
#define ADDR_24CXX_READ  0XA1


void AT24CXX_Init(void);
uint8_t AT24CXX_Check(void);

#endif
#include "24cxx.h"
#include "i2c.h"



void AT24CXX_Init(void){
	
    MX_I2C2_Init(); //IIC初始化
	
    while(AT24CXX_Check()){  //检测AT24C02
        printf1("AT24C02 Checked Failed!\r\n");
        HAL_Delay(500);
    }
    printf1("AT24C02 Checked Sucessed!\r\n");
}

//该函数仅做AT24C02的检测,检测AT24C02是否正常使用。
uint8_t AT24CXX_Check(void){
    uint8_t temp;
	
    HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);                
    if(temp==0x36)  
        return 0;          
    else{
        uint8_t data = 0x36;
        HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,255,I2C_MEMADD_SIZE_8BIT,&data,1,0xff);
        HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,255,I2C_MEMADD_SIZE_8BIT,&temp,1,0xff);   
        if(temp==0x36)  
            return 0;
    }
    return 1;                                             
}

注意事项:

AT24C02的IIC每次写之后要延时一段时间才能继续写 每次写之后要delay 5ms左右 不管硬件IIC采用何种形式(DMA,IT),都要确保两次写入的间隔大于5ms;
读写函数最后一个超时调整为1000以上 因为我们一次写8个字节,延时要久一点
AT24C02页写入只支持8个byte,所以需要分32次写入。这不是HAL库的bug,而是AT24C02的限制,其他的EEPROM可以支持更多byte的写入。

  • 在main.c文件下编写IIC测试代码
AT24C02的2Kbit分为32页,每页8个字节。而EEPROM也可以按页写入,本例使用了按页写入的方式,分32次写入。注意每次写入完毕需要延时5ms,是AT24C02芯片的要求;读取数据没有页的限制,可以一次全部读取256个字节
/* USER CODE BEGIN PV */
#define ADDR_24CXX_WRITE 0XA0
#define ADDR_24CXX_READ  0XA1
uint8_t WriteBuf[256];
uint8_t ReadBuf[256];
uint16_t i,j;
/* USER CODE END PV */
void SystemClock_Config(void);
int main(void){

///***省略***///
  /* USER CODE BEGIN 2 */
  AT24CXX_Init();//检测AT24C02是否存在
  printf1("\r\n*********STM32CubeMX I2C AT24C02 Example*********\r\n");
  for(i = 0;i < 256; i++){   //初始化写数据缓冲区
    WriteBuf[i] = i;
  }
  /* USER CODE END 2 */
  while (1){
		char key=KEY_Scan(0);
		  if(key == 1){
        for(j = 0;j < 32;j++){  //按页写入EEPROM,分32次写入,因为24c02每次只能写8个数据。
					//通过hi2c2(IIC2)往从机(ADDR_24CXX_WRITE)的8位(I2C_MEMADD_SIZE_8BIT)寄存器(8*j)中写入WriteBuf+8*j的8个数据,超时0xff
            if(HAL_I2C_Mem_Write(&hi2c2,ADDR_24CXX_WRITE,8*j,I2C_MEMADD_SIZE_8BIT,WriteBuf+8*j,8,0xFF) == HAL_OK){
                printf1("\r\nEEPROM 24C02 Write Test OK!\r\n");
                HAL_Delay(5);//每次写入需间隔5ms
            }
            else{
                printf1("\r\nEEPROM 24C02 Write Test False!\r\n");
                HAL_Delay(5);                   
            }
        }
    }

    if(key == 2){   //EEPROM读取没有页限制,可以一次读取256个字节
			//通过hi2c2(IIC2)往从机(ADDR_24CXX_READ)的8位(I2C_MEMADD_SIZE_8BIT)寄存器(0)中读出256个数据并存放在ReadBuf中,超时0xff
        HAL_I2C_Mem_Read(&hi2c2,ADDR_24CXX_READ,0,I2C_MEMADD_SIZE_8BIT,ReadBuf,256,0xFF);
        for(i=0;i<256;i++){
            printf1("0x%02X ",ReadBuf[i]);
        }

        if(memcmp(WriteBuf,ReadBuf,256) == 0){  //通过内存比较,判断读取和写入的数据是否相同
            printf1("\r\nEEPROM 24C02 Read Test OK!\r\n");
        }
        else{
            printf1("\r\nEEPROM 24C02 Read Test False!\r\n");
        }
    }

    HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
    HAL_Delay(500);
  }
}

5、下载验证

编译无误下载到开发板后,可以看到LED2指示灯不断闪烁,当按下S1按键后数据写入到24C02芯片内,当按下S2按键后读取24C02芯片的值,同时串口打印出相应信息

 6、参考文献

【STM32】HAL库 STM32CubeMX教程十二---IIC(读取AT24C02 )_hal iic-CSDN博客

 STM32CubeMX系列 | I2C总线 - 知乎 (zhihu.com) 

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

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

相关文章

《汇编语言》- 读书笔记 - 第17章-实验17 编写包含多个功能子程序的中断例程

《汇编语言》- 读书笔记 - 第17章-实验17 编写包含多个功能子程序的中断例程 逻辑扇区根据逻辑扇区号算出物理编号中断例程&#xff1a;通过逻辑扇区号对软盘进行读写 代码安装 int 7ch 测试程序效果 实现通过逻辑扇区号对软盘进行读写 逻辑扇区 计算公式: 逻辑扇区号 (面号*8…

【PCIe 链路训练】之均衡(equalization)

1、概述 这篇文章简单介绍一下PCIE phy的均衡原理和过程,USB phy,ethernet phy这些高速的串行serdes也有相同或者相似的结构。可以不用太关注其中的细节,等到debug的时候可以查询协议,但是需要了解这个故事讲的大概内容。整个equalization过程是controller和phy一起配合完成…

喜报|炼石免改造数据安全入选上海网安产业创新大会优秀案例

近日&#xff0c;上海网络安全产业创新大会隆重召开&#xff0c;上海普陀区委副书记、区长肖文高&#xff0c;上海市经济和信息化委员会总工程师葛东波出席并致辞&#xff0c;普陀区副区长肖立出席。大会以“产业赋能、生态打造”为主题&#xff0c;为发掘数据安全领域的优秀产…

【代码随想录算法训练营Day29】 491.递增子序列;46.全排列;47.全排列 II

文章目录 ❇️Day 29 第七章 回溯算法 part05✴️今日内容❇️491.递增子序列自己的思路随想录思路自己的代码 ❇️46.全排列思路代码流程 ❇️47.全排列 II思路代码 ❇️Day 29 第七章 回溯算法 part05 ✴️今日内容 491.递增子序列46.全排列47.全排列 II ❇️491.递增子序…

低压MOS在步进电机驱动器上的应用-REASUNOS瑞森半导体

一、前言 步进电机驱动器是一种用于控制步进电机运动的装置&#xff0c;它是将控制信号转换成步进电机可以识别的控制电压或电流的电路。它在工业自动化领域有着广泛的应用&#xff0c;如机器人、印刷机、木工机床、喷绘机等。步进电机驱动器的组成结构主要由以下部分&#xf…

《C缺陷和陷阱》-笔记

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 文章目录 前言 一、理解函数声明 1.(*(void(*)( ))0)( ); 2.signal 函数接受两个参数&#xff1a; 3.使用typedef 简化函数声明&#xff1a; 二、运算符的优先级…

面试经典150题【61-70】

文章目录 面试经典150题【61-70】61.旋转链表86.分隔链表104. 二叉树的最大深度100.相同的树226.翻转二叉树101.对称二叉树105.从前序与中序遍历序列构造二叉树106.从后序和中序遍历序列构造二叉树117.填充每个节点的下一个右侧节点指针II114.二叉树展开为链表 面试经典150题【…

修复 因 fstab 中UUID 错误导致系统无法正常工作的问题

操作系统&#xff1a; PVE 8.0 /debian 12 &#xff08;bookworm&#xff09; 问题症状&#xff1a;可以正常启动进入系统&#xff0c;但是系统盘以只读方式挂载 问题原因&#xff1a;/etc/fstab 中引导区的UUID 被错误修改导致 解决方法&#xff1a; 重启系统&#xff0c;在…

QT:用opencv的KNN识别图片中的LED数字(一)

前言 一款功能测试的软件demo,使用了QT作为界面,主要使用了opencv的KNN识别,使用gstreamer作为管道,用来打开图片。后期会写一篇打开摄像头实时识别的文章。 (正在写,未完成,稍候) 效果一预览: 效果二预览: 效果三预览: 正在写。。。 设计思路 1. 软件UI设…

吴恩达深度学习笔记:深度学习引言1.1-1.5

目录 第一门课&#xff1a;神经网络和深度学习 (Neural Networks and Deep Learning)第一周&#xff1a;深度学习引言(Introduction to Deep Learning)1.1 欢迎(Welcome)1.2 什么是神经网络&#xff1f;(What is a Neural Network)1.3 神经网络的监督学习(Supervised Learning …

【C++】C++模板基础知识篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化…

Trans论文复现:考虑源荷不平衡性的微电网鲁棒定价方法程序代码!

适用平台&#xff1a;MatlabYalmipCplex/Gurobi 程序针对目前微电网中高比例新能源发电的波动性和间歇性&#xff0c;提出了考虑源荷不平衡特性的微电网鲁棒定价方法&#xff0c;综合考虑电力市场边际收益和边际成本&#xff0c;利用价格波动来平衡电源和负荷。程序算例丰富、注…

腾讯云轻量 2核2G4M新用户首购活动,99续费同价来了!!

阿里云199一年续费同价&#xff0c;腾讯云99一年续费同价&#xff0c;平台卷起来&#xff0c;对用户的角度来说&#xff0c;真的是香麻了~ 腾讯云新春采购节&#xff0c;2核2G4兆的基础配置&#xff0c;新官方直接放大招&#xff0c;99一年&#xff0c;活动期间内&#xff0c;…

EXSI create datastore

文章目录 1. 简介2. 清空磁盘3. 删除表4. 创建database 1. 简介 在 ESXi 环境中创建数据存储(Datastore)的步骤如下: 登录 vSphere Web Client 打开 Web 浏览器,输入 ESXi 主机或 vCenter Server 的 IP 地址,使用有权限的账户登录。 在 ESXi 环境中创建数据存储(Datastore)…

二、TensorFlow结构分析(4)

TF数据流图图与TensorBoard会话张量Tensor变量OP高级API 目录 1、变量 2、高级API 1、变量 2、高级API

【Kafka系列 07】Kafka 如何保证消息不丢失

一、Kafka 消息不丢失的边界 一直以来&#xff0c;很多人对于 Kafka 丢失消息这件事情都有着自己的理解&#xff0c;因而也就有着自己的解决之道。在讨论具体的应对方法之前&#xff0c;我觉得我们首先要明确&#xff0c;在 Kafka 的世界里什么才算是消息丢失&#xff0c;或者…

华为云开年采购季Web及移动App上云体验,助力软件行业创新发展

随着云化、智能化浪潮的进一步深入&#xff0c;越来越多的应用软件开发商选择将核心产品从本地IDC机房搬迁到公有云上。但同时&#xff0c;软件开发商们也非常在意公有云厂商的可靠性与安全性&#xff0c;希望能够选择一家更加稳定可靠的云服务商&#xff0c;确保自身业务的连续…

02极简LLM逻辑与PyTorch快速入门

文章目录 02极简LLM逻辑与PyTorch快速入门极简LLM逻辑PyTorch环境安装&#xff08;重要&#xff0c;不难&#xff09;PyTorch 主要概念Tensors张量张量常见的形式&#xff1a;scalar、vector、matrix、n-dimensinal张量初始化张量参数&#xff1a;shape、datatype、device张量运…

从huggingface下载模型像本地加载但是UnicodeDecodeError

我自己是在Linux下出现了这个问题 原文&#xff1a;https://github.com/huggingface/transformers/issues/13674 The path for the AutoModel should be to a directory pointing to a pytorch_model.bin and to a config.json. Since you’re pointing to the .bin file dire…

论文笔记:Efficient Bootstrapping for Confidential Transactions

EcoBoost: Efficient Bootstrapping for Confidential Transactions 设计了一种被称为EcoBoost的新方法&#xff0c;以提高支持机密交易的区块链的引导效率。具体来说&#xff0c;利用随机抽样来验证高概率保密交易的正确性。因此&#xff0c;与事务数量相比**&#xff0c;验证…