• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

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

武飞扬头像
王博不是王博士
帮助1

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

学新通
支持局刷的屏幕,注意使用的时候不能一直用局刷对屏幕进行刷新,需要在做几次局刷之后,对屏幕进行一次全刷清屏。否则会造成屏幕显示效果异常
注意屏幕不能长时间上电,在屏幕不刷新的时候,要将屏幕设置成睡眠模式,或者进行断电处理。否则屏幕长时间保持高电压状态,会损坏膜片,无法修复。
使用墨水屏的时候,建议刷新时间间隔至少是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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgabefc
系列文章
更多 icon
同类精品
更多 icon
继续加载