草庐IT

0.96寸OLED显示(7针款SPI)

forever on time 2023-07-10 原文

文章最后附源代码链接

一、OLED屏

1、各项模式配置

  • SSD1306单片机接口由8个数据引脚和5个控制引脚组成。不同接口模式下的引脚分配如表所示。在BS[2:0]引脚上通过硬件选择可设置不同的MCU模式。

2、通讯模式

  • 通常我们所用的OLED屏有白色、蓝色、黄蓝双色等几种;屏的大小为0.96寸,像素点为128*64,所以我们也称之为0.96OLED屏或者12864屏。

  • 内部驱动IC为SSD1306;通信方式一般为SPI或者I2C。如下图所示,配置哪种模式主要是根据BS0、BS1和BS2这三个管脚的电平逻辑来的。

①IIC模式:

  • 电阻焊接R1、R4、R6、R7、R8。D1作为SCK时钟线,D0作为SDA数据线。SSD1306作为从机地址为0x78,DC脚作为更改从机地址引脚,DC接VCC,从机地址0x79,什么都不接地址为0x78。

  • 发送数据:起始信号-从机地址-应答-写数据模式(0x40)-应答-数据(8bit)-结束信号

  • 发送命令:起始信号-从机地址-应答-写命令模式(0x00)-应答-命令(8bit)-结束型号

②四线SPI模式:

  • 电阻焊接R3、R4。D1作为SClk时钟线,D0作为MOSI线,CS为片选NSS,DC为数据/命令线、RES复位线。

  • 发送数据:CS拉低-DC拉高-发送数据(8bit)-CS拉高

  • 发送命令:CS拉低-DC拉低-发送命令(8bit)-CS拉高

③三线SPI模式:

  • 电阻焊接R2,R3。D1作为SCLK时钟线,D0作为MOSI线,CS片选NSS,RES复位,DC拉低不用。数据有9位,首位就是数据/命令,因此不用DC线。

  • 发送数据:CS拉低-首位为1再接着发送8位数据-CS拉高

  • 发送命令:CS拉低-首位为0再接着发送8位命令-CS拉高

二、显示原理与取模方式

1、显示原理

OLED的显存分布情况。我们可以理解为:水平方向分布了128个像素点,垂直方向分布了64个像素点。而驱动芯片在点亮像素点的时候,是以8个像素点为单位的。官方的例程推荐的是垂直扫描的方式,也就是先画垂直方向的8个像素点(如下图所示),所以我们在画点的时候Y的取值为0-7,X的取值为0-127。页是芯片设计者为了方便将同一列的8个点阵编成一组,用一个8bit数表示,这样的8行128个数被称为1页。

2、取模方式

选择阴码、行列式(搭配页寻址模式)、逆向

三、OLED命令

1、命令的格式

①单级命令:直接发送一个命令就能设置OLED屏。

OLED_WriteCmd(0xAE); //关闭显示OLED_WriteCmd(0xA4); //设置整个显示打开/关闭OLED_WriteCmd(0xAF); //开启显示OLED_WriteCmd(0xA4); //设置整个显示打开/关闭

②多级命令:先发送一个命令,紧接着发送该命令的参数

OLED_WriteCmd(0x20); //打开寻址模式选择OLED_WriteCmd(0x02); //寻址模式选择页寻址模式

2、寻址模式设置命令

寻址模式命令:0x20

模式

命令

水平寻址模式

0x00

垂直寻址模式

0x01

页寻址模式

0x02

①页寻址模式(默认模式):

  • 从设定的页和列开始发送数据,列地址自动累加,页地址不会更新,如果超出范围则超出部分无效,可以不用事先指定每页中每列的长度。

地址设置:

  • y是页地址的编号:

使用或命令将这低四位与固定前缀0xb连接起来(0xb0 | y)

  • x是列地址的编号:

发送高四位的程序,先使用与命令(&)取得x的高4位(x & 0xf0)之后向右移4位,将高4位数据放到低4位((x & 0xf0) >> 4)之后使用或命令(|)加上固定前缀0x1即可(((x & 0xf0) >> 4) | 0x10)

发送低四位命令因为地址低四位的高四位为0x0,因此只需要使用与命令(&)将高四位置零即可(x & 0x0f)

②水平寻址:

  • 横向编码,列地址自动加,遇到设置范围的页尾时自动跳转到下一页,传输到设置范围的最后一页最后一列时自动复位。

地址设置:

OLED_WriteCmd(0x20) //寻址模式选择:(0x00水平/0x01垂直/0x02页)OLED_WriteCmd(0x00) //水平寻址模式OLED_WriteCmd(0x21) //设置列地址OLED_WriteCmd(0x00) //设置列起始位置OLED_WriteCmd(0x7F) //设置列终止位置OLED_WriteCmd(0x22) //设置页地址OLED_WriteCmd(0x00) //设置页起始位置OLED_WriteCmd(0x07) //设置页终止位置

③垂直寻址:

在垂直寻址模式下,当对显示内存进行读写操作后,页面地址指针自动加1。如果页地址指针到达页结束地址,则页地址指针重置为页开始地址,并且列地址指针加1。垂直寻址模式下页和列地址点的移动顺序如图所示。当列地址和页地址指针都到达结束地址时,指针被重定向到列的开始地址和通道的开始地址。

地址设置:

OLED_WriteCmd(0x20) //寻址模式选择:(0x00水平/0x01垂直/0x02页)OLED_WriteCmd(0x01) //垂直寻址模式OLED_WriteCmd(0x21) //设置列地址OLED_WriteCmd(0x00) //设置列起始位置OLED_WriteCmd(0x7F) //设置列终止位置OLED_WriteCmd(0x22) //设置页地址OLED_WriteCmd(0x00) //设置页起始位置OLED_WriteCmd(0x07) //设置页终止位置

3、基本命令

①对比度设置命令

进入对比度设置模式:0x81

之后输入对比度数值范围是0x00 - 0xFF(对比度实际上在这里就是设置发光部分的亮度,数值越大,亮度越大)

②显示开启/关闭

显示开启:0xA4

显示关闭:0xA5

③显示模式

阳码显示:0xA6

阴码显示:0xA7

④显示控制命令

关闭显示:0xAE

开启显示:0xAF

4、滚动命令

关闭滚动:0x2E(设置滚动参数前要先关闭滚动,防止RAM错乱)

开启滚动:0x2F

向右滚动:0x29

向左滚动:0x2a

A-F滚动参数配置,5个字节配置参数。

5、硬件配置(面板分辨率和布局相关)命令

①设置显示开始行

默认起始行:0x40

②设置列重映射(就是设置是否水平镜像)

将列地址0映射到SEG0:0xA0

将列地址127映射到SEG0:0xA1

设置左右方向,0xA1正常 0xA0左右反置

③设置多路复用率

开启多路复用率:0xA8

参数:A[5:0] 0到63配置参数。

④设置COM输出扫描方向

设置上下方向,0xC8正常 0xC0上下反置

⑤设置显示偏移量

开启显示偏移量:0xD3

参数:A[5:0] 垂直偏移量0-63

⑥设置COM引脚硬件配置

开启COM应交硬件配置;0xDA

参数:

A[4]=0b,顺序COM引脚配置

[4]=1b(RESET),可选COM引脚配置

A[5]=0b(RESET),禁用COM左右重映射

A[5]=1b,启用COM左右重映射

6、定时驱动方案设置命令

①设置显示时钟分频率/振荡器频率

开启命令:0xD5

参数A[7:0]:

A[3:0]:定义显示时钟(DCLK)的分割比(D):除比= A[3:0] + 1, RESET为0000b(除比= 1)

A[7:4]:设置振荡器频率,FOSC。振荡器频率随着A[7:4]的值增加,反之亦然。RESET为1000b范围:0000 ~ 1111 b频率随设定值增加而增加。

②设置预充电周期

开启命令:0xD9

参数A[7:0]:

A[3:0]:阶段1周期最多15个DCLK时钟,0是无效的条目(重置= 2h)

A[7:4]:阶段2周期最多15个DCLK时钟,0是无效的条目(重置= 2h)

③设置VCOMH取消选择级别

开启命令:0xDB

参数A[6:4]

④无操作命令

开启无操作:0xE3

四、代码

    • 引脚初始化和OLED初始化配置

/*引脚配置*/
#define OLED_W_D0(x)        GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)(x))
#define OLED_W_D1(x)        GPIO_WriteBit(GPIOB, GPIO_Pin_13, (BitAction)(x))
#define OLED_W_RES(x)        GPIO_WriteBit(GPIOB, GPIO_Pin_14, (BitAction)(x))
#define OLED_W_DC(x)        GPIO_WriteBit(GPIOB, GPIO_Pin_15, (BitAction)(x))
#define OLED_W_CS(x)        GPIO_WriteBit(GPIOA, GPIO_Pin_8, (BitAction)(x))

/*引脚初始化*/
void OLED_SPI_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
     GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    OLED_W_D0(1);
    OLED_W_D1(1);
    OLED_W_RES(1);
    OLED_W_DC(1);
    OLED_W_CS(1);
}

void OLED_Init(void)
{
    HAL_Delay(5);
    SPI_Init();
    
    OLED_WriteCmd(0xAE);    //关闭显示
    
    OLED_WriteCmd(0xD5);    //设置显示时钟分频比/振荡器频率
    OLED_WriteCmd(0x80);
    
    OLED_WriteCmd(0xA8);    //设置多路复用率
    OLED_WriteCmd(0x3F);
    
    OLED_WriteCmd(0xD3);    //设置显示偏移
    OLED_WriteCmd(0x00);
    
    OLED_WriteCmd(0x40);    //设置显示开始行
    
    OLED_WriteCmd(0xA1);    //设置左右方向,0xA1正常 0xA0左右反置
    
    OLED_WriteCmd(0xC8);    //设置上下方向,0xC8正常 0xC0上下反置

    OLED_WriteCmd(0xDA);    //设置COM引脚硬件配置
    OLED_WriteCmd(0x12);
    
    OLED_WriteCmd(0x81);    //设置对比度控制
    OLED_WriteCmd(0xCF);

    OLED_WriteCmd(0xD9);    //设置预充电周期
    OLED_WriteCmd(0xF1);

    OLED_WriteCmd(0xDB);    //设置VCOMH取消选择级别
    OLED_WriteCmd(0x30);

    OLED_WriteCmd(0xA4);    //设置整个显示打开/关闭

    OLED_WriteCmd(0xA6);    //设置正常/倒转显示

    OLED_WriteCmd(0x8D);    //设置充电泵
    OLED_WriteCmd(0x14);

    OLED_WriteCmd(0xAF);    //开启显示
        
    OLED_Clear();                //OLED清屏
    
}

2、显示功能代码(部分)

/**
  * @brief  SPI发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_SPI_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        OLED_W_D0(0);
        OLED_W_D1(Byte & (0x80 >> i));
        OLED_W_D0(1);
    }
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCmd(uint8_t Command)
{
    OLED_W_CS(0);
    OLED_W_DC(0);
    OLED_SPI_SendByte(Command);
    OLED_W_CS(1);
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
    OLED_W_CS(0);
    OLED_W_DC(1);
    OLED_SPI_SendByte(Data);
    OLED_W_CS(1);
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
    OLED_WriteCmd(0xB0 | Y);                                    //设置Y位置
    OLED_WriteCmd(0x10 | ((X & 0xF0) >> 4));    //设置X位置高4位
    OLED_WriteCmd(0x00 | (X & 0x0F));                    //设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
    uint8_t i, j;
    for (j = 0; j < 8; j++)
    {
        OLED_SetCursor(j, 0);
        for(i = 0; i < 128; i++)
        {
            OLED_WriteData(0x00);
        }
    }
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{          
    uint8_t i;
    OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);        //设置光标位置在上半部分
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i]);            //显示上半部分内容
    }
    OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);    //设置光标位置在下半部分
    for (i = 0; i < 8; i++)
    {
        OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);        //显示下半部分内容
    }
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
    uint8_t i;
    for (i = 0; String[i] != '\0'; i++)
    {
        OLED_ShowChar(Line, Column + i, String[i]);
    }
}

/**
  * @brief  OLED显示汉字
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  No:要显示汉字的个数
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowChinese(uint8_t Line,uint8_t Column,uint8_t No)
{
    uint8_t i;
    OLED_SetCursor((Line-1)*2,(Column-1)*16);
    for(i=0;i<16;i++)
    {
        OLED_WriteData(Chinese[2*No][i]);
    }
    OLED_SetCursor((Line-1)*2+1,(Column-1)*16);
    for(i=0;i<16;i++)
    {
        OLED_WriteData(Chinese[2*No+1][i]);
    }
}

/**
  * @brief  OLED显示图像
  * @param  Row1 起始行位置,范围:0~8
  * @param  Column1 起始列位置,范围:0~128
  * @param  Row2 终止行位置,范围:0~8
  * @param  Column2 终止列位置,范围:0~128
  * @param  BMP1:要显示gif的数组
  * @retval 无
  */
void OLED_ShowBMP(uint8_t Row1, uint8_t Column1,uint8_t Row2, uint8_t Column2,uint8_t BMP1[])
{     
 unsigned int i=0;
 unsigned char x,y;
  
//  if(y1%8==0) y=y1/8;      
//  else y=y1/8+1;
    for(x=Row1;x<Row2;x++)
    {
        OLED_SetCursor(x,Column1);
    for(y=Column1;y<Column2;y++)
        {      
            OLED_WriteData(BMP1[i++]);            
        }
    }
} 

3、滚动显示代码

void OLED_CloseRoll(void)
{
    //以下添加水平滚动效果
    OLED_WriteCmd(0x2e);//关滚动
    OLED_WriteCmd(0x2a);//29向右,2a向左
    OLED_WriteCmd(0x00);//A:空字节
    OLED_WriteCmd(0x00);//B:水平起始页
    OLED_WriteCmd(0x07);//C:水平滚动速度
    OLED_WriteCmd(0x07);//D:水平结束页
    OLED_WriteCmd(0x00);//E:每次垂直滚动位移
//    OLED_WriteCmd(0x2f);//开滚动
}
void OLED_OpenRoll(void)
{
    //以下添加水平滚动效果
    OLED_WriteCmd(0x2f);//开滚动
}

源文件连接:

链接:https://pan.baidu.com/s/1xlNhgYBokVcr8njH9ntNjQ

提取码:xiao

有关0.96寸OLED显示(7针款SPI)的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  4. ruby-on-rails - link_to 不显示任何 rails - 2

    我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article

  5. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  6. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  7. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  8. ruby-on-rails - 在 Flash 警报 Rails 3 中显示错误消息 - 2

    如果我在模型中设置验证消息validates:name,:presence=>{:message=>'Thenamecantbeblank.'}我如何让该消息显示在闪光警报中,这是我迄今为止尝试过的方法defcreate@message=Message.new(params[:message])if@message.valid?ContactMailer.send_mail(@message).deliverredirect_to(root_path,:notice=>"Thanksforyourmessage,Iwillbeintouchsoon")elseflash[:error]

  9. ruby-on-rails - Rails 4 WYSIWYG Bootsy 不显示格式 - 2

    我刚刚按照thebootsygempage上的安装说明进行操作在我保存并查看帖子内容之前,一切看起来都不错。这是输出在View中的样子:HeaderSubhead:似乎没有呈现任何html格式,因为它被引号或类似的东西转义了-其他人有这个问题吗?我没有在github页面或SO上看到任何问题来指出我正确的方向。除了遵循gem安装说明之外,我还没有做任何事情,但也许我错过了什么或者只是犯了一个愚蠢的错误。如果你还有什么想知道的,请尽管问。干杯 最佳答案 你需要有这样的东西,转义html: 关

  10. ruby - 为什么当我调用类的实例方法时,初始化不显示为方法? - 2

    我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认

随机推荐