From 3f477172f295a83b455a566a407c4c610275e7e5 Mon Sep 17 00:00:00 2001 From: RB Date: Sun, 27 Apr 2025 01:29:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=BA=9B=E6=96=B0?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- User/bsp/bsp.h | 17 --- User/bsp/i2c.c | 104 ++++++++++++++++++ User/bsp/i2c.h | 43 ++++++++ User/bsp/led.c | 61 +++++++++++ User/bsp/led.h | 36 ++++++ User/bsp/uart.c | 114 +++++++++++++++++++ User/bsp/uart.h | 47 ++++++++ User/device/oled.c | 268 +++++++++++++++++++++++++++++++++++++++++++++ User/device/oled.h | 26 +++++ 9 files changed, 699 insertions(+), 17 deletions(-) delete mode 100644 User/bsp/bsp.h create mode 100644 User/bsp/i2c.c create mode 100644 User/bsp/i2c.h create mode 100644 User/bsp/led.c create mode 100644 User/bsp/led.h create mode 100644 User/bsp/uart.c create mode 100644 User/bsp/uart.h create mode 100644 User/device/oled.c create mode 100644 User/device/oled.h diff --git a/User/bsp/bsp.h b/User/bsp/bsp.h deleted file mode 100644 index 19e162c..0000000 --- a/User/bsp/bsp.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define BSP_OK (0) -#define BSP_ERR (-1) -#define BSP_ERR_NULL (-2) -#define BSP_ERR_INITED (-3) -#define BSP_ERR_NO_DEV (-4) - -#define SIGNAL_BSP_USB_BUF_RECV (1u << 0) - -#ifdef __cplusplus -} -#endif diff --git a/User/bsp/i2c.c b/User/bsp/i2c.c new file mode 100644 index 0000000..b510e26 --- /dev/null +++ b/User/bsp/i2c.c @@ -0,0 +1,104 @@ +/* Includes ----------------------------------------------------------------- */ +#include "bsp\i2c.h" + +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ +static void (*I2C_Callback[BSP_I2C_NUM][BSP_I2C_CB_NUM])(void); + +/* Private function -------------------------------------------------------- */ +static BSP_I2C_t I2C_Get(I2C_HandleTypeDef *hi2c) { + if (hi2c->Instance == I2C1) return BSP_I2C_OLED; + else + return BSP_I2C_ERR; +} + +void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_MASTER_TX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_MASTER_TX_CPLT_CB](); + } +} + +void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_MASTER_RX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_MASTER_RX_CPLT_CB](); + } +} + +void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_SLAVE_TX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_SLAVE_TX_CPLT_CB](); + } +} + +void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_SLAVE_RX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_SLAVE_RX_CPLT_CB](); + } +} + +void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_LISTEN_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_LISTEN_CPLT_CB](); + } +} + +void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_MEM_TX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_MEM_TX_CPLT_CB](); + } +} + +void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_MEM_RX_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_MEM_RX_CPLT_CB](); + } +} + +void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_ERROR_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_ERROR_CB](); + } +} + +void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c) { + BSP_I2C_t bsp_i2c = I2C_Get(hi2c); + if (bsp_i2c != BSP_I2C_ERR) { + if (I2C_Callback[bsp_i2c][HAL_I2C_ABORT_CPLT_CB]) + I2C_Callback[bsp_i2c][HAL_I2C_ABORT_CPLT_CB](); + } +} + +/* Exported functions ------------------------------------------------------- */ +I2C_HandleTypeDef *BSP_I2C_GetHandle(BSP_I2C_t i2c) { + switch (i2c) { + case BSP_I2C_OLED: + return &hi2c1; + default: + return NULL; + } +} + +int8_t BSP_I2C_RegisterCallback(BSP_I2C_t i2c, BSP_I2C_Callback_t type, + void (*callback)(void)) { + if (callback == NULL) return BSP_ERR_NULL; + I2C_Callback[i2c][type] = callback; + return BSP_OK; +} diff --git a/User/bsp/i2c.h b/User/bsp/i2c.h new file mode 100644 index 0000000..1c91d21 --- /dev/null +++ b/User/bsp/i2c.h @@ -0,0 +1,43 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include + +#include "bsp/bsp.h" + +/* Exported constants ------------------------------------------------------- */ +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ +/* I2C实体枚举,与设备对应 */ +typedef enum { + BSP_I2C_OLED, + BSP_I2C_NUM, + BSP_I2C_ERR, +} BSP_I2C_t; + +/* I2C支持的中断回调函数类型,具体参考HAL中定义 */ +typedef enum { + HAL_I2C_MASTER_TX_CPLT_CB, + HAL_I2C_MASTER_RX_CPLT_CB, + HAL_I2C_SLAVE_TX_CPLT_CB, + HAL_I2C_SLAVE_RX_CPLT_CB, + HAL_I2C_LISTEN_CPLT_CB, + HAL_I2C_MEM_TX_CPLT_CB, + HAL_I2C_MEM_RX_CPLT_CB, + HAL_I2C_ERROR_CB, + HAL_I2C_ABORT_CPLT_CB, + BSP_I2C_CB_NUM, +} BSP_I2C_Callback_t; + +/* Exported functions prototypes -------------------------------------------- */ +I2C_HandleTypeDef *BSP_I2C_GetHandle(BSP_I2C_t i2c); +int8_t BSP_I2C_RegisterCallback(BSP_I2C_t i2c, BSP_I2C_Callback_t type, + void (*callback)(void)); + +#ifdef __cplusplus +} +#endif diff --git a/User/bsp/led.c b/User/bsp/led.c new file mode 100644 index 0000000..22018ab --- /dev/null +++ b/User/bsp/led.c @@ -0,0 +1,61 @@ +/* Includes ----------------------------------------------------------------- */ +#include "bsp\led.h" + +#include + +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ +static uint32_t led_stats; + +/* Private function -------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ + +int8_t BSP_LED_Set(BSP_LED_Channel_t ch, BSP_LED_Status_t s, float duty_cycle) { + if (duty_cycle > 1.0f) return BSP_ERR; + + uint32_t tim_ch; + uint16_t pulse = (uint16_t)(duty_cycle * (float)UINT16_MAX); + + switch (ch) { + case BSP_LED_1: + __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pulse); + tim_ch = TIM_CHANNEL_2; + break; + + case BSP_LED_2: + __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, pulse); + tim_ch = TIM_CHANNEL_3; + break; + + case BSP_LED_3: + __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, pulse); + tim_ch = TIM_CHANNEL_1; + break; + } + + switch (s) { + case BSP_LED_ON: + HAL_TIM_PWM_Start(&htim2, tim_ch); + led_stats |= tim_ch; + break; + + case BSP_LED_OFF: + HAL_TIM_PWM_Stop(&htim2, tim_ch); + led_stats &= ~tim_ch; + break; + + case BSP_LED_TAGGLE: + if (led_stats & tim_ch) { + HAL_TIM_PWM_Stop(&htim2, tim_ch); + led_stats &= ~tim_ch; + } else { + HAL_TIM_PWM_Start(&htim2, tim_ch); + led_stats |= tim_ch; + } + break; + } + + return BSP_OK; +} diff --git a/User/bsp/led.h b/User/bsp/led.h new file mode 100644 index 0000000..a329657 --- /dev/null +++ b/User/bsp/led.h @@ -0,0 +1,36 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include + +#include "bsp/bsp.h" + +/* Exported constants ------------------------------------------------------- */ +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ + +/* LED灯状态,设置用 */ +typedef enum { + BSP_LED_ON, + BSP_LED_OFF, + BSP_LED_TAGGLE, +} BSP_LED_Status_t; + +/* LED通道 */ +typedef enum { + BSP_LED_1, + BSP_LED_2, + BSP_LED_3, +} BSP_LED_Channel_t; + +/* Exported functions prototypes -------------------------------------------- */ + +int8_t BSP_LED_Set(BSP_LED_Channel_t ch, BSP_LED_Status_t s, float duty_cycle); + +#ifdef __cplusplus +} +#endif diff --git a/User/bsp/uart.c b/User/bsp/uart.c new file mode 100644 index 0000000..e82eba5 --- /dev/null +++ b/User/bsp/uart.c @@ -0,0 +1,114 @@ +/* Includes ----------------------------------------------------------------- */ +#include "bsp\uart.h" + +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ +static void (*UART_Callback[BSP_UART_NUM][BSP_UART_CB_NUM])(void); + +/* Private function -------------------------------------------------------- */ +static BSP_UART_t UART_Get(UART_HandleTypeDef *huart) { + if (huart->Instance == USART1) + return BSP_UART_SINDT; + else + return BSP_UART_ERR; +} + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_TX_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_TX_CPLT_CB](); + } + } +} + +void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_TX_HALF_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_TX_HALF_CPLT_CB](); + } + } +} + +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_RX_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_RX_CPLT_CB](); + } + } +} + +void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_RX_HALF_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_RX_HALF_CPLT_CB](); + } + } +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_ERROR_CB]) { + UART_Callback[bsp_uart][BSP_UART_ERROR_CB](); + } + } +} + +void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_ABORT_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_ABORT_CPLT_CB](); + } + } +} + +void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_ABORT_TX_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_ABORT_TX_CPLT_CB](); + } + } +} + +void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart) { + BSP_UART_t bsp_uart = UART_Get(huart); + if (bsp_uart != BSP_UART_ERR) { + if (UART_Callback[bsp_uart][BSP_UART_ABORT_RX_CPLT_CB]) { + UART_Callback[bsp_uart][BSP_UART_ABORT_RX_CPLT_CB](); + } + } +} + +/* Exported functions ------------------------------------------------------- */ +void BSP_UART_IRQHandler(UART_HandleTypeDef *huart) { + if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE)) { + __HAL_UART_CLEAR_IDLEFLAG(huart); + if (UART_Callback[UART_Get(huart)][BSP_UART_IDLE_LINE_CB]) { + UART_Callback[UART_Get(huart)][BSP_UART_IDLE_LINE_CB](); + } + } +} + +UART_HandleTypeDef *BSP_UART_GetHandle(BSP_UART_t uart) { + switch (uart) { + case BSP_UART_SINDT: + return &huart1; + default: + return NULL; + } +} + +int8_t BSP_UART_RegisterCallback(BSP_UART_t uart, BSP_UART_Callback_t type, + void (*callback)(void)) { + if (callback == NULL) return BSP_ERR_NULL; + UART_Callback[uart][type] = callback; + return BSP_OK; +} diff --git a/User/bsp/uart.h b/User/bsp/uart.h new file mode 100644 index 0000000..576dd05 --- /dev/null +++ b/User/bsp/uart.h @@ -0,0 +1,47 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include + +#include "bsp/bsp.h" + +/* Exported constants ------------------------------------------------------- */ +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ + +/* 要添加使用UART的新设备,需要先在此添加对应的枚举值 */ + +/* UART实体枚举,与设备对应 */ +typedef enum { + BSP_UART_SINDT, + BSP_UART_NUM, + BSP_UART_ERR, +} BSP_UART_t; + +/* UART支持的中断回调函数类型,具体参考HAL中定义 */ +typedef enum { + BSP_UART_TX_HALF_CPLT_CB, + BSP_UART_TX_CPLT_CB, + BSP_UART_RX_HALF_CPLT_CB, + BSP_UART_RX_CPLT_CB, + BSP_UART_ERROR_CB, + BSP_UART_ABORT_CPLT_CB, + BSP_UART_ABORT_TX_CPLT_CB, + BSP_UART_ABORT_RX_CPLT_CB, + + BSP_UART_IDLE_LINE_CB, + BSP_UART_CB_NUM, +} BSP_UART_Callback_t; + +/* Exported functions prototypes -------------------------------------------- */ +UART_HandleTypeDef *BSP_UART_GetHandle(BSP_UART_t uart); +int8_t BSP_UART_RegisterCallback(BSP_UART_t uart, BSP_UART_Callback_t type, + void (*callback)(void)); + +#ifdef __cplusplus +} +#endif diff --git a/User/device/oled.c b/User/device/oled.c new file mode 100644 index 0000000..246df6c --- /dev/null +++ b/User/device/oled.c @@ -0,0 +1,268 @@ +/* Includes ----------------------------------------------------------------- */ +#include "device/oled.h" +#include "bsp/i2c.h" +#include +#include +/* Private define ----------------------------------------------------------- */ +#define OLED_I2C_ADDR 0x78 // OLED I2C 地址 +#define OLED_WIDTH 128 +#define OLED_HEIGHT 64 + +/* Private variables -------------------------------------------------------- */ +static uint8_t oled_buffer[OLED_WIDTH * OLED_HEIGHT / 8]; +static struct { + uint8_t x_min; + uint8_t x_max; + uint8_t y_min; + uint8_t y_max; + uint8_t dirty; // 标志是否有脏区域 +} dirty_rect = {0, 0, 0, 0, 0}; + +/* Private function prototypes ---------------------------------------------- */ +static void OLED_WriteCommand(uint8_t cmd); +static void OLED_WriteData(uint8_t *data, uint16_t size); +static void OLED_MarkDirty(uint8_t x, uint8_t y); +static void OLED_UpdateDirtyScreen(void); + +static const uint8_t oled_font[95][8] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, /* " ", 0 */ + {0x00,0x00,0x00,0xcf,0xcf,0x00,0x00,0x00,}, /* "!", 1 */ + {0x00,0x0c,0x06,0x00,0x0c,0x06,0x00,0x00,}, /* """, 2 */ + {0x24,0xe4,0x3c,0x27,0xe4,0x3c,0x27,0x24,}, /* "#", 3 */ + {0x00,0x20,0x46,0xf9,0x9f,0x62,0x04,0x00,}, /* "$", 4 */ + {0x06,0x09,0xc6,0x30,0x0c,0x63,0x90,0x60,}, /* "%", 5 */ + {0x00,0x00,0x6e,0x91,0xa9,0x46,0xa0,0x00,}, /* "&", 6 */ + {0x00,0x00,0x00,0x1c,0x0e,0x00,0x00,0x00,}, /* "'", 7 */ + {0x00,0x00,0x3c,0x42,0x81,0x00,0x00,0x00,}, /* "(", 8 */ + {0x00,0x00,0x00,0x81,0x42,0x3c,0x00,0x00,}, /* ")", 9 */ + {0x00,0x10,0x54,0x38,0x38,0x54,0x10,0x00,}, /* "*", 10 */ + {0x00,0x10,0x10,0xfc,0x10,0x10,0x00,0x00,}, /* "+", 11 */ + {0x00,0x00,0x00,0xc0,0x60,0x00,0x00,0x00,}, /* ",", 12 */ + {0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,}, /* "-", 13 */ + {0x00,0x00,0x00,0x00,0xc0,0xc0,0x00,0x00,}, /* ".", 14 */ + {0x00,0x00,0x00,0xc0,0x38,0x07,0x00,0x00,}, /* "/", 15 */ + {0x00,0x00,0x7c,0x92,0x8a,0x7c,0x00,0x00,}, /* "0", 16 */ + {0x00,0x00,0x00,0x84,0xfe,0x80,0x00,0x00,}, /* "1", 17 */ + {0x00,0x00,0x8c,0xc2,0xa2,0x9c,0x00,0x00,}, /* "2", 18 */ + {0x00,0x00,0x44,0x92,0x92,0x6c,0x00,0x00,}, /* "3", 19 */ + {0x00,0x20,0x38,0x24,0xfe,0x20,0x00,0x00,}, /* "4", 20 */ + {0x00,0x00,0x5e,0x92,0x92,0x62,0x00,0x00,}, /* "5", 21 */ + {0x00,0x00,0x78,0x94,0x92,0x62,0x00,0x00,}, /* "6", 22 */ + {0x00,0x00,0x82,0x62,0x1a,0x06,0x00,0x00,}, /* "7", 23 */ + {0x00,0x00,0x6c,0x92,0x92,0x6c,0x00,0x00,}, /* "8", 24 */ + {0x00,0x00,0x8c,0x52,0x32,0x1c,0x00,0x00,}, /* "9", 25 */ + {0x00,0x00,0x00,0x6c,0x6c,0x00,0x00,0x00,}, /* ":", 26 */ + {0x00,0x00,0x80,0xec,0x6c,0x00,0x00,0x00,}, /* ";", 27 */ + {0x00,0x00,0x10,0x28,0x44,0x00,0x00,0x00,}, /* "<", 28 */ + {0x00,0x00,0x24,0x24,0x24,0x24,0x00,0x00,}, /* "=", 29 */ + {0x00,0x00,0x00,0x44,0x28,0x10,0x00,0x00,}, /* ">", 30 */ + {0x00,0x00,0x0c,0xa2,0x92,0x1c,0x00,0x00,}, /* "?", 31 */ + {0x00,0x3c,0x42,0x99,0xa5,0xa2,0x3c,0x00,}, /* "@", 32 */ + {0x00,0xe0,0x1c,0x12,0x12,0x1c,0xe0,0x00,}, /* "A", 33 */ + {0x00,0xfe,0x92,0x92,0x9c,0x90,0x60,0x00,}, /* "B", 34 */ + {0x00,0x38,0x44,0x82,0x82,0x82,0x44,0x00,}, /* "C", 35 */ + {0x00,0xfe,0x82,0x82,0x82,0x82,0x7c,0x00,}, /* "D", 36 */ + {0x00,0xfe,0x92,0x92,0x92,0x92,0x92,0x00,}, /* "E", 37 */ + {0x00,0xfe,0x12,0x12,0x12,0x12,0x02,0x00,}, /* "F", 38 */ + {0x00,0x7c,0x82,0x92,0x92,0x72,0x00,0x00,}, /* "G", 39 */ + {0x00,0xfe,0x10,0x10,0x10,0x10,0xfe,0x00,}, /* "H", 40 */ + {0x00,0x82,0x82,0xfe,0x82,0x82,0x00,0x00,}, /* "I", 41 */ + {0x00,0x82,0x82,0x7e,0x02,0x02,0x00,0x00,}, /* "J", 42 */ + {0x00,0xfe,0x10,0x28,0x44,0x82,0x00,0x00,}, /* "K", 43 */ + {0x00,0xfe,0x80,0x80,0x80,0x80,0x00,0x00,}, /* "L", 44 */ + {0xfc,0x02,0x04,0xf8,0x04,0x02,0xfc,0x00,}, /* "M", 45 */ + {0x00,0xfe,0x04,0x18,0x30,0x40,0xfe,0x00,}, /* "N", 46 */ + {0x00,0x7c,0x82,0x82,0x82,0x82,0x7c,0x00,}, /* "O", 47 */ + {0x00,0x00,0xfe,0x12,0x12,0x0c,0x00,0x00,}, /* "P", 48 */ + {0x00,0x00,0x3c,0x42,0xc2,0xbc,0x00,0x00,}, /* "Q", 49 */ + {0x00,0x00,0xfe,0x32,0x52,0x8c,0x00,0x00,}, /* "R", 50 */ + {0x00,0x00,0x4c,0x92,0x92,0x64,0x00,0x00,}, /* "S", 51 */ + {0x00,0x02,0x02,0xfe,0x02,0x02,0x00,0x00,}, /* "T", 52 */ + {0x00,0x7e,0x80,0x80,0x80,0x80,0x7e,0x00,}, /* "U", 53 */ + {0x00,0x0c,0x30,0xc0,0x30,0x0c,0x00,0x00,}, /* "V", 54 */ + {0x7c,0x80,0x80,0x78,0x80,0x80,0x7c,0x00,}, /* "W", 55 */ + {0x00,0x84,0x48,0x30,0x30,0x48,0x84,0x00,}, /* "X", 56 */ + {0x00,0x06,0x08,0xf0,0x08,0x06,0x00,0x00,}, /* "Y", 57 */ + {0x00,0x00,0xc2,0xa2,0x92,0x8e,0x00,0x00,}, /* "Z", 58 */ + {0x00,0x00,0xfe,0x82,0x82,0x82,0x00,0x00,}, /* "[", 59 */ + {0x00,0x00,0x06,0x18,0x60,0x80,0x00,0x00,}, /* "\", 60 */ + {0x00,0x00,0x82,0x82,0x82,0xfe,0x00,0x00,}, /* "]", 61 */ + {0x00,0x30,0x0c,0x02,0x0c,0x30,0x00,0x00,}, /* "^", 62 */ + {0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,}, /* "_", 63 */ + {0x00,0x00,0x04,0x0c,0x18,0x00,0x00,0x00,}, /* "`", 64 */ + {0x00,0x00,0x60,0x90,0x90,0xe0,0x00,0x00,}, /* "a", 65 */ + {0x00,0x00,0xf8,0xa0,0xe0,0x00,0x00,0x00,}, /* "b", 66 */ + {0x00,0x00,0x60,0x90,0x90,0x00,0x00,0x00,}, /* "c", 67 */ + {0x00,0x00,0xe0,0xa0,0xf8,0x00,0x00,0x00,}, /* "d", 68 */ + {0x00,0x00,0x70,0xa8,0xa8,0x90,0x00,0x00,}, /* "e", 69 */ + {0x00,0x00,0x10,0xf8,0x14,0x00,0x00,0x00,}, /* "f", 70 */ + {0x00,0x00,0xd8,0xa4,0x7c,0x00,0x00,0x00,}, /* "g", 71 */ + {0x00,0x00,0xf8,0x20,0xe0,0x00,0x00,0x00,}, /* "h", 72 */ + {0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x00,}, /* "i", 73 */ + {0x00,0x00,0x40,0x90,0x74,0x00,0x00,0x00,}, /* "j", 74 */ + {0x00,0x00,0xf8,0x60,0x90,0x00,0x00,0x00,}, /* "k", 75 */ + {0x00,0x00,0x78,0x80,0x80,0x00,0x00,0x00,}, /* "l", 76 */ + {0x00,0xe0,0x10,0xe0,0x10,0xe0,0x00,0x00,}, /* "m", 77 */ + {0x00,0x00,0xf0,0x10,0x10,0xe0,0x00,0x00,}, /* "n", 78 */ + {0x00,0x00,0x60,0x90,0x90,0x60,0x00,0x00,}, /* "o", 79 */ + {0x00,0x00,0xf0,0x48,0x48,0x30,0x00,0x00,}, /* "p", 80 */ + {0x00,0x00,0x30,0x48,0x48,0xf0,0x00,0x00,}, /* "q", 81 */ + {0x00,0x00,0x00,0xf0,0x20,0x10,0x00,0x00,}, /* "r", 82 */ + {0x00,0x00,0x90,0xa8,0xa8,0x48,0x00,0x00,}, /* "s", 83 */ + {0x00,0x10,0x10,0xf8,0x90,0x90,0x00,0x00,}, /* "t", 84 */ + {0x00,0x00,0x78,0x80,0x80,0xf8,0x00,0x00,}, /* "u", 85 */ + {0x00,0x18,0x60,0x80,0x60,0x18,0x00,0x00,}, /* "v", 86 */ + {0x00,0x38,0xc0,0x38,0xc0,0x38,0x00,0x00,}, /* "w", 87 */ + {0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,}, /* "x", 88 */ + {0x00,0x8c,0x50,0x20,0x10,0x0c,0x00,0x00,}, /* "y", 89 */ + {0x00,0x88,0xc8,0xa8,0x98,0x88,0x00,0x00,}, /* "z", 90 */ + {0x00,0x00,0x10,0x7c,0x82,0x00,0x00,0x00,}, /* "{", 91 */ + {0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,}, /* "|", 92 */ + {0x00,0x00,0x00,0x82,0x7c,0x10,0x00,0x00,}, /* "}", 93 */ + {0x00,0x08,0x04,0x04,0x08,0x10,0x10,0x08,}, /* "~", 94 */ +}; + +/* Exported functions ------------------------------------------------------- */ + +void OLED_Init(void) { + OLED_WriteCommand(0xAE); // 关闭显示 + OLED_WriteCommand(0x20); // 设置内存寻址模式 + OLED_WriteCommand(0x10); // 页寻址模式 + OLED_WriteCommand(0xB0); // 设置页起始地址 + OLED_WriteCommand(0xC8); // 设置COM扫描方向 + OLED_WriteCommand(0x00); // 设置低列地址 + OLED_WriteCommand(0x10); // 设置高列地址 + OLED_WriteCommand(0x40); // 设置显示起始行 + OLED_WriteCommand(0x81); // 设置对比度 + OLED_WriteCommand(0xFF); // 最大对比度 + OLED_WriteCommand(0xA1); // 设置段重映射 + OLED_WriteCommand(0xA6); // 正常显示 + OLED_WriteCommand(0xA8); // 设置多路复用比率 + OLED_WriteCommand(0x3F); // 1/64 + OLED_WriteCommand(0xA4); // 输出跟随 RAM 内容 + OLED_WriteCommand(0xD3); // 设置显示偏移 + OLED_WriteCommand(0x00); // 无偏移 + OLED_WriteCommand(0xD5); // 设置显示时钟分频比/振荡频率 + OLED_WriteCommand(0xF0); // 高频 + OLED_WriteCommand(0xD9); // 设置预充电周期 + OLED_WriteCommand(0x22); // 修复缺少分号 + OLED_WriteCommand(0xDA); // 设置COM引脚硬件配置 + OLED_WriteCommand(0x12); // 修复缺少分号 + OLED_WriteCommand(0xDB); // 设置VCOMH电压 + OLED_WriteCommand(0x20); // 修复缺少分号 + OLED_WriteCommand(0x8D); // 设置充电泵 + OLED_WriteCommand(0x14); // 修复缺少分号 + OLED_WriteCommand(0xAF); // 打开显示 +} + +void OLED_Clear(void) { + memset(oled_buffer, 0, sizeof(oled_buffer)); + dirty_rect.x_min = 0; + dirty_rect.x_max = OLED_WIDTH - 1; + dirty_rect.y_min = 0; + dirty_rect.y_max = OLED_HEIGHT - 1; + dirty_rect.dirty = 1; + OLED_UpdateScreen(); +} + +void OLED_UpdateScreen(void) { + OLED_UpdateDirtyScreen(); +} + +void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color) { + if (x >= OLED_WIDTH || y >= OLED_HEIGHT) return; + + if (color) { + if (!(oled_buffer[x + (y / 8) * OLED_WIDTH] & (1 << (y % 8)))) { + oled_buffer[x + (y / 8) * OLED_WIDTH] |= (1 << (y % 8)); + OLED_MarkDirty(x, y); + } + } else { + if (oled_buffer[x + (y / 8) * OLED_WIDTH] & (1 << (y % 8))) { + oled_buffer[x + (y / 8) * OLED_WIDTH] &= ~(1 << (y % 8)); + OLED_MarkDirty(x, y); + } + } +} + +void OLED_DrawChar(uint8_t x, uint8_t y, char ch, uint8_t color) { + if (ch < ' ' || ch > '~') return; + + if (x >= OLED_WIDTH || y >= OLED_HEIGHT || x + 8 > OLED_WIDTH || y + 8 > OLED_HEIGHT) { + return; + } + + const uint8_t *font_data = oled_font[ch - ' ']; + + for (uint8_t i = 0; i < 8; i++) { + uint8_t column_data = font_data[i]; + for (uint8_t j = 0; j < 8; j++) { + if (column_data & (1 << j)) { + OLED_DrawPixel(x + i, y + j, color); + } else { + OLED_DrawPixel(x + i, y + j, !color); + } + } + } +} + +void OLED_DrawString(uint8_t x, uint8_t y, const char *str, uint8_t color) { + while (*str) { + OLED_DrawChar(x, y, *str, color); + x += 8; + if (x + 8 > OLED_WIDTH) { + x = 0; + y += 8; + } + if (y + 8 > OLED_HEIGHT) { + break; + } + str++; + } +} + +/* Private functions -------------------------------------------------------- */ + +static void OLED_MarkDirty(uint8_t x, uint8_t y) { + if (!dirty_rect.dirty) { + dirty_rect.x_min = x; + dirty_rect.x_max = x; + dirty_rect.y_min = y; + dirty_rect.y_max = y; + dirty_rect.dirty = 1; + } else { + if (x < dirty_rect.x_min) dirty_rect.x_min = x; + if (x > dirty_rect.x_max) dirty_rect.x_max = x; + if (y < dirty_rect.y_min) dirty_rect.y_min = y; + if (y > dirty_rect.y_max) dirty_rect.y_max = y; + } +} + +static void OLED_UpdateDirtyScreen(void) { + if (!dirty_rect.dirty) return; + + uint8_t y_start = dirty_rect.y_min / 8; + uint8_t y_end = dirty_rect.y_max / 8; + + for (uint8_t i = y_start; i <= y_end; i++) { + OLED_WriteCommand(0xB0 + i); + OLED_WriteCommand(dirty_rect.x_min & 0x0F); + OLED_WriteCommand(0x10 | (dirty_rect.x_min >> 4)); + uint8_t width = dirty_rect.x_max - dirty_rect.x_min + 1; + OLED_WriteData(&oled_buffer[dirty_rect.x_min + i * OLED_WIDTH], width); + } + + dirty_rect.dirty = 0; +} + +static void OLED_WriteCommand(uint8_t cmd) { + uint8_t data[2] = {0x00, cmd}; + HAL_I2C_Master_Transmit(BSP_I2C_GetHandle(BSP_I2C_OLED), OLED_I2C_ADDR, data, 2, HAL_MAX_DELAY); +} + +static void OLED_WriteData(uint8_t *data, uint16_t size) { + uint8_t buffer[size + 1]; + buffer[0] = 0x40; + memcpy(&buffer[1], data, size); + HAL_I2C_Master_Transmit(BSP_I2C_GetHandle(BSP_I2C_OLED), OLED_I2C_ADDR, buffer, size + 1, HAL_MAX_DELAY); +} \ No newline at end of file diff --git a/User/device/oled.h b/User/device/oled.h new file mode 100644 index 0000000..0c9a7de --- /dev/null +++ b/User/device/oled.h @@ -0,0 +1,26 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include + +/* Exported constants ------------------------------------------------------- */ +#define OLED_COLOR_BLACK 0 +#define OLED_COLOR_WHITE 1 + +/* Exported functions prototypes -------------------------------------------- */ +void OLED_Init(void); +void OLED_Clear(void); +void OLED_UpdateScreen(void); +void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color); +void OLED_DrawString(uint8_t x, uint8_t y, const char *str, uint8_t color); +void OLED_DrawChar(uint8_t x, uint8_t y, char ch, uint8_t color); +void OLED_ShowChinese(uint8_t x, uint8_t y, uint8_t index); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file