OLED+8080并行实现!一文看懂

8080并口

        8080并口模式是一种由Intel提出的并行总线协议,广泛应用于MCU与外部设备(如LCD、存储器)的高速数据传输。其核心特点是通过多根控制线与数据线协同操作,实现高效读写控制

时序

根据时序的写入一个字节实现:

void Write_8080_Byte(uint8_t data, uint8_t is_data) 
{
    // 1. 设置D/I引脚(命令或数据)
    HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, is_data ? GPIO_PIN_SET : GPIO_PIN_RESET);
    
    // 2. 拉低片选
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
    
    // 3. 加载数据到GPIO端口(假设数据线接在GPIOB的D0-D7)
    // STM32的GPIO端口(如GPIOB)通常由16个引脚(D0-D15)组成,每个引脚对应ODR寄存器的一个位(ODR是一个16位寄存器)--8080模式
    GPIOB->ODR = (GPIOB->ODR & 0xFF00) | data;  // 仅修改低8位
    
    // 4. 生成WR低电平并保持Tsu
    HAL_GPIO_WritePin(WR_GPIO_Port, WR_Pin, GPIO_PIN_RESET);
    __NOP(); __NOP(); __NOP();  // 约15ns@72MHz
    
    // 5. WR上升沿锁存数据
    HAL_GPIO_WritePin(WR_GPIO_Port, WR_Pin, GPIO_PIN_SET);
    
    // 6. 释放片选
    HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
}

拓展

        用HAL库实现IIC写入一个数据,本质就是使用IIC库函数根据从设备地址写入数据(控制字节+数据)

        注意:HAL_I2C_Master_Transmit函数要求传入的目标地址是7位地址左移1位后的值,即8位地址格式。若OLED的7位地址是0x3C,则:写操作地址:0x3C << 1 = 0x78 (0b01111000)。 读操作地址:0x3C << 1 | 1 = 0x79 (0b01111001)

/* 定义OLED的I2C地址(假设为0x3C,需根据实际模块调整) */
#define OLED_I2C_ADDR    0x3C

void Write_I2C_Byte(uint8_t data, uint8_t is_data) {
    uint8_t buffer[2];
    buffer[0] = is_data ? 0x40 : 0x00;  // 控制字节:0x00(命令)或0x40(数据)
    buffer[1] = data;                    // 数据或命令字节

    // 通过I2C发送数据包
    HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR << 1, buffer, 2, HAL_MAX_DELAY);
}

OLED

常用命令

页地址模式:对GRAM进行操作时,列地址指针会自动递增。当列地址指针到达列结束地址时,重置为开始地址,但页地址指针不变。用户必须设置新的页面和列地址,以便访问下一页GRAM内容。----------1. 发送内存地址模式命令0x20 2. 发送页地址模式命令0x02,默认为页地址模式

static uint8_t g_oled_gram[128][8];	 /* OLED的显存 */

void oled_refresh_gram(void) 
{	
	uint8_t 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( g_oled_gram[ n ][ i ], OLED_DATA) ;
		}
	}
}

一共八次循环八次页写入,列地址在该模式下会自动地址,写完一页的所有列之后需要重置页和列

简单来讲,128*64的分辨率就是128*64bit,二维数组GRAM[128][8]队友与之对应,GRAM[128][x]代表一页,GRAM[y][x]代表一页中的一列。

画点函数

void oled_draw_point(uint8_t  x, uint8_t  y, uint8_t  dot) 
{	
	uint8_t pos, bx, temp = 0;
	if (x > 127 || y > 63)	 return;	 /* 超出范围了 */ 		
	pos = y / 8; 		/*  页地址 */
	bx = y % 8; 		/*  计算y在对应字节里面的位置 */
	temp = 1 << bx;	/*  转换后y对应的bit位置 */
	
	if ( dot )	/*  画实心点 */
		g_oled_gram[ x ][ pos ] |= temp;
	else
		g_oled_gram[ x ][ pos ] &= ~temp;
}

 字符显示

        字符显示的原理就是根据一个字符点阵,维护唯一的一个GRAM[128][64],改变其中的值,然后刷新(oled_refresh_gram(void)),发送GRAM到驱动芯片, 在字符宽度为16*8的情况下,根据字符的点阵数据,对GRAM进行改写

	uint8_t oled_ascii_1608[]=
{
  0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,
  0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04
} ;
void oled_show_char_test(uint8_t x, uint8_t y, uint8_t mode) 
{
	uint8_t temp, t1, t;
	uint8_t y0 = y;                 // 起始y坐标
	
	for (t = 0; t < 16; t++)  // 处理16列(字符宽度16像素)
	{     
		temp = oled_ascii_1608[t];  // 获取当前列数据
	
		for (t1 = 0; t1 < 8; t1++) 
		{ 
			// 处理每列的8个像素(字符高度8像素)
			if (temp & 0x80)        // 检查最高位(最上方像素)
				oled_draw_point(x, y, mode);
			else
				oled_draw_point(x, y, !mode);
	
			temp <<= 1;             // 左移处理下一位
			y++;                    // y坐标递增
	
			if ((y - y0) == 8) 
			{    // 已处理完8行(一列的高度)
				y = y0;             // 重置y坐标到起始位置
				x++;                // 移至下一列(x递增)
				break;              // 跳出内层循环,处理下一列
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值