历史上的今天
返回首页

历史上的今天

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

正在发生

2021年12月10日 | 【STM32】0.96寸OLED显示屏(7针SPI协议)软件模拟SPI

2021-12-10 来源:eefocus

概述

某宝上买的OLED,IIC/SPI都可以,买来看的时候发现背面焊的是SPI。板子上又没有硬件SPI,只好用软件模拟SPI。很久之前学的了,现在把它写在CSDN上,各位大佬如有什么想法,欢迎评论!(PS:文末会附上此工程的全部文件,欢迎下载交流)


3.1硬件设计

硬件方面不多讲,直接看某宝上图片。

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

某宝上介绍的比较详细,需要注意的是这个OLED可以焊接电阻R1~R4中的某几个来选择IIC或者SPI协议,详情见以下图片

在这里插入图片描述

3.2软件设计

3.2.1编程要点

1、初始化GPIO口来模拟SPI,每个人设置的GPIO口不同,开发板与OLED接线也会不同,所以在拿到别人的程序代码时,一定要看看ta是用那几个GPIO口来模拟的,不要看ta程序开头的注释,很有可能ta后面把模拟的GPIO口改过,而注释没改

2、OLED驱动程序,这里的驱动程序可以参考别人写的,然后自己再加以修改或者补充。

3、取模,包括文字取模和图片取模。根据自己的需要来取模。需要取模软件的可以私信我。


3.2.2代码分析

1、OLED驱动头文件oled.h

#ifndef __OLED_H

#define __OLED_H       

#include "sys.h"

#include "stdlib.h"      

//OLED模式设置

//0:4线串行模式

//1:并行8080模式

#define OLED_MODE 0

#define SIZE 16

#define XLevelL  0x00

#define XLevelH  0x10

#define Max_Column 128

#define Max_Row  64

#define Brightness 0xFF 

#define X_WIDTH  128

#define Y_WIDTH  64    


//-----------------OLED端口定义----------------          

#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOE,GPIO_Pin_2)//CLK

#define OLED_SCLK_Set() GPIO_SetBits(GPIOE,GPIO_Pin_2)


#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOE,GPIO_Pin_3)//DIN

#define OLED_SDIN_Set() GPIO_SetBits(GPIOE,GPIO_Pin_3)


#define OLED_RST_Clr() GPIO_ResetBits(GPIOE,GPIO_Pin_4)//RES

#define OLED_RST_Set() GPIO_SetBits(GPIOE,GPIO_Pin_4)


#define OLED_DC_Clr() GPIO_ResetBits(GPIOE,GPIO_Pin_5)//DC

#define OLED_DC_Set() GPIO_SetBits(GPIOE,GPIO_Pin_5)       


#define OLED_CS_Clr()  GPIO_ResetBits(GPIOC,GPIO_Pin_13)//CS

#define OLED_CS_Set()  GPIO_SetBits(GPIOC,GPIO_Pin_13)


#define OLED_CMD  0 //写命令

#define OLED_DATA 1 //写数据


//OLED控制用函数

void OLED_WR_Byte(u8 dat,u8 cmd);     

void OLED_Display_On(void);

void OLED_Display_Off(void);                    

void OLED_Init(void);

void OLED_Clear(void);

void OLED_DrawPoint(u8 x,u8 y,u8 t);

void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);

void OLED_ShowChar(u8 x,u8 y,u8 chr);

void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);

void OLED_ShowString(u8 x,u8 y, u8 *p);  

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

void OLED_ShowCHinese(u8 x,u8 y,u8 no);

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

#endif  


2、OLED驱动文件oled.c

#include "oled.h"

#include "stdlib.h"

#include "oledfont.h"    

#include "delay.h"

//OLED的显存

//存放格式如下.

//[0]0 1 2 3 ... 127 

//[1]0 1 2 3 ... 127 

//[2]0 1 2 3 ... 127 

//[3]0 1 2 3 ... 127 

//[4]0 1 2 3 ... 127 

//[5]0 1 2 3 ... 127 

//[6]0 1 2 3 ... 127 

//[7]0 1 2 3 ... 127       


#if OLED_MODE==1

//向SSD1106写入一个字节。

//dat:要写入的数据/命令

//cmd:数据/命令标志 0,表示命令;1,表示数据;

void OLED_WR_Byte(u8 dat,u8 cmd)

{

 DATAOUT(dat);     

 if(cmd)

   OLED_DC_Set();

 else 

   OLED_DC_Clr();     

 OLED_CS_Clr();

 OLED_WR_Clr();  

 OLED_WR_Set();

 OLED_CS_Set();   

 OLED_DC_Set();  

}           

#else

//向SSD1106写入一个字节。

//dat:要写入的数据/命令

//cmd:数据/命令标志 0,表示命令;1,表示数据;

void OLED_WR_Byte(u8 dat,u8 cmd)

 u8 i;     

 if(cmd)

   OLED_DC_Set();

 else 

   OLED_DC_Clr();    

 OLED_CS_Clr();

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

 {     

  OLED_SCLK_Clr();

  if(dat&0x80)

     OLED_SDIN_Set();

  else 

     OLED_SDIN_Clr();

  OLED_SCLK_Set();

  dat<<=1;   

 }         

 OLED_CS_Set();

 OLED_DC_Set();      

#endif


 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)|0x01,OLED_CMD); 

}      

//开启OLED显示    

void OLED_Display_On(void)

{

 OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令

 OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON

 OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON

}

//关闭OLED显示     

void OLED_Display_Off(void)

{

 OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令

 OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF

 OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF

}         

//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!   

void OLED_Clear(void)  

{  

 u8 i,n;      

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

 {  

  OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)

  OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址

  OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   

  for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 

 } //更新显示

}


//在指定位置显示一个字符,包括部分字符

//x:0~127

//y:0~63

//mode:0,反白显示;1,正常显示     

//size:选择字体 16/12 

void OLED_ShowChar(u8 x,u8 y,u8 chr)

{       

 unsigned char c=0,i=0; 

  c=chr-' ';//得到偏移后的值   

  if(x>Max_Column-1){x=0;y=y+2;}

  if(SIZE ==16)

   {

   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 { 

    OLED_Set_Pos(x,y+1);

    for(i=0;i<6;i++)

    OLED_WR_Byte(F6x8[c][i],OLED_DATA);   

   }

}

//m^n函数

u32 oled_pow(u8 m,u8 n)

{

 u32 result=1;  

 while(n--)result*=m;    

 return result;

}      

//显示2个数字

//x,y :起点坐标  

//len :数字的位数

//size:字体大小

//mode:模式 0,填充模式;1,叠加模式

//num:数值(0~4294967295);      

void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)

{          

 u8 t,temp;

 u8 enshow=0;         

 for(t=0;t {

  temp=(num/oled_pow(10,len-t-1))%10;

  if(enshow==0&&t<(len-1))

  {

   if(temp==0)

   {

    OLED_ShowChar(x+(size/2)*t,y,' ');

    continue;

   }else enshow=1; 

     

  }

   OLED_ShowChar(x+(size/2)*t,y,temp+'0'); 

 }

//显示一个字符号串

void OLED_ShowString(u8 x,u8 y,u8 *chr)

{

 unsigned char j=0;

 while (chr[j]!='')

 {  OLED_ShowChar(x,y,chr[j]);

   x+=8;

  if(x>120){x=0;y+=2;}

   j++;

 }

}

//显示汉字

void OLED_ShowCHinese(u8 x,u8 y,u8 no)

{             

 u8 t,adder=0;

 OLED_Set_Pos(x,y); 

    for(t=0;t<16;t++)

  {

    OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);

    adder+=1;

     } 

  OLED_Set_Pos(x,y+1); 

    for(t=0;t<16;t++)

   { 

    OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);

    adder+=1;

      }     

}

/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/

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

{  

 unsigned int j=0;

 unsigned char x,y;

  

  if(y1%8==0) y=y1/8;      

  else y=y1/8+1;

 for(y=y0;y {

  OLED_Set_Pos(x0,y);

    for(x=x0;x     {      

      OLED_WR_Byte(BMP[j++],OLED_DATA);      

     }

 }


//初始化SSD1306         

void OLED_Init(void)

{    

  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);  //使能E端口时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 |GPIO_Pin_3 ;  

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;            //推挽输出

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

  GPIO_Init(GPIOE, &GPIO_InitStructure);   //初始化GPIOE3,6

  GPIO_SetBits(GPIOE,GPIO_Pin_2 |GPIO_Pin_3);  

  

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); //使能E端口时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;            //推挽输出

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

  GPIO_Init(GPIOE, &GPIO_InitStructure);   //初始化GPIOD3,6

  GPIO_SetBits(GPIOE,GPIO_Pin_4|GPIO_Pin_5);  

  

  OLED_RST_Set();

  delay_ms(100);

  OLED_RST_Clr();

  delay_ms(200);

  OLED_RST_Set();        

  

  OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel

  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  Set Mapping RAM     Display Start Line (0x00~0x3F)

 OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register

 OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness

 OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

 OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

 OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display

 OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)

 OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty

 OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)

 OLED_WR_Byte(0x00,OLED_CMD);//-not offset

 OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency

推荐阅读

史海拾趣

Califia Lighting公司的发展小趣事

Califia Lighting公司的创立源于创始人对节能照明技术的深刻理解和前瞻视野。在电子照明行业快速发展的背景下,他们看到了LED照明技术的巨大潜力,并决定投身其中。凭借对技术的热爱和对市场的敏锐洞察,Califia Lighting成功研发出了一系列高性能的LED灯具和模块,为公司的起步奠定了坚实的基础。

超霸(GP)公司的发展小趣事

绿索超容深知技术创新是企业发展的核心动力。因此,公司积极与东南大学、南京大学等高校开展合作,引入具有自主知识产权的独特技术和工艺,成功开发出GS系列有机双电层超级电容及模组。这些产品不仅在性能上达到了国际领先水平,还获得了多项技术专利。技术上的突破,不仅提升了绿索超容的市场竞争力,也为其赢得了业界的广泛认可。

Custom Electronics Inc公司的发展小趣事

在市场竞争日益激烈的背景下,CEI意识到品牌建设的重要性。公司加大了对品牌形象的宣传力度,通过广告、展览、研讨会等多种方式,提高了品牌知名度和美誉度。同时,CEI还注重产品质量的提升和售后服务的完善,赢得了广大客户的信赖和支持。

Alan Industries Inc公司的发展小趣事

为了进一步提升竞争力,Alan Industries Inc.积极寻求与其他企业的战略合作。公司与多家知名供应商建立了长期稳定的合作关系,确保了原材料的稳定供应和成本控制。同时,公司还通过并购和投资等方式,整合了产业链上下游资源,形成了完整的产业生态圈。这些战略举措使得公司在市场竞争中更具优势,实现了快速发展。

大毅科技公司的发展小趣事

作为一家有社会责任感的企业,大毅科技始终关注环境保护和可持续发展。公司积极推行绿色生产理念,采用环保材料和节能技术,减少生产过程中的废弃物排放和能源消耗。同时,大毅科技还积极参与公益事业和社区活动,回馈社会。这些举措不仅体现了公司的社会责任感,也赢得了社会的广泛赞誉。

以上是关于大毅科技在电子行业中的5个发展故事概述。这些故事展示了大毅科技在创立、生产基地拓展、品质认证与国际化、技术创新与研发以及社会责任与可持续发展等方面的努力和成就。

CTS公司的发展小趣事

在业务发展过程中,CTS公司还通过一系列收购来扩展其业务范围和增强竞争力。例如,CTS完成了对Alpha Ceramics的收购,这是一家为军事和航空航天市场提供传感器和换能器制造商的压电陶瓷材料供应商。这一收购使CTS能够进一步增强其在特定领域的专业能力,并为客户提供更全面的解决方案。

问答坊 | AI 解惑

请教各位老师:100MHz正玄波峰值如何采集?

产品中要求能用计算机采集到100MHz正玄波峰值,有这么快的同步AD采集卡吗?…

查看全部问答>

Linux必学的60个命令

Linux必学的60个命令....…

查看全部问答>

Code_Composer_Studio(CCS)集成开发环境(IDE)入门指导书V10

Code_Composer_Studio(CCS)集成开发环境(IDE)入门指导书V10…

查看全部问答>

给已经初学工控和即将进入工控的初学朋友几点忠告

 给已经初学工控和即将进入工控的初学朋友几点忠告;    1.   如果你是一个性格外向,不喜欢逻辑思维。建议你不要学工控,因为工控是一门逻辑性很强的学科。    2.  如果你是一个对金钱期望值很大很高的 ...…

查看全部问答>

急急。。一个嵌入式的菜鸟问题。。。。

我是一个在校生,由于临时被拉到一个机器人项目组来,以前是学网络编程在这方面实在是没时间学,所以请大家帮帮忙啊,在编译的时候出现了这样的一个错误: error C2597: illegal reference to non-static member \'CSerialPortDlg::hFile 源代码\ ...…

查看全部问答>

小弟是菜鸟,想请教一个VxSim中的时间设置问题

我最近用VxSim作仿真,我知道系统默认的时钟频率是一秒钟60tick,但是我想修改,可不可以再VxSim下修改每秒钟的tick数?要是能修改怎么修改阿?先谢谢大家了!!…

查看全部问答>

欲购买ARM、DSP、FPGA、单片机、GPRS、数据采集卡、总线控制器等设备----实验、开发、仿真及调试

  欲购买ARM、DSP、FPGA、单片机、GPRS、数据采集卡、总线控制器等设备----实验、开发、仿真及调试 目的:学习、开发 要求:资料全、有例程、价格合理,售后服务好、所买的实验设备和开发板(装置)要一致。 由于计划要求一次性购买,所 ...…

查看全部问答>

基础不扎实,关键时候就掉链子

昨天二次面试结束了,佩服面试大哥的提问技巧,都问晕了。 连const都搞乱了。呵呵,鄙视一下自己。…

查看全部问答>

【MSP430共享】MSP430单片机的端口介绍

 MSP430的端口有P1、P2、P3、P4、P5、P6、S和COM(型号不同,包含的端口也不仅相同,如MSP430X11X系列只有P1,P2端口,而MSP430X4XX系列则包含全部上述端口),它们都可以直接用于输入/输出。MSP430系统中没有专门的输入/输出指令,输入/输出操 ...…

查看全部问答>

Nios ii与农业生产

各位前辈,我是FPGA的新手,但是我一直在思索FPGA与农业的结合点,尤其是与山区农业的结合点,因为我就是山区的,甚至在我们那边的农村生活是多么的不方便,而现代机械在山区的使用由于地势的原因,受到了很大的限制,因此我想能否用FPGA对山区的农 ...…

查看全部问答>