OLED屏幕改SSD1306 I2C接口:与EEPROM共用软件I2C总线(PB4/PB5,0x78),数据流式传输,storage_lock互斥;字库SPI不动;释放PC8/PC9/PA11

This commit is contained in:
helei 2026-09-20 10:10:32 +08:00
parent 3cd34e6a2b
commit 1af245d43d
4 changed files with 58 additions and 63 deletions

View File

@ -63,7 +63,8 @@
| NET_LED | **PB13**LED2 仍 PC13 |
| EEPROM I2CSCL/SDA | **PB5/PB4** |
| W25Q64CS/DO/CLK/DI | **PB8/PB9/PB6/PB7** |
| OLEDCS2/FSO/CS1/DC/MOSI/CLK/RES | **PC12/PA12/PC8/PC9/PA15/PB3/PA11** |
| OLED 屏幕 | **SSD1306 I2CSCL=PB5/SDA=PB4与 EEPROM 共总线,地址 0x78无 RST** |
| 字库 IC独立 SPI | CLK=PB3 DI=PA15 FSO=PA12 CS2=PC12 |
| HR_IN 缺料检测 | **PA8 下拉输入,高=缺料→停投料关继电器1只记日志不接传感器不影响投料** |
| KEY1~4 | **PC6/PC7/PB14/PB15 上拉输入,功能预留** |
| 取消 | PA8 手动模式开关MANUAL_MODE 已删) |

View File

@ -1,28 +1,23 @@
/* oled.c - 128x64 OLED + 晶联讯 GB2312 字库 IC 驱动GPIO 模拟 SPI
* 485CRC oledisp.c
* CLK=PB3 MOSI=PA15 DC=PC9 CS1=PC8 FSO=PA12 CS2=PC12 RST=PA11 */
/* oled.c - 128x64 OLED(SSD1306, I2C) + 晶联讯 GB2312 字库 IC(SPI) 驱动
* : I2C , EEPROM I2C 线(SCL=PB5 SDA=PB4), RST ;
* 24C02 storage_lock()
* : SPI (CLK=PB3 DI=PA15 FSO=PA12 CS2=PC12) */
#include "oled.h"
#include "qrcodegen.h"
#include "iic.h"
#include "app_loop.h" /* storage_lock/unlock */
#include <string.h>
#define OLED_CLK_PORT GPIOB
#define OLED_CLK_PIN GPIO_PIN_3
#define OLED_MOSI_PORT GPIOA
#define OLED_MOSI_PIN GPIO_PIN_15
#define OLED_DC_PORT GPIOC
#define OLED_DC_PIN GPIO_PIN_9
#define OLED_CS1_PORT GPIOC
#define OLED_CS1_PIN GPIO_PIN_8
#define OLED_FSO_PORT GPIOA
#define OLED_FSO_PIN GPIO_PIN_12
#define OLED_CS2_PORT GPIOC
#define OLED_CS2_PIN GPIO_PIN_12
#define OLED_RST_PORT GPIOA
#define OLED_RST_PIN GPIO_PIN_11 /* 复位脚,低电平复位(板内上拉,默认拉高即可) */
#define lcd_cs1(a) HAL_GPIO_WritePin(OLED_CS1_PORT, OLED_CS1_PIN, (GPIO_PinState)(a))
#define lcd_dc(a) HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, (GPIO_PinState)(a))
#define lcd_mosi(a) HAL_GPIO_WritePin(OLED_MOSI_PORT, OLED_MOSI_PIN, (GPIO_PinState)(a))
#define lcd_clk(a) HAL_GPIO_WritePin(OLED_CLK_PORT, OLED_CLK_PIN, (GPIO_PinState)(a))
#define rom_cs2(a) HAL_GPIO_WritePin(OLED_CS2_PORT, OLED_CS2_PIN, (GPIO_PinState)(a))
@ -60,11 +55,10 @@ static void oled_gpio_init(void)
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/* 先置好空闲电平再开推挽,避免毛刺 */
/* 屏幕已改 I2C(不占 GPIO); 这里只初始化字库 IC 的 SPI 四线: CLK/DI/FSO/CS2
* */
HAL_GPIO_WritePin(OLED_CLK_PORT, OLED_CLK_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(OLED_MOSI_PORT, OLED_MOSI_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(OLED_CS1_PORT, OLED_CS1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(OLED_CS2_PORT, OLED_CS2_PIN, GPIO_PIN_SET);
g.Mode = GPIO_MODE_OUTPUT_PP;
@ -73,35 +67,33 @@ static void oled_gpio_init(void)
g.Pin = OLED_CLK_PIN; HAL_GPIO_Init(OLED_CLK_PORT, &g);
g.Pin = OLED_MOSI_PIN; HAL_GPIO_Init(OLED_MOSI_PORT, &g);
g.Pin = OLED_DC_PIN; HAL_GPIO_Init(OLED_DC_PORT, &g);
g.Pin = OLED_CS1_PIN; HAL_GPIO_Init(OLED_CS1_PORT, &g);
g.Pin = OLED_CS2_PIN; HAL_GPIO_Init(OLED_CS2_PORT, &g);
/* RST(PA11):推挽输出,默认高(板内上拉,这里也主动拉高) */
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
g.Pin = OLED_RST_PIN;
g.Mode = GPIO_MODE_OUTPUT_PP;
g.Pull = GPIO_NOPULL;
g.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(OLED_RST_PORT, &g);
fso_output();
}
/*==== 写字节到屏幕DC=0 指令 / DC=1 数据)====*/
/*==== SSD1306 I2C 传输(与 EEPROM 共用软件 I2C 总线) ====*/
#define OLED_I2C_ADDR 0x78 /* 8 位写地址(7 位 0x3C); 模块 SA0 拉高时为 0x7A */
/* 写字节到屏幕dc=0 指令 / dc=1 数据): START+地址+控制字节+数据+STOP */
static void oled_write(uint8_t dc, uint8_t dat)
{
lcd_dc(dc);
lcd_cs1(0);
for (int i = 0; i < 8; i++) {
lcd_clk(0);
lcd_mosi(dat & 0x80);
lcd_clk(1);
dat <<= 1;
iicStart();
iicSendByteAck(OLED_I2C_ADDR);
iicSendByteAck(dc ? 0x40 : 0x00);
iicSendByteAck(dat);
iicStop();
}
lcd_dc(1);
lcd_cs1(1);
/* 数据流: 一次 START 连续写多字节(清屏/画图用, 比逐字节事务快约 3 倍) */
static void oled_data_begin(void)
{
iicStart();
iicSendByteAck(OLED_I2C_ADDR);
iicSendByteAck(0x40);
}
static void oled_data_byte(uint8_t d) { iicSendByteAck(d); }
static void oled_data_end(void) { iicStop(); }
/*==== 设置页/列地址 ====*/
static void lcd_address(uint8_t page, uint8_t column)
@ -159,15 +151,16 @@ void oled_show_qrcode(const char *text)
}
/* 写左半屏 64 列(整页覆写, 不影响右侧文本区) */
lcd_cs1(0);
rom_cs2(1);
storage_lock();
for (uint8_t pg = 0; pg < 8; pg++) {
oled_write(0, 0xb0 + pg);
oled_write(0, 0x00);
oled_write(0, 0x10);
for (uint8_t x = 0; x < 64; x++) oled_write(1, pagebuf[pg][x]);
oled_data_begin();
for (uint8_t x = 0; x < 64; x++) oled_data_byte(pagebuf[pg][x]);
oled_data_end();
}
lcd_cs1(1);
storage_unlock();
/* 右侧 ID 文本: x=64 起每行 8 个 ASCII, 最多 3 行 */
int len = (int)strlen(id);
@ -185,35 +178,31 @@ void oled_show_qrcode(const char *text)
/*==== 关显示(黑屏,断电预警时调用)====*/
void oled_off(void)
{
storage_lock();
oled_write(0, 0xAE); /* display off */
storage_unlock();
}
/*==== 全屏清屏 ====*/
void oled_clear(void)
{
lcd_cs1(0);
rom_cs2(1);
storage_lock();
for (uint8_t i = 0; i < 8; i++) {
oled_write(0, 0xb0 + i);
oled_write(0, 0x00);
oled_write(0, 0x10);
for (uint8_t j = 0; j < 128; j++) oled_write(1, 0x00);
oled_data_begin();
for (uint8_t j = 0; j < 128; j++) oled_data_byte(0x00);
oled_data_end();
}
lcd_cs1(1);
storage_unlock();
}
/*==== 屏幕初始化SSD1306 兼容序列)====*/
void oled_init(void)
{
HAL_Delay(400); /* 等屏幕/字库上电稳定 */
HAL_Delay(400); /* 等屏幕/字库上电稳定(I2C 屏无 RST 脚, 靠上电延时) */
oled_gpio_init();
/* 硬件复位一次屏幕RST 低 10ms保证从确定状态开始初始化 */
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
HAL_Delay(120);
lcd_cs1(0);
rom_cs2(1);
oled_write(0, 0xAE); /* display off */
oled_write(0, 0x20); /* 寻址模式 */
@ -243,33 +232,35 @@ void oled_init(void)
oled_write(0, 0x8d); /* DC-DC */
oled_write(0, 0x14);
oled_write(0, 0xaf); /* display on */
lcd_cs1(1);
oled_clear();
}
/*==== 显示 16x16 点阵(汉字)====*/
static void display_graphic_16x16(uint8_t page, uint8_t column, const uint8_t *dp)
{
lcd_cs1(0);
rom_cs2(1);
storage_lock();
for (uint8_t j = 2; j > 0; j--) {
lcd_address(column, page);
for (uint8_t i = 0; i < 16; i++) oled_write(1, *dp++);
oled_data_begin();
for (uint8_t i = 0; i < 16; i++) oled_data_byte(*dp++);
oled_data_end();
page++;
}
lcd_cs1(1);
storage_unlock();
}
/*==== 显示 8x16 点阵ASCII====*/
static void display_graphic_8x16(uint8_t page, uint8_t column, const uint8_t *dp)
{
lcd_cs1(0);
storage_lock();
for (uint8_t j = 2; j > 0; j--) {
lcd_address(column, page);
for (uint8_t i = 0; i < 8; i++) oled_write(1, *dp++);
oled_data_begin();
for (uint8_t i = 0; i < 8; i++) oled_data_byte(*dp++);
oled_data_end();
page++;
}
lcd_cs1(1);
storage_unlock();
}
/*==== 字库 IC 写字节(指令/地址)====*/
@ -303,7 +294,6 @@ static uint8_t rom_read_byte(void)
static void rom_read_n(uint8_t ah, uint8_t am, uint8_t al, uint8_t *buf, uint8_t len)
{
rom_cs2(0);
lcd_cs1(1);
lcd_clk(0);
rom_write_byte(0x03); /* 读指令 */
rom_write_byte(ah);

View File

@ -4,8 +4,8 @@
#include "main.h"
/* 128x64 OLEDSSD1306 兼容指令)+ 晶联讯 GB2312 字库 IC全部 GPIO 模拟 SPI。
* 线(V1.7.0 )CLK=PB3 MOSI=PA15 DC=PC9 CS1=PC8() FSO=PA12(,MCU方向)
* CS2=PC12() RST=PA11
* ÆÁÄ»: SSD1306 I2C(SCL=PB5 SDA=PB4, Óë EEPROM ¹²×ÜÏß, ÎÞ RST)
* ×Ö¿â: SPI(CLK=PB3 DI=PA15 FSO=PA12 CS2=PC12)
* GB2312/GBK GBK
* 128x6416 4 row 0~3 8 16 ASCII */

View File

@ -21,6 +21,10 @@
控制命令改三段式FC03 预读(判定在线 + 快照命令前反馈)→ FC05 → 150ms → FC03 校验跳变;
命令链路最终无应答即判离线并应答平台 `ext relay board offline`,下次命令自动重新探测恢复;
断电恢复触发点不变(离线→上线比对 EEPROM 逐路补发)
- **OLED 屏幕改 I2C 接口**SSD1306 I2C 版,无 RST 脚):与 EEPROM 共用软件 I2C 总线SCL=PB5/SDA=PB4
地址 0x78显示数据流式传输一次 START 连续写,比逐字节事务快约 3 倍);与 24C02 的跨任务互斥
用 storage_lock 包每个完整显示事务;字库 IC 仍为独立 SPICLK=PB3/DI=PA15/FSO=PA12/CS2=PC12暂不动
释放 IOPC8(CS1)、PC9(DC)、PA11(RST) 共 3 个(后续字库并入 Flash SPI 可再省 2 个)
- **联网方式改为开机按键手动选择**(废除自动切换):欢迎页后 10s 倒计时KEY1(PC6)=4G /
KEY2(PC7)=WiFi 固定热点 / KEY3(PB14)=SmartConfig 配网;倒计时内按不同键**可反复切换选中项**
**重复按当前项=立即确认**,超时=当前选中项生效;初始选中项=EEPROM 记忆的上次选择(首次默认 4G