电子墨水屏又称电子纸, 其结构是两片基板, 上面分布着微小透明颗粒, 颗粒是一种带正负电的黑色, 红色和白色粒子密封于内部液态微胶囊. 不同颜色的带电粒子会因施加电场的不同, 朝不同的方向运动,在显示屏表面呈现出黑或白, 红或白的效果, 这样,在电子纸的表面就可以显示出图案和文字, 视觉效果与纸张极为类似, 不发光, 只有画素颜色变化时(例如从黑转到白)才耗电, 掉电后屏上画面仍保留, 这个特性使其特别适合于在路牌, 标签, 价签这样的场合使用. 但是这个特性也会带来一些副作用, 例如长时间展示同一画面, 会导致显示颗粒老化, 画面不易清除, 以及刷新慢等情况. 在长时间不使用时, 建议清屏(白屏)后再断电, 放置时显示面朝上. 如果需要长时间展示一个画面, 最好设置为每隔数小时刷新一次, 减缓老化.
之前在合宙上买了一片1.54寸的墨水屏一直在吃灰, 这次趁点亮的机会把AIR32F103上的驱动示例给做了.
微雪可能是因为墨水屏才被大家熟知, 其实这家做了相当多的电路模块, 主要做外销, 国内了解的比较少.
他们维护了一个品类众多(45种)的墨水屏型号列表, 在 GitHub 上有一个专门的代码仓库
https://github.com/waveshare/e-Paper
微雪的这个驱动库代码质量还是不错的. 里面带了针对 RaspberryPi, Arduino 和 STM32 的驱动, STM32的这个驱动, 用的硬件是 STM32F103ZET6, 迁移到AIR32F103很方便.
驱动库当前支持以下的45种墨水屏型号, 从1.54寸到7.5寸, 其命名方式是 1N54 代表 1.54英寸, 如果同一尺寸有多个, 用 B, C, D, V2, V3 等后缀区分.
EPD_1IN54
EPD_1IN54B_V2
EPD_1IN54B
EPD_1IN54C
EPD_1IN64G
EPD_2IN7_V2
EPD_2IN7
EPD_2IN7B_V2
EPD_2IN7B
EPD_2IN9_V2
EPD_2IN9
EPD_2IN9B_V3
EPD_2IN9BC
EPD_2IN9D
EPD_2IN13_V2
EPD_2IN13_V3
EPD_2IN13
EPD_2IN13B_V3
EPD_2IN13B_V4
EPD_2IN13BC
EPD_2IN13D
EPD_2IN36G
EPD_2IN66
EPD_2IN66B
EPD_3IN0G
EPD_3IN7
EPD_3IN52
EPD_4IN01F
EPD_4IN2
EPD_4IN2B_V2
EPD_4IN2BC
EPD_4IN37G
EPD_5IN65F
EPD_5IN83_V2
EPD_5IN83
EPD_5IN83B_V2
EPD_5IN83BC
EPD_7IN3F
EPD_7IN3G
EPD_7IN5_HD
EPD_7IN5_V2
EPD_7IN5
EPD_7IN5B_HD
EPD_7IN5B_V2
EPD_7IN5BC
将微雪仓库导出, 需要的部分都在 STM32/STM32-F103ZET6/User 目录下, 将其中代码部分复制到AIR32F103的库目录下, 形成目录结构为
Libraries
├── AIR32F10xLib
├── CMSIS
├── Debug
├── DeviceSupport
├── EPaper
│ ├── Config # 配置文件
│ ├── e-Paper # 对应每一个型号的 .c 和 .h 文件, 驱动的核心
│ ├── Examples # 对应每一个型号的测试示例, 都实现了 EPD_test(void) 这个方法
│ ├── Fonts # 字体, 5个英文字体, 2个中文字体(只是少数几个汉字)
│ └── GUI # 点线面的绘制方法
因为目的是要在 GNU GCC 下使用 Makefile 编译, 所以有些地方需要优化一下
变成这样的结构
├── EPaper
│ ├── EPD_Config_Template.h
│ ├── Examples
│ ├── Fonts
│ ├── GUI
│ └── Lib
进一步将每一个型号提取为宏, 然后对 Lib 和 Examples 下的每个驱动和测试 c 文件, 增加宏判断
#ifdef EPD_1IN54
...
#endif
这样可以在 EPD_Config.h 中使用宏配置启用哪一个型号, 例如对于合宙这块1.54的屏, 只需要启用 1N54 这个宏
/**
* Uncomment the part number to enable
*/
// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// #define EPD_1IN54B
// #define EPD_1IN54C
// #define EPD_1IN64G
...
...
// #define EPD_7IN5B_V2
// #define EPD_7IN5BC
这样编译时未启用的型号, 其驱动和测试会直接跳过
编辑项目模板的 Makefile, 增加配置项, y 代表启用墨水屏驱动
# Build with Waveshare e-paper lib, y:yes, n:no
USE_EPAPER ?= y
以及对应的编译包含项, 这里使用的是修改过名称后的目录名
ifeq ($(USE_EPAPER),y)
CDIRS += Libraries/EPaper/Lib \
Libraries/EPaper/Examples \
Libraries/EPaper/Fonts \
Libraries/EPaper/GUI
INCLUDES += Libraries/EPaper/Lib \
Libraries/EPaper/Examples \
Libraries/EPaper/Fonts \
Libraries/EPaper/GUI
endif
接线是典型的 SPI 接线方式, 和普通LCD一样, 但是没有背光, 增加了一个 Busy 脚
* Waveshare 1.54' E-Paper Demo
*
* AIR32 E-Paper
* - PA2 BUSY
* - PA3 CS
* - PA4 DC(Data/Command)
* - PA5 SCK/SCL
* - PA6 RES
* - PA7 SI/SDA
* - GND GND
* - 3.3V VCC
将 EPD_Config_Template.h 复制到项目目录下, 更名为 EPD_Config.h 并打开编辑
启用 EPD_1IN54
, 将其反注释
EPD_DEBUG
设为1
, 可以开启串口日志输出
定义 RESET, DC, CS, BUSY 这几个 GPIO 对应的 PORT和 PIN, 这些 PIN 脚随后需要在程序中初始化
定义几个关键方法的宏
/**
#define EPD_DEBUG 1
/**
/**
#endif
因为是示例项目, 就不单独分文件了, 都添加到 main.c.
初始化普通 GPIO, PA2是输入, PA3, PA4, PA6 都是输出
void APP_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
初始化SPI1, 这里用 PA5作为SCL, PA7作为SDA
void APP_SPI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_5 | GPIO_Pin_7);
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
对应 EPD_Config.h 中的 EPD_SPI_WriteByte() 宏定义, 创建 SPI 的字节读写方法
uint8_t SPI_TxRx(uint8_t data)
{
uint8_t retry = 0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET && ++retry);
SPI_I2S_SendData(SPI1, data);
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET && ++retry);
return SPI_I2S_ReceiveData(SPI1);
}
在 main() 中初始化后直接调用微雪自带的测试函数. 这个测试会写入图, 然后写入文字, 局部刷新, 最后清屏, 进入睡眠.
int main(void)
{
//...
APP_GPIO_Config();
APP_SPI_Config();
EPD_test();
while (1);
}
原驱动库中文使用的是 GB2312 的编码, 而我在 Ubuntu 下肯定是不用 GBK 的, 所以会乱码, 我把这部分都改成 UTF-8 了, 因此对应的汉字的字节数也从2变成了3, 需要做对应的修改
fonts.h
typedef struct
{
unsigned char index[3]; //<-- 从 2 改成 3
const char matrix[MAX_HEIGHT_FONT*MAX_WIDTH_FONT/8];
} CH_CN;
GUI_Paint.c
void Paint_DrawString_CN(UWORD Xstart, UWORD Ystart, const char * pString, cFONT* font,
UWORD Color_Foreground, UWORD Color_Background)
{
//...
/* Point on the next character */
p_text += 3; //<-- 从 2 改成 3
//...
原先的字体定义方式为
/*-- 文字: 好 --*/
/*-- 微软雅黑12; 此字体下对应的点阵为:宽x高=16x21 --*/
{"好",
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00},
这种初始化赋值应该是 ARM GCC 支持, 但是 GUN GCC 不支持, 编译会报错, 两个struct成员变量不能用同一个花括号, 需要改为
/*-- 文字: 好 --*/
/*-- 微软雅黑12; 此字体下对应的点阵为:宽x高=16x21 --*/
{
index:"好",
matrix: {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},
或者下面这种形式
/*-- 文字: 好 --*/
/*-- 微软雅黑12; 此字体下对应的点阵为:宽x高=16x21 --*/
{
"好",
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x73,0xFF,0x70,0x0F,0xFE,0x1E,
0x7E,0x3C,0x6E,0x38,0xEE,0x30,0xEF,0xFF,0xFC,0x30,0x7C,0x30,0x38,0x30,0x3E,0x30,
0x7E,0x30,0xE0,0x30,0xC1,0xF0,0x00,0x00,0x00,0x00}
},
经过以上的修改, 就可以正常编译了.
代码已经提交到 GitHub 仓库
将目录下的文件复制替换掉 User 目录下的文件, 再编辑 Makefile, 开启 EPaper 库就能编译.
如果需要驱动其它型号的墨水屏, 编辑 EPD_Config.h 将#define EPD_1IN54
注释掉, 再将需要启用的型号取消注释即可.
手机扫一扫
移动阅读更方便
你可能感兴趣的文章