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; // 跳出内层循环,处理下一列
}
}
}
}