历史上的今天
返回首页

历史上的今天

今天是:2025年08月15日(星期五)

正在发生

2018年08月15日 | STM32-SPI之OLED

2018-08-15 来源:eefocus

   OLED作为一种新型的显示设备,由于其优秀的性能,并且随着产量的提高价格也在不断的下降。受到了现在很多显示设备产品的青睐。高清晰,高对比的都使人们对它的使用越来越多了。对于OLED它的驱动方式有很多种,SPI、IIC、8080并口等方式,不同的方式有不同的优点。本篇文章采用的STM32自身的SPI总线的控制方式,还可以通过软件的方式来模拟SPI,难度都不大。 
首先来看一下关于STM32的SPI的寄存器和函数,至于什么是SPI就没有必要解释了。 
这里写图片描述
由于STM32的固件库手册版本的原因 我用的手册可能没有全部包括SPI的函数,详细的可以看英文原版的手册。 
这里写图片描述
SPI的引脚映射关系 
这里写图片描述
SPI的GPIO模式的设置 
这里写图片描述
至于OLED大家可以参考SSD1306的相关手册,是它的驱动芯片手册。OLED在显示方面的重点是,由于OLED屏幕分辨率为128*64, 
在使用的时候是将高度分为8个单位,每个单位8个像素点。称为8页,当我们在写显示数据的时候,就需要将取模得到的数据分为页和X轴的显示方式。详细的资料参考技术手册。下面附上源码,仅供参考。

#ifndef _OLED_SPI_H

#define _OLED_SPI_H

#include "stm32f10x.h"

#define     OLED_DC_H                       GPIO_SetBits(GPIOA, GPIO_Pin_11)

#define     OLED_DC_L                       GPIO_ResetBits(GPIOA, GPIO_Pin_11)

#define     OLED_RST_L                      GPIO_ResetBits(GPIOA, GPIO_Pin_12)

#define     OLED_RST_H                      GPIO_SetBits(GPIOA, GPIO_Pin_12)

#define     X_WIDTH         128

#define     Y_WIDTH         64

#define         Page                        8

#define     RCC_APB2Periph_OLED_PORT        RCC_APB2Periph_GPIOA

#define     OLED_PORT                       GPIOA

#define     OLED_RST_PIN                    GPIO_Pin_12

#define         OLED_SCK_PIN                                        GPIO_Pin_5

#define         OLED_SDA_PIN                                        GPIO_Pin_7

#define     OLED_DC_PIN                     GPIO_Pin_11


void LCD_Init(void);

void LCD_CLS(void);

void LCD_Fill(unsigned char bmp_dat);

void LCD_Set_Pos(unsigned char x, unsigned char y);

void LCD_WrCmd(unsigned char cmd);

void LCD_WrDat(unsigned char dat);

void OLED_ShowChar(int x, int y, const unsigned char *p);


void OLED_ShowChinese(int x, int y, const unsigned char *p);


#endif

 

#include "OLED_SPI.h"


void SPI_Configuration(void)

{

      SPI_InitTypeDef  SPI_InitStructure;

      GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1 | RCC_APB2Periph_OLED_PORT, ENABLE);


      SPI_SSOutputCmd(SPI1, ENABLE);


      GPIO_InitStructure.GPIO_Pin = OLED_SCK_PIN | OLED_SDA_PIN ;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

      GPIO_Init(OLED_PORT, &GPIO_InitStructure);



      GPIO_InitStructure.GPIO_Pin = OLED_RST_PIN | OLED_DC_PIN | GPIO_Pin_4 ;

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

      GPIO_Init(OLED_PORT, &GPIO_InitStructure);



      SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

      SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

      SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

      SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

      SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

      SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

      SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;

      SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

      SPI_InitStructure.SPI_CRCPolynomial = 7;

      SPI_Init(SPI1, &SPI_InitStructure);

      /* Enable SPI1 */

      SPI_Cmd(SPI1, ENABLE);

}

void OLED_WB(uint8_t data)

{


    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);


    SPI_I2S_SendData(SPI1, data);

}

void LCD_WrDat(unsigned char dat)

{

    OLED_DC_H;

    OLED_WB(dat);

}


void LCD_WrCmd(unsigned char cmd)

{

    OLED_DC_L;

    OLED_WB(cmd);

}


void LCD_Set_Pos(unsigned char x, unsigned char y)

{


        LCD_WrCmd((0xb0+(y&0x0f)));  

      LCD_WrCmd((((x & 0xf0)>>4)|0x10));            //设置OLED水平坐标的高4位

      LCD_WrCmd((x & 0x00));                                //设置OLED水平坐标的低4位

}

void OLED_ShowChar(int x, int y, const unsigned char *p)            //显示字符

 {

   int i = 0;

    LCD_Set_Pos(x, y);                                                  //首先确定开始的坐标

  for(i = 0; i < 16; i+=2)                                      //

   {

      LCD_WrDat(p[i]);                                              //每次显示一个字节      每个char占用16个x像素

    }

   LCD_Set_Pos(x, y+1);                                             //转到下一页显示剩下字节

    for(i = 1; i < 16; i+=2)

    {

        LCD_WrDat(p[i]);

     }

}


void OLED_ShowChinese(int x, int y, const unsigned char *p)

 {

    int i = 0;

    LCD_Set_Pos(x, y);

    for(i = 0; i < 32; i+=2)

    {

         LCD_WrDat(p[i]);

     }

         LCD_Set_Pos(x, y+1);

     for(i = 1; i < 32; i+=2)

    {

         LCD_WrDat(p[i]);

     }


 }

void LCD_DLY_ms(unsigned int ms)

{

    unsigned int a;

    while(ms)

    {

        a=1335;

        while(a--);

        ms--;

    }

    return;

}

void LCD_Fill(unsigned char bmp_dat)

{

    unsigned char y,x;


    LCD_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)

    LCD_WrCmd(0x00);//


    LCD_WrCmd(0x21);//-Set Column Address

    LCD_WrCmd(0x00);

    LCD_WrCmd(0x7f);


    LCD_WrCmd(0x22);//-Set Page Address

    LCD_WrCmd(0x00);

    LCD_WrCmd(0x07);


    LCD_DLY_ms(1);

    for(y=0;y

    {

        for(x=0;x

        {

            LCD_WrDat(bmp_dat);

        }

    }

}


/*********************清屏函数***********************/

void LCD_CLS(void)

{

    unsigned char y,x;

    for(y=0;y<8;y++)

    {

        LCD_WrCmd(0xb0+y);

        LCD_WrCmd(0x01);

        LCD_WrCmd(0x10);

        for(x=0;x

        LCD_WrDat(0);

        LCD_DLY_ms(200);

    }

}


void LCD_Init(void)

{

        SPI_Configuration();

        OLED_RST_L;

        LCD_DLY_ms(50);

        OLED_RST_H;

    //从上电到下面开始初始化要有足够的时间,即等待RC复位完毕


    LCD_WrCmd(0xae);//--turn off oled panel


    LCD_WrCmd(0xa8);//--set multiplex ratio(1 to 64)

    LCD_WrCmd(0x3f);//--1/64 duty

    LCD_WrCmd(0xd3);//-set display offset   Shift Mapping RAM Counter (0x00~0x3F)

    LCD_WrCmd(0x00);//-not offset

    LCD_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)

    LCD_WrCmd(0xa0);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

    LCD_WrCmd(0xc0);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

    LCD_WrCmd(0xda);//--set com pins hardware configuration

    LCD_WrCmd(0x12);

    LCD_WrCmd(0x81);//--set contrast control register

    LCD_WrCmd(0xcf); // Set SEG Output Current Brightness

    LCD_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)

    LCD_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)

    LCD_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency

    LCD_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec

    LCD_WrCmd(0x8d);//--set Charge Pump enable/disable

    LCD_WrCmd(0x14);//--set(0x10) disable

    LCD_WrCmd(0xaf);//--turn on oled panel


    LCD_WrCmd(0xd9);//--set pre-charge period

    LCD_WrCmd(0xf8);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock


    LCD_WrCmd(0xdb);//--set vcomh

    LCD_WrCmd(0x40);//Set VCOM Deselect Level


    LCD_Fill(0x00);  //初始清屏

}


推荐阅读

史海拾趣

GISMA Steckverbinder GmbH公司的发展小趣事

GISMA深知产品质量对于企业生存和发展的重要性。因此,公司建立了完善的质量管理体系,并通过了DIN ISO 9001(DNV)等国际质量认证。这一认证不仅证明了GISMA在产品生产过程中的严格质量控制能力,也为其赢得了更多客户的信任和认可。GISMA始终坚持质量第一的原则,不断提升产品质量和服务水平,确保每一款产品都能达到客户的期望和要求。通过持续的质量管理和改进活动,GISMA在电子行业中树立了良好的品牌形象和口碑。

Ampire Co Ltd公司的发展小趣事

GISMA深知客户需求的重要性,因此始终将客户需求放在首位。公司拥有一支专业的研发团队和客户服务团队,能够根据客户的具体需求量身定制产品,提供从设计到生产的全方位服务。这种定制化服务模式不仅赢得了客户的广泛赞誉,也进一步巩固了GISMA在电子行业中的市场地位。通过深入了解客户需求,GISMA不断优化产品设计和生产流程,为客户提供更加优质的产品和服务。

Cableform Inc公司的发展小趣事

Cableform Inc公司起源于一位名叫约翰·卡贝尔的电气工程师的创意。在20世纪中期,约翰看到了电子工业的巨大潜力,特别是在电磁控制领域。于是,在1945年,他创立了Cableform Inc,专注于研发和生产电磁控制设备。起初,公司只有几名员工,面临着资金短缺和技术挑战。然而,约翰凭借着对技术的执着和对市场的敏锐洞察,成功设计出了一款具有竞争力的磁铁控制器,为公司的发展奠定了基石。

DYMO公司的发展小趣事

在XX世纪XX年代,DYMO公司推出了一款具有划时代意义的标签打印机。这款打印机采用了全新的打印技术,能够打印出清晰、耐用的标签,并且支持多种字体和图案。这一创新技术让DYMO公司在标签打印领域取得了领先地位,并为其后续的产品线奠定了坚实的基础。

Gaomi Xinghe Electronics公司的发展小趣事

背景:随着中国经济的快速发展和消费者对电子产品需求的不断增加,Galaxy公司敏锐地捕捉到这一市场机遇。

行动:在2003年初,Galaxy以缜密的市场调研为基础,全力部署进入大陆市场。同年6月,公司推出了以“影驰”命名的Geforce家族系列产品,迅速吸引了众多游戏发烧友和电子产品爱好者的关注。随后,公司又在多个城市设立了销售和服务网点,为消费者提供更加便捷的产品体验和服务。

成果:经过多年的深耕细作,Galaxy在大陆市场取得了显著成绩,品牌影响力不断增强,市场份额稳步提升。

南晶电子(DGNJDZ)公司的发展小趣事

在发展过程中,南晶电子始终秉持合作共赢的理念。公司与上下游企业建立了紧密的合作关系,共同推动产业链的发展。同时,南晶电子还积极参与社会公益事业,为社会进步和发展贡献自己的力量。通过与各方的共同努力,南晶电子在电子行业树立了良好的企业形象和口碑。

问答坊 | AI 解惑

SM8951-8952 系列产品.

SM8951/8952系列产品是内潜4/8K字节的内存的8位单片机微型控制器,它具有多达32个I/O,4K/8K的内存既可作为程序存储空间,也可以作为数据存储空间,或程序,数据混合空间。这些硬件特性和其强大的指令系统,使它能应用与不同的场合,因此是一种通用 ...…

查看全部问答>

优秀博客赏析----STM32笔记之—RTC

STM32笔记之—RTC  https://home.eeworld.com.cn/?uid-78216-action-viewspace-itemid-12720 STM32(Cortex-M3)中有两个优先级的概念 https://home.eeworld.com.cn/?uid-78216-action-viewspace-itemid-12719 如何使用STM32的窗口看门狗 ...…

查看全部问答>

数字信号处理

各位大侠!我有一个问题想请教! 我们单位领导想把车间诸多的设备运行状况(包括正常、事故、停车)信号都能集中显示。每台设备的运行状况由操作员发出。现在的问题是如果有100~200个指令,我如何把这些指令通过处理,以以太网接口的形式输出。最 ...…

查看全部问答>

我该如何再开始?

大家好!很高兴能够来到这里,与大家进行交流!        首先,我先做一下自我介绍:我是一名车辆工程的硕士,毕业已经近两年,本科专业是电子,研究生的课题是用MTALAB做的关于HEV的仿真。看到这里的时候,可能有人会说,你的 ...…

查看全部问答>

想实现总开关接通后,电路里有六路开关也一并接通

来自EEWORLD合作群:arm linux fpga 嵌入0(49900581) 群主:wangkj 请教个问题 我现在想实现一个目的:总开关接通后 电路里有六路开关也一并接通 最好有那种上电便可以通电的开关 输入电压要求90V 有点类似twh8778 或者cd4066的…

查看全部问答>

evc DirectDraw 中DirectDrawCreate创建失败

LPDIRECTDRAW         pDD = NULL; hRet = ::DirectDrawCreate(NULL, &pDD, NULL); 返回-2005532450 不知道什么原因? 高手指点啊。…

查看全部问答>

怎么能选定我列表视图中的一个项,并保持那个文件名

我建立了一个列表视图,在程序运行后,把一个CF卡的里的很多文件名都显示在了上面,现在想实现这样一个功能,就是在程序运行后,能用鼠标点其中一个文件名,然后读出这个文件的名字,以方便我实现某个按键打开这个文件,那,这个读出文件名字的功能 ...…

查看全部问答>

求教Windows CE4.2 开发的几个基础问题,高分提问。。。。

最近要在WindowCE4.2平台上进行开发,痛苦的是没有相应的SDK,只知道该PDA的CPU是IntelPXA255的(通过查看属性显示的),如果采用标准的SDK发现无法使用MFC,如果用Mobile2003的SDK则提示“找不到组件。。。”。不知如何是好? 我已经下载了PB4.2 ...…

查看全部问答>

DTMF

我想用单片机获取电话机的DTMF信号 但是没有思路 有没有高人给我一点指点呢?…

查看全部问答>

《AlientekSTM32原理图》--原理图pdf文档上传

原理图和PCB的pdf文档下载: ALIENTEK MiniSTM32开发板原理图与PCB.pdf (827.67 KB) 下载次数: 901 2010-11-10 00:28 下载 (178.81 KB) 2010-11-9 01:50 下载 (166.03 KB) 2010 ...…

查看全部问答>