16:【stm32】I2C的使用一:I2C片上外设的使用

I2C

  • 1、片上外设
    • 1.1:寄存器与内部结构
  • 2、通过I2C向外发送数据
    • 2.1:I2C的初始化
      • 2.1.1:初始化SCL和SDA
      • 2.1.2:使能时钟PCLK1(APB1)
      • 2.1.3:配置I2C1的参数
    • 2.2:发送数据
      • 2.2.1:等待总线空闲(BUSY标志位)
      • 2.2.2:发送起始位(START,SB标志位)
      • 2.2.3:发送地址(AF,ADDR标志位)
      • 2.2.4:发送数据

具体的通过I2C通信协议传输数据帧的相关信息参考《C51单片机》里面的第13节OLED屏的使用

1、片上外设

如图:I2C片上外设挂载在APB1总线上面,并且I2C1由复用重映射,I2C2没有重映射。
在这里插入图片描述
在这里插入图片描述

1.1:寄存器与内部结构

在这里插入图片描述

TDR -Transmit Data Register -发送数据寄存器
RDR -Receive Data Register -接收数据寄存器
CR  -Control Register -控制寄存器
SR1 -Status Register 1 -状态寄存器1
SR2 -Status Register 2 -状态寄存器2
CCR -Clock Control Register -时钟控制寄存器
  • SR1:状态寄存器1

    SB:起始位发送完成,0代表没有起始位产生,1代表检测到了起始位。
    AF/ADDR:AF代表接收到NAK,寻址失败AF=1;ADDR代表选址成功,寻址成功-ADDR=1。
    TXE:发送数据寄存器TDR空,1代表空,0代表非空。
    RXNE:接收数据寄存器RDR非空,1代表非空,0代表空。
    BTF:发送完成。1代表发送完成
    
  • SR2:状态寄存器2

    TRA
    BUSY:用于查询总线的空闲状态,0为空闲,1为忙。
    MSL
    
  • CR:控制寄存器

    PE:SCL的开关。
    START:用于产生一个起始位,写入1代表发送一个起始位。
    ACK:用于产生一个应答信号。
    

2、通过I2C向外发送数据

2.1:I2C的初始化

在这里插入图片描述

2.1.1:初始化SCL和SDA

我们使用I2C1,初始化SCL和SDA所连接的IO口,把他们配置为复用开漏模式。

//1 .开启GPIOB挂载的总线时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//初始化IO引脚
GPIO_InitTypeDef GPIOInitStruct;
GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式
GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;
GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&GPIOInitStruct);

2.1.2:使能时钟PCLK1(APB1)

//2 .开启I2C挂载APB1总线的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放

2.1.3:配置I2C1的参数

在这里插入图片描述
标志模式下:波特率max = 100K,当波特率>=100K时,就按照快速模式进行。快速模式下:波特率max = 400K。
I2C_DutyCycle:在快速模式下,配置时钟信号的形状,即时钟信号的占空比。2:1 = 低电平:高电平/16:9 = 低电平:高电平
下面灰色是工作在从机模式下才需要进行配置的。

//3 .配置I2C1的参数
I2C_InitTypeDef I2CInitStruct;
I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400K
I2CInitStruct.I2C_Mode = I2C_Mode_I2C;//标准的I2C模式,一般不使用SMBus
I2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1
I2C_Init(I2C1,&I2CInitStruct);
//4 .使能I2C
I2C_Cmd(I2C1,ENABLE);//闭合开关,PE

2.2:发送数据

在这里插入图片描述在这里插入图片描述

2.2.1:等待总线空闲(BUSY标志位)

在这里插入图片描述

//1 .等待总线空闲 
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);

2.2.2:发送起始位(START,SB标志位)

在这里插入图片描述

//2 .发送起始位
I2C_GenerateSTART(I2C1,ENABLE);
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成

2.2.3:发送地址(AF,ADDR标志位)

在这里插入图片描述
发送地址前先清除AF标志位,

//3 .发送地址//3.1 清除标志位AF
I2C_ClearFlag(I2C1,I2C_FLAG_AF);//3.2 发送8为数据,7+1
I2C_SendData(I2C1,SlaveADDr & 0xfe);//3.3 等待发送成功
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET)
{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了{ret = ERROR;goto STOP;}
}
STOP:I2C_GenerateSTOP(I2C1,ENABLE);//发送停止位while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);//等待总线空闲

2.2.4:发送数据

在这里插入图片描述
发送数据前先清除ADDR标志位,清除ADDR(先读SR1寄存器,再度SR2寄存器)。

//4 .发送数据//4.1 清除ADDR标志位
I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1
I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2//4.2 向TDR寄存器写入数据
uint32_t i;
for(i = 0; i < Size ;i++)//Size是数据数组的个数
{while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}}I2C_SendData(I2C1,pData[i]);//向TDR写入数据
}while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成
{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}
}

最终代码①:

	//1 .等待总线空闲 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);//2 .发送起始位I2C_GenerateSTART(I2C1,ENABLE);while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成//3 .发送地址//3.1 清除标志位AFI2C_ClearFlag(I2C1,I2C_FLAG_AF);//3.2 发送8为数据,7+1I2C_SendData(I2C1,SlaveADDr & 0xfe);//3.3 等待发送成功while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了{ret = ERROR;goto STOP;}}//4 .发送数据//4.1 清除ADDR标志位I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2//4.2 向TDR寄存器写入数据uint32_t i;for(i = 0; i < Size ;i++){while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}}I2C_SendData(I2C1,pData[i]);}while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}}//5 .发送STOP
STOP:I2C_GenerateSTOP(I2C1,ENABLE);while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);

代码测试:通过向OLED模式发送指令将其屏幕点亮

#include "stm32f10x.h"void App_I2C_Init(void);
void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size);int main(void)
{//OLED指令uint8_t oled_init_command[] = {0x00, // Command Stream0xa8, 0x3f, // Set MUX Ratio0xd3, 0x00, // Set Display Offset0x40, // Set Display Start Line0xa0, // Set Segment re-map0xc0, // Set COM Output Scan Direction0xda, 0x02, // Set COM Pins hardware configuration0x81, 0x7f, // Set Contrast Control0xa5, // Enable Entire Display On0xa6, // Set Normal Display0xd5, 0x80, // Set OSC Frequency0x8d, 0x14, // Enable charge pump regulator0xaf, // Display on};App_I2C_Init();App_I2C_Send(0x78, oled_init_command, sizeof(oled_init_command)/sizeof(uint8_t));while(1){}
}void App_I2C_Init(void)
{//1 .开启GPIOB挂载的总线时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//初始化IO引脚GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_OD;//复用输出开漏模式GPIOInitStruct.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIOInitStruct);//2 .开启I2C挂载APB1总线的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启时钟RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//对I2C1进行复位RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//对I2C1进行释放//3 .配置I2C1的参数I2C_InitTypeDef I2CInitStruct;I2CInitStruct.I2C_ClockSpeed = 400000;//配置波特率,最高400KI2CInitStruct.I2C_Mode = I2C_Mode_I2C;//一般不使用SMBusI2CInitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//2:1I2C_Init(I2C1,&I2CInitStruct);//4 .使能I2CI2C_Cmd(I2C1,ENABLE);
}void App_I2C_Send(uint8_t SlaveADDr,uint8_t* pData,uint16_t Size)
{ErrorStatus ret = SUCCESS;//1 .等待总线空闲 while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);//2 .发送起始位I2C_GenerateSTART(I2C1,ENABLE);while(I2C_GetFlagStatus(I2C1,I2C_FLAG_SB) == RESET);//起始位发送完成//3 .发送地址//3.1 清除标志位AFI2C_ClearFlag(I2C1,I2C_FLAG_AF);//3.2 发送8为数据,7+1I2C_SendData(I2C1,SlaveADDr & 0xfe);//3.3 等待发送成功while(I2C_GetFlagStatus(I2C1,I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET)//地址发送失败了{ret = ERROR;goto STOP;}}//4 .发送数据//4.1 清除ADDR标志位I2C_ReadRegister(I2C1,I2C_Register_SR1);//读取SR1I2C_ReadRegister(I2C1,I2C_Register_SR2);//读取SR2//4.2 向TDR寄存器写入数据uint32_t i;for(i = 0; i < Size ;i++){while(I2C_GetFlagStatus(I2C1,I2C_FLAG_TXE) == RESET)//等待TXE为1{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}}I2C_SendData(I2C1,pData[i]);}while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BTF) == RESET)//等待发送完成{if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF) == SET){ret = ERROR;goto STOP;}}//5 .发送STOP
STOP:I2C_GenerateSTOP(I2C1,ENABLE);while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) == SET);
}

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

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

相关文章

Ⅰ、基于 WebGPU 从 0 到 1 渲染 GLTF:第一个三角形

Ⅰ、基于 WebGPU 从 0 到 1 渲染 GLTF&#xff1a;第一个三角形 WebGPU 是一种面相网页的现代图形 API&#xff0c;由主要浏览器供应商开发。与 WebGL 相比&#xff0c;WebGPU 对 GPU 提供了更直接的控制&#xff0c;使应用程序能更有效地利用硬件&#xff0c;类似于 Vulkan 和…

如何在C++ QT 程序中集成cef3浏览器组件去显示网页?

目录 1、问题描述 2、为什么选择cef3浏览器组件 3、cef3组件的介绍与下载 4、将cef3组件封装成sdk 5、如何使用cef3组件加载web页面 5.1、了解CefApp与CefClient 5.2、初始化与消息循环 5.3、如何创建浏览器 5.4、重载CefClient类 6、在qt客户端集成cef组件 7、最后…

「12月·长沙」第三届传感、测量、通信和物联网技术国际会议(SMC-IoT 2024)

第三届传感、测量、通信和物联网技术国际会议&#xff08;SMC-IoT 2024&#xff09;将于2024年11月29日-2024年12月1日召开&#xff0c;由湖南涉外经济学院主办。会议中发表的文章将会被收录, 并于见刊后提交EI核心索引。 会议旨在围绕传感、测量、通信和物联网技术等相关研究…

基于node.js的宠物寄存管理系统,基于express的宠物寄存系统

摘 要 伴随着社会以及科学技术的发展&#xff0c;互联网已经渗透在人们的身边&#xff0c;网络慢慢的变成了人们的生活必不可少的一部分&#xff0c;紧接着网络飞速的发展&#xff0c;系统管理这一名词已不陌生&#xff0c;越来越多的宠物店等机构都会定制一款属于自己个性化…

DWA局部路径规划算法

DWA——Dynamic Window Approach动态窗口法 发展 动态窗口法是一种局部路径规划算法&#xff0c;起源于对移动机器人在复杂环境中实时避障的需求。该算法由F. D. Proentzen和O. Khatib提出&#xff0c;后经过不断优化&#xff0c;已成为移动机器人领域中的标准算法之一。 运…

xss.function靶场(hard)

文章目录 WW3源码分析源码 DOMPpurify框架绕过覆盖变量notifyjs作用域和作用链域构建payload WW3 源码 <!-- Challenge --> <div><h4>Meme Code</h4><textarea class"form-control" id"meme-code" rows"4"><…

Spring Boot实战:使用模板方法模式优化数据处理流程

概述 在软件开发过程中&#xff0c;我们经常需要处理各种各样的数据&#xff0c;这些数据可能来自不同的源&#xff0c;比如数据库、文件系统或者外部API等。尽管数据来源不同&#xff0c;但很多情况下处理这些数据的步骤是相似的&#xff1a;读取数据、清洗数据、转换数据格式…

华为的流程管理

华为建设流程体系始于2000年&#xff0c;那时华为公司面临着快速扩张和全球化发展的挑战&#xff0c;意识到传统的管理模式已经无法满足业务发展的需求。为了提高公司的管理效率和竞争优势&#xff0c;华为决定启动流程体系的建设。在建设过程中&#xff0c;华为借鉴了业界最佳…

云计算的三大服务模式:IaaS、PaaS、SaaS的深入解析

在数字化转型的浪潮中&#xff0c;云计算以其独特的灵活性、可扩展性和成本效益&#xff0c;正逐渐成为企业IT架构的核心。云计算提供了三种主要的服务模式&#xff0c;分别是基础设施即服务&#xff08;IaaS&#xff09;、平台即服务&#xff08;PaaS&#xff09;和软件即服务…

Spring发送邮件性能优化?如何集成发邮件?

Spring发送邮件安全性探讨&#xff01;Spring发送邮件功能有哪些&#xff1f; 邮件发送的性能逐渐成为影响用户体验的重要因素之一。AokSend将探讨如何在Spring框架中进行Spring发送邮件的性能优化&#xff0c;确保系统能够高效、稳定地处理大量邮件请求。 Spring发送邮件&am…

和鲸携手山东大学数字人文实验室,推动新文科与人工智能融合发展

为深入推进产教融合与校企合作&#xff0c;推动人工智能在人文学科中的广泛应用与深入发展&#xff0c;8 月 15 日&#xff0c;山东大学数字人文实验室与和鲸科技 101 计划推进会暨新文科人工智能实验室标杆案例打造讨论会于威海顺利召开。山东大学数字人文实验室副主任陈建红、…

12.2 使用prometheus-sdk向pushgateway打点

本节重点介绍 : 使用golang sdk打prometheus4种指标&#xff0c;推送到pushgateway gauge、counter、histogram、summary的初始化4种类似的设置值的方法推送到pushgateway的方法 prometheus配置采集pushgateway&#xff0c;grafana上配大盘 golang-sdk 项目地址 https://git…

系统架构设计师 - 软件工程(2)

软件工程 软件工程&#xff08;13-22分&#xff09;非常重要软件系统建模系统设计界面设计 ★★软件设计结构化设计 ★★面向对象设计 ★★★★★基本过程设计原则设计模式创建型模式&#xff1a;创建对象结构型模式&#xff1a;更大的结构行为型模式&#xff1a;交互及职责分配…

科三预约考试,为什么我场次排名在前,后面排名又变了

什么时候知道是否预约成功 系统确认考试预约结果的时间一般为考试前5-7个工作日&#xff0c;同时根据预约人数系统会自行判断提前1-2日或延长1-2日公示预约结果&#xff0c;学员至少考试前三天会收到预约成功短信通知。 如果预约失败了怎么办&#xff1f;会计入考试次数吗&am…

Java之线程篇一

目录 如何理解进程&#xff1f; 进程和线程的区别 线程的优点 线程的缺点 线程异常 线程用途 创建线程 方法一&#xff1a;继承Thread类&#xff0c;重写run() 观察线程 小结 方法二&#xff1a; 实现Runnable接口&#xff0c;重写run() 方法三&#xff1a;继承Threa…

【西安电子科技大学】2024年士兵计划考研信息总结!

西安电子科技大学 学校简介上方图片奖助学金下方图片研招网址https://gr.xidian.edu.cn/普通复试https://gr.xidian.edu.cn/info/1073/13301.htm士兵复试总分为各学科门类、各专业学位类别&#xff08;领域&#xff09;国家A类线&#xff0c;单科不限。士兵名额20报考说明无录取…

MES系统从哪几方面提升企业制造水平?

在当今这个快速变化的制造环境中&#xff0c;企业对于提升制造水平的追求从未停止。制造执行系统&#xff08;MES&#xff09;作为连接企业战略规划与车间实际操作的核心工具&#xff0c;其重要性日益凸显。盘古信息MES系统&#xff0c;凭借其独特的功能模块和创新的设计理念&a…

两种图像透明背景转特定颜色方法的比较

之前写过一篇博客&#xff0c;关于透明背景转换为特定颜色&#xff0c;当时使用了NumPy数组采用布尔索引转换的方式&#xff0c;这次我们把这种转换和常规的逐像素转换的方式进行比较&#xff0c;看那种方法效率更高。记得以前使用Matlab的时候&#xff0c;显然是矩阵布尔索引的…

基于SSM的体育馆预约管理系统---附源码84196

摘 要 体育馆作为一个重要的运动场所&#xff0c;需要进行预约管理以保证资源的合理利用和场馆秩序的维护。传统的人工预约管理方式存在效率低、容易出错等问题&#xff0c;因此&#xff0c;在互联网高速发展的当下&#xff0c;需要设计和实现一个基于SSM的体育馆预约管理系统&…

优思学院|六西格玛实施关键:如何整合定性与定量数据

在精益六西格玛的世界中&#xff0c;数据不仅是工具&#xff0c;更是推动变革和改进的关键力量。了解定性数据和定量数据的区别&#xff0c;可以为流程改进提供强大的见解和策略。 定性数据与定量数据的本质 首先&#xff0c;定性数据和定量数据是两种截然不同的概念。定性数据…