一、epaper_drive.c
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "app_error.h"
// 定义引脚连接
#define EPD_SPI_INSTANCE 0
#define EPD_CS_PIN 2
#define EPD_DC_PIN 3
#define EPD_RESET_PIN 4
#define EPD_BUSY_PIN 5
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(EPD_SPI_INSTANCE);
// 初始化SPI通信
static void spi_init(void)
{
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = EPD_CS_PIN;
spi_config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED;
spi_config.frequency = NRF_SPI_FREQ_4M;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL));
}
// 发送命令
static void epd_send_command(uint8_t command)
{
nrf_gpio_pin_clear(EPD_DC_PIN);
nrf_drv_spi_transfer(&spi, &command, 1, NULL, 0);
}
// 发送数据
static void epd_send_data(uint8_t data)
{
nrf_gpio_pin_set(EPD_DC_PIN);
nrf_drv_spi_transfer(&spi, &data, 1, NULL, 0);
}
// 等待墨水屏就绪
static void epd_wait_until_idle(void)
{
while(nrf_gpio_pin_read(EPD_BUSY_PIN) == 1) { // 低电平表示就绪
nrf_delay_ms(10);
}
nrf_delay_ms(200);
}
// 墨水屏硬件复位
static void epd_reset(void)
{
nrf_gpio_pin_set(EPD_RESET_PIN);
nrf_delay_ms(200);
nrf_gpio_pin_clear(EPD_RESET_PIN);
nrf_delay_ms(10);
nrf_gpio_pin_set(EPD_RESET_PIN);
nrf_delay_ms(200);
}
// 初始化墨水屏
void epd_init(void)
{
// 配置控制引脚
nrf_gpio_pin_dir_set(EPD_CS_PIN, NRF_GPIO_PIN_DIR_OUTPUT);
nrf_gpio_pin_dir_set(EPD_DC_PIN, NRF_GPIO_PIN_DIR_OUTPUT);
nrf_gpio_pin_dir_set(EPD_RESET_PIN, NRF_GPIO_PIN_DIR_OUTPUT);
nrf_gpio_pin_dir_set(EPD_BUSY_PIN, NRF_GPIO_PIN_DIR_INPUT);
// 初始化SPI
spi_init();
// 复位并初始化屏幕
epd_reset();
epd_send_command(0x12); // 软复位
epd_wait_until_idle();
epd_send_command(0x01); // 设置驱动电压
epd_send_data(0x03); // 电压设置值
epd_send_data(0x00);
epd_send_data(0x2b);
epd_send_data(0x2b);
epd_send_command(0x3C); // 边框波形
epd_send_data(0x01); // 边框设置值
// 其他初始化命令...
}
// 设置局部刷新区域
void epd_set_partial_window(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
epd_send_command(0x44); // 设置RAM X地址开始/结束位置
epd_send_data((x >> 3) & 0xFF);
epd_send_data(((x + w - 1) >> 3) & 0xFF);
epd_send_command(0x45); // 设置RAM Y地址开始/结束位置
epd_send_data(y & 0xFF);
epd_send_data((y >> 8) & 0xFF);
epd_send_data((y + h - 1) & 0xFF);
epd_send_data(((y + h - 1) >> 8) & 0xFF);
epd_send_command(0x4E); // 设置RAM X地址计数器
epd_send_data((x >> 3) & 0xFF);
epd_send_command(0x4F); // 设置RAM Y地址计数器
epd_send_data(y & 0xFF);
epd_send_data((y >> 8) & 0xFF);
}
// 局部刷新显示
void epd_partial_display_update(void)
{
epd_send_command(0x22); // 显示更新控制2
epd_send_data(0x0F); // 启用局部刷新
epd_send_command(0x20); // 触发显示更新
epd_wait_until_idle();
}
// 向局部区域写入数据
void epd_write_partial_data(const uint8_t *data, uint32_t size)
{
epd_send_command(0x24); // 向RAM写入黑色/白色数据
for (uint32_t i = 0; i < size; i++) {
epd_send_data(data[i]);
}
}
// 主函数示例
int main(void)
{
epd_init();
// 准备局部刷新数据
uint8_t partial_data[1024]; // 根据实际刷新区域大小调整
// ...填充局部刷新数据...
// 设置局部刷新区域并更新显示
epd_set_partial_window(50, 50, 100, 100); // x=50, y=50, width=100, height=100
epd_write_partial_data(partial_data, sizeof(partial_data));
epd_partial_display_update();
// 进入低功耗模式
while(1) {
__WFI();
}
}
二、epaper_drive.h
#ifndef EPD_DRIVER_H
#define EPD_DRIVER_H
#include <stdint.h>
/**
* @brief 初始化墨水屏
*/
void epd_init(void);
/**
* @brief 设置局部刷新窗口
* @param x 起始X坐标
* @param y 起始Y坐标
* @param w 宽度
* @param h 高度
*/
void epd_set_partial_window(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
/**
* @brief 向局部区域写入数据
* @param data 数据缓冲区指针
* @param size 数据大小
*/
void epd_write_partial_data(const uint8_t *data, uint32_t size);
/**
* @brief 执行局部刷新显示
*/
void epd_partial_display_update(void);
#endif // EPD_DRIVER_H
三、epaper_drive.c代码解读