这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 学习AI8051开发板例程:36AI8051的硬件SPI驱动SSD1306的OL

共1条 1/1 1 跳转至

学习AI8051开发板例程:36AI8051的硬件SPI驱动SSD1306的OLED显示

高工
2026-03-18 19:01:21     打赏

一: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);

三:实物测试如下:

36-1.png





关键词: AI8051     SPI     OLED    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]