STC32G12K128内部集成的I2C总线实现oled12864显示

2023-11-10

STC32G 系列的单片机内部集成了一个 I2C 串行总线控制器。I2C 是一种高速同步通讯总线,通讯使用 SCL(时钟线)和 SDA(数据线)两线进行同步通讯。对于 SCL 和 SDA 的端口分,STC32G 系列的单片机提供了切换模式,可将 SCL 和 SDA 切换到不同的 I/O 口上,以方便用户将一组 I2C 总线当作多组进行分时复用。与标准 I2C 协议相比较,忽略了如下两种机制:

 发送起始信号(START)后不进行仲裁
 时钟信号(SCL)停留在低电平时不进行超时检测

STC32G 系列的 I2C 总线提供了两种操作模式:主机模式(SCL 为输出口,发送同步时钟信号)和从机模式(SCL 为输入口,接收同步时钟信号),这里要实现oled12864的显示,所以用到的是主机模式。

如上图所示,要用到的初始化函数为:void    I2C_Init(I2C_InitTypeDef *I2Cx),在主机模式下要对结构体的属性进行设置的只有:I2C_InitStructure.I2C_Mode,I2C_InitStructure.I2C_Enable, I2C_InitStructure.I2C_Speed,I2C_InitStructure.I2C_MS_WDTA,

从stc32g的数据手册知道内部集成的I2C总线功能是有规定引脚的,这里我们选择SCL:P25,SDA:P24:

 所以,我们的I2C初始化函数为:

void	I2C_config(void)
{
	I2C_InitTypeDef		I2C_InitStructure;
	I2C_InitStructure.I2C_Mode      = I2C_Mode_Master;		//主从选择   I2C_Mode_Master, I2C_Mode_Slave
	I2C_InitStructure.I2C_Enable    = ENABLE;							//I2C功能使能,   ENABLE, DISABLE
	I2C_InitStructure.I2C_Speed     = 13;							 		//I2C总线速度,   0~63
	I2C_InitStructure.I2C_MS_WDTA   = DISABLE;							//使能主机自动发送设置,   ENABLE, DISABLE
	I2C_Init(&I2C_InitStructure);
	
	I2C_SW(I2C_P24_P25);					//I2C_P14_P15,I2C_P24_P25,I2C_P76_P77,I2C_P33_P32
}

 接下来看一下官方的库函数中的STC32G_I2C.c文件

//========================================================================
// 函数: u8	Get_MSBusy_Status (void)
// 描述: 获取主机忙碌状态.
// 参数: none.
// 返回: 主机忙碌状态.
// 版本: V1.0, 2012-11-22
//========================================================================
u8 Get_MSBusy_Status(void)
{
	return (I2CMSST & 0x80);
}

//========================================================================
// 函数: void	Wait (void)
// 描述: 等待主机模式I2C控制器执行完成I2CMSCR.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void Wait()
{
	while (!(I2CMSST & 0x40));
	I2CMSST &= ~0x40;
}

//========================================================================
// 函数: void Start (void)
// 描述: I2C总线起始函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Start()
{
	I2CMSCR = 0x01;                         //发送START命令
	Wait();
}

//========================================================================
// 函数: void SendData (char dat)
// 描述: I2C发送一个字节数据函数.
// 参数: 发送的数据.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendData(char dat)
{
	I2CTXD = dat;                           //写数据到数据缓冲区
	I2CMSCR = 0x02;                         //发送SEND命令
	Wait();
}

//========================================================================
// 函数: void RecvACK (void)
// 描述: I2C获取ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void RecvACK()
{
	I2CMSCR = 0x03;                         //发送读ACK命令
	Wait();
}

//========================================================================
// 函数: char RecvData (void)
// 描述: I2C读取一个字节数据函数.
// 参数: none.
// 返回: 读取数据.
// 版本: V1.0, 2020-09-15
//========================================================================
char RecvData()
{
	I2CMSCR = 0x04;                         //发送RECV命令
	Wait();
	return I2CRXD;
}

//========================================================================
// 函数: void SendACK (void)
// 描述: I2C发送ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendACK()
{
	I2CMSST = 0x00;                         //设置ACK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	Wait();
}

//========================================================================
// 函数: void SendNAK (void)
// 描述: I2C发送NAK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendNAK()
{
	I2CMSST = 0x01;                         //设置NAK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	Wait();
}

//========================================================================
// 函数: void Stop (void)
// 描述: I2C总线停止函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Stop()
{
	I2CMSCR = 0x06;                         //发送STOP命令
	Wait();
}

//========================================================================
// 函数: void SendCmdData (u8 cmd, u8 dat)
// 描述: I2C发送一个字节数据函数.
// 参数: 命令/数据.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendCmdData(u8 cmd, u8 dat)
{
	I2CTXD = dat;                           //写数据到数据缓冲区
	I2CMSCR = cmd;                          //设置命令
	Wait();
}

//========================================================================
// 函数: void	I2C_WriteNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C写入数据函数.
// 参数: addr: 指定地址, *p写入数据存储位置, number写入数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void I2C_WriteNbyte(u8 addr, u8 *p, u8 number)  /*  WordAddress,First Data Address,Byte lenth   */
{
	Start();                                //发送起始命令
	SendData(SLAW);                         //发送设备地址+写命令
	RecvACK();
	SendData(addr);                         //发送存储地址
	RecvACK();
	do
	{
		SendData(*p++);
		RecvACK();
	}
	while(--number);
	Stop();                                 //发送停止命令
}

//========================================================================
// 函数: void	I2C_ReadNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C读取数据函数.
// 参数: addr: 指定地址, *p读取数据存储位置, number读取数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void I2C_ReadNbyte(u8 addr, u8 *p, u8 number)   /*  WordAddress,First Data Address,Byte lenth   */
{
	Start();                                //发送起始命令
	SendData(SLAW);                         //发送设备地址+写命令
	RecvACK();
	SendData(addr);                         //发送存储地址
	RecvACK();
	Start();                                //发送起始命令
	SendData(SLAR);                         //发送设备地址+读命令
	RecvACK();
	do
	{
		*p = RecvData();
		p++;
		if(number != 1) SendACK();          //send ACK
	}
	while(--number);
	SendNAK();                              //send no ACK	
	Stop();                                 //发送停止命令
}

 这个文件中有我们所熟知的I2C通信所必须的Wait(),Start(),Senddata()等的函数,它们的用法用过I2C通信的相信都知道了,但在STC32G_I2C.h这个头文件中只包含了以下几个函数的声明:

void	I2C_Init(I2C_InitTypeDef *I2Cx);
void	I2C_WriteNbyte(u8 addr, u8 *p, u8 number);
void	I2C_ReadNbyte( u8 addr, u8 *p, u8 number);
u8 Get_MSBusy_Status(void);
void SendCmdData(u8 dat, u8 cmd);

所以我们使用I2C总线有两种方法,第一种是把所有函数的声明都添加到头文件中,这样就可以调用Wait(),Start(),Senddata()等函数;第二种方法是用头文件中给的函数,也就是I2C_WriteNbyte(u8 addr, u8 *p, u8 number)这个函数。这里我们详细讲第二种方法,I2C_WriteNbyte()这个函数需要输入三个参数,u8 addr, u8 *p, u8 number,这里指定地址我们可以理解为对oled是进行写数据操纵还是写命令操作,所以输入时输入以下两个中一个就行:

#define OLED_CMD  0x00	//写命令
#define OLED_DATA 0x40	//写数据

p为要输入数据或命令的指针,可以一次输入多个数据,number为数据数。这里还有一点要注意的:SLAW的宏定义需要修改如下:

#define SLAW    0x78

然后就可以移植中景园的oled51例程,需要修改的只有OLED_WR_Byte()这一函数:

void OLED_WR_Byte(u8 dat,u8 mode)
{
	#if 0
	Start();
	SendData(0x78);
	RecvACK();
	SendData(mode);
	RecvACK();
	SendData(dat);
	SendNAK();
	Stop();
	
	#else
	I2C_WriteNbyte(mode,&dat,1);
	
	#endif
	
}

然后就可以显示啦

 还有两点要注意的是,这里的memory mode 需要修改一下:

原因可能是库函数中定义的常量太多导致无法显示,修改后就可正常显示。而另一个问题是我发现在单独显示字符串,也就是在主函数中只调用OLED_ShowString()这一函数时oled无法显示,并且好像连单片机都无法正常使用,有大神路过的话希望能帮忙解惑一下。 

同样的,项目我放在主页资源上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STC32G12K128内部集成的I2C总线实现oled12864显示 的相关文章

  • FileOutputStream的基本使用

    package com wondream myframework app basictest io import org apache commons logging Log import org apache commons loggin
  • Flutter插件介绍以及常用插件推荐

    Flutter插件 Flutter使用的Dart语言无法直接调用Android系统提供的Java接口 这时就需要使用插件来实现中转 Flutter官方提供了丰富的原生接口封装 android alarm manager 访问Android系
  • Qt Assistant介绍

    简介 Qt Assistant也就是我们常说的Qt助手 是一款用于呈现在线文档的工具 简介 一分钟学会使用 Qt参考文档 Qt Assistant详解 命令行选项 工具窗口 文档窗口 工具栏 菜单 文件菜单 编辑菜单 查看菜单 前往菜单 书
  • Mac M1 mysql安装指南

    https segmentfault com a 1190000020656076111 https zhuanlan zhihu com p 360858309 看这两篇足够了
  • ES6如何声明一个类?类如何继承?

    在 JavaScript 中 您可以使用关键字 class 来声明一个类 类是一种模板 用于创建对象的构造函数 其中包含了属性和方法 以下是声明一个类的基本语法 class ClassName constructor 构造函数 用于创建对象
  • CSDN湘苗培优,遇见更好的自己

    现在 只要你是IT技术爱好者 想要高起点步入职场 快人一步不是梦 湘苗培优 你不容错过 点击蓝色的 湘苗培优 小编带你深入了解如何实现它
  • 深度特征融合---理解add和concat之多层特征融合

    一 如何理解concat和add的方式融合特征 在各个网络模型中 ResNet FPN等采用的element wise add来融合特征 而DenseNet等则采用concat来融合特征 那add与concat形式有什么不同呢 事实上两者都
  • iOS15适配 UINavigationBar和UITabBar设置无效,变成黑色以及uiscrollview为根试图无法到顶

    今天更新了xcode13 运行项目发现iOS15以上的手机导航栏和状态栏之前设置的颜色等属性都不起作用了 都变成了黑色 滚动的时候才能变成正常的颜色 经确认得用UINavigationBarAppearance和UITabBarAppear
  • tms sparkle实现apk下载安装。

    缘起 存放在pc端的apk 如何下载到手机端并安装 一种是通过IM通讯工具 或是复制到u盘上 或是ftp下载 还有就是通过云盘安装 但是以上方法都不是非常方便 思路 下面介绍一种思路 将apk文件存放在pc端的某一路径下 然后生成html文
  • 个人笔记篇-SpringBoot集成Socket

    前言 在我的另一篇文章中 有简单介绍过Socket的相关概念链接 SpringBoot简单集成WebSocket 初步了解后 本次再进行一个深入通俗的理解 Socket作为一种通信机制 通常也被称为 套接字 它类似于人们之间的 打电话行为

随机推荐

  • golang学习笔记

    目录 golang学习笔记 golang知识点 go打开本地文档方法 fmt 打印占位符特殊作用 slice本质 strings包 Stringer Interface golang学习笔记 go官方学习内容是最好最权威的入门go语言的资料
  • 2021最新Java笔试题及答案,Java面试真题精选

    二 回顾整理阿里面试题 基本就这样了 还有一些零星的问题想不起来了 答案也整理出来了 自我介绍 JVM如何加载一个类的过程 双亲委派模型中有哪些方法 HashMap如何实现的 HashMap和ConcurrentHashMap区别 Conc
  • 【安全开发】python—基于正则表达式的爬虫

    0x00 前置 1 搜索引擎 百度 谷歌 企业内部知识库 2 互联网 公网 无需授权 深网 需要授权 暗网 非正式渠道 无法使用常规手段访问 友情提醒 没事别看 3 规则 爬取互联网公开的信息 但正常情况也需要遵守robots协议 网络爬虫
  • 【华为OD机试 2023 B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • Qt Graphics View Framework 图形视图框架

    QT的2D绘图我们使用QPainter实现少量绘图是很理想的 但是如果是要绘制大量的2D图形并且需要能够控制管理时就会显得力不从心 好在QT视图体系提供了QGraphics View Framework的框架 使用这个框架可以将各图形项进行
  • MySQL 8.0用户管理

    1 禁止root用户远程访问 1 在安装MySQL数据库软件时 我们已经设置了禁止root远程登录 参见 https blog csdn net chengyuqiang article details 121282247 2 root用户
  • Kubernetes (k8s 1.23) 安装与卸载

    镜像下载 域名解析 时间同步请点击 阿里云开源镜像站 请注意k8s在1 24版本不支持docker容器 本文使用kubeadm进行搭建 1 查看系统版本信息以及修改配置信息 1 1 安装k8s时 临时关闭swap 如果不关闭在执行kubea
  • MySQL的sum函数优化

    有一张表 结构如下 Field Type Null Key Default Extra ID bigint 20 NO PRI NULL auto increment
  • 51单片机开发问题之不能直接对端口管脚输出高低点电平

    在做51单片机点亮一个了led的时候遇到一个问题 不能直接用P0 0 0 对单片机管脚输出高低电平 Keil编译器会报错 如图 用sbit定义一个变量来控制管脚就行
  • 网络安全学习路线是怎样的?从入门到入坟,看这篇就够了

    为什么要学习安全 近几年网络安全事件层出不穷 相信大家哪怕没遇到过 但也听过不少了吧 如服务器遭受入侵被黑 用户帐号被盗 被钓鱼 勒索病毒等 这些一旦发生 对企业而言都是不小的打击 因此 网络安全不容忽视 同时随着时代的不断发展 公司对于运
  • DOM0和DOM2

    DOM事件绑定 DOM0级事件 特点 所有的浏览器都支持 事件只能注册一次 后面的会覆盖旧的 注册方式 1 在html上添加 div div 其中this指向自身 2 匿名函数d nclick function 其中 this 指向自身 3
  • 美国科技大佬成功之前混得都有多惨

    摘要 超过三分之一在美国成立的顶尖高科技公司是由在国外出生的人创立的 他们的成功经验带动许多移民来到美国实现美国梦的希望 id cproIframe u1503021 2 width 250 height 250 src http pos
  • 使用DBN实现风速预测matlab代码

    使用DBN实现风速预测matlab代码 风速预测在实际生产生活中有着广泛的应用 对于风电场 农业灌溉 城市规划等领域都有着重要的意义 本文将介绍如何使用深度信念网络 Deep Belief Networks DBN 来实现风速预测 并提供相
  • Mysql数据库的导入和导出

    Mysql数据库的导入和导出 1 导入 2 导出 Mysql数据库的可移植性是比较好的 在命令行状态下可用仅仅一行的代码就实现数据库的导入和导出 不论是在Windows操作系统还是Linux操作系统下的命令行 命令基本上完全一致 1 导入
  • QT主窗口与子窗口互相传值笔记

    1 主窗口向子窗口传值 将子窗口定义为主窗口的成员变量 在子窗口中定义接受数据的成员变量 主窗口中可以使用子窗口成员变量来访问他的成员变量 于是就能直接赋值了 void Main wgt test son wgt num 18 2 子窗口向
  • PAT 1015 德才论 (25分) C语言实现

    1015 德才论 25分 宋代史学家司马光在 资治通鉴 中有一段著名的 德才论 是故才德全尽谓之圣人 才德兼亡谓之愚人 德胜才谓之君子 才胜德谓之小人 凡取人之术 苟不得圣人 君子而与之 与其得小人 不若得愚人 现给出一批考生的德才分数 请
  • 将文件或目录移动到另外的目录

    File or directory to be moved File file new File filename Destination directory File dir new File directoryname Move fil
  • Flutter编译卡在Running Gradle task ‘assembleDebug‘

    为什么卡在这一步 把网络断开 发现了问题 卡在了下载运行环境和依赖库的步骤 jcenter 下载速度太慢 知道原因就好办了 需要修改3个地方 1 首先找到fultter sdk所在文件夹的位置 依次进入 flutter packages f
  • 单端口RAM实现FIFO

    RAM分类 单口ram 单端口RAM只有一组数据线和一组地址线 只有一个时钟 读写共用地址线 输出只有一个端口 所以单端口RAM的读写操作不能同时进行 当wea拉高时 会将数据写入对应的地址 同时douta输出的数据与此时写入的数据是一致的
  • STC32G12K128内部集成的I2C总线实现oled12864显示

    STC32G 系列的单片机内部集成了一个 I2C 串行总线控制器 I2C 是一种高速同步通讯总线 通讯使用 SCL 时钟线 和 SDA 数据线 两线进行同步通讯 对于 SCL 和 SDA 的端口分 STC32G 系列的单片机提供了切换模式