STM32单片机实战开发笔记-I2C通讯总线【wulianjishu666】

嵌入式单片机开发实战例程合集:

链接:https://pan.baidu.com/s/11av8rV45dtHO0EHf8e_Q0Q?pwd=28ab
提取码:28ab

I2C模块测试

  1. 功能描述

I2C总线接口连接微控制器和串行I2C总线。它提供多主机功能,控制所有I2C总线特定的时序,协议,仲裁和定时。支持标准和快速两种模式,同时与SMBus 2.0兼容.

  1. 主要特性
  1. 并行总线/I2C总线协议转换器
  2. 多主机功能:同一接口即可做主设备也可做从设备
  3. I2C主设备功能
  • 产生时钟
  • 产生起始和停止信号
  1. I2C从设备功能
  • 可编程的I2C地址检测
  • 可响应2个从地址的双地址能力
  • 停止位检测
  1. 产生和检测7位/10位地址和广播呼叫
  2. 支持不同的通讯速度
  • 标准速度(高至100KHZ)
  • 快速(高至400KHZ)
  1. 状态标志
  • 发送器/接收器模式标志
  • 字节发送结束标志
  • I2C总线忙标志
  1. 错误标志
  • 主模式时的时钟丢失
  • 地址/数据传输后的应答(ACK)错误
  • 检测到起始和停止错位
  • 禁止拉长时钟功能后的上溢或下溢
  1. 2个中断向量
  • 1个中断用于地址/数据通讯成功
  • 1个中断用于出错
  1. 可选的拉长时钟功能
  2. 具单字节缓冲器的DMA
  1. 通信过程

主模式时,I2C接口启动数据传输并产生时钟信号。串行数据传输总是以起始条件开始和停止条件结束。主模式时,由软件控制产生起始条件和停止条件。

从模式时,I2C接口能识别它自己的地址(7位或10位)和广播呼叫地址。软件控制开启或禁止广播呼叫地址的识别。

数据和地址按8位/字节进行传输,高位在前。跟在起始条件后面的第一,二个字节是地址(7位模式为1个字节,10位模式为2个字节)。地址只在主模式发送。

在一个字节传输的8个时钟后的第9个时钟期间,接收器必须回送一个应答位(ACK)给发生器。

  1. EEPROM

CAT24WC16是CATALYST公司生产的串行电可擦除的可编程存储器。其内部共有128页,每一页为16字节,每一字节为8位。CAT24WC16以一个字节为一个存储单元,共有2K个存储单元。因此任一存储单元的地址为11位(A0~A11),地址范围为0x00~0x7FF(2K地址范围)。

CAT24WC16的特性如下:

  1. 1.8~6.0V工作电压范围。
  2. 存储容量为16KB.
  3. 16字节页写缓冲器。
  4. 与400KHZ的I2C总线兼容。
  5. 符合双向数据传输协议。
  6. 数据保存时间长达100年,具有硬件写保护和软件数据保护功能
  7. 自动定时擦写周期

引脚说明:

引脚名称

功能

功能描述

VCC GND

电源,地

为芯片提供3.3V电源

A0 A1 A2

地址选择

在串行总线结构中,最多可以连接8个CAT24WC16芯片,则用A0,A1,A2设置地址以示区别 A0 A1 A2 悬空为0

WP

写保护

此引脚接地允许写操作,接VCC被禁止

SCL

时钟线

串行时钟输入

SDA

数据线

双向串行数据输入/输出

5、硬件电路

  1. 软件代码

/********************************************************************

* 说明 :通过I2C总线实现对EEPROM的读写操作

/*******************************************************************

本实验使用CAT24WC16:

        CAT24WC16是CATALSYT公司生产的串行电可擦除的可编程存储器。其内部共有128页,每一页

为16字节,每一个字节8位。CAT24WC16以一个字节为一个存储单元,共有2K个存储单元。因此任一

存储单位地址为11位(A0~A11),地址范围为0x00~0x7FF(2K地址范围)。

*******************************************************************/

#include"stm32f10x_lib.h"

#include"IIC.h"

#define EEPROM_ADDRESS      0xA0

#define      I2C2_SLAVE_ADDRESS7  0xA0

#define I2C_Speed      200000

#define I2C_PageSize  16

void I2C_Configuration(void)

{

        GPIO_InitTypeDef      GPIO_InitStructure;

        I2C_InitTypeDef I2C_InitStructure;

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);

       RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

        GPIO_Init(GPIOB,&GPIO_InitStructure);

        /*  I2C Configuration */

        I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;      //设置I2C为I2C模式

        I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;    //I2C快速模式

        I2C_InitStructure.I2C_OwnAddress1 = I2C2_SLAVE_ADDRESS7;

        I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;      //使能应答

        I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

        I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;

        /*   I2C Peripheral Enable*/

        I2C_Cmd(I2C2,ENABLE);

        I2C_Init(I2C2,&I2C_InitStructure);

}

void I2C2_Init(void)

{

        I2C_Configuration();  

}

void I2C_ByteWrite(u8 *pBuffer,u8 WriteAddr)

{      

        I2C_WaitEepromStandbyState();                                                

        /* [1]Send Start Condition  发送起始信号*/

        I2C_GenerateSTART(I2C2,ENABLE);

        /* [2]Test On EV5 and clear it  起始信号已发送并清除该事件 */

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

        /* [3]Send EEPROM address for write  发送器件地址*/

        I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);

        /* [4]Test on Ev6 and clear it 地址发送结束 */

while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        /* [5]Send EEPROM's internal address to  write 发送器件内部写入地址 */

        I2C_SendData(I2C2,WriteAddr);

        /* [6]Test on EV8 _1 and clear it 移位寄存器空 */

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        /* [7]Send the byte to be writeen 发送数据*/

        I2C_SendData(I2C2,*pBuffer);

        /* [8]Test on EV8 and clear it 发送缓冲区空*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        /* [9]Send STOP condition 发送停止信号 */

        I2C_GenerateSTOP(I2C2,ENABLE);

}

void I2C_PageWrite(u8 *pBuffer,u8 WriteAddr,u8 NumByteToWrite)

{

        I2C_WaitEepromStandbyState();

        /*[1]Send START condition 发送起始条件*/

        I2C_GenerateSTART(I2C2,ENABLE);

        /*[2]Test on EV5 and clear it 起始信号发送是否成功*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

        /*[3]Send EEPROM address for write 发送器件地址*/

        I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);

        /*[4]Test on EV6 and clear it  发送器件地址是否成功*/

while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        /*[5]Send EEPROM'S internal address to write to 发送数据的写入首地址*/

        I2C_SendData(I2C2,WriteAddr);

                

        /*[6]Test on EV8 and clear it  发送内部地址是否成功*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        /*[7]Send data to Written 发送数据*/

          while(NumByteToWrite--)

           {

                       /*Send the current byte 发送当前一个字节*/

                       I2C_SendData(I2C2,*pBuffer);

                        /* Point to the next byte to be written 地址++*/

                          pBuffer++;

                         /*Test on EV8 and clear it 发送缓冲区是否为空*/                                     while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

          }

        /*[8]Send STOP condition 发送停止信号*/

        I2C_GenerateSTOP(I2C2,ENABLE);

}

 void I2C_BufferWrite(u8 *pBuffer,u8 WriteAddr,u16 NumByteToWrite)

 {

        u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;

       Addr = WriteAddr % I2C_PageSize;

       count = I2C_PageSize - Addr;

       NumOfPage =  NumByteToWrite / I2C_PageSize;

       NumOfSingle = NumByteToWrite % I2C_PageSize;

        I2C_WaitEepromStandbyState();

  /* If WriteAddr is I2C_PageSize aligned  */

  if(Addr == 0)

  {

    /* If NumByteToWrite < I2C_PageSize */

    if(NumOfPage == 0)

    {

      I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);

      I2C_WaitEepromStandbyState();

    }

    /* If NumByteToWrite > I2C_PageSize */

    else 

    {

      while(NumOfPage--)

      {

        I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);

    I2C_WaitEepromStandbyState();

        WriteAddr +=  I2C_PageSize;

        pBuffer += I2C_PageSize;

      }

      if(NumOfSingle!=0)

      {

        I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);

        I2C_WaitEepromStandbyState();

      }

    }

  }

  /* If WriteAddr is not I2C_PageSize aligned  */

  else

  {

    /* If NumByteToWrite < I2C_PageSize */

    if(NumOfPage== 0)

    {

      I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);

      I2C_WaitEepromStandbyState();

    }

    /* If NumByteToWrite > I2C_PageSize */

    else

    {

      NumByteToWrite -= count;

      NumOfPage =  NumByteToWrite / I2C_PageSize;

      NumOfSingle = NumByteToWrite % I2C_PageSize;     

     

      if(count != 0)

      { 

        I2C_PageWrite(pBuffer, WriteAddr, count);

        I2C_WaitEepromStandbyState();

        WriteAddr += count;

        pBuffer += count;

      }

     

      while(NumOfPage--)

      {

        I2C_PageWrite(pBuffer, WriteAddr, I2C_PageSize);

        I2C_WaitEepromStandbyState();

        WriteAddr +=  I2C_PageSize;

        pBuffer += I2C_PageSize; 

      }

      if(NumOfSingle != 0)

      {

        I2C_PageWrite(pBuffer, WriteAddr, NumOfSingle);

        I2C_WaitEepromStandbyState();

      }

    }

  }         

 }

void I2C_WaitEepromStandbyState(void)

{

        vu16 SR1_Tmp = 0;

  do

  {

    /* Send START condition */

    I2C_GenerateSTART(I2C2, ENABLE);

    /* Read I2C1 SR1 register */

    SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);

    /* Send EEPROM address for write */

    I2C_Send7bitAddress(I2C2, EEPROM_ADDRESS, I2C_Direction_Transmitter);

  }while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));

 

  /* Clear AF flag */

  I2C_ClearFlag(I2C2, I2C_FLAG_AF);      

}

void I2C_BufferRead(u8 *pBuffer,u8 ReadAddr,u16 NumByteToRead)

{

        I2C_WaitEepromStandbyState();

        /*Send START Condition 发送起始信号*/

        I2C_GenerateSTART(I2C2,ENABLE);

        /*Test on EV5 and clear it 检测起始信号是否发送成功*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

        /* In the case of a singel data transfer disable ACK before readint the data*/

        if(NumByteToRead==1)

        {

                 I2C_AcknowledgeConfig(I2C2,DISABLE);//如果NumByteToRead则不需1字节一应答

        }

        /*Send EEPROM ADDRESS for write */

        I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Transmitter);

        /* Test on EV6 and clear it*/

while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

        /* Enable I2C*/

        I2C_Cmd(I2C2,ENABLE);

        /* Send EEPROM'S internal address to write to*/

        I2C_SendData(I2C2,ReadAddr);

        /*Test on EV8 and clear it*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

        /*Send START condition again*/

        I2C_GenerateSTART(I2C2,ENABLE);

        /*Test on EV5 and clear it*/

        while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT));

        /*Send EEPROM address for read*/

        I2C_Send7bitAddress(I2C2,EEPROM_ADDRESS,I2C_Direction_Receiver);

        /*Test on EV6 and clear it*/

while(!I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));

    /*Read Data*/

        while(NumByteToRead)

        {

                 /*Test on EV7 and clear it*/

                 if(I2C_CheckEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED))

                 {

                         if(NumByteToRead == 2)                             

                         {

                                  /*Disable Acknowledgement*/

                                  I2C_AcknowledgeConfig(I2C2,DISABLE);   //一般在最后一个字节关闭应答

                         }

                         if(NumByteToRead == 1)

                         {

                                  /*Send STOP condition */  //最后一位要关闭应答,发送停止信号

                                  I2C_GenerateSTOP(I2C2,ENABLE);

                         }

                         /*Read a byte from the EEPROM*/

                         *pBuffer = I2C_ReceiveData(I2C2);

                         /*Point to the next location where the byte read will be saved*/

                         pBuffer++;

                         /*Decrement the read bytes counter*/

                         NumByteToRead--;

                 }

        }

        /*Enable Acknowledgement to be ready for anotherreception*/

   I2C_AcknowledgeConfig(I2C2,ENABLE);                //允许再次应答           

}

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

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

相关文章

QCC3071/QCC3081/QCC3083/QCC3084/QCC5171/QCC5181/QCC3091/QCC3095平台LDAC解码

QCC3071/QCC3081/QCC3083/QCC3084/QCC5171/QCC5181/QCC3091/QCC3095平台LDAC解码 LDAC Decoder Evaluation Kit for QCC5181 and QCC5171 (The 5181 Kit) 随着Qualcomm DSP向下开放&#xff0c;QCC3071/QCC3081/QCC3083/QCC3084目前可以可以实现LDAC Decoder。 QCC3071/QCC3…

MATLAB 多项式

MATLAB 多项式 MATLAB将多项式表示为行向量&#xff0c;其中包含按幂次降序排列的系数。例如&#xff0c;方程P(x) X 4 7 3 - 5 9可以表示为 p [1 7 0 -5 9]; 求值多项式 polyval函数用于求一个特定值的多项式。例如&#xff0c;在 x 4 时&#xff0c;计算我们之前的多项式…

运行时数据区-基础

运行时数据区-基础 为什么学习运行时数据区Java内存区域&#xff08;运行时数据区域&#xff09;和内存模型&#xff08;JMM&#xff09; 区别组成部分&#xff08;jdk1.7 / jdk1.8&#xff09;从线程隔离性分类与类加载的关系每个区域的功能参考文章 为什么学习运行时数据区 …

Amazon EKS创建S3数据存储卷

亚马逊相关文档 1、创建适用于 Amazon S3的IAM策略 创建存储桶amazoneks {"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": "s3express:CreateSession","Resource": &…

Java零基础入门到精通_Day 9

1.ArrayList 编程的时候如果要存储多个数据&#xff0c;使用长度固定的数组存储格式&#xff0c;不一定满足我们的需求&#xff0c;更适应不了变化的需求&#xff0c;那么&#xff0c;此时该如何选择呢? 集 合 集合类的特点:提供一种存储空间可变的存储模型&#xff0c;存储的…

2024年 Java 面试八股文——SpringBoot篇

目录 1. 什么是 Spring Boot&#xff1f; 2. 为什么要用SpringBoot 3. SpringBoot与SpringCloud 区别 4. Spring Boot 有哪些优点&#xff1f; 5. Spring Boot 的核心注解是哪个&#xff1f;它主要由哪几个注解组成的&#xff1f; 6. Spring Boot 支持哪些日志框架&#…

信息系统项目管理师0086:项目内外部运行环境(6项目管理概论—6.2项目基本要素—6.2.5项目内外部运行环境)

点击查看专栏目录 文章目录 6.2.5项目内外部运行环境1.组织过程资产2.组织内部的事业环境因素3.组织外部的事业环境因素6.2.5项目内外部运行环境 项目在内部和外部环境中存在和运作,这些环境对价值交付有不同程度的影响。内部和外部环境可能会影响规划和其他项目活动。这些影响…

《苍穹外卖》Day12部分知识点记录——数据统计-Excel报表

一、工作台 需求分析和设计 接口设计 今日数据接口订单管理接口菜品总览接口套餐总览接口订单搜索&#xff08;已完成&#xff09;各个状态的订单数量统计&#xff08;已完成&#xff09; 代码实现 今日数据接口 1. WorkspaceController 注意不要导错包了 package com.sk…

【Linux IO基础】缓冲区

概念 缓冲区的主要作用是提高效率 --- 提高使用者的效率&#xff0c;因为有缓冲区的存在&#xff0c;我们可以积累一部分再统一发送&#xff0c;提高发送的效率。 刷新方式 缓冲区因为能够暂存数据&#xff0c;必定要有一定的刷新方式&#xff1a; 一般策略&#xff1a; 无…

【JavaEE】线程的概念

文章目录 1、什么是线程2、进程和线程的区别3、多线程的概述4、在Java中实现多线程的方法1.继承Thread类2.实现Runnable接口3.使用匿名内部类来继承Thread类&#xff0c;实现run方法4.使用匿名内部类来实现Runnable接口&#xff0c;实现run方法5.使用 lambda表达式 1、什么是线…

ubuntu20中ros与anaconda的python版本冲突问题

系统环境 原本系统是ubuntu20 noetic&#xff0c;python都在/usr/bin中&#xff0c;一共是两个版本的python&#xff0c;一个是python3.8&#xff0c;另一个是python2.7。 问题发现 当安装anaconda后&#xff0c;并且将anaconda的bin目录加入到系统环境中时候&#xff0c;…

【微服务】——Docker 基础知识

这里写自定义目录标题 1.1 了解Docker1.1.1应用部署的环境问题1.1.2.Docker解决依赖兼容问题1.1.3.Docker解决操作系统环境差异1.1.4.小结 1.2.Docker和虚拟机的区别1.3.Docker架构1.3.1.镜像和容器1.3.2.DockerHub1.3.3.Docker架构1.3.4.小结 1.4.安装Docker——未实践 2.Dock…

【莫比乌斯变换-03】python实现圆对圆的变换

文章目录 一、说明二、python实现复平面的莫比乌斯变换三、线的变换四、画笑脸 一、说明 我们在前面的文章中&#xff0c;叙述了莫比乌斯变换的复数分析&#xff0c;以及种种几何属性&#xff0c;本篇中叙述如何程序地实现&#xff1a;复平面上的圆在莫比乌斯变换下的图像是另…

【ONE·基础算法 || 回溯和剪枝(暴搜/深搜)】

总言 主要内容&#xff1a;编程题举例&#xff0c;熟悉理解回溯剪枝类题型&#xff08;如何画决策树&#xff0c;如何使用深搜进行递归&#xff0c;如何运用剪枝&#xff0c;如何在一维数组/二维数组中使用&#xff09;。 文章目录 总言1、回溯和剪枝2、全排列&#xff08;med…

【机器学习】BK- SDM与LCM的融合策略在文本到图像生成中的应用

突破边缘设备限制&#xff1a;BK-SDM与LCM的融合策略在文本到图像生成中的应用 一、引言二、稳定扩散算法的挑战与现状三、BK-SDM与LCM的融合策略利用高质量图像-文本对进行训练为LCM量身定制高级蒸馏过程 四、结论与展望 一、引言 随着人工智能技术的飞速发展&#xff0c;文本…

数据结构(十)----图

目录 一.图的概念 1.图的定义 2.图的类别 3.图的性质 4.几种特殊形态的图 二.图的存储结构 1.邻接矩阵&#xff08;顺序存储&#xff09; 2.邻接表&#xff08;顺序链式存储&#xff09; 3.十字链表 4.邻接多重表 四.图的遍历 1.广度优先遍历&#xff08;BFS&#…

Mysql复习笔记: 基础概念(待补充)

一. 基础概念 通用概念: 网络连接必须得分配给一个线程去进行处理&#xff0c;由一个线程来监听请求以及读取请求数据&#xff0c;比如从网络连接中读取和解析出来一条我们的系统发送过去的SQL语句 在数据库中&#xff0c;哪怕执行一条SQL语句&#xff0c;其实也可以是一个独立…

Python | Leetcode Python题解之第59题螺旋矩阵II

题目&#xff1a; 题解&#xff1a; class Solution:def generateMatrix(self, n: int) -> List[List[int]]:matrix [[0] * n for _ in range(n)]num 1left, right, top, bottom 0, n - 1, 0, n - 1while left < right and top < bottom:for col in range(left, r…

pandas学习笔记11

DataFrame结构 DataFrame 一个表格型的数据结构&#xff0c;既有行标签&#xff08;index&#xff09;&#xff0c;又有列标签&#xff08;columns&#xff09;&#xff0c;它也被称异构数据表&#xff0c;所谓异构&#xff0c;指的是表格中每列的数据类型可以不同&#xff0c;…

python中type,object,class 三者关系

type,object,class 三者关系 在python中&#xff0c;所有类的创建关系遵循&#xff1a; type -> int -> 1 type -> class -> obj例如&#xff1a; a 1 b "abc" print(type(1)) # <class int> 返回对象的类型 print(type(int)) …