I2C代码硬件实现

news2024/9/24 19:19:17

环境

芯片:STM32F103ZET6
库:来自HAL的STM32F1XX.H

原理图

 有图可知SCL和SDA两条线接到了PB10和PB11  芯片的复用功能是I2C2

代码

  • Driver_I2C.h

    • #include "Driver_I2C.h"
      
      void Driver_I2C_Init(void)
      {
          /* 1. 打开引脚和片上外设的时钟 I2C2 PB10 PB11 */
          RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
          RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
      
          /* 2. 配置引脚模式 PB10 复用开漏输出 1111   PB11  复用开漏输出 */
          GPIOB->CRH |= (GPIO_CRH_CNF10 | GPIO_CRH_CNF11 | GPIO_CRH_MODE10 | GPIO_CRH_MODE11);
      
          /* 3. 配置I2C的寄存器 */
          // 3.1 选择使用I2C模式 0   选择使用SMBUS模式 1
          I2C2->CR1 &= ~I2C_CR1_SMBUS;
      
          // 3.2 配置接入时钟频率
          I2C2->CR2 &= ~I2C_CR2_FREQ;
          I2C2->CR2 |= 36;
      
          // 3.3 选择I2C的速度模式 标准模式100K/S 0   快速模式 400K/S 1
          I2C2->CCR &= ~I2C_CCR_FS;
          I2C2->CCR &= ~I2C_CCR_CCR;
          // 3.4 选择分频系数  -> 计算方法    CCR *  1 / 设置的时钟频率(36) = 5   CCR = 180
          I2C2->CCR |= 180;
      
          // 3.5 设置上升沿时间周期  ->  等于标准模式中最大允许SCL上升时间为1us 对应的周期+1 = 36+1 = 37
          I2C2->TRISE &= ~I2C_TRISE_TRISE;
          I2C2->TRISE |= 37;
      
          // 3.2 打开I2C2总开关  ->  配置的最后打开
          I2C2->CR1 |= I2C_CR1_PE;
      }
      
      /* I2C的启动停止信号 使用寄存器标记不断发送  ->  SR1中SB被硬件置位为1 表示发送完成 */
      uint8_t Driver_I2C_Start(void)
      {
          // 1. 置位CR1 产生启动信号
          I2C2->CR1 |= I2C_CR1_START;
      
          // 2. 设置超时次数 0xffff
          uint16_t timeout = 0xffff;
          // 每次判断是否起始信号发送成功都记录一次
          // 超过timeout次数  认为发送起始信号失败
          while (timeout && ((I2C2->SR1 & I2C_SR1_SB) == 0))
          {
              timeout--;
          }
      
          return timeout > 0 ? OK : FAIL;
      }
      // 调用的时候注意  在当前收发完成之后 会自动发停止位
      void Driver_I2C_Stop(void)
      {
          // 置位CR1 stop
          I2C2->CR1 |= I2C_CR1_STOP;
      }
      
      void Driver_I2C_ACK(void)
      {
          I2C2->CR1 |= I2C_CR1_ACK;
      }
      void Driver_I2C_NACK(void)
      {
          I2C2->CR1 &= ~I2C_CR1_ACK;
      }
      
      /* 发送设备地址 */
      uint8_t Driver_I2C_SendADDR(uint8_t dev_addr)
      {
          // 发送设备地址的流程 在 启动信号之后紧接的位置  不会在次之前发数据
          I2C2->DR = dev_addr;
      
          // 等待发送完成  SR1 ADDR = 1
          uint16_t timeout = 0xffff;
          while (timeout && (I2C2->SR1 & I2C_SR1_ADDR) == 0)
          {
              timeout--;
          }
      
          // 重新置位ADDR地址发送成功位   给下一次发送地址做准备
          if (timeout > 0)
          {
              I2C2->SR2;
          }
      
          return timeout > 0 ? OK : FAIL;
      }
      
      /* 发送一个字节 向DR赋值*/
      uint8_t Driver_I2C_SendChar(uint8_t ch)
      {
          uint16_t timeout = 0xffff;
          // 1. 判断状态  当前是否空闲能发信的数据   TXE = 1
          while (timeout && (I2C2->SR1 & I2C_SR1_TXE) == 0)
          {
              timeout--;
          }
          if (timeout > 0)
          {
              // 2. 发送数据
              I2C2->DR = ch;
              timeout = 0xffff;
              // 3. 判断状态  第二步发送的数据完成啦    BTF = 1
              while (timeout && ((I2C2->SR1 & I2C_SR1_BTF) == 0))
              {
                  timeout--;
              }
          }
          return timeout > 0 ? OK : FAIL;
      }
      
      /* 读取一个字节 从DR读值*/
      uint8_t Driver_I2C_ReceiveChar(void)
      {
          // return 返回接收的数据
          uint16_t timeout = 0xffff;
          // 1. 判断状态RXNE = 1 说明有数据可以读
          while (timeout && ((I2C2->SR1 & I2C_SR1_RXNE) == 0))
          {
              timeout--;
          }
      
          return timeout > 0 ? I2C2->DR : 0;
      }
      
  • Driver_I2C.c

    • #ifndef __DRIVER_I2C
      #define __DRIVER_I2C
      
      #include "stm32f10x.h"
      
      #define OK 0
      #define FAIL 1
      
      void Driver_I2C_Init(void);
      
      /* I2C的启动停止信号 使用寄存器标记不断发送  ->  SR1中SB被硬件置位为1 表示发送完成 */
      uint8_t Driver_I2C_Start(void);
      void Driver_I2C_Stop(void);
      
      /* 只有在读数据 接收数据的时候 才会使用到  如果收到的字节是最后一个  发NACK  如果不是最后一个 发ACK */
      void Driver_I2C_ACK(void);
      void Driver_I2C_NACK(void);
      
      /* 发送设备地址 */
      uint8_t Driver_I2C_SendADDR(uint8_t dev_addr);
      
      /* 发送一个字节 */
      uint8_t Driver_I2C_SendChar(uint8_t ch);
      
      /* 读取一个字节 */
      uint8_t Driver_I2C_ReceiveChar(void);
      
      #endif
      

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

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

相关文章

【提示学习论文】AAPL: Adding Attributes to Prompt Learning for Vision-Language Models

AAPL: Adding Attributes to Prompt Learning for Vision-Language Models(2024CVPR) 问题:在unseen class上,性能提升有限解决:在提示学习中引入对抗性标记嵌入adversarial token embedding, 将低层次视觉…

SOMEIP_ETS_060: SD_Discover_Port_and_IP

测试目的: 验证设备(DUT)能够响应测试器发出的多播FindService消息,并返回一个单播OfferService消息,列出所有必要的IP地址和端口,以满足与DUT的所有可能通信需求。 描述 本测试用例旨在检查DUT是否能够…

清理linux的buff/cache缓存

通过free -m命令,查看内存占用率。 如果buff/cache 占用内存过高的话,执行以下命令 sync && echo 1 > /proc/sys/vm/drop_caches sync && echo 2 > /proc/sys/vm/drop_caches sync && echo 3 > /proc/sys/vm/drop_ca…

文字怎么生成二维码扫码展示?文本活码在线生成的3步操作技巧

现在很多人会将文本信息用生成二维码的方式来展现,通过二维码来分享内容能够有效的提升内容的传播效率,简化其他人获取信息的流程。只需要通过扫码就能在手机上预览内容,更加符合现在人们的生活习惯,而且这种方式可以降低制作者的…

bedtools安装与使用(v2.31.1)生物信息学工具29

01 背景 bedtools:一个用于基因组算术的强大工具集 总体而言,bedtools 工具集是一个多功能的工具包,可用于广泛的基因组分析任务。其中最广泛使用的工具能够进行基因组算术运算,即在基因组上执行集合论操作。例如,be…

前端实现投影坐标和地理坐标系(CGCS2000)转换

前言 地理坐标系和投影坐标系是地理信息系统(GIS)和制图学中用于描述地球表面位置的两种不同的参考系统。它们在使用方式和应用场景上有显著的区别。 1、什么是地理坐标系和投影坐标系? 1.1、地理坐标系 地理坐标系是基于地球的三维球面模…

虚拟机安装centos7-桥接模式

1、打开虚拟机,点击文件,选择新建虚拟机 2、选择典型,点击下一步 3、选择稍后安装操作系统,点击下一步 4、选择系统类型及版本,点击下一步,因centos7是Linux操作系统,且是64位的,所以…

隐藏的艺术:滥用 404 页面的新 Magecart 活动

介绍 一项新的、复杂的、隐蔽的 Magecart 网页窃取活动已针对 Magento 和 WooCommerce 网站展开。该活动的部分受害者与食品和零售行业的大型组织有关。 根据我们发现的证据,该活动已经持续了几周,在某些情况下甚至更长。该活动采用了一种我们以前从未遇到过的高级隐藏技术…

Linux 内核源码分析---组播/策略路由选择

在 Linux 实现中,组播路由选择不像单播路由选择那样可以由内核单独处理,组播守护程序种类繁多,如 mrouted 和 pimd,它们分别基于距离矢量组播路由选择协议(Distance Vector Multicast Routing Protocol,DVM…

《在数字化时代筑牢软件服务的稳定性防线》

📢博客主页:https://blog.csdn.net/2301_779549673 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📢本文由 JohnKi 原创,首发于 CSDN🙉 📢未来很长&#…

transform解题reserve

1.64位无壳,拖入ida检查。 选中函数按n键可以更改名称,便于分析和利用 。 重点: 2.分析加密过程,理解用于后续脚本编写。 str2以下表对应的元素作为索引遍历flag的每个元素赋值给str1数组,之后与新的str1每个元素异或…

数分基础(02)销售趋势分析

文章目录 销售趋势分析1. 数据集2. 销售趋势3. 步骤3.1 数据读取与预处理:3.2 计算按月、季度、年度的总销售额 4. 分析工具:Python 或 Excel5. Python5.1 Global_Superstore2.xlsx 文件位置5.2 读取数据集并检查其基本信息5.3 绘制趋势图来观察销售额的…

掌握C语言文件操作

1. 什么是文件 磁盘上的文件就是文件。 然而在程序设计中,我们所谈的文件有两种,一种是程序文件,另一种是数据文件(从文件功能的角度来分类的) 文件名 一个文件要有一个唯一的文件标识,以便用户识别和引用…

金蝶云星空开发简单账表《物料年采购入库报表》

文章目录 业务背景业务需求方案设计详细设计测试业务背景 系统现有功能不支持查询过去一年内所有物料的入库数,需要人工导出,然后再汇总。 业务需求 可以查询所有物料的入库数,多个物料,单个物料,多个组织,单个组织的入库数,以及支持查询入库数大于某个阈值。 方案设…

燃气灶行业分析、淘宝平台销售分析

内容:1.燃气灶(不含集成灶)整体行业分析 2.淘宝平台销量分析 3.针对性建议(涉及商业信息就略) 一、基本情况 (一)产品定义: 以液化石油气(液态)、人工煤…

DRF——router路由,parser解析器

文章目录 路由解析器1.JSONParser2.FormParser3.MultiPartParser4.FileUploadParser 路由 在之前进行drf开发时,对于路由我们一般进行两种配置: 视图继承APIView from django.urls import path from app01 import viewsurlpatterns [path(api/users/, …

趣味算法------尾部零的个数(C语言,python双重解法)

目录 题目描述&#xff1a; 解题思路&#xff1a; 具体代码&#xff1a; 注意&#xff1a; 题目描述&#xff1a; 给出数字 n(0<n<1000000)&#xff0c;计算出 n 阶乘尾部零的个数。 输入输出格式 输入格式 一个整数。 输出格式 一个整数。 输入输出样例 输入 11 输…

技术分享-商城篇-用户订单管理(十五)

前言 在前面的文章中&#xff0c;我们详细阐述了商品模块、购物模块、支付模块等B2B2C&#xff08;Business-to-Business-to-Consumer&#xff09;电商中核心基础模块&#xff0c;接下来我们来聊一下基础模块中最后一个环节订单模块&#xff0c;订单模块属于购物体系闭环内容&…

C语言典型例题50

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 例题4.2 使用do……while语句循环求1234……100&#xff1b; 代码&#xff1a; //《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 //例题4.2 使用do……while语句循环求1234……100&#xff1b;#incl…

Axure RP实战:打造高效滑块验证码

Axure RP在验证码设计中的应用(滑块拖动) 前言 在数字化时代&#xff0c;验证码已成为保护用户账户安全和防止恶意攻击的重要工具。 它不仅提高了系统的安全性&#xff0c;还增加了用户对平台的信任度。 然而&#xff0c;验证码的设计并非易事&#xff0c;它需要在安全性和…