AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动
创始人
2024-06-01 12:08:50
0

目录

  • AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告
  • AIR32F103(二) Linux环境和LibOpenCM3项目模板
  • AIR32F103(三) Linux环境基于标准外设库的项目模板
  • AIR32F103(四) 27倍频216MHz,CoreMark跑分测试
  • AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
  • AIR32F103(六) ADC,I2S,DMA和ADPCM实现的录音播放功能
  • AIR32F103(七) AIR32F103CBT6/CCT6启用96K内存
  • AIR32F103(八) 集成Helix MP3解码库播放MP3
  • AIR32F103(九) CAN总线的通信和ID过滤机制及实例
  • AIR32F103(十) 在无系统环境和FreeRTOS环境集成LVGL
  • AIR32F103(十一) 在AIR32F103上移植微雪墨水屏驱动

电子墨水屏 Electronic Paper, Digital Paper

电子墨水屏又称电子纸, 其结构是两片基板, 上面分布着微小透明颗粒, 颗粒是一种带正负电的黑色, 红色和白色粒子密封于内部液态微胶囊. 不同颜色的带电粒子会因施加电场的不同, 朝不同的方向运动,在显示屏表面呈现出黑或白, 红或白的效果, 这样,在电子纸的表面就可以显示出图案和文字, 视觉效果与纸张极为类似, 不发光, 只有画素颜色变化时(例如从黑转到白)才耗电, 掉电后屏上画面仍保留, 这个特性使其特别适合于在路牌, 标签, 价签这样的场合使用. 但是这个特性也会带来一些副作用, 例如长时间展示同一画面, 会导致显示颗粒老化, 画面不易清除, 以及刷新慢等情况. 在长时间不使用时, 建议清屏(白屏)后再断电, 放置时显示面朝上. 如果需要长时间展示一个画面, 最好设置为每隔数小时刷新一次, 减缓老化.

之前在合宙上买了一片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

将微雪驱动库移植到AIR32F103

添加驱动库代码

将微雪仓库导出, 需要的部分都在 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 编译, 所以有些地方需要优化一下

  1. 将目录重命名一下, e-Paper 改为 Lib
  2. 将 Debug.h 删除, 其内容集成到 DEV_Config.h
  3. 将 DEV_Config.c 和 DEV_Config.h 的公用部分(固定部分)提取为 EPD_Common.c 和 EPD_Common.h, 放到 Lib 下
  4. 将 DEV_Config.h 中的配置部分提出来创建 EPD_Config_Template.h, 这个文件在创建项目时, 可以更名为 EPD_Config.h 放到项目目录下.

变成这样的结构

├── 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

编辑项目模板的 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/GUIINCLUDES  += Libraries/EPaper/Lib \Libraries/EPaper/Examples \Libraries/EPaper/Fonts \Libraries/EPaper/GUI
endif

驱动墨水屏的示例项目

硬件部分

  • AIR32F103CBT6, 墨水屏驱动编译完只有30多KByte, 所以用哪个型号都可以
  • 合宙的1.54寸墨水屏. 如果使用其它墨水屏, 记得修改启用对应的宏

接线是典型的 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.h

  1. 将 EPD_Config_Template.h 复制到项目目录下, 更名为 EPD_Config.h 并打开编辑
  2. 启用 EPD_1IN54, 将其反注释
  3. EPD_DEBUG设为1, 可以开启串口日志输出
  4. 定义 RESET, DC, CS, BUSY 这几个 GPIO 对应的 PORT和 PIN, 这些 PIN 脚随后需要在程序中初始化
  5. 定义几个关键方法的宏

/*** Uncomment to enable the part
*/
// #define EPD_1IN02
// #define EPD_1IN54_V2
#define EPD_1IN54
// #define EPD_1IN54B_V2
// ...
// #define EPD_7IN5BC#define EPD_DEBUG 1/*** e-Paper GPIO*/
#define EPD_RST_PIN     GPIOA, GPIO_Pin_6
#define EPD_DC_PIN      GPIOA, GPIO_Pin_4
#define EPD_CS_PIN      GPIOA, GPIO_Pin_3
#define EPD_BUSY_PIN    GPIOA, GPIO_Pin_2/*** GPIO read and write*/
#define EPD_Digital_Write(_pin, _value) GPIO_WriteBit(_pin, _value == 0? Bit_RESET:Bit_SET)
#define EPD_Digital_Read(_pin)          GPIO_ReadInputDataBit(_pin)
#define EPD_SPI_WriteByte(_value)       SPI_TxRx(_value)
#define EPD_Delay_ms(__xms)             Delay_Ms(__xms)#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 改成 3const 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 仓库

https://github.com/IOsetting/air32f103-template/tree/master/Examples/NonFreeRTOS/SPI/Waveshare_1N54_E-Paper

将目录下的文件复制替换掉 User 目录下的文件, 再编辑 Makefile, 开启 EPaper 库就能编译.

如果需要驱动其它型号的墨水屏, 编辑 EPD_Config.h 将#define EPD_1IN54注释掉, 再将需要启用的型号取消注释即可.

上一篇:TCP UPD详解

下一篇:leetcode 55. 跳跃游戏

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...