当前位置: 首页 > news >正文

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

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_PPGPIO_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 - PB11GPIO_ResetBits(GPIOB, GPIO_Pin_11);delay_xms(20);GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2); // set PB10 as IIC2 SCLGPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2); // set PB11 as IIC2 SDAI2C_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 KhzI2C_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 addressI2C_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 signalIIC_SendStartSignal_CheckEvent();I2C_Send7bitAddress(I2C2, OLED_ADDRESS, I2C_Direction_Transmitter); // send device addr and write bitI2C_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_CmdI2C_SendByteDataWaitAck();IIC_Delay(IIC_TIMEOUT_COUNTER);I2C_SendData(I2C2, mode); // 0x00, low 8-bits, cmd codeI2C_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 stm32l151c8t6INFO_LOG("[OLED_Init] init start\r\n");OLED_SendCmd(0xAE); // display offOLED_SendCmd(0x02); // set colum start addressOLED_SendCmd(0x10); // set colum end addressOLED_SendCmd(0x40); // set start line (first row)OLED_SendCmd(0xB0); // set page addressOLED_SendCmd(0x81); // set contrast ratioOLED_SendCmd(0xCF); // 128OLED_SendCmd(0xA1); // set segment remapping, from right to leftOLED_SendCmd(0xA6); // forward display, normal or reverseOLED_SendCmd(0xA8); // multiple reuse rate, multiple ratioOLED_SendCmd(0x3F); // duty = 1 / 64OLED_SendCmd(0xAD); // set charge pump enableOLED_SendCmd(0x8B); // enable DC-DCOLED_SendCmd(0x33); // set VPP = 10VOLED_SendCmd(0xC8); // set output scan direction, COM[N - 1] to COM[0], COM scan directionOLED_SendCmd(0xD3); // set display offsetOLED_SendCmd(0x00); // 0x00OLED_SendCmd(0xD5); // set internal clock frequence, set osc frequencyOLED_SendCmd(0xC0);OLED_SendCmd(0xD9); // set pre-charge periodOLED_SendCmd(0x1F); // 0x22OLED_SendCmd(0xDA); // set COM pins, pin layoutOLED_SendCmd(0x12);OLED_SendCmd(0xDB); // set electrical level, set VCOMHOLED_SendCmd(0x40);OLED_SendCmd(0xAF); // enable display, display onINFO_LOG("[OLED_Init] init complete\r\n");
}

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

void OLED_Test(void)
{OLED_SendCmd(0xB0); // page 0OLED_SendCmd(0x00); // colume 0 low 4-bitsOLED_SendCmd(0x10); // colume 0 high 8-bitsOLED_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 timeoutstatic void IIC_Delay(uint32_t delay_time)
{uint32_t delayTime;for (delayTime = 0; delayTime < delay_time; delayTime++){}
}

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

相关文章:

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

1. STM32L151C8T6 硬件IIC 控制OLED 屏&#xff0c;OLED 驱动IC CH1116G, 查阅OLED 数据手册 2. STM32 硬件IIC 初始化&#xff0c;用的标准库&#xff0c;固件库 // stm32l151c8t6 as master, oled control ic (CH1116G) as slave, and communicate by master iic2 void STM3…...

Redis图文指南

1、什么是 Redis&#xff1f; Redis&#xff08;REmote DIctionary Service&#xff09;是一个开源的键值对数据库服务器。 Redis 更准确的描述是一个数据结构服务器。Redis 的这种特殊性质让它在开发人员中很受欢迎。 Redis不是通过迭代或者排序方式处理数据&#xff0c;而是…...

C++17 std::string_view介绍与使用

std::string_view介绍 std::string_view是C17增加的新内容。它是一个轻量级的、只读的字符串视图&#xff0c;可以用来表示一个字符串或字符串的一部分。std::string_view可以提高代码的可读性、可维护性和性能。 std::string_view与std::string的主要区别在于&#xff0c;st…...

写得了代码,焊得了板!嵌入式开发工程师必修之代码管理方案(下)

目录 极狐GitLab嵌入式开发场景解决方案 3.1 高可用部署与灾备 3.2 组织管理 3.3 分支策略 3.4 分支保护 3.5 推送规则 3.6 代码评审 3.7 数据保护 3.8 其他相关 本文来自 武让 极狐GitLab 高级解决方案架构师 &#x1f4a1; 前两篇文章&#xff0c;作者介绍了嵌入式开…...

Matlab论文插图绘制模板第110期—水平双向柱状图

在之前的文章中&#xff0c;分享了很多Matlab柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来看一种特殊的柱状图&#xff1a;水平双向柱状图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下…...

【广州华锐互动】VR全景工厂虚拟导览,虚拟现实技术提升企业数字化信息管理水平

随着工业4.0的到来&#xff0c;VR工厂全景制作成为了越来越多工业企业的选择。传统的工厂管理方式往往存在诸多问题&#xff0c;如信息不对称、安全隐患等。为了解决这些问题&#xff0c;VR工厂全景制作应运而生&#xff0c;它通过结合虚拟现实现实技术和数据采集技术&#xff…...

idea 创建mybatis xml文件时找不到

1、File >Settings 如图 &#xff1a; 2、添加模板&#xff1a;如下图 3、添加xml模板 如下图&#xff1a; 模板内容&#xff1a; <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//E…...

Python钢筋混凝土结构计算.pdf-混凝土构件计算

计算原理&#xff1a; 代码实现&#xff1a; #钢筋混凝土参数 def c_hrb(): global fcuk,HRB,Ec,fc,ft,ftk,Es,fy,fyp,fyk global a1,epsilon_cu fcukEcfcftftk0.0 HRBEsfyfypfyk0.0 #矩形应力图系数a1&#xff0c;C50以下为1.0 a11.0 #正截面混凝土极限压应变epsilon_cu&#…...

mysql5.7-基于docker-compose搭建主从同步

一、环境信息 系统版本&#xff1a;CentOS Linux release 7.9.2009 (Core) cat /etc/centos-release Docker版本&#xff1a;Docker version 20.10.6, build 370c289 docker --version Docker-compose版本&#xff1a;Docker Compose version v2.10.2 docker-compose --versio…...

【USRP】调制解调系列5:16QAM、32QAM、64QAM、256QAM、1024QAM、基于labview的实现

QAM 正交振幅键控是一种将两种调幅信号&#xff08;2ASK和2PSK&#xff09;汇合到一个信道的方法&#xff0c;因此会双倍扩展有效带宽&#xff0c;正交调幅被用于脉冲调幅。正交调幅信号有两个相同频率的载波&#xff0c;但是相位相差90度&#xff08;四分之一周期&#xff0c…...

Odoo|5分钟创建自定义的业务系统唯一序列号

在业务操作中&#xff0c;经常会遇到需要生成全局唯一序列号数据的情况&#xff0c;比如订单号、报价单号等。为了确保数据的唯一性和准确性&#xff0c;通常我们会使用Redis或其他分布式锁机制来实现。然而&#xff0c;很多人可能不知道&#xff0c;odoo框架本身提供了一个原生…...

mysql索引为什么提高查询速度(底层原理)

一、索引原理图 二、索引数据存储到硬盘而不是内存&#xff1f; 硬盘内存 成本低成本高 容量大容量小 读写速度一般读取速度快 断电后数据永久存储断电后数据清空 三、硬盘数据为什么要读取到内存&#xff1f;为啥不直接…...

算法通关村——位运算在查找重复元素中的妙用

用4KB内存寻找重复元素 给定一个数组&#xff0c;包含从1到N的整数&#xff0c;N最大为32000&#xff0c;数组可能还有重复值&#xff0c;且N的取值不定&#xff0c;若只有4KB的内存可用&#xff0c;该如何打印数组中所有重复元素。 如果不要求使用4KB&#xff0c;最简单就是…...

使用环境中的视觉地标和扩展卡尔曼滤波器定位移动机器人研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【python基础知识】5.for循环和while循环

文章目录 前言for...in...循环语句for循环&#xff1a;空房间for循环&#xff1a;一群排队办业务的人range()函数for循环&#xff1a;办事流程 while循环while循环&#xff1a;放行条件while循环&#xff1a;办事流程 两种循环对比 前言 上一关&#xff0c;我们学习了两种新的…...

STM32CUBEMX_创建时间片轮询架构的软件框架

STM32CUBEMX_创建时间片轮询架构的软件框架 说明&#xff1a; 1、这种架构避免在更新STM32CUBEMX配置后把用户代码清除掉 2、利用这种时间片的架构可以使得代码架构清晰易于维护 创建步骤&#xff1a; 1、使用STM32CUBEMX创建基础工程 2、新建用户代码目录 3、构建基础的代码框…...

vue 插槽Slots

vue插槽官网 <button class"fancy-btn"><slot></slot> <!-- 插槽出口 --> </button><slot> 元素是一个插槽出口 (slot outlet)&#xff0c;标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。 // 定义一个Child.vue…...

论文阅读《Nougat:Neural Optical Understanding for Academic Documents》

摘要 科学知识主要存储在书籍和科学期刊中&#xff0c;通常以PDF的形式。然而PDF格式会导致语义信息的损失&#xff0c;特别是对于数学表达式。我们提出了Nougat&#xff0c;这是一种视觉transformer模型&#xff0c;它执行OCR任务&#xff0c;用于将科学文档处理成标记语言&a…...

较难的换根dp:P6213 「SWTR-04」Collecting Coins

传送门 前题提要:感觉这道换根dp可以说是集中了换根dp的所有较高难度的操作和思想,以及较高的一些实现细节,可以说能够完全写出这道题才叫真正理解了换根dp,非常值得一做. 首先读完题意,不难发现这道题有很多限制.点的访问次数限制,必须访问某一个点,想要获得最大的贡献,没有…...

Springboot - 15.二级分布式缓存集成-Caffeine

&#x1f440;中文文档 Caffeine &#x1f440;使用Caffeine &#xff08;本地缓存&#xff09; 当与Spring Boot结合使用时&#xff0c;Caffeine提供了一个直观且功能强大的二级缓存解决方案。Spring Boot的缓存抽象使得整合Caffeine变得相当简单。以下是如何在Spring Boot…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

如何做好一份技术文档?从规划到实践的完整指南

如何做好一份技术文档&#xff1f;从规划到实践的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...

21-Oracle 23 ai-Automatic SQL Plan Management(SPM)

小伙伴们&#xff0c;有没有迁移数据库完毕后或是突然某一天在同一个实例上同样的SQL&#xff0c; 性能不一样了、业务反馈卡顿、业务超时等各种匪夷所思的现状。 于是SPM定位开始&#xff0c;OCM考试中SPM必考。 其他的AWR、ASH、SQLHC、SQLT、SQL profile等换作下一个话题…...

代理服务器-LVS的3种模式与调度算法

作者介绍&#xff1a;简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们上一章介绍了Web服务器&#xff0c;其中以Nginx为主&#xff0c;本章我们来讲解几个代理软件&#xff1a…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术点解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术点解析 第一轮&#xff1a;基础概念问题 请解释Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; 程序员JY回答&#xff1a;Spring框架的核心容器是IoC容器&#xff08;控制反转…...

【立体匹配】:双目立体匹配SGBM:(1)运行

注&#xff1a;这是一个专题&#xff0c;我会一步步介绍SGBM的实现&#xff0c;按照我的使用和优化过程逐步改善算法&#xff0c;附带实现方法 系列文章【立体匹配】&#xff1a;双目立体匹配SGBM&#xff1a;&#xff08;1&#xff09;运行 【立体匹配】&#xff1a;双目立体匹…...

【Unity】R3 CSharp 响应式编程 - 使用篇(二)

一、通用的事件监听用法 using System;using R3;using UnityEngine;namespace Aladdin.Standard.Observable.Common{public class CommonObservable : MonoBehaviour{// 默认会调用1次public SerializableReactiveProperty<int> serializableReactiveProperty;…...

Elasticsearch中的监控(Monitoring)功能介绍

Elasticsearch 的 监控&#xff08;Monitoring&#xff09; 功能用于实时跟踪集群的运行状态、性能指标和资源使用情况&#xff0c;帮助管理员及时发现潜在问题、优化配置并确保集群稳定高效运行。它通过内置工具和集成方案&#xff0c;提供从节点到集群、从硬件到服务层的全方…...