OLED引脚介绍:
CS:OLED片选信号
RST:OLED复位端口
DC: 命令/数据选择端口(0:读写命令, 1: 读写数据)
SCLK(D0):串口时钟线
SDIN(D1): 串口数据线
关于SPI的相关知识,可以参见这篇博客:
首先是SPI.C,包含了对该模块的各种操作,就是对SPI 写进行符合OLED的包装。写字符,写数字,写字符串,可调显示字体大小,但是需要包含两个ASCII字库。
#include "spi.h" #include "word.h" //字库头文件 #define OLED_Order 0 //定义写命令 #define OLED_Data 1 //定义写数据 //尽在内部调用函数 static u32 oled_pow(u8 m,u8 n); static void OLED_GPIO_INIT(void); static void SPI_Write(u8 data, u8 Mode); static void OLED_Coord(u8 x, u8 y); //使用管脚初始化 static void OLED_GPIO_INIT(void) { GPIO_InitTypeDef GPIO_InitStruct; //开启GPIOD的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //设置GPIO的基本参数 GPIO_InitStruct.GPIO_Pin = OLED_CS_PIN | OLED_RST_PIN | OLED_DC_PIN | OLED_D0_PIN | OLED_D1_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //输出速度50MHz GPIO_Init(OLED_PORT, &GPIO_InitStruct); GPIO_SetBits(OLED_PORT, OLED_CS_PIN | OLED_RST_PIN | OLED_DC_PIN | OLED_D0_PIN | OLED_D1_PIN); } /* SPI写数据/命令 * Mode :OLED_Order:写命令 OLED_Data:写数据 * data :数据/命令 */ static void SPI_Write(u8 data, u8 Mode) { u8 i = 0; if(Mode) { OLED_DC(1); //DC引脚输入高,表示写数据 } else { OLED_DC(0); //DC引脚输入低,表示写命令 } OLED_CS(0); //CS引脚输入低,片选使能 for(i = 0; i < 8; i++) { OLED_D0(0); //D0引脚输入低 if(data&0x80) //判断传输的数据最高位为1还是0 { OLED_D1(1); //D1引脚输入高 } else { OLED_D1(0); //D1引脚输入低 } OLED_D0(1); //D1引脚输入高 data<<=1; //将数据左移一位 } OLED_DC(1); //DC引脚输入低 OLED_CS(1); //CS引脚输入高,片选失能 } /* 设置OLED屏的显示坐标 * X : 表示OLED的水平坐标(0—127) * Y : 表示OLED的页(0—7) */ static void OLED_Coord(u8 x, u8 y) { SPI_Write((0xb0 + y) ,OLED_Order); SPI_Write((((x & 0xf0)>>4) | 0x10), OLED_Order);//高4位 SPI_Write((x & 0x0f)|0x01, OLED_Order);//低4位 } //清屏,一开始这里写错了,把写命令写成了写数据,导致清屏不正确,发现屏幕上有很多噪点,说明没有清屏成功。 void OLED_Clear(void) { u8 i = 0, j = 0; for(i = 0; i < 8; i++) { SPI_Write(0xb0 + i,OLED_Order); SPI_Write(0x00,OLED_Order); SPI_Write(0x10,OLED_Order); for(j = 0; j < 128; j++) { SPI_Write(0x00, OLED_Data); } } } //关oled显示 void OLED_Display_Off(void) { SPI_Write(0x8D,OLED_Order); SPI_Write(0x10,OLED_Order); SPI_Write(0xAE,OLED_Order); } //开oled显示 void OLED_Display_On(void) { //电荷泵设置(初始化时必须打开,否则看不到显示) SPI_Write(0x8D, OLED_Order); SPI_Write(0x14, OLED_Order);//bit2 0:关闭 1:打开 SPI_Write(0xAF, OLED_Order);//0xAF:开显示 } //oled参数初始化 void OLED_Init(void) { OLED_GPIO_INIT(); //端口初始化 OLED_RST(1); delay_ms(100); OLED_RST(0); delay_ms(100); OLED_RST(1); SPI_Write(0xAE, OLED_Order);//0xAE:关显示 SPI_Write(0x00, OLED_Order);//设置低列地址 SPI_Write(0x10, OLED_Order);//设置高列地址 //设置行显示的开始地址(0-63) //40-47: (01xxxxx) SPI_Write(0x40, OLED_Order); //设置对比度 SPI_Write(0x81, OLED_Order); SPI_Write(0xff, OLED_Order);//这个值越大,屏幕越亮(和上条指令一起使用)(0x00-0xff) SPI_Write(0xA1, OLED_Order);//0xA1: 左右反置, 0xA0: 正常显示(默认0xA0) SPI_Write(0xC8, OLED_Order);//0xC8: 上下反置, 0xC0: 正常显示(默认0xC0) //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮) //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮) SPI_Write(0xA6, OLED_Order); SPI_Write(0xA8, OLED_Order);//设置多路复用率(1-64) SPI_Write(0x3F, OLED_Order);//(0x01-0x3f)(默认为3f) //设置显示抵消移位映射内存计数器 SPI_Write(0xD3, OLED_Order); SPI_Write(0x00, OLED_Order);//(0x00-0x3f)(默认为0x00) //设置显示时钟分频因子/振荡器频率 SPI_Write(0xD5, OLED_Order); //低4位定义显示时钟(屏幕的刷新时间)(默认:0000)分频因子= [3:0]+1 //高4位定义振荡器频率(默认:1000) SPI_Write(0x80, OLED_Order);// //时钟预充电周期 SPI_Write(0xD9, OLED_Order); SPI_Write(0xF1, OLED_Order);//[3:0],PHASE 1; [7:4] PHASE 2 //设置COM硬件应脚配置 SPI_Write(0xDA, OLED_Order); SPI_Write(0x12, OLED_Order);//[5:4] 默认:01 SPI_Write(0xDB, OLED_Order);// SPI_Write(0x40, OLED_Order);// //设置内存寻址方式 SPI_Write(0x20, OLED_Order); //00: 表示水平寻址方式 //01: 表示垂直寻址方式 //10: 表示页寻址方式(默认方式) SPI_Write(0x02, OLED_Order);// //电荷泵设置(初始化时必须打开,否则看不到显示) SPI_Write(0x8D, OLED_Order); SPI_Write(0x14, OLED_Order);//bit2 0:关闭 1:打开 //设置是否全部显示 0xA4: 禁止全部显示 SPI_Write(0xA4, OLED_Order); //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮) //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮) SPI_Write(0xA6, OLED_Order);// SPI_Write(0xAF, OLED_Order);//0xAF:开显示 SPI_Write(0xAF, OLED_Order); //不知道为什么要写两次 OLED_Clear(); OLED_Coord(0,0); } //显示汉字,设置坐标, void OLED_ShowChinese(u8 x, u8 y, u8 chinese) { u8 t,adder=0; OLED_Coord(x,y); for(t=0;t<16;t++) //每行16个元素,一个字需要两行字符串 { SPI_Write(Hzk[2*chinese][t],OLED_Data); adder+=1; } OLED_Coord(x,y+1); for(t=0;t<16;t++) { SPI_Write(Hzk[2*chinese+1][t],OLED_Data); adder+=1; } } //在指定位置显示一个字符,包括部分字符 //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) //8*16字符 { OLED_Coord(x,y); for(i=0;i<8;i++) SPI_Write(F8X16[c*16+i],OLED_Data); OLED_Coord(x,y+1); for(i=0;i<8;i++) SPI_Write(F8X16[c*16+i+8],OLED_Data); } else //6*8字符 { OLED_Coord(x,y+1); for(i=0;i<6;i++) SPI_Write(F6x8[c][i],OLED_Data); } } //显示字符串 void OLED_Show_String(u8 x, u8 y, u8 *chr) { u8 j=0; while (chr[j]!='\0') { OLED_ShowChar(x,y,chr[j]); x+= 8 ; if(x>120){x=0;y+=2;} //自动换行写 j++; } } //m^n函数 static u32 oled_pow(u8 m,u8 n) { u32 result = 1; while(n--)result*=m; return result; } //显示数字 //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 = 0, temp = 0; u8 enshow=0; for(t=0;t<len;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'); } }