STM32 硬件IIC 控制OLED I2C卡死问题

news2024/11/26 9:29:26

1. STM32L151C8T6 硬件IIC 控制OLED 屏,OLED 驱动IC CH1116G, 查阅OLED 数据手册

在这里插入图片描述

2. STM32 硬件IIC 初始化,用的标准库,固件库

// stm32l151c8t6 as master, oled control ic (CH1116G) as slave, and communicate by master iic2
void STM32L151C8T6_IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef I2C_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // GPIO_OType_OD, GPIO_OType_PP
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_400KHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct); // IIC2 SCL - PB10, SDA - PB11

    GPIO_ResetBits(GPIOB, GPIO_Pin_11);
    delay_xms(20);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2); // set PB10 as IIC2 SCL
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2); // set PB11 as IIC2 SDA

    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStruct.I2C_ClockSpeed = iic_clockSpeed_400Khz; // must be less than 100 Khz
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStruct.I2C_Mode = I2C_Mode_SMBusHost; // 这里很重要
    I2C_InitStruct.I2C_OwnAddress1 = IIC2_NOT_USE_OWN_ADDR; // do not use own address

    I2C_Init(I2C2, &I2C_InitStruct);

    I2C_Cmd(I2C2, ENABLE);

    I2C_AcknowledgeConfig(I2C2, ENABLE);
}

3. GPIO 引脚速率要和 I2C 速率匹配,这很重要

在这里插入图片描述

3.1 I2C模式,我这里选的是主机模式,选其它模式就会出问题

在这里插入图片描述

4. OLED 硬件I2C 发送函数封装,给OLED发送的东西分两种:①发的是数据,②发的是命令

// master (STM32L151C8T6) send cmd instruction to oled screen control ic (CH1116G)
void OLED_SendCmd(uint8_t cmd)
{
    WaitFor_IIC_ReadyToWorking();

    I2C_GenerateSTART(I2C2, ENABLE); // iic start signal

    IIC_SendStartSignal_CheckEvent();

    I2C_Send7bitAddress(I2C2, OLED_ADDRESS, I2C_Direction_Transmitter); // send device addr and write bit

    I2C_SendDeviceAddrWaitAck();

    IIC_SendByteToOLED(iic_transmitType_Cmd);

    IIC_Delay(IIC_TIMEOUT_COUNTER);
    I2C_SendData(I2C2, cmd);
    I2C_SendByteDataWaitAck();

    I2C_GenerateSTOP(I2C2, ENABLE);
    IIC_Delay(IIC_TIMEOUT_COUNTER);
}

5. IIC 发送数据之前先检查I2C 是否有空,STM32 为了规避飞利浦的发明专利,把硬件I2C 搞的很复杂,导致固件库会有卡死的问题,据说HAL 库解决了这问题,本人没用过HAL库

static void WaitFor_IIC_ReadyToWorking(void)
{
    while (I2C2->SR2 & 0x02)
    {
        INFO_LOG("[WaitFor_IIC_ReadyToWorking] i2c2 is busy\r\n");
    }
}

6. 发送完起始信号后,要检查起始信号事件, 不要用固件库检查事件函数,会卡死的

static void IIC_SendStartSignal_CheckEvent(void)
{
    while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0001)))
    {
        printf("[IIC_SendStartSignal_CheckEvent][] I2C_SR1=0x%04x, I2C2_SR2=0x%04x\r\n", I2C2->SR1, I2C2->SR2);
    }
    while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0003)) == 0x0003)
    {
        printf("[IIC_SendStartSignal_CheckEvent][] I2C_SR1=0x%04x, I2C2_SR2=0x%04x\r\n", I2C2->SR1, I2C2->SR2);
    }
}

7. 发送完设备地址也要检查发送设备地址这个事件,同样不能用固件库函数

static void I2C_SendDeviceAddrWaitAck(void)
{
    while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0082)) == 0x0082)
    {
    }
    while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0007)) == 0x0007)
    {
    }
}

8. 发送命令给OLED 屏,这里要发两次,我也暂时没弄明白为什么,这个地方搞死我了,好惨

static void IIC_SendByteToOLED(uint8_t mode)
{
    IIC_Delay(IIC_TIMEOUT_COUNTER);
    I2C_SendData(I2C2, mode); // 0x00, high 8-bits, cmd code, iic_transmitType_Cmd
    I2C_SendByteDataWaitAck();

    IIC_Delay(IIC_TIMEOUT_COUNTER);
    I2C_SendData(I2C2, mode); // 0x00, low 8-bits, cmd code
    I2C_SendByteDataWaitAck();
}

9. 发送完命令后要检查标志位, while 里面可以啥都不写,空转,死等,也可以加一个超时退出,但是超时退出只能解决卡死的问题,并不能解决I2C busy 卡死导致发不出去数据的问题,治标不治本,这一点被别人说的坑死了,网上有人说超时退出可以解决卡死问题,但仅仅只解决了卡死问题,I2C 还是没有工作起来,我们的最终目的是让I2C 工作起来

static void I2C_SendByteDataWaitAck(void)
{
    while (!((uint16_t)(I2C2->SR1) & (uint16_t)(0x0080)) == 0x0080)
    {
    }
    while (!((uint16_t)(I2C2->SR2) & (uint16_t)(0x0007)) == 0x0007)
    {
    }
}

10. OLED 初始化,不同的驱动IC 会有所区别,但是可以先用我这个套用一下试试,我是在STM32L151C8T6 芯片上还跑了FreeRTOS 实时操作系统的

void OLED_Init(void)
{
    delay_xms(20); // oled startup slowly than stm32l151c8t6
    INFO_LOG("[OLED_Init] init start\r\n");

    OLED_SendCmd(0xAE); // display off

    OLED_SendCmd(0x02); // set colum start address
    OLED_SendCmd(0x10); // set colum end address

    OLED_SendCmd(0x40); // set start line (first row)

    OLED_SendCmd(0xB0); // set page address

    OLED_SendCmd(0x81); // set contrast ratio
    OLED_SendCmd(0xCF); // 128

    OLED_SendCmd(0xA1); // set segment remapping, from right to left

    OLED_SendCmd(0xA6); // forward display, normal or reverse

    OLED_SendCmd(0xA8); // multiple reuse rate, multiple ratio
    OLED_SendCmd(0x3F); // duty = 1 / 64

    OLED_SendCmd(0xAD); // set charge pump enable
    OLED_SendCmd(0x8B); // enable DC-DC

    OLED_SendCmd(0x33); // set VPP = 10V

    OLED_SendCmd(0xC8); // set output scan direction, COM[N - 1] to COM[0], COM scan direction

    OLED_SendCmd(0xD3); // set display offset
    OLED_SendCmd(0x00); // 0x00

    OLED_SendCmd(0xD5); // set internal clock frequence, set osc frequency
    OLED_SendCmd(0xC0);

    OLED_SendCmd(0xD9); // set pre-charge period
    OLED_SendCmd(0x1F); // 0x22

    OLED_SendCmd(0xDA); // set COM pins, pin layout
    OLED_SendCmd(0x12);

    OLED_SendCmd(0xDB); // set electrical level, set VCOMH
    OLED_SendCmd(0x40);

    OLED_SendCmd(0xAF); // enable display, display on

    INFO_LOG("[OLED_Init] init complete\r\n");
}

11. OLED 测试函数封装,B 站博主keysking

void OLED_Test(void)
{
    OLED_SendCmd(0xB0); // page 0
    OLED_SendCmd(0x00); // colume 0 low 4-bits
    OLED_SendCmd(0x10); // colume 0 high 8-bits

    OLED_SendCmd(0x40);
    OLED_SendCmd(0xAA);
}

12. 主函数调用OLED 初始化函数和测试函数,先延时一会再初始化,因为STM32 比OLED的控制IC 起来的快很多,CH1116G

int main(void)
{
	delay_xms(1000);
    OLED_Init();
    OLED_Test();
}

13. IIC_Delay 函数

#define IIC_TIMEOUT_COUNTER    0x1000 // iic transmit timeout

static void IIC_Delay(uint32_t delay_time)
{
    uint32_t delayTime;
    for (delayTime = 0; delayTime < delay_time; delayTime++)
    {
    }
}

14. 用逻分仪抓的数据看不出来细节,可以用示波器抓一下波形,看细节,这个波形都变形了,查看原理图,上面接了两个电容,把SCL 和SDA 当成高频信号,给我滤掉了,导致这波形乱七八糟的,直接把原理图上的两个对地电容去掉,或者更好其它容量的电容,我这里是直接去掉了

在这里插入图片描述

15. 接了两个对地电容,把正常信号当成高频滤掉了

在这里插入图片描述

16. 正常波形,应该是这样的,方波才对,正弦波是有问题的,这里还有一个小台阶,待处理

在这里插入图片描述

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

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

相关文章

基于FPGA的ECG心电信号峰值检测和心率计算,包括testbench测试文件和ECG数据转换为coe文件程序

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 vivado2019.2 matlab2022a 3.部分核心程序 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 202…

联想M7600D激光打印机墨粉盒清零方法

粉盒没有墨粉了&#xff0c;加粉后回来安装回打印机里还是会显示请更换墨粉盒&#xff1b;这个时候你就需要将粉盒的计数归一下零&#xff0c;好让机器重新计数&#xff1b;那么怎么清零呢&#xff1f;用什么方法清零呢&#xff1f;在哪里操作呢&#xff1f;下面我就告诉你一个…

Android中的view绘制流程,简单理解

简单理解 Android中的View类代表用户界面中基本的构建块。一个View在屏幕中占据一个矩形区域、并且负责绘制和事件处理。View是所有widgets的基础类&#xff0c;widgets是我们通常用于创建和用户交互的组件&#xff0c;比如按钮、文本输入框等等。子类ViewGroup是所有布局&…

Facebook 广告:如何为移动设备投放广告

图片来源于&#xff1a;SaleSmartly官网 如果您希望目标受众发现并看到您的企业&#xff0c;那么广告是至关重要的&#xff0c;但是哪些是宣传您的品牌的最佳方式呢&#xff1f;当今最常用的平台&#xff08;手机&#xff09;上的广告怎么样&#xff1f;能够回答这些问题很重要…

el-select数据过多的解决(纯前端)

前言 el-select数据过多这个问题应该很多人都遇到过&#xff0c;在生产环境中数据几百、几千条是比较常见的。当数据过多时&#xff0c;就会造成浏览器卡顿&#xff0c;如果客户电脑性能不行&#xff0c;浏览器直接卡死也有可能。 解决 先说一下现在项目中遇到的两种解决方案…

Activiti基础入门

文章目录 Activiti项目搭建引用依赖项Activiti服务初始化数据库配置配置文件测试demo Activiti功能服务RepositoryService&#xff1a;RuntimeService&#xff1a;TaskService&#xff1a;HistoryService&#xff1a;ManagementService&#xff1a;DynamicBpmnService&#xff…

使用【宝塔+docker】在云服务器上部署基于SpringBoot 和 Dubbo RPC 的项目:踩坑记录

待部署的项目包括&#xff1a;前端front&#xff0c;服务提供者backend&#xff0c;服务消费者gateway&#xff0c;注册中心nacos 服务器信息&#xff1a;腾讯云入门级服务器2核2G&#xff08;后续有对服务器进行升级&#xff09; 部署工具&#xff1a;前端使用宝塔部署&#x…

【python】logging报错KeyError: ‘formatters‘

报错 Traceback (most recent call last):File "E:\Python\lib\runpy.py", line 194, in _run_module_as_main return _run_code(code, main_globals, None, File &qu…

免费电脑清理工具:清除垃圾文件,提升性能表现

当电脑使用一段时间后&#xff0c;许多已安装的应用程序、文件或其他项目会在硬盘上积累起来。这会导致电脑运行速度变慢&#xff0c;或Windows提示你硬盘空间不足。在这个时候&#xff0c;你需要使用电脑清理工具来清理电脑。 电脑清理软件为用户提供了一种简单的方法…

【计组】2.3浮点数表示和运算

一、浮点数的表示 浮点数尾数的规格化 注&#xff1a;进行左规和右规仅移动数值位符号位不变 解释&#xff1a;尾数的最高数值位必须是一个有效位即算术意义上的1 规格化应用&#xff08;与双符号位结合&#xff09; 规格化浮点数的特点&#xff1a; 其中首位为符号位&#…

Linux之autofs自动挂载服务

目录 Linux之autofs自动挂载服务 产生原因 安装 配置文件分析 文件路径 作用 etc/auto.master文件内容格式 挂载参数 案例 案例1 --- 服务器创建共享目录&#xff0c;客户端实现自动挂载 案例2 --- 自动挂载光盘 Linux之autofs自动挂载服务 产生原因 在一般NFS文件系…

算法训练营day42|动态规划 part04(01背包问题基础(两种解决方案)、416.分割等和子集)

文章目录 01背包----二维dp数组01背包----滚动数组416.分割等和子集思路分析背包解法思考总结 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最…

第三方软件检测机构资质要求有哪些?专业测试报告如何申请?

科技信息的快速发展使得人们对于软件产品极度依赖&#xff0c;因此要想保障产品质量&#xff0c;测试必不可少。作为一家合格的软件检测机构&#xff0c;应当严格遵守相关资质要求&#xff0c;保证测试报告的专业性和可信度。 一、第三方软件检测机构需要具备的资质 1. 认证资…

Allegro如何通过当前PCB查看env的路径操作指导

Allegro如何通过当前PCB查看env的路径操作指导 在用Allegro做PCB设计的之前,所有的快捷键都需要定义到ENV文件中。在添加env文件之前需要找到env文件的路径,如下图 不同机器定义env路径是不一样的 下面介绍如何找到env路径,具体操作如下 点击Tools选择Utlities

巨额亏损,股价遭受重创,Polestar极星汽车已陷入困境

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 8月31日&#xff0c;由吉利汽车&#xff08;00175&#xff09;和沃尔沃汽车合资创建的瑞典电动汽车公司Polestar极星汽车&#xff08;PSNY&#xff09;公布了2023年第二季度财报。 这家电动汽车公司在去年通过SPAC上市后&am…

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书南京财经大学图书馆

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书南京财经大学图书馆

026:vue中el-progress逆向倒计时方式显示

第026个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

【NKeditor】富文本编辑器上传图片

目录 目的&#xff1a; 效果 实现方法&#xff1a; 1、下载NKeditor插件库 2、部署 3、实现 4、自定义工具栏 目的&#xff1a; 使用NKeditor富文本编辑器上传图片&#xff0c;同时上传到七牛云存储上。后端语言使用ThinkPHP。 效果 实现方法&#xff1a; 1、下载NKe…

【构造】CF Edu 12 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 这种题一定要从小数据入手&#xff0c;不然很有可能走歪思路 先考虑n 1的情况&#xff0c;直接输出即可 然后是n 2的情况&#xff0c;如果相加是质数&#xff0c;就输出2个&#xff0c;否则就输出一个 然后…

使用 【jacoco】对基于 SpringBoot 和 Dubbo RPC 的项目生成测试覆盖率报告:实践+原理

基于 Dubbo RPC 的项目中有一个提供者项目backend、一个消费者项目gateway、以及注册中心nacos。本篇文章记录在windows本地对该框架的测试过程&#xff0c;以及介绍jacoco的基本原理 测试过程 官网下载安装包解压到本地&#xff0c;https://www.jacoco.org/jacoco/ 只需要用…