stm32驱动微雪墨水屏1.54inch e-Paper V2

2023-05-16

我一起驱动墨水屏

  • 一、墨水屏相关基础(摘自微雪官方)
  • 二、干起来
    • PART2 配置I/O
    • PART2 底层硬件接口必要的调用函数
    • PART3 功能函数
    • PART4 应用函数
  • 三、应用
  • 注意
  • **[代码下载:**](https://download.csdn.net/download/weber33/87020361)

一、墨水屏相关基础(摘自微雪官方)

1.54寸墨水屏裸屏 e-Paper 200x200分辨率 黑白
支持局刷的屏幕,注意使用的时候不能一直用局刷对屏幕进行刷新,需要在做几次局刷之后,对屏幕进行一次全刷清屏。否则会造成屏幕显示效果异常
注意屏幕不能长时间上电,在屏幕不刷新的时候,要将屏幕设置成睡眠模式,或者进行断电处理。否则屏幕长时间保持高电压状态,会损坏膜片,无法修复。
使用墨水屏的时候,建议刷新时间间隔至少是180s, 并且至少每24小时做一次刷新,如果长期不使用墨水屏的话,要将墨水屏刷白存放。(具体储存环境需求参考数据手册)
屏幕进入睡眠模式之后,会忽略发送的图片数据,只有重新初始化才能正常刷新
控制 0x3C 或 0x50 (具体参照数据手册)寄存器可以调节边框颜色,在例程中可以调节 Border Waveform Control 寄存器或者 VCOM AND DATA INERTVAL SETTING 进行设置。
如果发现制作的图片数据在屏幕上显示错误,建议检查一下图片大小设置是否正确,调换一下宽度和高度设置再试一下。
墨水屏的工作电压要求是 3.3V,如果您购买的是裸屏的话,设计电路的时候如果需要配合 5V 工作环境的话,建议做一下电平转换处理。新版驱动板(Rev2.1及后续版本)加入了电平处理电路,可以同时支持 3.3V 和 5V 工作环境,老版本只能支持 3.3V 工作环境,使用的时候可以先确认一下版本号(版本号在板名下)。
屏幕的 FPC 排线比较脆弱,注意使用的时候沿屏幕水平方向弯曲排线,不可以沿屏幕垂直方向弯曲排线。
墨水屏屏幕较为脆弱,注意尽量避免跌落、碰撞、用力按压。

二、干起来

PART2 配置I/O

stm32使用HAL库配置。用I/O口模拟SPI通信。
I/O配置。

#define LED_Pin GPIO_PIN_2
#define LED_GPIO_Port GPIOA
#define INK_MOSI_Pin GPIO_PIN_5
#define INK_MOSI_GPIO_Port GPIOA
#define INK_CLK_Pin GPIO_PIN_6
#define INK_CLK_GPIO_Port GPIOA
#define INK_CS_Pin GPIO_PIN_7
#define INK_CS_GPIO_Port GPIOA
#define INK_DC_Pin GPIO_PIN_0
#define INK_DC_GPIO_Port GPIOB
#define INK_RST_Pin GPIO_PIN_1
#define INK_RST_GPIO_Port GPIOB
#define INK_IS_BUSY_Pin GPIO_PIN_8
#define INK_IS_BUSY_GPIO_Port GPIOA
#define KEY_USER_Pin GPIO_PIN_15
#define KEY_USER_GPIO_Port GPIOA
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, LED_Pin|INK_MOSI_Pin|INK_CLK_Pin
                          |INK_CS_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, INK_DC_Pin|INK_RST_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pins : LED_Pin INK_MOSI_Pin INK_CLK_Pin
                           INK_CS_Pin */
  GPIO_InitStruct.Pin = LED_Pin||INK_MOSI_Pin|INK_CLK_Pin
                          |INK_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : INK_DC_Pin INK_RST_Pin */
  GPIO_InitStruct.Pin = INK_DC_Pin|INK_RST_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : INK_IS_BUSY_Pin KEY_USER_Pin */
  GPIO_InitStruct.Pin = INK_IS_BUSY_Pin|KEY_USER_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

PART2 底层硬件接口必要的调用函数

主要有设备初始化函数:int DEV_Module_Init(void);设备退出函数:void DEV_Module_Exit(void);模拟SPI度的函数void DEV_SPI_WriteByte(UBYTE value);SPI延时函数void SpiWrite(unsigned char value);

#ifndef _DEV_CONFIG_H_
#define _DEV_CONFIG_H_

#include "main.h"
//#include "stm32f1xx_hal.h"
//#include "stm32f1xx_hal_gpio.h"
#include <stdint.h>
#include <stdio.h>



extern void SpiWrite(unsigned char value);
/**
 * data
**/
#define UBYTE   uint8_t
#define UWORD   uint16_t
#define UDOUBLE uint32_t

/**
 * e-Paper GPIO
**/
#define EPD_RST_PIN     INK_RST_GPIO_Port, INK_RST_Pin
#define EPD_DC_PIN      INK_DC_GPIO_Port, INK_DC_Pin
#define EPD_CS_PIN      INK_CS_GPIO_Port, INK_CS_Pin
#define EPD_BUSY_PIN    INK_IS_BUSY_GPIO_Port, INK_IS_BUSY_Pin


#define EPD_W21_MOSI_0    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET)
#define EPD_W21_MOSI_1    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET)

#define EPD_W21_CLK_0    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET)
#define EPD_W21_CLK_1    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET)

#define EPD_W21_CS_0    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET)
#define EPD_W21_CS_1    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET)

#define EPD_W21_DC_0    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET)
#define EPD_W21_DC_1    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET)

#define EPD_W21_RST_0    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET)
#define EPD_W21_RST_1    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET)



/**
 * GPIO read and write
**/
#define DEV_Digital_Write(_pin, _value) HAL_GPIO_WritePin(_pin, _value == 0? GPIO_PIN_RESET:GPIO_PIN_SET)
#define DEV_Digital_Read(_pin) HAL_GPIO_ReadPin(_pin)

/**
 * delay x ms
**/
#define DEV_Delay_ms(__xms) HAL_Delay(__xms);

void DEV_SPI_WriteByte(UBYTE value);

int DEV_Module_Init(void);
void DEV_Module_Exit(void);
#endif

/********************上面是头文件中的定义,下面是c实现的函数*******************/

void SpiDelay(unsigned char xrate)
{
    unsigned char i;
    while (xrate)
    {
        for (i = 0; i < 1; i++);
        xrate--;
    }
}

void SpiWrite(unsigned char value)
{
    unsigned char i;

    SpiDelay(1);
    for (i = 0; i < 8; i++)
    {
        EPD_W21_CLK_0;
        SpiDelay(1);
        if (value & 0x80)
            EPD_W21_MOSI_1;
        else
            EPD_W21_MOSI_0;
        value = (value << 1);
        SpiDelay(1);
        EPD_W21_CLK_1;
        SpiDelay(1);
    }
}


//extern SPI_HandleTypeDef hspi1;
void DEV_SPI_WriteByte(UBYTE value)
{
//    HAL_SPI_Transmit(&hspi1, &value, 1, 1000);
		SpiWrite(value);
}

int DEV_Module_Init(void)
{
    DEV_Digital_Write(EPD_DC_PIN, 0);
    DEV_Digital_Write(EPD_CS_PIN, 0);
    DEV_Digital_Write(EPD_RST_PIN, 1);
		return 0;
}

void DEV_Module_Exit(void)
{
    DEV_Digital_Write(EPD_DC_PIN, 0);
    DEV_Digital_Write(EPD_CS_PIN, 0);

    //close 5V
    DEV_Digital_Write(EPD_RST_PIN, 0);
}

PART3 功能函数

EPD_1in54_V2.c
#include “EPD_1in54_V2.h”

复位函数static void EPD_1IN54_V2_Reset(void)
发送命令函数static void EPD_1IN54_V2_SendCommand(UBYTE Reg)
发送数据函数static void EPD_1IN54_V2_SendData(UBYTE Data)
读空闲状态函数static void EPD_1IN54_V2_ReadBusy(void)
开启显示全屏函数static void EPD_1IN54_V2_TurnOnDisplay(void)

开启显示部分区域函数static void EPD_1IN54_V2_TurnOnDisplayPart(void)
设置显示区域函数static void EPD_1IN54_V2_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
static void EPD_1IN54_V2_Lut(UBYTE *lut)
static void EPD_1IN54_V2_SetLut(UBYTE *lut)
static void EPD_1IN54_V2_SetCursor(UWORD Xstart, UWORD Ystart)
屏幕初始化void EPD_1IN54_V2_Init(void)
屏幕局部初始化void EPD_1IN54_V2_Init_Partial(void)
屏幕清除void EPD_1IN54_V2_Clear(void)
向RAM发送显示的图像void EPD_1IN54_V2_Display(UBYTE *Image)
显示部分区域图像void EPD_1IN54_V2_DisplayPartBaseImage(UBYTE *Image)
向RAM发送部分显示图像void EPD_1IN54_V2_DisplayPart(UBYTE *Image)
屏幕休眠void EPD_1IN54_V2_Sleep(void)
测试例程int EPD_test(void)

PART4 应用函数

GUI_Paint.c中包含画点、线 、矩形等函数。使用时调用即可。

三、应用

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  EPD_1IN54_V2_Init();
  EPD_1IN54_V2_Clear();
  DEV_Delay_ms(500);
  //Create a new image cache
    UBYTE *BlackImage;
    /* you have to edit the startup_stm32fxxx.s file and set a big enough heap size */
    UWORD Imagesize = ((EPD_1IN54_V2_WIDTH % 8 == 0)? (EPD_1IN54_V2_WIDTH / 8 ): (EPD_1IN54_V2_WIDTH / 8 + 1)) * EPD_1IN54_V2_HEIGHT;
    if((BlackImage = (UBYTE *)malloc(Imagesize)) == NULL) {
        printf("Failed to apply for black memory...\r\n");
        return -1;
    }
    printf("Paint_NewImage\r\n");
    Paint_NewImage(BlackImage, EPD_1IN54_V2_WIDTH, EPD_1IN54_V2_HEIGHT, 270, WHITE);
    
    #if 1   //show image for array    
    printf("show image for array\r\n");
    Paint_SelectImage(BlackImage);
    Paint_Clear(WHITE);
    Paint_DrawBitMap(gImage_1in54);

    EPD_1IN54_V2_Display(BlackImage);
    DEV_Delay_ms(2000);
#endif

#if 1   // Drawing on the image
    printf("Drawing\r\n");
    //1.Select Image
    Paint_SelectImage(BlackImage);
    Paint_Clear(WHITE);

    // 2.Drawing on the image
    Paint_DrawPoint(5, 10, BLACK, DOT_PIXEL_1X1, DOT_STYLE_DFT);
    Paint_DrawPoint(5, 25, BLACK, DOT_PIXEL_2X2, DOT_STYLE_DFT);
    Paint_DrawPoint(5, 40, BLACK, DOT_PIXEL_3X3, DOT_STYLE_DFT);
    Paint_DrawPoint(5, 55, BLACK, DOT_PIXEL_4X4, DOT_STYLE_DFT);

    Paint_DrawLine(20, 10, 70, 60, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);
    Paint_DrawLine(70, 10, 20, 60, BLACK, DOT_PIXEL_1X1, LINE_STYLE_SOLID);
    Paint_DrawLine(170, 15, 170, 55, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);
    Paint_DrawLine(150, 35, 190, 35, BLACK, DOT_PIXEL_1X1, LINE_STYLE_DOTTED);

    Paint_DrawRectangle(20, 10, 70, 60, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
    Paint_DrawRectangle(85, 10, 130, 60, BLACK, DOT_PIXEL_1X1, DRAW_FILL_FULL);

    Paint_DrawCircle(170, 35, 20, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
    Paint_DrawCircle(170, 85, 20, BLACK, DOT_PIXEL_1X1, DRAW_FILL_FULL);
    Paint_DrawString_EN(5, 85, "waveshare", &Font20, BLACK, WHITE);
    Paint_DrawNum(5, 110, 123456789, &Font20, BLACK, WHITE);

    Paint_DrawString_CN(5, 135,"���abc", &Font12CN, BLACK, WHITE);
    Paint_DrawString_CN(5, 155, "΢ѩ����", &Font24CN, WHITE, BLACK);

    EPD_1IN54_V2_Display(BlackImage);
    DEV_Delay_ms(2000);
#endif

#if 1   //Partial refresh, example shows time    

    // The image of the previous frame must be uploaded, otherwise the
    // first few seconds will display an exception.
    
    EPD_1IN54_V2_DisplayPartBaseImage(BlackImage);

    // enter partial mode
	EPD_1IN54_V2_Init_Partial();
    printf("Partial refresh\r\n");
    Paint_SelectImage(BlackImage);
    PAINT_TIME sPaint_time;
    sPaint_time.Hour = 12;
    sPaint_time.Min = 34;
    sPaint_time.Sec = 56;
    UBYTE num = 10;
    for (;;) {
        sPaint_time.Sec = sPaint_time.Sec + 1;
        if (sPaint_time.Sec == 60) {
            sPaint_time.Min = sPaint_time.Min + 1;
            sPaint_time.Sec = 0;
            if (sPaint_time.Min == 60) {
                sPaint_time.Hour =  sPaint_time.Hour + 1;
                sPaint_time.Min = 0;
                if (sPaint_time.Hour == 24) {
                    sPaint_time.Hour = 0;
                    sPaint_time.Min = 0;
                    sPaint_time.Sec = 0;
                }
            }
        }
        Paint_ClearWindows(15, 65, 15 + Font20.Width * 7, 65 + Font20.Height, WHITE);
        Paint_DrawTime(15, 65, &sPaint_time, &Font20, WHITE, BLACK);
        num = num - 1;
        if(num == 0) {
            break;
        }
        EPD_1IN54_V2_DisplayPart(BlackImage);
        DEV_Delay_ms(500);//Analog clock 1s
    }

#endif
    printf("Clear...\r\n");
    EPD_1IN54_V2_Init();
    EPD_1IN54_V2_Clear();

    printf("Goto Sleep...\r\n");
    EPD_1IN54_V2_Sleep();
    free(BlackImage);
    BlackImage = NULL;
    // close 5V
    printf("close 5V, Module enters 0 power consumption ...\r\n");
    DEV_Module_Exit();
    
  /* USER CODE END 2 */
  /* USER CODE BEGIN WHILE */
    while (1) {
			HAL_Delay(10000);
    }

}

当然,还有需要的字体文件等。。。

注意

注意:由于使用malloc开辟空间,stm32启动文件中默认的空间不足,该函数返回null导致编译能过,但运行不下去。
对于malloc和free对内存堆栈块的空间操作,在keilMDK中需要满足下面几个条件:
1、使用的代码文件中需要包含头文件 <stdlib.h>
2、在工程的属性设置中需要把 Use MicroLIB 选项勾选,如下图。

3、这时候原则上就可以使用空间申请和释放的两个操作函数了,但是由于STM32在startup_stm32f10x_hd.s中分配的堆空间只有0x00000200个字节,所以很多时候调用malloc函数时如果申请空间超过0X200则返回了NULL,这时候就需要到该文件对这个值进行设置。

上面工作完成后,我们就可以愉快地尽情使用malloc和free两个函数了!!

修改启动文件startup_stm32l051xx.s,将堆栈大小由默认200改为大于5000,不够的话在稍微大一点。

**代码下载:**

https://download.csdn.net/download/weber33/87020361

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

stm32驱动微雪墨水屏1.54inch e-Paper V2 的相关文章

  • 如何释放linux的内存

    你们知道怎么释放linux的内存吗不知道的话跟着学习啦小编一起来学习怎么释放linux的内存 释放linux的内存的步骤 Linux下操作频繁时 xff0c 物理内存会被快速用完 xff0c 当操作结束后 xff0c 物理内存没有被正常的释

随机推荐

  • 跨域的五种解决方案详解

    1 跨域解决方案一 cors技术 CORS 全称cross origin resource share xff08 资源共享 xff09 工作原理 xff1a 服务器 在返回响应报文的时候 xff0c 在响应头中 设置一个允许的header
  • MySQL 日期时间类型精确到毫秒

    MySQL 常用的日期时间类型常用的是datetime timestamp 其中datetime占用5个字节 xff08 有些文档中说占用8个字节是不对的 xff0c 默认也不会保存毫秒 xff09 DATETIME和TIMESTAMP两种
  • Spring Boot——Thymeleaf

    哈喽 xff01 大家好 xff0c 我是 xff0c 一位上进心十足的 Java领域博主 xff01 的写作风格 xff1a 喜欢用 通俗易懂 的文笔去讲解每一个知识点 xff0c 而不喜欢用 高大上 的官方陈述 博客的领域是 面向后端技
  • [BZOJ3185][Coci2011][DP]kamion

    考虑转化一下问题 令 f i j k 表示从i到j恰好用了k步 xff0c 并且到j的时候火车厢为空的方案数 那么转移就是 f i j k 61 f a b k 1 f c j k 2 xff0c 转移成立当且仅当存在i gt a的边 xf
  • 查看docker 容器的端口

    查看docker 容器的端口 sudo netstat tulpn grep docker 查看指定端口 xff0c 可以结合grep命令 xff1a netstat ap grep 80 查找指定端口使用的pid fuser 80 tcp
  • Docker服务的停止命令(systemctl stop docker)

    停止Docker服务 停止docker服务 systemctl stop docker 非root用户使用 停止docker服务 sudo systemctl stop docker
  • Docker查找镜像版本的命令

    Docker查找镜像版本的命令 有时候想查一下镜像有哪些版本 xff0c 因为有墙 xff0c 官网一直在转圈进不去 xff0c 这时候就可以使用命令查询了 xff0c 以centos为例 xff0c 自己想要哪个更改一下命令就可以了 do
  • ES6 如何将 Set 转化为数组

    例如 xff1a const mySet 61 new Set Set 对象具有以下特征 xff1a Set 实例的成员唯一 xff0c 不会重复 Set 实例可以存储任何类型的值 xff0c 包括基本类型和对象 Set 实例是可迭代的 x
  • Request.url用法

    網址 xff1a http localhost 1897 News Press Content aspx 123 id 61 1 toc Request ApplicationPath Request PhysicalPath D Proj
  • oracle IO 优化

    数据库的作用就是实现对数据的管理和查询 任何一个数据库系统 xff0c 必然存在对数据的大量读或者写或者两中操作都大量存在 IO问题也往往是导致数据库性能问题的重要原因 在这篇文章中 xff0c 主要帮助大家在理解Oracle的读写操作机制
  • oracle中imp命令详解

    oracle中imp命令详解 Oracle的导入实用程序 Import utility 允许从数据库提取数据 xff0c 并且将数据写入操作系统文 件 imp使用的基本格式 xff1a imp username password 64 se
  • C# 非顶端窗口截图

    panel上可以通过DrawToBitmap截图 xff0c 不管是否在屏幕外是否有遮挡 Bitmap sourceBitmap 61 new Bitmap 400 300 Control ct 61 frmMain mianForm pa
  • bat中的特殊字符,以及需要在bat中当做字符如何处理

    bat中的特殊字符 xff0c 以及需要在bat中当做字符如何处理 批处理 Bat 中特殊符号的实际作用 xff0c Windows 批处理中特殊符号的作用 xff1a 64 隐藏命令的回显 在for中表示使用增强的变量扩展 xff1b 在
  • rviz无法显示的问题

    1 启用初始化配置 首先删除保存好的rviz xff0c 运行最初始化的配置 rviz运行后会选择保存在 home cbc rviz default rviz 删除之后 xff0c 重新运行 xff1a roscore rosrun rvi
  • 用C语言编写一个HTTP协议的目录浏览和文件下载服务器

    include lt stdarg h gt include lt errno h gt include lt stdio h gt include lt fcntl h gt include lt unistd h gt include
  • 编写浏览器使用的OCX全过程

    随着互联网的飞速发展 现在的人们都习惯了打开浏览器进行工作 基于WEB的程序蜂拥而至 几乎变得无所不能 由于WEB脚本语言的限制 xff0c 对于本地计算机的访问受到很大的限制 开发WEB的程序员都会因为WEB的打印而烦恼 xff0c 对于
  • Linux平台下启动oracle 11g EM控制台

    当我们的oracle服务器是使用的Linux Unix系统时 我们从windows或者其他的客户端想用启动oracle的EM工具了解一些系统系统信息时 可以采用如下方式 首先在服务器端打开一个窗口 输入如下命令 emctl start or
  • Oracle日常性能查看

    判断回滚段竞争的SQL语句 xff1a xff08 当Ratio大于2时存在回滚段竞争 xff0c 需要增加更多的回滚段 xff09 select rn name rs GETS rs WAITS rs WAITS rs GETS 100
  • Double.ToString 方法 (String)

    double numbers 61 1054 32179 195489100 8377 1 0437E21 1 0573e 05 string specifiers 61 34 C 34 34 E 34 34 e 34 34 F 34 34
  • stm32驱动微雪墨水屏1.54inch e-Paper V2

    我一起驱动墨水屏 一 墨水屏相关基础 xff08 摘自微雪官方 xff09 二 干起来PART2 配置I OPART2 底层硬件接口必要的调用函数PART3 功能函数PART4 应用函数 三 应用注意 代码下载 xff1a https do