IIC 通信协议之stm32 驱动OLED

前言

    使用stm32 驱动4 Pin 的OLED, 现在网上开源的资料多的是,但是为了锻炼自己使用第一手资料的能力,今天我还是从数据手册开始,从头造一波轮子,同时也是为了加深自己对 IIC 协议的理解 ,本系列内容我会从单片机和linux两个板子做一些OLED的 验证,希望后面大家在学习IIC 相关内容的时候,可以少走一些弯路。为了大家学习方面,这些文章也会在我的微信公众号同步,方便大家随时查看,欢迎大家扫码关注。

在这里插入图片描述

1. 查阅数据手册

   在我们实际工作中,需要我们从头造轮子的机会其实并不多,但是作为搞嵌入式这个行业的,阅读一些简单的数据手册的能力还是要有的,万一碰到碰到一个比较棘手的问题,说不定就需要我们不得不去看芯片的参考手册了。本篇我就以4Pin 的OLED 使用的SSD1306为例,通过stm32 实现对他的驱动。

  我们 打开他的数据手册,首先不要被全英文的吓到了,现在网上各种的翻译软件都比较给力。再说了,这个手册其实并不需要从头到尾一字不落的读完,首先我们看一下芯片的简单说明,了解芯片的大致的特性。
  
  其次:根据自己选择的芯片,使用的通讯方式,着重去看相对应的章节,比如我们本次使用的就是4 Pin的 IIC通信的,所以我们直接去找参考手册中介绍IIC 的.

在这里插入图片描述
a. IIC 从机地址是有SA0 决定的,并且R/W# 决定是读取数据还是写入数据。R/W# = 0 为写模式,R/W# = 1 为读数据。

IIC 通信协议:
在这里插入图片描述
S 信号 和 P 信号:
在这里插入图片描述
ACK 信号 和NAck 信号:
在这里插入图片描述
数据传输的时候要保证SDA 总线上数据稳定:
在这里插入图片描述
发送数据还是命令室友D/C# 引脚决定的: D/C# = 1 发送data , D/C# = 0 发送的是命令;

在这里插入图片描述

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

在这里插入图片描述

SSD 1306 显存大小: 128列 * 64行

在这里插入图片描述
如果要驱动SSD1306 首先要实现IIC 总线的驱动代码,即IIC 协议的实现,如果使用的是stm32单片机 来驱动的话,其实可以直接使用硬件IIC,当然了软件IIC也是可以的,本篇我们就先以软件模拟IIC来驱动他。

2. 软件模拟IIC 实现

2.1

#define SCL_Pin GPIO_Pin_6
#define SDA_Pin GPIO_Pin_7
#define IIC_GPIO_Port GPIOB


#define OLED_SCLK_LOW   GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define OLED_SCLK_HIGH  GPIO_SetBits(GPIOB,GPIO_Pin_6)
#define OLED_SDA_LOW    GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define OLED_SDA_HIGH   GPIO_SetBits(GPIOB,GPIO_Pin_7)

void OLED_Config(void)
{              
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); 
     
  GPIO_InitStructure.GPIO_Pin = SCL_Pin|SDA_Pin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(IIC_GPIO_Port, &GPIO_InitStructure);
}

/*IIC  起始信号*/
void i2c_start()
{
    OLED_SCLK_HIGH;

    OLED_SDA_HIGH;
    OLED_SDA_LOW;

    OLED_SCLK_LOW;
}

/*IIC 停止信号*/
void i2c_stop()
{
    OLED_SCLK_HIGH;

    OLED_SDA_LOW;
    OLED_SDA_HIGH;
    
}

/*等待应答:提供一个scl 时钟周期*/
void i2c_wait_ack(void)
{
    OLED_SCLK_HIGH;
    OLED_SCLK_LOW;
}

void Write_IIC_Byte(unsigned char IIC_Byte)
{
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_LOW;
	for(i=0;i<8;i++)		
	{
		m=da;
		m=m&0x80;
		if(m==0x80)
		{
			OLED_SDA_HIGH;
		}
		else 
			OLED_SDA_LOW;
		da=da<<1;
		OLED_SCLK_HIGH;
		OLED_SCLK_LOW;
	}
}

/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
	i2c_start();
	Write_IIC_Byte(0x78);       //Slave address,SA0=0
	i2c_wait_ack();	
	Write_IIC_Byte(0x00);		//write command
	i2c_wait_ack();	
	Write_IIC_Byte(IIC_Command); 
	i2c_wait_ack();	
	i2c_stop();
}

/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
	i2c_start();
	Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
	i2c_wait_ack();	
	Write_IIC_Byte(0x40);			//write data
	i2c_wait_ack();	
	Write_IIC_Byte(IIC_Data);
	i2c_wait_ack();	
	i2c_stop();
}

void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
	{
		Write_IIC_Data(dat);
	}
	else 
	{
		Write_IIC_Command(dat);	
	}
}

3. OLED 设备驱动程序


void OLED_Init(void)
{ 
 	OLED_Config();
 	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);	

	delay_ms(100);
	OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
}  


void OLED_Set_Pos(unsigned char x, unsigned char y)
{
	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xF0) >> 4)|0x10, OLED_CMD);
	OLED_WR_Byte( (x&0x0F), OLED_CMD);
}

void OLED_Display_On(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);  //设置电荷泵
	OLED_WR_Byte(0x14,OLED_CMD);  //开启电荷泵
	OLED_WR_Byte(0xAF,OLED_CMD);  //OLED唤醒
}

void OLED_Display_Off(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);	//设置电荷泵
	OLED_WR_Byte(0x10,OLED_CMD);    //关闭电荷泵
	OLED_WR_Byte(0xAE,OLED_CMD);    //关闭屏幕显示
}
				    
void OLED_Clear(void)
{
	u8 i = 0, n = 0; 
	
	for(i = 0; i < 8; i++)
	{
		OLED_WR_Byte(0xb0+i,OLED_CMD);	//设置页地址
		OLED_WR_Byte(0x00,OLED_CMD);    // 设置显示位置-列低地址
		OLED_WR_Byte(0x10,OLED_CMD);    // 设置显示位置-列高地址
		for(n = 0; n < 128; n++) OLED_WR_Byte(0,OLED_DATA);
	}
}


void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_size)
{
	unsigned char c = 0, i = 0;
	c = chr - ' ';
	
	if(x > 128 - 1)
	{
		x = 0;
		y += 2;
	}
	
	if(Char_size == 8)
	{
	    OLED_Set_Pos(x,y);
		for(i = 0; i < 8; i++)
		 OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);		//显示低字节
		
		OLED_Set_Pos(x,y+1);
		for(i = 0; i < 8; i++ )
		  OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);   //显示高字节
	}
	else 
	{
		 字体为6号
		OLED_Set_Pos(x,y);
		for(i=0;i<6;i++)
			OLED_WR_Byte(F6x8[c][i],OLED_DATA);
	}
}

void OLED_ShowString(u8 x, u8 y,u8* chr, u8 Char_size)
{
	while(*chr != '\0')
	{
		OLED_ShowChar(x,y,*chr, Char_size);
		x+=Char_size;
		
		if(x > 120)
		{
			x = 0;
			y += 2;
		}	
		chr++;
	}
}


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring总结】注解开发

本篇讲的内容主要是基于Spring v2.5的注解来完成bean的定义 之前都是使用纯配置的方式来定义的bean 文章目录 前言1. Spring v2.5 注解开发定义bean第一步&#xff1a;在需要定义的类上写上注解Component第二步&#xff1a;在Spring Config中定义扫描包第三步&#xff1a;主方法…

关于链表的几道算法题

1.删除链表的倒数第n个节点 力扣https://leetcode.cn/submissions/detail/482739445/ /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(…

第八部分:JSP

目录 JSP概述 8.1&#xff1a;什么是JSP&#xff0c;它有什么作用&#xff1f; 8.2&#xff1a;JSP的本质是什么&#xff1f; 8.3&#xff1a;JSP的三种语法 8.3.1&#xff1a;jsp头部的page指令 8.3.2&#xff1a;jsp中的常用脚本 ①声明脚本&#xff08;极少使用&#xf…

单链表在线OJ题(详解+图解)

1.删除链表中等于给定值 val 的所有节点 本题的要求是输入一个val的整形值&#xff0c;若链表中节点存储的值与val相等&#xff0c;则删除这个节点&#xff0c;并最后返回这个删除节点后的链表&#xff0c;思路如下&#xff1a; 我们可以直接使用while循环&#xff0c;并且使用…

青少年CTF-WEB-2048

题目环境&#xff1a; 针对这种游戏通关类题目&#xff0c;常见的有两种情况 一、有参数改参数的数值达到题目规定的分数即可拿到flag 二、没有参数那么flag就是被编码了&#xff0c;找编码即可 这道题并没有说题目通关即可获得flag&#xff0c;也并没有发现参数 所以这里猜测f…

HFSS螺旋线圈的设计与仿真

HFSS螺旋线圈的设计与仿真 HFSS中设计螺旋线圈的方法&#xff1a;参考文献&#xff1a; HFSS中设计螺旋线圈的方法&#xff1a; 打开软件Ansys Eletronics Desktop 2022 R1&#xff0c; 建立工程&#xff0c; File/New 插入HFSS设计&#xff0c; Project/Insert HFSS Design …

基于瞬态优化算法优化概率神经网络PNN的分类预测 - 附代码

基于瞬态优化算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于瞬态优化算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于瞬态优化优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

数据结构——树状数组

文章目录 前言问题引入问题分析树状数组lowbit树状数组特性初始化一个树状数组更新操作前缀和计算区间查询 总结 前言 原题的连接 最近刷leetcode的每日一题的时候&#xff0c;遇到了一个区间查询的问题&#xff0c;使用了一种特殊的数据结构树状数组&#xff0c;学习完之后我…

RobotFramework之用例执行时添加命令行参数(十三)

学习目录 引言 标签tag 设置变量 随机执行顺序 设置监听器 输出日志目录和文件 引言 Robot Framework 提供了许多命令行选项&#xff0c;可用于控制测试用例的执行方式以及生成的输出。本节介绍一些常用的选项语法。 标签tag 之前文章我们介绍过&#xff0c;在测试套件…

基于STC12C5A60S2系列1T 8051单片的模数芯片ADC0809实现模数转换应用

基于STC12C5A60S2系列1T 8051单片的模数芯片ADC0809实现模数转换应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍模数芯片ADC0809介绍通过模数芯片ADC0809把电压模…

基于灰色神经网络的预测算法——订单需求预测

大家好&#xff0c;我是带我去滑雪&#xff01; 灰色系统理论的不确定性处理与神经网络的非线性建模相结合&#xff0c;有望更好地处理实际问题中的不确定性和复杂性。本期使用灰色神经网络实现预测冰箱订单需求。 一、问题背景与模型建立 &#xff08;1&#xff09;灰色理论…

中国制库:创新引领,效率突破,塑造行业新标准

制库是一家专注于企业知识应用的在线SAAS平台,主要构成部分包括制度、表单、流程、制问和集合。作为集合了各种管理制度的平台,制库不仅提供了丰富的制度资源,还通过SAAS版实现了知识集成、修订和应用的全流程。目标是打造中国全面的企业制度库,帮助企业快速建立核心管理系统,并…

ON1 Photo RAW MAX 2024 v18.0.4.14758

ON1 Photo RAW MAX 2024 for mac是一款专业的raw照片编辑软件&#xff0c;提供了各种各样的编辑工具&#xff0c;包括调整曝光、对比度、色彩、锐化、裁剪、旋转和去除红眼等功能&#xff0c;用户可以根据具体需求对照片进行精确的调整。ON1 Photo RAW MAX 2024还提供了智能修复…

98.qt qml-使用曲线图综合示例、支持多种鼠标交互、支持百万数据显示(已适配黑白风格)

在上章我们只是简单实现了曲线图和折线图的显示: 79.qt qml-如何在QML中使用QCustomPlot之曲线/折线示例(已适配黑白风格)_qml 折线图_诺谦的博客-CSDN博客 所以本章实现综合示例、并添加多种功能如下所示: 详细显示:鼠标任意移动显示具体值内容鼠标右击: 弹出菜单栏,支持…

【C++】:继承

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关C继承的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

洛谷 P1064 [NOIP2006 提高组] 金明的预算方案 python解析

P1064 [NOIP2006 提高组] 金明的预算方案 时间&#xff1a;2023.11.19 题目地址&#xff1a;[NOIP2006 提高组] 金明的预算方案 题目分析 动态规划的0-1背包&#xff0c;采用动态数组。如果不了解的话&#xff0c;可以先看看这个背包DP。 这个是0-1背包的标准状态转移方程 f…

域名的理解

域名的分类 见下图 这里引用的阿里云对域名的定义&#xff0c;个人理解是有两种叫法&#xff0c;一种是传统的叫法&#xff0c;也就是将sample.org.cn划分成了三级域名&#xff0c;还有一种叫法是基于用户注册的域名来说的&#xff0c;将用户注册的整体域名称作一级域名&…

SOME/IP 协议介绍(五)指南

指南&#xff08;信息性&#xff09; 选择传输协议 SOME/IP直接支持互联网上使用最广泛的两种传输协议&#xff1a;用户数据报协议&#xff08;UDP&#xff09;和传输控制协议&#xff08;TCP&#xff09;。UDP是一种非常简洁的传输协议&#xff0c;仅支持最重要的功能&#…

Java Swing实现简单的文本编辑器

内容要求 1) 本次程序设计是专门针对 Java 课程的,要求使用 Java 语言进行具有一定代码量的程序开发。程序的设计要结合一定的算法&#xff0c;在进行代码编写前要能够设计好自己的算法。 本次程序设计涉及到 Java 的基本语法&#xff0c;即课堂上所介绍的变量、条件语句、循…

Jmeter配置脚本录制进行抓包并快速分析、定位接口问题

对于测试人员、开发人员来说&#xff0c;善用抓包工具确实是快速分析和定位问题的一大必备神技&#xff0c;现将配置过程记录如下: 1、打开jmeter后&#xff0c;首先添加—个线程组: 2、线程组可以重新命名按项目名称分类: 如果你想学习自动化测试&#xff0c;我这边给你推荐一…
最新文章