2026-09-20 10:10:32 +08:00
|
|
|
|
/* oled.c - 128x64 OLED(SSD1306, I2C) + <20><><EFBFBD><EFBFBD>Ѷ GB2312 <20>ֿ<EFBFBD> IC(SPI) <20><><EFBFBD><EFBFBD>
|
2026-09-20 11:12:43 +08:00
|
|
|
|
* <EFBFBD><EFBFBD>Ļ: I2C <EFBFBD>ӿ<EFBFBD>(ԭ<EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> OLED_SCL/OLED_SDA), <EFBFBD><EFBFBD> EEPROM <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I2C <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* (SCL=PB5 SDA=PB4, <EFBFBD><EFBFBD> iic.h), <EFBFBD><EFBFBD> RST <EFBFBD><EFBFBD>; <EFBFBD><EFBFBD>ַ OLED_I2C_ADDR=0x78;
|
2026-09-20 10:10:32 +08:00
|
|
|
|
* <EFBFBD><EFBFBD> 24C02 <EFBFBD>Ŀ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> storage_lock(ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
2026-09-20 12:09:19 +08:00
|
|
|
|
* <EFBFBD>ֿ<EFBFBD>: SPI, <EFBFBD><EFBFBD> W25Q64 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(ROM_CLK=PB6 ROM_DI=PB7 ROM_DO=PB9), ROM_CS=PB3 <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭѡ;
|
2026-09-20 11:12:43 +08:00
|
|
|
|
* ROM_DO(PB9) <EFBFBD>̶<EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(W25Q64_Init <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>), <EFBFBD>ֿ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> storage_lock <EFBFBD><EFBFBD> Flash <EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
2026-09-04 20:09:04 +08:00
|
|
|
|
|
|
|
|
|
|
#include "oled.h"
|
2026-09-13 20:37:06 +08:00
|
|
|
|
#include "qrcodegen.h"
|
2026-09-20 10:10:32 +08:00
|
|
|
|
#include "iic.h"
|
|
|
|
|
|
#include "app_loop.h" /* storage_lock/unlock */
|
2026-09-04 20:09:04 +08:00
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
2026-09-20 11:12:43 +08:00
|
|
|
|
#define ROM_CLK_PORT GPIOB
|
|
|
|
|
|
#define ROM_CLK_PIN GPIO_PIN_6 /* <20>ֿ<EFBFBD> CLK, <20><> W25Q64 CLK <20><><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define ROM_DI_PORT GPIOB
|
|
|
|
|
|
#define ROM_DI_PIN GPIO_PIN_7 /* <20>ֿ<EFBFBD> DI, <20><> W25Q64 DI <20><><EFBFBD><EFBFBD> */
|
|
|
|
|
|
#define ROM_DO_PORT GPIOB
|
|
|
|
|
|
#define ROM_DO_PIN GPIO_PIN_9 /* <20>ֿ<EFBFBD> DO(FSO), <20><> W25Q64 DO <20><><EFBFBD><EFBFBD>, <20><>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD> */
|
2026-09-20 12:09:19 +08:00
|
|
|
|
#define ROM_CS_PORT GPIOB
|
|
|
|
|
|
#define ROM_CS_PIN GPIO_PIN_3
|
2026-09-04 20:09:04 +08:00
|
|
|
|
|
2026-09-20 11:12:43 +08:00
|
|
|
|
#define rom_di(a) HAL_GPIO_WritePin(ROM_DI_PORT, ROM_DI_PIN, (GPIO_PinState)(a))
|
|
|
|
|
|
#define rom_clk(a) HAL_GPIO_WritePin(ROM_CLK_PORT, ROM_CLK_PIN, (GPIO_PinState)(a))
|
|
|
|
|
|
#define rom_cs(a) HAL_GPIO_WritePin(ROM_CS_PORT, ROM_CS_PIN, (GPIO_PinState)(a))
|
|
|
|
|
|
#define ROM_DO_READ HAL_GPIO_ReadPin(ROM_DO_PORT, ROM_DO_PIN)
|
2026-09-04 20:09:04 +08:00
|
|
|
|
|
|
|
|
|
|
static uint8_t s_row = 0; /* <20><>ǰҳ<C7B0><D2B3>ַ<EFBFBD><D6B7>16px <20><> <20><> 2<><32> */
|
|
|
|
|
|
static uint8_t s_col = 0; /* <20><>ǰ<EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>أ<EFBFBD> */
|
|
|
|
|
|
|
2026-09-20 10:18:31 +08:00
|
|
|
|
/* ע: <20>ֿ<EFBFBD> DO(FSO) <20><> W25Q64 DO <20><><EFBFBD><EFBFBD>(PB9), <20><> W25Q64_Init <20>̶<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD> */
|
2026-09-04 20:09:04 +08:00
|
|
|
|
/*==== GPIO <20><>ʼ<EFBFBD><CABC> ====*/
|
|
|
|
|
|
static void oled_gpio_init(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
GPIO_InitTypeDef g = {0};
|
|
|
|
|
|
|
|
|
|
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
|
|
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
|
|
|
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
|
|
|
|
|
|
2026-09-20 10:18:31 +08:00
|
|
|
|
/* <20><>Ļ I2C <20><>ռ GPIO; <20>ֿ<EFBFBD> CLK(PB6)/DI(PB7) <20><> W25Q64 <20><><EFBFBD><EFBFBD>(<28><> Init <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>),
|
|
|
|
|
|
* DO(PB9) <EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD> Init <EFBFBD><EFBFBD><EFBFBD><EFBFBD>), <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD>ֿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭѡ CS2(PC12), Ĭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߲<EFBFBD>ѡ<EFBFBD><EFBFBD> */
|
2026-09-20 11:12:43 +08:00
|
|
|
|
HAL_GPIO_WritePin(ROM_CS_PORT, ROM_CS_PIN, GPIO_PIN_SET);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
g.Mode = GPIO_MODE_OUTPUT_PP;
|
|
|
|
|
|
g.Pull = GPIO_PULLUP;
|
|
|
|
|
|
g.Speed = GPIO_SPEED_FREQ_LOW;
|
2026-09-20 11:12:43 +08:00
|
|
|
|
g.Pin = ROM_CS_PIN; HAL_GPIO_Init(ROM_CS_PORT, &g);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-20 10:10:32 +08:00
|
|
|
|
/*==== SSD1306 I2C <20><><EFBFBD><EFBFBD>(<28><> EEPROM <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> I2C <20><><EFBFBD><EFBFBD>) ====*/
|
|
|
|
|
|
#define OLED_I2C_ADDR 0x78 /* 8 λд<CEBB><D0B4>ַ(7 λ 0x3C); ģ<><C4A3> SA0 <20><><EFBFBD><EFBFBD>ʱΪ 0x7A */
|
|
|
|
|
|
|
|
|
|
|
|
/* д<>ֽڵ<D6BD><DAB5><EFBFBD>Ļ<EFBFBD><C4BB>dc=0 ָ<><D6B8> / dc=1 <20><><EFBFBD>ݣ<EFBFBD>: START+<2B><>ַ+<2B><><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>+<2B><><EFBFBD><EFBFBD>+STOP */
|
2026-09-04 20:09:04 +08:00
|
|
|
|
static void oled_write(uint8_t dc, uint8_t dat)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
iicStart();
|
|
|
|
|
|
iicSendByteAck(OLED_I2C_ADDR);
|
|
|
|
|
|
iicSendByteAck(dc ? 0x40 : 0x00);
|
|
|
|
|
|
iicSendByteAck(dat);
|
|
|
|
|
|
iicStop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: һ<><D2BB> START <20><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD>ֽ<EFBFBD>(<28><><EFBFBD><EFBFBD>/<2F><>ͼ<EFBFBD><CDBC>, <20><><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD><D6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ 3 <20><>) */
|
|
|
|
|
|
static void oled_data_begin(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
iicStart();
|
|
|
|
|
|
iicSendByteAck(OLED_I2C_ADDR);
|
|
|
|
|
|
iicSendByteAck(0x40);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
2026-09-20 10:10:32 +08:00
|
|
|
|
static void oled_data_byte(uint8_t d) { iicSendByteAck(d); }
|
|
|
|
|
|
static void oled_data_end(void) { iicStop(); }
|
2026-09-04 20:09:04 +08:00
|
|
|
|
|
|
|
|
|
|
/*==== <20><><EFBFBD><EFBFBD>ҳ/<2F>е<EFBFBD>ַ ====*/
|
|
|
|
|
|
static void lcd_address(uint8_t page, uint8_t column)
|
|
|
|
|
|
{
|
|
|
|
|
|
oled_write(0, 0xb0 + column); /* ҳ<><D2B3>ַ */
|
|
|
|
|
|
oled_write(0, ((page & 0xf0) >> 4) | 0x10); /* <20>е<EFBFBD>ַ<EFBFBD><D6B7> 4 λ */
|
|
|
|
|
|
oled_write(0, (page & 0x0f)); /* <20>е<EFBFBD>ַ<EFBFBD><D6B7> 4 λ */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-13 20:37:06 +08:00
|
|
|
|
/*==== <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ά<EFBFBD><CEAC>ҳ: <20><><EFBFBD><EFBFBD>=text(<28>豸 ClientID), <20><><EFBFBD><EFBFBD> QR <20>װ<D7B5><D7B0><EFBFBD>, <20>Ҳ<EFBFBD> ID <20>ı<EFBFBD> ====
|
|
|
|
|
|
* QR <EFBFBD><EFBFBD> Nayuki qrcodegen <EFBFBD><EFBFBD><EFBFBD><EFBFBD>(V1~V3 <EFBFBD>Զ<EFBFBD>, ECC-L, 2px/ģ<EFBFBD><EFBFBD><EFBFBD>Ŵ<EFBFBD>), <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+2 ģ<EFBFBD>龲<EFBFBD><EFBFBD>;
|
|
|
|
|
|
* <EFBFBD>Ҳ<EFBFBD> x=64 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>ӡ ID(ÿ<EFBFBD><EFBFBD> 8 <EFBFBD>ַ<EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD> 3 <EFBFBD><EFBFBD>) */
|
|
|
|
|
|
void oled_show_qrcode(const char *text)
|
|
|
|
|
|
{
|
|
|
|
|
|
static uint8_t qr[qrcodegen_BUFFER_LEN_FOR_VERSION(3)];
|
|
|
|
|
|
static uint8_t tmp[qrcodegen_BUFFER_LEN_FOR_VERSION(3)];
|
|
|
|
|
|
static uint8_t pagebuf[8][64];
|
|
|
|
|
|
|
|
|
|
|
|
char id[21];
|
|
|
|
|
|
strncpy(id, text, 20);
|
|
|
|
|
|
id[20] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (!qrcodegen_encodeText(id, tmp, qr, qrcodegen_Ecc_LOW, 1, 3,
|
|
|
|
|
|
qrcodegen_Mask_AUTO, true)) {
|
|
|
|
|
|
return; /* <20><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>(ID Ϊ<><CEAA>/<2F><><EFBFBD><EFBFBD>)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ */
|
|
|
|
|
|
}
|
|
|
|
|
|
int qs = qrcodegen_getSize(qr); /* 21/25/29 */
|
|
|
|
|
|
int px = qs * 2; /* 2px/ģ<><C4A3> -> 42/50/58 */
|
|
|
|
|
|
int x0 = 2;
|
|
|
|
|
|
int y0 = (64 - px) / 2; /* <20><>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD> */
|
|
|
|
|
|
|
|
|
|
|
|
memset(pagebuf, 0, sizeof(pagebuf));
|
|
|
|
|
|
/* <20><EFBFBD>(<28><> 2 ģ<><C4A3>=4px <20><><EFBFBD><EFBFBD>): <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
int lx = x0 - 4, rx = x0 + px + 4;
|
|
|
|
|
|
int ty = y0 - 4, by = y0 + px + 4;
|
|
|
|
|
|
if (lx < 0) lx = 0; if (rx > 64) rx = 64;
|
|
|
|
|
|
if (ty < 0) ty = 0; if (by > 64) by = 64;
|
|
|
|
|
|
for (int y = ty; y < by; y++)
|
|
|
|
|
|
for (int x = lx; x < rx; x++)
|
|
|
|
|
|
pagebuf[y >> 3][x] |= (uint8_t)(1u << (y & 7));
|
|
|
|
|
|
|
|
|
|
|
|
/* QR <20><>ģ<EFBFBD><C4A3>: <20><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ */
|
|
|
|
|
|
for (int r = 0; r < qs; r++) {
|
|
|
|
|
|
for (int c = 0; c < qs; c++) {
|
|
|
|
|
|
if (qrcodegen_getModule(qr, c, r)) {
|
|
|
|
|
|
for (int dy = 0; dy < 2; dy++) {
|
|
|
|
|
|
for (int dx = 0; dx < 2; dx++) {
|
|
|
|
|
|
int y = y0 + r * 2 + dy;
|
|
|
|
|
|
int x = x0 + c * 2 + dx;
|
|
|
|
|
|
pagebuf[y >> 3][x] &= (uint8_t)~(1u << (y & 7));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* д<><D0B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 64 <20><>(<28><>ҳ<EFBFBD><D2B3>д, <20><>Ӱ<EFBFBD><D3B0><EFBFBD>Ҳ<EFBFBD><D2B2>ı<EFBFBD><C4B1><EFBFBD>) */
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_lock();
|
2026-09-13 20:37:06 +08:00
|
|
|
|
for (uint8_t pg = 0; pg < 8; pg++) {
|
|
|
|
|
|
oled_write(0, 0xb0 + pg);
|
|
|
|
|
|
oled_write(0, 0x00);
|
|
|
|
|
|
oled_write(0, 0x10);
|
2026-09-20 10:10:32 +08:00
|
|
|
|
oled_data_begin();
|
|
|
|
|
|
for (uint8_t x = 0; x < 64; x++) oled_data_byte(pagebuf[pg][x]);
|
|
|
|
|
|
oled_data_end();
|
2026-09-13 20:37:06 +08:00
|
|
|
|
}
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_unlock();
|
2026-09-13 20:37:06 +08:00
|
|
|
|
|
|
|
|
|
|
/* <20>Ҳ<EFBFBD> ID <20>ı<EFBFBD>: x=64 <20><>ÿ<EFBFBD><C3BF> 8 <20><> ASCII, <20><><EFBFBD><EFBFBD> 3 <20><> */
|
|
|
|
|
|
int len = (int)strlen(id);
|
|
|
|
|
|
oled_locate(0, 8);
|
|
|
|
|
|
oled_print("ID:");
|
|
|
|
|
|
for (int r = 0; r < 3 && r * 8 < len; r++) {
|
|
|
|
|
|
char seg[9];
|
|
|
|
|
|
memcpy(seg, id + r * 8, 8); /* id <20><> NUL <20><><EFBFBD><EFBFBD>, β<><CEB2><EFBFBD>̴<EFBFBD><CCB4>ᱻ NUL <20>ض<EFBFBD> */
|
|
|
|
|
|
seg[8] = 0;
|
|
|
|
|
|
oled_locate(1 + r, 8);
|
|
|
|
|
|
oled_print(seg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-04 20:09:04 +08:00
|
|
|
|
/*==== <20><><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>Ԥ<EFBFBD><D4A4>ʱ<EFBFBD><CAB1><EFBFBD>ã<EFBFBD>====*/
|
|
|
|
|
|
void oled_off(void)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_lock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
oled_write(0, 0xAE); /* display off */
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_unlock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== ȫ<><C8AB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ====*/
|
|
|
|
|
|
void oled_clear(void)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_lock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
for (uint8_t i = 0; i < 8; i++) {
|
|
|
|
|
|
oled_write(0, 0xb0 + i);
|
|
|
|
|
|
oled_write(0, 0x00);
|
|
|
|
|
|
oled_write(0, 0x10);
|
2026-09-20 10:10:32 +08:00
|
|
|
|
oled_data_begin();
|
|
|
|
|
|
for (uint8_t j = 0; j < 128; j++) oled_data_byte(0x00);
|
|
|
|
|
|
oled_data_end();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_unlock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>Ļ<EFBFBD><C4BB>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>SSD1306 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>====*/
|
|
|
|
|
|
void oled_init(void)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
HAL_Delay(400); /* <20><><EFBFBD><EFBFBD>Ļ/<2F>ֿ<EFBFBD><D6BF>ϵ<EFBFBD><CFB5>ȶ<EFBFBD>(I2C <20><><EFBFBD><EFBFBD> RST <20><>, <20><><EFBFBD>ϵ<EFBFBD><CFB5><EFBFBD>ʱ) */
|
2026-09-04 20:09:04 +08:00
|
|
|
|
oled_gpio_init();
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_cs(1);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
oled_write(0, 0xAE); /* display off */
|
|
|
|
|
|
oled_write(0, 0x20); /* Ѱַģʽ */
|
|
|
|
|
|
oled_write(0, 0x10); /* ˮƽѰַ */
|
|
|
|
|
|
oled_write(0, 0xb0);
|
|
|
|
|
|
oled_write(0, 0xc8); /* COM ɨ<>跽<EFBFBD><E8B7BD> */
|
|
|
|
|
|
oled_write(0, 0x00);
|
|
|
|
|
|
oled_write(0, 0x10);
|
|
|
|
|
|
oled_write(0, 0x40); /* <20><>ʼ<EFBFBD><CABC> */
|
|
|
|
|
|
oled_write(0, 0x81); /* <20>Աȶ<D4B1> */
|
|
|
|
|
|
oled_write(0, 0xFF);
|
|
|
|
|
|
oled_write(0, 0xa1); /* <20><><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3> */
|
|
|
|
|
|
oled_write(0, 0xa6); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ */
|
|
|
|
|
|
oled_write(0, 0xa8); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
oled_write(0, 0x3F);
|
|
|
|
|
|
oled_write(0, 0xa4);
|
|
|
|
|
|
oled_write(0, 0xd3); /* <20><>ʾƫ<CABE><C6AB> */
|
|
|
|
|
|
oled_write(0, 0x00);
|
|
|
|
|
|
oled_write(0, 0xd5); /* ʱ<>ӷ<EFBFBD>Ƶ */
|
|
|
|
|
|
oled_write(0, 0xf0);
|
|
|
|
|
|
oled_write(0, 0xd9); /* Ԥ<><D4A4><EFBFBD><EFBFBD> */
|
|
|
|
|
|
oled_write(0, 0x22);
|
|
|
|
|
|
oled_write(0, 0xda); /* COM Ӳ<><D3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
|
|
|
oled_write(0, 0x12);
|
|
|
|
|
|
oled_write(0, 0xdb); /* VCOMH */
|
|
|
|
|
|
oled_write(0, 0x20);
|
|
|
|
|
|
oled_write(0, 0x8d); /* DC-DC */
|
|
|
|
|
|
oled_write(0, 0x14);
|
|
|
|
|
|
oled_write(0, 0xaf); /* display on */
|
|
|
|
|
|
oled_clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>ʾ 16x16 <20><><EFBFBD><EFBFBD><F3A3A8BA>֣<EFBFBD>====*/
|
|
|
|
|
|
static void display_graphic_16x16(uint8_t page, uint8_t column, const uint8_t *dp)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_lock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
for (uint8_t j = 2; j > 0; j--) {
|
|
|
|
|
|
lcd_address(column, page);
|
2026-09-20 10:10:32 +08:00
|
|
|
|
oled_data_begin();
|
|
|
|
|
|
for (uint8_t i = 0; i < 16; i++) oled_data_byte(*dp++);
|
|
|
|
|
|
oled_data_end();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
page++;
|
|
|
|
|
|
}
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_unlock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>ʾ 8x16 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ASCII<49><49>====*/
|
|
|
|
|
|
static void display_graphic_8x16(uint8_t page, uint8_t column, const uint8_t *dp)
|
|
|
|
|
|
{
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_lock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
for (uint8_t j = 2; j > 0; j--) {
|
|
|
|
|
|
lcd_address(column, page);
|
2026-09-20 10:10:32 +08:00
|
|
|
|
oled_data_begin();
|
|
|
|
|
|
for (uint8_t i = 0; i < 8; i++) oled_data_byte(*dp++);
|
|
|
|
|
|
oled_data_end();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
page++;
|
|
|
|
|
|
}
|
2026-09-20 10:10:32 +08:00
|
|
|
|
storage_unlock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20>ֿ<EFBFBD> IC д<>ֽڣ<D6BD>ָ<EFBFBD><D6B8>/<2F><>ַ<EFBFBD><D6B7>====*/
|
|
|
|
|
|
static void rom_write_byte(uint8_t dat)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_di(dat & 0x80);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
dat <<= 1;
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_clk(0);
|
|
|
|
|
|
rom_clk(1);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20>ֿ<EFBFBD> IC <20><>һ<EFBFBD>ֽ<EFBFBD> ====*/
|
|
|
|
|
|
static uint8_t rom_read_byte(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t ret = 0;
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_clk(1);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_clk(0);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
ret <<= 1;
|
2026-09-20 11:12:43 +08:00
|
|
|
|
if (ROM_DO_READ) ret |= 1;
|
|
|
|
|
|
rom_clk(1);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><><EFBFBD>ֿ<EFBFBD> IC <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> DataLen <20>ֽ<EFBFBD> ====*/
|
|
|
|
|
|
static void rom_read_n(uint8_t ah, uint8_t am, uint8_t al, uint8_t *buf, uint8_t len)
|
|
|
|
|
|
{
|
2026-09-20 10:18:31 +08:00
|
|
|
|
storage_lock(); /* <20><> W25Q64 <20><><EFBFBD><EFBFBD> SPI <20><><EFBFBD><EFBFBD>, <20><> Flash <20><>д<EFBFBD><D0B4><EFBFBD><EFBFBD> */
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_cs(0);
|
|
|
|
|
|
rom_clk(0);
|
2026-09-04 20:09:04 +08:00
|
|
|
|
rom_write_byte(0x03); /* <20><>ָ<EFBFBD><D6B8> */
|
|
|
|
|
|
rom_write_byte(ah);
|
|
|
|
|
|
rom_write_byte(am);
|
|
|
|
|
|
rom_write_byte(al);
|
|
|
|
|
|
for (uint8_t i = 0; i < len; i++) buf[i] = rom_read_byte();
|
2026-09-20 11:12:43 +08:00
|
|
|
|
rom_cs(1);
|
2026-09-20 10:18:31 +08:00
|
|
|
|
storage_unlock();
|
2026-09-04 20:09:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>λ<EFBFBD><CEBB>row 0~3<><33>16px <20>У<EFBFBD><D0A3><EFBFBD>col8 Ϊ 8 <20><><EFBFBD>ص<EFBFBD>λ ====*/
|
|
|
|
|
|
void oled_locate(uint8_t row, uint8_t col8)
|
|
|
|
|
|
{
|
|
|
|
|
|
s_row = row * 2;
|
|
|
|
|
|
s_col = col8 * 8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>ʾ GBK <20>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>16x16 <20><><EFBFBD><EFBFBD> / 8x16 ASCII<49><49><EFBFBD><EFBFBD><EFBFBD>뻻<EFBFBD><EBBBBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѷ<EFBFBD>ֿ<EFBFBD><D6BF>ֲᣩ====*/
|
|
|
|
|
|
void oled_print(const char *s)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint8_t fontbuf[32];
|
|
|
|
|
|
uint8_t y = s_row;
|
|
|
|
|
|
uint8_t x = s_col;
|
|
|
|
|
|
const uint8_t *text = (const uint8_t *)s;
|
|
|
|
|
|
uint32_t fontaddr;
|
|
|
|
|
|
|
|
|
|
|
|
s_col += strlen(s) * 8; /* λ<><CEBB><EFBFBD>Լӣ<D4BC><D3A3><EFBFBD> 8px/<2F>ַ<EFBFBD><D6B7>ƣ<EFBFBD> */
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t i = 0;
|
|
|
|
|
|
while (text[i] > 0x00) {
|
|
|
|
|
|
if ((text[i] >= 0xb0 && text[i] <= 0xf7) && text[i+1] >= 0xa1) {
|
|
|
|
|
|
/* GB2312 <20><><EFBFBD>֣<EFBFBD>Address = ((MSB-0xB0)*94 + (LSB-0xA1) + 846) * 32 */
|
|
|
|
|
|
fontaddr = (text[i] - 0xb0) * 94;
|
|
|
|
|
|
fontaddr += (text[i+1] - 0xa1) + 846;
|
|
|
|
|
|
fontaddr *= 32;
|
|
|
|
|
|
rom_read_n((uint8_t)(fontaddr >> 16), (uint8_t)(fontaddr >> 8),
|
|
|
|
|
|
(uint8_t)fontaddr, fontbuf, 32);
|
|
|
|
|
|
display_graphic_16x16(y, x, fontbuf);
|
|
|
|
|
|
i += 2;
|
|
|
|
|
|
x += 16;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((text[i] >= 0xa1 && text[i] <= 0xa3) && text[i+1] >= 0xa1) {
|
|
|
|
|
|
/* GB2312 ȫ<>Ƿ<EFBFBD><C7B7>ţ<EFBFBD>Address = ((MSB-0xA1)*94 + (LSB-0xA1)) * 32 */
|
|
|
|
|
|
fontaddr = (text[i] - 0xa1) * 94;
|
|
|
|
|
|
fontaddr += (text[i+1] - 0xa1);
|
|
|
|
|
|
fontaddr *= 32;
|
|
|
|
|
|
rom_read_n((uint8_t)(fontaddr >> 16), (uint8_t)(fontaddr >> 8),
|
|
|
|
|
|
(uint8_t)fontaddr, fontbuf, 32);
|
|
|
|
|
|
display_graphic_16x16(y, x, fontbuf);
|
|
|
|
|
|
i += 2;
|
|
|
|
|
|
x += 16;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (text[i] >= 0x20 && text[i] <= 0x7e) {
|
|
|
|
|
|
/* ASCII 8x16<31><36>Address = (char-0x20)*16 + 0x3CF80 */
|
|
|
|
|
|
fontaddr = (text[i] - 0x20) * 16 + 0x3cf80;
|
|
|
|
|
|
rom_read_n((uint8_t)(fontaddr >> 16), (uint8_t)(fontaddr >> 8),
|
|
|
|
|
|
(uint8_t)fontaddr, fontbuf, 16);
|
|
|
|
|
|
display_graphic_8x16(y, x, fontbuf);
|
|
|
|
|
|
i += 1;
|
|
|
|
|
|
x += 8;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
i++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD> px <20><><EFBFBD><EFBFBD> ====*/
|
|
|
|
|
|
void oled_xoff(uint8_t px)
|
|
|
|
|
|
{
|
|
|
|
|
|
s_col += px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ؿ<EFBFBD><D8BF>ȣ<EFBFBD><C8A3><EFBFBD><EFBFBD><EFBFBD>/ȫ<><C8AB> 16px<70><78>ASCII 8px ====*/
|
|
|
|
|
|
uint8_t oled_text_w(const char *s)
|
|
|
|
|
|
{
|
|
|
|
|
|
const uint8_t *p = (const uint8_t *)s;
|
|
|
|
|
|
uint32_t w = 0;
|
|
|
|
|
|
while (*p) {
|
|
|
|
|
|
if (p[0] >= 0xa1 && p[1] >= 0xa1) { w += 16; p += 2; }
|
|
|
|
|
|
else { w += 8; p += 1; }
|
|
|
|
|
|
}
|
|
|
|
|
|
return (uint8_t)(w > 128 ? 128 : w);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*==== <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؿ<EFBFBD><D8BF>ȣ<EFBFBD><C8A3><EFBFBD><EFBFBD><EFBFBD> 128px <20>ÿո<C3BF><D5B8><EFBFBD><EFBFBD>루<EFBFBD><EBA3A8><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD>ݣ<EFBFBD>====*/
|
|
|
|
|
|
void oled_print_line(const char *s)
|
|
|
|
|
|
{
|
|
|
|
|
|
const uint8_t *p = (const uint8_t *)s;
|
|
|
|
|
|
uint32_t w = 0;
|
|
|
|
|
|
while (*p) {
|
|
|
|
|
|
if (p[0] >= 0xa1 && p[1] >= 0xa1) { w += 16; p += 2; } /* <20><><EFBFBD><EFBFBD>/ȫ<><C8AB> */
|
|
|
|
|
|
else { w += 8; p += 1; } /* ASCII */
|
|
|
|
|
|
}
|
|
|
|
|
|
oled_print(s);
|
|
|
|
|
|
while (w < 128) { oled_print(" "); w += 8; }
|
|
|
|
|
|
}
|