一:SSD1306的知识分享
SSD1306是一款非常流行的芯片,专门用来驱动那种小型的单色OLED屏幕。现在0.91寸、0.96寸的OLED模块,核心基本都是它。
简单来说,SSD1306是一个“大脑”,它内部包含了控制器、一个128×64比特的显示缓冲区(SRAM)以及一个升压电路(电荷泵)。单片机不需要一直刷新屏幕,只需要把要显示的内容写入SSD1306的缓冲区,它就会自动驱动屏幕显示了。
分辨率:它原生支持最大 128×64 的点阵屏幕。市面上常见的0.96寸屏幕通常就是这个分辨率,而0.91寸的屏幕则只使用了其中的128×32部分。
丰富的接口:SSD1306非常灵活,支持多种通信方式,方便你连接各种单片机:
I2C接口:最常见,只需2个引脚(SDA, SCL),连线简单,非常适合初学者和引脚紧张的开发板。
SPI接口:速度比I2C快,可以实现非常高的刷新率(有爱好者用SPI实现了超过500Hz的帧率)。通常需要4或5个引脚。
并行接口:支持6800/8080系列并行接口,速度最快,但占用引脚也多,现在已较少使用。
单色显示:只能显示一种颜色,比如白色、蓝色或黄蓝双色(双色是固定的上黄下蓝区域,不能每个像素单独变色)。
低功耗:正常工作时电流大约在20mA左右,休眠时甚至只有微安级别,非常适合电池供电的项目。
工作电压:逻辑电压通常为3.3V,但很多模块会自带稳压芯片,因此可以直接使用5V供电
二:AI8051 代码如下所示:
2.1 SPI 初始化
void SPI_Config(u8 SPI_io)
{
SPI_io &= 3;
SPCTL = SPI_speed & 3; //配置SPI 速度, 这条指令先执行, 顺便Bit7~Bit2清0
SSIG = 1; //1: 忽略SS脚,由MSTR位决定主机还是从机 0: SS脚用于决定主机还是从机。
SPEN = 1; //1: 允许SPI, 0:禁止SPI,所有SPI管脚均为普通IO
DORD = 0; //1:LSB先发, 0:MSB先发
MSTR = 1; //1:设为主机 0:设为从机
CPOL = 1; //1: 空闲时SCLK为高电平, 0:空闲时SCLK为低电平
CPHA = 1; //1: 数据在SCLK前沿驱动,后沿采样. 0: 数据在SCLK前沿采样,后沿驱动.
// SPR1 = 0; //SPR1,SPR0 00: fosc/4, 01: fosc/8
// SPR0 = 0; // 10: fosc/16, 11: fosc/2
P_SW1 = (P_SW1 & ~0x0c) | ((SPI_io<<2) & 0x0c); //切换IO
HSCLKDIV = 1; //HSCLKDIV主时钟分频
SPI_CLKDIV = 1; //SPI_CLKDIV主时钟分频
SPSTAT = 0x80 + 0x40; //清0 SPIF和WCOL标志
}2.2 SPI的中断处理部分
void SPI_DMA_ISR (void) interrupt DMA_SPI_VECTOR
{
if(SPI_TxCnt >= 8) //判断发送是否完毕, 1.46ms @40MHz SPI-4T, 1.04ms @40MHz SPI-2T.
{
DMA_SPI_CR = 0; //关闭SPI DMA
B_SPI_DMA_busy = 0; //清除SPI-DMA忙标志,SPI DMA中断中清除此标志,使用SPI DMA前要确认此标志为0
SPSTAT = 0x80 + 0x40; //清0 SPIF和WCOL标志
HSSPI_CFG2 = SPI_IOSW | SS_DACT; //使用SPI查询或中断方式时,要禁止FIFO
P_OLED_CS = 1;
}
else //仍有数据要发送
{
if(!B_TxCmd) //还没有发设置地址命令,则先发设置地址命令
{
B_TxCmd = 1; //指示已发地址命令
CmdTmp[0] = (u8)(0xb0 + SPI_TxCnt);
CmdTmp[1] = (u8)(((0>>4) & 0x0f) + 0x10); //设置列地址的高4 位
CmdTmp[2] = 0 & 0x0f; //设置列地址的低4 位
P_OLED_DC = 0; //写命令
DMA_SPI_TXAH = (u8)((u16)CmdTmp >> 8); //SPI DMA发送命令首地址
DMA_SPI_TXAL = (u8)CmdTmp;
DMA_SPI_AMTH = 0; //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_SPI_AMT = 3-1; //设置传输总字节数(低8位).
DMA_SPI_CR = DMA_ENSPI | SPI_TRIG_M | SPI_TRIG_S | SPI_CLRFIFO; //启动SPI DMA发送命令
}
else
{
B_TxCmd = 0; //清除已发地址命令
P_OLED_DC = 1; //写数据
DMA_SPI_TXAH = (u8)(SPI_TxAddr >> 8); //SPI DMA发送数据首地址
DMA_SPI_TXAL = (u8)SPI_TxAddr;
DMA_SPI_AMTH = 0; //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_SPI_AMT = 128-1; //设置传输总字节数(低8位).
DMA_SPI_CR = DMA_ENSPI | SPI_TRIG_M | SPI_TRIG_S | SPI_CLRFIFO; //启动SPI DMA发送命令
SPI_TxAddr += 128; //要发送数据的首地址, 一次DMA传输16字节
SPI_TxCnt++; //发送次数+1
}
}
DMA_SPI_STA = 0; //清除中断标志
}2.3 OLED屏幕初始化:
P1n_standard(Pin1); // SPI引脚设置为准双向口, SPI和控制信号 PullUpEnable(P1PU, Pin1); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1 P3n_standard(0x2c); // SPI引脚设置为准双向口, SPI和控制信号 PullUpEnable(P3PU, 0x2c); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1 P4n_standard(Pin7); // SPI引脚设置为准双向口, SPI和控制信号 PullUpEnable(P4PU, Pin7); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1 P_OLED_CS = 1; P_OLED_RST = 1; P_OLED_DC = 1; P_OLED_DIN = 1; P_OLED_CLK = 1; P_OLED_RST = 0; LCD_delay_ms(100); P_OLED_RST = 1; LCD_delay_ms(100); OLED_WriteCMD(0xAE); //Set Display Off OLED_WriteCMD(0xd5); //display divide ratio/osc. freq. mode OLED_WriteCMD(0x80); // OLED_WriteCMD(0xA8); //multiplex ration mode:63 OLED_WriteCMD(0x3F); OLED_WriteCMD(0xD3); //Set Display Offset OLED_WriteCMD(0x00); OLED_WriteCMD(0x40); //Set Display Start Line OLED_WriteCMD(0x8D); //Set Display Offset OLED_WriteCMD(0x14); OLED_WriteCMD(0xA1); //Segment Remap OLED_WriteCMD(0xC8); //Sst COM Output Scan Direction OLED_WriteCMD(0xDA); //common pads hardware: alternative OLED_WriteCMD(0x12); OLED_WriteCMD(0x81); //contrast control OLED_WriteCMD(0xCF); OLED_WriteCMD(0xD9); //set pre-charge period OLED_WriteCMD(0xF1); OLED_WriteCMD(0xDB); //VCOM deselect level mode OLED_WriteCMD(0x40); //set Vvcomh=0.83*Vcc OLED_WriteCMD(0xA4); //Set Entire Display On/Off OLED_WriteCMD(0xA6); //Set Normal Display OLED_WriteCMD(0xAF); //Set Display On FillAll(0);
2.4 主程序显示部分
for(i=0; i<1024; i++) DisTmp[i] = 0; //清除显存 SPI_DMA_TRIG(DisTmp); while(B_SPI_DMA_busy); //等待SPI DMA完成 printf_ASCII_text(0, 0, " OLED12864 SSD1306"); // for(i=0; i<8; i++) WriteHZ16((u8)(i*16),2,i); printf_ASCII_text(0, 2, " EEPW KEYBOARD007 "); printf_ascii_10x24(0,5,"-123456789"); LCD_delay_ms(3000);
三:实物测试如下:

我要赚赏金
