APM32使用I2C驱动OLED

实验效果

IIC硬件显示

本次实验主要讲APM32的I2C外设的初始化和APM32作为主机如何发送数据,OLED的驱动写起来较难本次实验不涉及。由于条件有限本次只能讲主机发送,接收也没有涉及。

硬件原理图

IIC接口

源代码

I2C初始化部分

#ifndef __BSP__IIC_H__
#define __BSP__IIC_H__
#include "apm32f10x.h"
#include "apm32f10x_gpio.h"
#include "apm32f10x_i2c.h"
#include "apm32f10x_rcm.h"#define IIC_OWN_ADDRESS 0X0A // 与从机地址不同即可#define OLED_ADDRESS 0x78 // 从机地址
#define OLED_IIC I2C1     // 使用I2C1
#define OLED_IIC_CLOCK RCM_APB1_PERIPH_I2C1
#define OLDE_IIC_SCL_PIN GPIO_PIN_6
#define OLDE_IIC_SDA_PIN GPIO_PIN_7#define OLED_GPIO_SCL_PORT GPIOB
#define OLED_GPIO_SDA_PORT GPIOB#define OLED_GPIO_SCL_CLOCK RCM_APB2_PERIPH_GPIOB
#define OLED_GPIO_SDA_CLOCK RCM_APB2_PERIPH_GPIOBvoid OLED_IIC_Config(void);
#endif
#include "bsp_iic.h"/*** @brief I2C GPIO 配置* @param*/
static void OLED_GPIO_Config(void)
{GPIO_Config_T GPIO_ConfigStruct;RCM_EnableAPB2PeriphClock(OLED_GPIO_SCL_CLOCK | OLED_GPIO_SDA_CLOCK);// 开漏输出GPIO_ConfigStruct.mode = GPIO_MODE_AF_OD;GPIO_ConfigStruct.pin = OLDE_IIC_SCL_PIN;GPIO_ConfigStruct.speed = GPIO_SPEED_10MHz;GPIO_Config(OLED_GPIO_SCL_PORT, &GPIO_ConfigStruct);GPIO_ConfigStruct.pin = OLDE_IIC_SDA_PIN;GPIO_Config(OLED_GPIO_SDA_PORT, &GPIO_ConfigStruct);
}/*** @brief 配置I2C* @param*/
void OLED_IIC_Config(void)
{I2C_Config_T I2C_ConfigStruct;RCM_EnableAPB1PeriphClock(OLED_IIC_CLOCK);OLED_GPIO_Config();// 在接收到一个字节后返回一个应答(匹配的地址或数据)I2C_ConfigStruct.ack = I2C_ACK_ENABLE;// I2C的寻址模式I2C_ConfigStruct.ackAddress = I2C_ACK_ADDRESS_7BIT;// 通信速率I2C_ConfigStruct.clockSpeed = 100000;// 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比I2C_ConfigStruct.dutyCycle = I2C_DUTYCYCLE_2;// I2C模式I2C_ConfigStruct.mode = I2C_MODE_I2C;// 主主机地址I2C_ConfigStruct.ownAddress1 = IIC_OWN_ADDRESS;I2C_Config(OLED_IIC, &I2C_ConfigStruct);I2C_Enable(OLED_IIC);
}

主机发送部分

#ifndef __APP_IIC_H__
#define __APP_IIC_H__
#include "bsp_iic.h"uint8_t App_IIC_MasterTransmit(I2C_T *IIC, uint8_t SlaveAddress, const uint8_t *pData, uint8_t Size);#endif
#include "app_iic.h"/*** @brief IIC主模式发送数据,支持多字节发送,起始和停止均在这个函数中,APM32手册没有具体流程,根据STM32手册编写* @param IIC   F1可选I2C1、I2C2* @param SlaveAddress  从机地址* @param pData 要发送的数据* @param Size  数据长度* @return SUCCESS成功,ERROR失败*/
uint8_t App_IIC_MasterTransmit(I2C_T *IIC, uint8_t SlaveAddress, const uint8_t *pData, uint8_t Size)
{uint8_t ret = SUCCESS;uint32_t i = 0;// 1. 等待总线空闲while (I2C_ReadStatusFlag(IIC, I2C_FLAG_BUSBSY) == SET);// 2. 发送起始位I2C_EnableGenerateStart(IIC);// 等待起始位发送完成while (I2C_ReadStatusFlag(IIC, I2C_FLAG_START) == RESET);//  3.发送地址// 清除AE标志位I2C_ClearStatusFlag(IIC, I2C_FLAG_AE);I2C_Tx7BitAddress(IIC, SlaveAddress, I2C_DIRECTION_TX);while (I2C_ReadStatusFlag(IIC, I2C_FLAG_ADDR) == RESET){if (I2C_ReadStatusFlag(IIC, I2C_FLAG_AE) == SET){ret = ERROR;goto STOP;}}// 4. 发送数据// 清除ADDR标志位I2C_ReadRegister(IIC, I2C_REGISTER_STS1);I2C_ReadRegister(IIC, I2C_REGISTER_STS2);for (i = 0; i < Size; i++){while (I2C_ReadStatusFlag(IIC, I2C_FLAG_TXBE) == RESET){if (I2C_ReadStatusFlag(IIC, I2C_FLAG_AE) == SET){ret = ERROR;goto STOP;}}I2C_TxData(IIC, pData[i]);}while (I2C_ReadStatusFlag(IIC, I2C_FLAG_BTC) == RESET){}// 5.发送停止位
STOP:I2C_EnableGenerateStop(IIC);// 等待总线空闲while (I2C_ReadStatusFlag(IIC, I2C_FLAG_BUSBSY) == SET);return ret;
}

主程序部分

/*** @brief SCL-->PB6*        SDA-->PB7*/#include "bsp_oled.h"int main(void)
{/*模块初始化*/OLED_Init(); // OLED初始化/*OLED显示*/OLED_ShowChar(1, 1, 'Y'); // 1行1列显示字符YOLED_ShowString(1, 3, "Hardware IIC!"); // 1行3列显示字符串Hardware IIC!OLED_ShowNum(2, 1, 12345, 5); // 2行1列显示十进制数字12345,长度为5OLED_ShowSignedNum(2, 7, -55, 2); // 2行7列显示有符号十进制数字-55,长度为2OLED_ShowHexNum(3, 1, 0xA5A5, 4); // 3行1列显示十六进制数字0xA5A5,长度为4OLED_ShowBinNum(4, 1, 0xA5A5, 16); // 4行1列显示二进制数字0xA5A5,长度为16// C语言无法直接写出二进制数字,故需要用十六进制表示while (1){}
}

代码分析

bsp_iic.c

/*** @brief I2C GPIO 配置* @param*/
static void OLED_GPIO_Config(void)
{GPIO_Config_T GPIO_ConfigStruct;RCM_EnableAPB2PeriphClock(OLED_GPIO_SCL_CLOCK | OLED_GPIO_SDA_CLOCK);// 开漏输出GPIO_ConfigStruct.mode = GPIO_MODE_AF_OD;GPIO_ConfigStruct.pin = OLDE_IIC_SCL_PIN;GPIO_ConfigStruct.speed = GPIO_SPEED_10MHz;GPIO_Config(OLED_GPIO_SCL_PORT, &GPIO_ConfigStruct);GPIO_ConfigStruct.pin = OLDE_IIC_SDA_PIN;GPIO_Config(OLED_GPIO_SDA_PORT, &GPIO_ConfigStruct);
}

I2C需要两个GPIO,一个作为SCL,另一个作为SDA,IIC的GPIO和其他外设配置就一个点不太相同,GPIO_ConfigStruct.mode = GPIO_MODE_AF_OD;模式要设置成复用开漏输出模式。

我们主要讲下I2C相关参数如何配置

/*** @brief 配置I2C* @param*/
void OLED_IIC_Config(void)
{I2C_Config_T I2C_ConfigStruct;RCM_EnableAPB1PeriphClock(OLED_IIC_CLOCK);OLED_GPIO_Config();// 在接收到一个字节后返回一个应答(匹配的地址或数据)I2C_ConfigStruct.ack = I2C_ACK_ENABLE;// I2C的寻址模式I2C_ConfigStruct.ackAddress = I2C_ACK_ADDRESS_7BIT;// 通信速率I2C_ConfigStruct.clockSpeed = 100000;// 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比I2C_ConfigStruct.dutyCycle = I2C_DUTYCYCLE_2;// I2C模式I2C_ConfigStruct.mode = I2C_MODE_I2C;// 主主机地址I2C_ConfigStruct.ownAddress1 = IIC_OWN_ADDRESS;I2C_Config(OLED_IIC, &I2C_ConfigStruct);I2C_Enable(OLED_IIC);
}

先来看下结构体中的参数

/*** @brief I2C Config structure definition*/
typedef struct
{uint32_t            clockSpeed;I2C_MODE_T          mode;I2C_DUTYCYCLE_T     dutyCycle;uint16_t            ownAddress1;I2C_ACK_T           ack;I2C_ACK_ADDRESS_T   ackAddress;
} I2C_Config_T;

clockSpeed通信速率,这个值主要根据从机来选,我们要填的参数要小于从机所支持的最高通信速率。我们这里填100000,属于标准模式的速度。

I2C_MODE_TI2C模式,可选参数I2C_MODE_I2CI2C模式、I2C_MODE_SMBUUSDEVICESMBUS从机模式、I2C_MODE_SMBUSHOSTSMBUS主机模式。我们这里选I2C模式,另外两个位系统管理总线,主要用在PC上。

I2C_DUTYCYCLE_TI2C的时钟线SCL的占空比,可选I2C_DUTYCYCLE_16_9低电平比高电平为16:9、I2C_DUTYCYCLE_2低电平比高电平为2:1,两个选项其实区别不大,若从机无特殊要求,随便选即可。

ownAddress1主机地址,这个地址可以随便填,但是不能和其他设备地址相同,要保证唯一性即可。

ack应答使能,可选I2C_ACK_ENABLE使能应答、I2C_ACK_DISABLE禁止应答。这个主要是接收数据时用到,接收到一个字节后自动返回一个应答。一般都是使能的,不过我们这次实验没用到,因为我们主机只发送数据没有接收。

ackAddressI2C寻址模式,可选参数I2C_ACK_ADDRESS_7BIT7位地址、I2C_ACK_ADDRESS_10BIT10位地址。这个要根据从机来选,一般还是7位的多,我们这里选I2C_ACK_ADDRESS_7BIT

填好这些参数后把结构体填入初始化函数中即可,然后使能I2C外设。

app_i2c.c

我们主要来讲下APM32作为I2C主机如何发送数据。APM32的参考手册没写如何发送,我不得不去看STM32手册,RM0008 Rev21 760页。

IIC主机发送流程

我们主要看7bit的发送,上面这种图可能看得不够清楚,我们结合下方流程图看

IIC主机发送流程图

  1. 首先时等待总线空闲 while (I2C_ReadStatusFlag(IIC, I2C_FLAG_BUSBSY) == SET);,STM32手册上写了要等待总线空闲之后才可以发送起始位,不看手册我们自己想应该也是要等待总线空闲。
  2. 发送起始位I2C_EnableGenerateStart(IIC);
  3. 等待EV5并处理,可以while(!I2C_ReadEventStatus(I2C1, I2C_EVENT_MASTER_MODE_SELECT));,我们这里没这样写,我们是while (I2C_ReadStatusFlag(IIC, I2C_FLAG_START) == RESET)我们是等待START位置位,怎么理解EV5这个事件呢,其实EV5就是个别名,我们的写法只是没用别名,具体出来了。
  4. 在发送从机地址之前我们清除了AE标志位(应答错误标志)I2C_ClearStatusFlag(IIC, I2C_FLAG_AE);,怎么理解呢?可以说是为了保险起见,给这个标志位赋了初值。I2C_Tx7BitAddress(IIC, SlaveAddress, I2C_DIRECTION_TX);发送七位地址,SlaveAddress为从机地址,I2C_DIRECTION_TX为发送模式,I2C_DIRECTION_RX为接收模式。
  5. 发送完地址后要等待EV6事件,也就是等待ADDR置位(主机地址模式地址发送完成),while (I2C_ReadStatusFlag(IIC, I2C_FLAG_ADDR) == RESET),在等待ADDR置位的同时我们一直在检测AE标志位,若出现错误直接跳转到错误部分,结束发送。ADDR置位表示从机地址发送完成,需要清除该标志位,I2C_ReadRegister(IIC, I2C_REGISTER_STS1);
    I2C_ReadRegister(IIC, I2C_REGISTER_STS2);,读这两个寄存器就可以清除ADDR标志位。
  6. 然后就是发送数据,通过一个for循环发,有多少发多少,在发之前要等到发送缓冲区为空,这一点和串口那边发送有些相似。
for (i = 0; i < Size; i++)
{while (I2C_ReadStatusFlag(IIC, I2C_FLAG_TXBE) == RESET){if (I2C_ReadStatusFlag(IIC, I2C_FLAG_AE) == SET){ret = ERROR;goto STOP;}}I2C_TxData(IIC, pData[i]);
}
  1. 发送缓冲区数据发送完成后等待完成数据字节传输标志置位,这里也和串口那边的标志位相似。
  2. 完成一系列操作后就可以发送停止位了,一套发送完成。

完成这个函数后,就可以去移植OLED驱动了,把接口函数改好即可。具体代码可以参考Git仓库

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

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

相关文章

QT布局详解

ui设计器设计界面很方便&#xff0c;为什么还要手写代码? (1)更好的控制布局 (2)更好的设置qss (3)代码复用 创建水平布局 包含头文件 #include<QHBoxLayout> 创建水平布局QHBoxLayout *pHLay new QHBoxLayout(父窗口指针);//一般填this QPushButton *pBtn1 n…

宏集eXware物联网网关在水务管理系统上的应用

一、前言 水务管理系统涵盖了对城市水网、供水、排水、污水处理等多个环节的监控与管理。随着物联网&#xff08;IoT&#xff09;技术的快速发展&#xff0c;物联网网关逐渐成为水务管理系统中的关键组成部分。 宏集物联网网关以其高效的数据采集、传输和管理功能&#xff0c…

不修改内核镜像的情况下,使用内核模块实现高效监控调度时延

一、背景 在之前的博客 调度时延的观测_csdn 调度时延的观测 杰克崔-CSDN博客 里&#xff0c;我们讲了多种监控调度时延的方法&#xff0c;有依靠系统现有节点来监控&#xff0c;但是依赖系统现有节点做不到每个单词调度时延的监控&#xff0c;也讲了通过修改内核代码&#xf…

在 ASP.NET C# Web API 中实现 Serilog 以增强请求和响应的日志记录

介绍 日志记录是任何 Web 应用程序的关键方面。它有助于调试、性能监控和了解用户交互。在 ASP.NET C# 中&#xff0c;集成 Serilog 作为记录请求和响应&#xff08;包括传入和传出的数据&#xff09;的中间件可以显著提高 Web API 的可观察性和故障排除能力。 在过去的几周里&…

【开源免费】基于Vue和SpringBoot的技术交流分享平台(附论文)

博主说明&#xff1a;本文项目编号 T 053 &#xff0c;文末自助获取源码 \color{red}{T053&#xff0c;文末自助获取源码} T053&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

JVM指令集概览:基础与应用

写在文章开头 在现代软件开发中,Java 语言凭借其“一次编写,到处运行”的理念成为了企业级应用的首选之一。这一理念的背后支撑技术正是 Java 虚拟机(JVM)。JVM 是一个抽象的计算机,它实现了 Java 编程语言的各种特性,并且能够执行编译后的字节码文件。了解 JVM 的工作原…

电子应用设计方案-33:智能AI投影仪系统方案设计

智能 AI 投影仪系统方案设计 一、引言 随着科技的不断进步&#xff0c;投影仪在家庭娱乐、商务办公和教育培训等领域的应用越来越广泛。智能 AI 投影仪作为一种创新的投影设备&#xff0c;结合了人工智能技术&#xff0c;为用户带来更便捷、智能和个性化的使用体验。 二、系统…

基于springboot 的体质测试数据分析及可视化设计LWPPT

技术可行性&#xff1a;技术背景 本企业网站在Windows操作系统中进行开发&#xff0c;并且目前PC机的性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的&#xff0c;也是当下广泛应用的技术之一。 系统的开发环境和配置都是可以自行安装的&#x…

SQL进阶——C++与SQL进阶实践

在C开发中&#xff0c;SQL数据库的操作是开发者常见的任务之一。虽然前面我们已经介绍了如何在C中通过数据库连接执行基本的SQL查询&#xff0c;但在实际项目中&#xff0c;我们通常需要更加复杂和高效的数据库操作。存储过程与函数的调用、复杂SQL查询的编写、以及动态构造SQL…

Spring Boot日志总结

文章目录 1.我们的日志2.日志的作用3.使用日志对象打印日志4.日志框架介绍5.深入理解门面模式(外观模式)6.日志格式的说明7.日志级别7.1日志级别分类7.2配置文件添加日志级别 8.日志持久化9.日志文件的拆分9.1官方文档9.2IDEA演示文件分割 10.日志格式的配置11.更简单的日志输入…

CSDN设置成黑色背景(谷歌 Edge)

一.谷歌浏览器 浏览器地址输入&#xff1a;Chrome://flags搜索框输入&#xff1a;enable-force-dark将default 改成 enabled&#xff0c;点击重启浏览器 二.Edge浏览器 浏览器地址输入&#xff1a;edge://flags搜索里面输入Auto Dark Mode for Web Contents将default 改成 e…

实现PDF文档加密,访问需要密码

01. 背景 今天下午老板神秘兮兮的来问我&#xff0c;能不能做个文档加密功能&#xff0c;就是那种用户下载打开需要密码才能打开的那种效果。boss都发话了&#xff0c;那必须可以。 需求&#xff1a;将pdf文档经过加密处理&#xff0c;客户下载pdf文档&#xff0c;打开文档需要…

Android内容提供者

一、ContentProvider 实现跨程序共享数据 创建内容提供者&#xff1a;extends ContentProvider类 访问数据 Uri uri Uri.parse("uri路径") 查询数据 ContentResolver resolver context.getContentResolver(); Cursor cur resolver.query(Uri,projection,sel…

基于JSP+MySQL的网上招聘系统的设计与实现

摘要 在这样一个经济飞速发展的时代&#xff0c;人们的生存与生活问题已成为当代社会需要关注的一个焦点。对于一个刚刚 踏入社会的年轻人来说&#xff0c;他对就业市场和形势了解的不够详细&#xff0c;同时对自己的职业规划也很模糊&#xff0c;这就导致大量的 时间被花费在…

如何全面备份你的Mac电脑:邮件、联系人、桌面文件和Safari书签

在卖掉或更换电脑之前&#xff0c;备份所有重要数据是非常关键的步骤。本文将指导你如何备份MacBook Pro上的邮件、联系人、桌面文件以及Safari的书签。 1. 备份Safari书签 如果你使用Safari浏览器&#xff0c;可以按照以下步骤导出书签&#xff1a; 打开Safari。点击顶部菜…

三维渲染中顺序无关的半透明混合(OIT)(一Depth Peeling)

>本文收集关于透明对象渲染技术中关于OIT技术的资料&#xff0c;尝试用简单的逻辑对这些内容进行整理。 1、透明对象的特殊对待 不要小瞧png图片和jpg图片的差异&#xff01;在一般的三维平台&#xff0c;png代表的是带透明通道的纹理&#xff0c;而jpg代表的是不带透明的…

行业分析---2024年蔚来汽车三季度财报及科技日

1 前言 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 《行业分析-…

mac上的建议xftp 工具

mac上的建议xftp 工具 最近使用mac比较频繁了&#xff0c;但是第一次重度使用mac里面有很多的工具都是新的&#xff0c;有的window版本的工具无法使用。 xftp 的平替 Cyberduck 从它的官网上下载是免费的&#xff0c;但是如果使用 Apple store 要花费198呢。这不就剩下一大笔…

C++ - 二叉搜索树讲解

二叉搜索树概念和定义 二叉搜索树是一个二叉树&#xff0c;其中每个节点的值都满足以下条件&#xff1a; 节点的左子树只包含小于当前节点值的节点。节点的右子树只包含大于当前节点值的节点。左右子树也必须是二叉搜索树。 二叉树搜索树性质 从上面的二叉搜索树定义中可以了…

【WRF后处理】WRF模拟效果评价及可视化:MB、RMSE、IOA、R

【WRF后处理】模拟效果评价及可视化 准备工作模型评价指标Python实现代码Python处理代码:导入站点及WRF模拟结果可视化图形及评价指标参考在气象和环境建模中(如使用 WRF 模型进行模拟),模型性能评价指标是用于定量评估模拟值与观测值之间偏差和拟合程度的重要工具。 本博客…