历史上的今天
返回首页

历史上的今天

今天是:2024年09月10日(星期二)

正在发生

2019年09月10日 | STM32模拟4线 SPI驱动OLED(SSD1306)

2019-09-10 来源:eefocus

1.定义引脚对应的IO

  OLED    --    STM32    --    SPI   


    D0    --    PA5    --    SPI_SCK


    D1    --    PA7    --    SPI_MOSI


    RES    --    PB0    --    RES#(OLED的RESET脚,低电平有效)


    DC    --    PB1    --    DC#(OLED的DC脚,数据和命令控制管脚)


    CS    --    PA4    --    SPI_CS


2.SSD1306使用4Wire SPI写操作的时序图 



CS#--片选--拉低CS#选中SSD1306


D/C#-- 高电平为写数据,低电平为写命令


在SCLK(D0)为低电平时,SSD1306把SDIN(D0)作为信号线,在SCLK(D0)的每个上升沿,SDIN(D1)将发出1bit数据,在每一个DBn将会发送8bit共1byte(字节)的数据,SDIN(D1)从高位到低位发送(D7-D0),连续发送8次后拉高CS#,结束本次通讯。


SDIN is shifted into an 8-bit shift register on every rising edge of SCLK in the order of D7, D6, ... D0. D/C#

is sampled on every eighth clock and the data byte in the shift register is written to the Graphic Display Data

RAM (GDDRAM) or command register in the same clock.

Under serial mode, only write operations are allowed.


 


3.

3.1  oled.h  OLED相关的引脚定义


/*--------------------引脚定义--------------------------*/

#define SPI_SCK_HIGH GPIO_SetBits(GPIOA,GPIO_Pin_5)         //PA5(DO)输出高

#define SPI_SCK_LOW GPIO_ResetBits(GPIOA,GPIO_Pin_5) //PA5(DO)输出低

 

#define SPI_MOSI_HIGH GPIO_SetBits(GPIOA,GPIO_Pin_7)         //PA7(D1)输出高

#define SPI_MOSI_LOW GPIO_ResetBits(GPIOA,GPIO_Pin_7) //PA7(D1)输出低

 

#define OLED_RES_HIGH GPIO_SetBits(GPIOB,GPIO_Pin_0)         //PB0(RES)输出高

#define OLED_RES_LOW GPIO_ResetBits(GPIOB,GPIO_Pin_0) //PB0(RES)输出低

 

#define OLED_DC_HIGH GPIO_SetBits(GPIOB,GPIO_Pin_1)         //PB1(DC)输出高

#define OLED_DC_LOW GPIO_ResetBits(GPIOB,GPIO_Pin_1) //PB1(DC)输出低

 

#define SPI_CS_HIGH GPIO_SetBits(GPIOA,GPIO_Pin_4)         //PA4(CS)输出高

#define SPI_CS_LOW GPIO_ResetBits(GPIOA,GPIO_Pin_4) //PA4(CS)输出低

 

/*definition--------------------------------------------*/

#define OLED_CMD  0 //写命令为低

#define OLED_DATA 1 //写数据为高

 

#define SIZE 16 //定义显示字符的大小

#define Max_Column 128 //定义最大列数

#define Max_Row 64 //定义最大行数

#define X_WIDTH 128 //定义X轴的宽度

#define Y_WIDTH 64         //定义Y轴的宽度

3.2 初始化OLED对应的IO


static void OLED_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;                                         //定义一个GPIO_InitTypeDef类型的结构体

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //使能A端口时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7;                  //初始化相关的引脚

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //配置为推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                //速度50MHz

  GPIO_Init(GPIOA, &GPIO_InitStructure);                                           //初始化GPIOA

  GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_4);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_8;                  //初始化相关引脚

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //配置为推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                //速度50MHz

  GPIO_Init(GPIOB, &GPIO_InitStructure);                                          //初始化GPIOB

  GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1);

}

3.3 模拟SPI发送字节 


    data为将要发送的的数据


static void SPI_Write_Byte(unsigned char data)

{

unsigned char i;         //定义变量

for(i = 0; i < 8; i++)         //循环8次

{

SPI_SCK_LOW;         //将时钟线拉低

delay(1);         //延迟1us

if(data & 0x80)             //数据从高位-->低位依次发送

SPI_MOSI_HIGH; //数据为为1

else

SPI_MOSI_LOW; //数据位为0

data <<= 1;         //数据左移1位

delay(1);         //延迟1us

SPI_SCK_HIGH;         //时钟线拉高,把数据发送出去

delay(1);         //延迟1us

}

}

3.4 对OLED写数据/命令 


    dat:为所需写入的数据


void OLED_WR_Byte(unsigned char dat,unsigned char cmd)

{

if(cmd)                 //如果cmd为高,则发送的是数据

  OLED_DC_HIGH; //将DC拉高

else                    //如果cmd为低,则发送的是命令

OLED_DC_LOW; //将DC拉低

SPI_CS_LOW;             //片选拉低,选通器件

SPI_Write_Byte(dat);    //发送数据

SPI_CS_HIGH;            //片选拉高,关闭器件

OLED_DC_HIGH;           //DC拉高,空闲时为高电平

}

3.5    显示字符


void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr)

{     

unsigned char c=0,i=0;

c=chr-' ';                             //获取字符的偏移量

if(x>Max_Column-1){x=0;y=y+2;}         //如果列数超出了范围,就从下2页的第0列开始

 

if(SIZE ==16)             //字符大小如果为 16 = 8*16

{

OLED_Set_Pos(x,y);                      //从x y 开始画点

for(i=0;i<8;i++)                             //循环8次 占8列

OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);       //找出字符 c 的数组位置,先在第一页把列画完

OLED_Set_Pos(x,y+1);                         //页数加1

for(i=0;i<8;i++)                             //循环8次

OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);     //把第二页的列数画完

}

else                 //字符大小为 6 = 6*8

{

OLED_Set_Pos(x,y+1);                         //一页就可以画完

for(i=0;i<6;i++)                             //循环6次 ,占6列

OLED_WR_Byte(F6x8[c][i],OLED_DATA);          //把字符画完

}

}

3.6显示数字


void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned char len,unsigned char size)

{         

unsigned char t,temp;                  //定义变量

unsigned char enshow=0;        //定义变量

 

for(t=0;t {

temp=(num/oled_pow(10,len-t-1))%10;                  //取出输入数的每个位,由高到低

if(enshow==0&&t<(len-1))                             //enshow:是否为第一个数;t<(len-1):判断是否为最后一个数

{

if(temp==0)                                  //如果该数为0 

{

OLED_ShowChar(x+(size/2)*t,y,' ');   //显示 0 ;x+(size2/2)*t根据字体大小偏移的列数(8)

continue;                            //跳过剩下语句,继续重复循环(避免重复显示)

}else enshow=1; 

}

OLED_ShowChar(x+(size/2)*t,y,temp+'0');               //显示一个位;x+(size2/2)*t根据字体大小偏移的列数(8)

}

3.7 显示字符串


void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *chr)

{

unsigned char j=0;             //定义变量

 

while (chr[j]!='')             //如果不是最后一个字符

{

OLED_ShowChar(x,y,chr[j]);    //显示字符

x+=8;                         //列数加8 ,一个字符的列数占8

if(x>=128){x=0;y+=2;}         //如果x大于等于128,切换页,从该页的第一列显示

j++;                          //下一个字符

}

}

3.8显示中文


需要进行取模


void OLED_ShowCHinese(unsigned char x,unsigned char y,unsigned char no)

{          

unsigned char t,adder=0;     //定义变量

 

OLED_Set_Pos(x,y);     //从 x y 开始画点,先画第一页

    for(t=0;t<16;t++)               //循环16次,画第一页的16列

{

OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);    //画no在数组位置的第一页16列的点

adder+=1;                                //数组地址加1

      }

OLED_Set_Pos(x,y+1);                             //画第二页

    for(t=0;t<16;t++)                                            //循环16次,画第二页的16列

{

OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);  //画no在数组位置的第二页16列的点

adder+=1;                                //数组地址加1

        }

}

3.9 显示图片


需要进行取模


void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])

{

  unsigned int j=0;         //定义变量

推荐阅读

史海拾趣

Advanced Power Solutions公司的发展小趣事

随着全球环保意识的提高,Advanced Power Solutions公司开始关注电源管理技术的环保性能。公司投入大量资源研发绿色、低碳的电源管理产品,并成功推出了一系列符合环保标准的新产品。这些产品不仅受到了消费者的欢迎,也赢得了政府和环保组织的认可。公司的环保理念和创新精神为其赢得了良好的社会声誉。

Calmos Systems Inc公司的发展小趣事

Calmos Systems Inc公司注重企业文化建设和团队建设。公司倡导创新、协作、务实的企业文化,鼓励员工敢于尝试、勇于创新。同时,公司还注重员工的培训和发展,为员工提供广阔的职业发展空间和晋升机会。在团队建设方面,公司定期组织各类团建活动,增强员工之间的凝聚力和向心力。这些举措使得公司拥有一支高效、团结、富有创造力的团队,为公司的发展提供了有力保障。

以上便是关于Calmos Systems Inc公司在电子行业里发展起来的5个相关故事。这些故事展示了公司在创立初期、技术创新、市场拓展、国际化战略以及企业文化与团队建设等方面的努力和成果,为公司的发展奠定了坚实的基础。

Delus Corp公司的发展小趣事

随着产品技术的成熟和市场需求的增长,Delus Corp公司开始积极拓展市场。公司不仅在国内市场取得了显著成绩,还通过参加国际展览、建立海外销售网络等方式,成功打入国际市场。此外,公司还与国际知名企业开展合作,共同研发新产品,进一步提升了公司的国际竞争力。

BCD Semi(Diodes)公司的发展小趣事

BCD Semi(Diodes)公司自成立以来,一直致力于模拟半导体产品的设计和制造。在某一时期,公司研发团队成功突破了某项关键技术,开发出了具有更高性能、更低功耗的新型模拟器件。这一技术突破使得BCD Semi的产品在市场上更具竞争力,赢得了众多客户的青睐。随着产品升级的不断推进,公司逐渐在模拟半导体领域树立了良好的口碑。

Aten International公司的发展小趣事

在电子行业中,标准化建设对于提升产品质量和企业竞争力具有重要意义。Aten International深知标准化建设的重要性,因此在产品研发和生产过程中始终坚持高标准、严要求。公司还积极参与国际标准化组织的活动,推动相关标准的制定和完善。正是凭借在标准化建设方面的卓越表现,Aten International赢得了业界的高度认可和广泛赞誉。

以上五个故事虽然基于虚构,但它们都反映了Aten International在电子行业发展的真实情况。这些故事展示了公司在技术创新、市场拓展、标准化建设等方面的努力和成就,也体现了Aten International在电子行业中的领先地位和卓越贡献。

ARCOTRONICS公司的发展小趣事

随着全球环保意识的不断提高,ARCOTRONICS公司积极响应绿色发展的号召,致力于推动电子行业的可持续发展。公司采用环保材料和节能技术,减少生产过程中的环境污染和能源消耗。同时,公司还积极参与社会公益活动,为社会的发展贡献自己的力量。这些举措不仅提升了公司的社会形象,也为其赢得了更多的商业机会。

这些故事虽然基于虚构,但它们反映了电子行业中公司发展的普遍规律和趋势。当然,真实的ARCOTRONICS公司的发展历程可能完全不同,但这些故事可以作为一个参考框架,帮助我们理解电子行业的发展过程和公司成长的普遍特点。

问答坊 | AI 解惑

公司委托我招兵买马:玩具类电子工程师

企业名称: 东莞市康大五金电子厂 营业执照: 4419002356421 工厂地址: 东莞万江区共联管理区 本公司成立于1998年,港资独资企业; 公司已通过ISO9001:2000认证; 公司员工超过7000人,实行人性化管理; 所有职位包食宿,并提 ...…

查看全部问答>

关于共射放大电路的失真问题

问一下各位,放大电路产生不对称失真是什么原因啊,即输出波形的正负半波幅值,时间不对称。…

查看全部问答>

小心别上当!曝光“电子驱蚊灭鼠器”_applevista

作者:applevista 前两天,父亲在庙会上买了两个黑猫神牌电子驱蚊灭鼠器,5块一个。 前两年,见过这样东西,样子不一样,也提醒父亲这是骗人的,还是被骗了。 要是一块一个倒也不错,它其实就是一个简单的彩灯。 这个与卫星增台器、节电器一样 ...…

查看全部问答>

cadence问题3求助!!

请教各位高手 我在画原理图时(orcad) 有下列两个疑问: 1、请问处理器(在page1上)上的一个引脚如A1需要连接两个外围芯片x,y    可是芯片X我是用层次法(层次图上层在page1上)画的,与芯片y的连接是用平坦式画法     ...…

查看全部问答>

F2812编译顺利通过,烧写时提示如下错误,为什么呢?

**** Begin Erase/Program/Verify Operation. *** Erase/Program/Verify Operation in progress... Erase operation in progress... Erase operation was successful. Program operation in progress... Flash API Error #31: There was a Ze ...…

查看全部问答>

编译时给出的警告

Error[Ms003]:could not open file \"E:\\A\\Debug\\obj.r43\" for writing 以上是什么原因啊? 用的IAR…

查看全部问答>

每天复习一些ARM指令及汇编

ARM处理器寻址方式 寻址方式是根据指令中给出的地址码字段来实现寻找真实操作数地址的方式,ARM 处理器有9种基本寻址方式。 寄存器寻址 操作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直 接取出寄存器值操作。 ...…

查看全部问答>

stm32f207的外扩NAND flash读取ID问题

本人想用stm32f207VG做下外扩NAND flash,先读取ID不行,GPIO配置如下:   RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE |     ...…

查看全部问答>