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

这篇具有很好参考价值的文章主要介绍了stm32驱动微雪墨水屏1.54inch e-Paper V2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

stm32驱动微雪墨水屏1.54inch e-Paper V2
支持局刷的屏幕,注意使用的时候不能一直用局刷对屏幕进行刷新,需要在做几次局刷之后,对屏幕进行一次全刷清屏。否则会造成屏幕显示效果异常
注意屏幕不能长时间上电,在屏幕不刷新的时候,要将屏幕设置成睡眠模式,或者进行断电处理。否则屏幕长时间保持高电压状态,会损坏膜片,无法修复。
使用墨水屏的时候,建议刷新时间间隔至少是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文章来源地址https://www.toymoban.com/news/detail-425063.html

到了这里,关于stm32驱动微雪墨水屏1.54inch e-Paper V2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 使用micropython(ESP8266、ESP32)驱动SES 2.66寸墨水屏显示中文

    由于需要做一些低功耗的东西,所以最近在尝试玩墨水屏。出于成本考虑(没钱的另一种委婉说法)从咸鱼淘到2块便宜的二手SES 2.66寸三色墨水屏,并使用micropython将其驱动起来,并用字库的方法显示中文。 1.硬件连线 SES 2.66墨水屏 SES 2.66墨水屏带驱动小板 买到的屏幕是图上

    2024年01月22日
    浏览(40)
  • 【STM32】实战3.1—用STM32与TB6600驱动器驱动42步进电机(一)

    目录 0 参考资料出处 1 实验预期效果 2 硬件学习 2.1 TB6600驱动器  2.1.1 通过拨码开关设定细分与电流 2.1.2 共阴共阳接线法 2.2 开关电源(AC转DC变压器) 电源线 2.3 42步进电机 2.3.1 基本知识 2.3.2 转速细分控制 2.3.3 满步、半步、微步驱动原理 3 软件配置与硬件接线 3.1 STM32CubeM

    2024年02月02日
    浏览(58)
  • STM32--舵机驱动

    目录 舵机接线: 数字舵机与模拟舵机的区别: 舵机驱动(90度、180度、270度、360度): 90度舵机驱动: 180度舵机驱动: 270度舵机驱动: 360度舵机驱动: STM32定时器配置: stm32f4为例(时钟频率为84Mhz): stm32f1为例(时钟频率为72Mhz): STM32定时器PWM输出配置要点: STM32定时

    2024年04月15日
    浏览(30)
  • STM32驱动开发

    本文简单介绍STM32标准库下的部分驱动开发流程(F1系列芯片),扩展介绍部分重要的属性。 复用功能 将某些功能复用到其他引脚上使用。 属性 引脚(GPIO_Pin):芯片对应的引脚。 速率(GPIO_Speed):输出驱动电路的响应速度,做输入时此功能无效。芯片内部在I/O口的输出部分安排了

    2024年02月15日
    浏览(34)
  • STM32MP157驱动开发——按键驱动(中断)

    对于使用中断的按键驱动,内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以,需要做的只是修改设备树指定引脚及键值 中断是引入其他基础知识的前提:休眠-唤醒、POLL 机制、异步通知、定时器、中断的线程化处理都离不开中断 设备树相关 查看原理图确定按键使用的

    2024年02月15日
    浏览(47)
  • 基础篇010.2 STM32驱动RC522 RFID模块之二:STM32硬件SPI驱动RC522

    目录 1. 实验硬件及原理图 1.1 RFID硬件 1.2 硬件原理图 2. 单片机与RFID硬件模块分析 3. 利用STM32CubeMX创建MDK工程 3.1 STM32CubeMX工程创建 3.2 配置调试方式 3.3 配置时钟电路 3.4 配置时钟 3.5 配置GPIO 3.6 配置SPI 3.7 配置串口 3.8 项目配置 4. MDK工程驱动代码调试 4.1 按键、LED程序 4.1.1 Us

    2024年02月09日
    浏览(53)
  • STM32MPU6050角度的读取(STM32驱动MPU6050)

    注:文末附STM32驱动MPU6050代码工程链接,需要的读者请自取。 MPU6050是一款集成了三轴陀螺仪和三轴加速度计的传感器芯片,由英国飞利浦半导体(现为恩智浦半导体)公司生产。它通过电子接口(如I2C或SPI)与微控制器进行通信,可用于测量物体的加速度和角速度,广泛应

    2024年02月20日
    浏览(54)
  • stm32-iic 时序驱动

    数据发送

    2024年02月12日
    浏览(35)
  • 基础篇010.3 STM32驱动RC522 RFID模块之三:STM32软件模拟SPI驱动RC522

    目录   1. 实验硬件及原理图 2. 利用STM32CubeMX创建MDK工程 2.1 STM32CubeMX工程创建 2.2 配置调试方式 2.3 配置时钟电路 2.4 配置时钟 2.5 配置GPIO 2.6 配置串口 2.7 项目配置 3. MDK工程驱动代码调试 3.1 按键、LED程序 3.2 SPI软件模拟程序 3.3 RC522驱动程序 3.4 UART串口printf,scanf函数串口重定

    2024年04月17日
    浏览(54)
  • STM32MP157驱动开发——按键驱动(tasklet)

    阅读Linux 系统中异常与中断可知,Linux 系统对中断处理的演进过程中,实现了中断的扩展:硬件中断、软件中断 硬件中断有:GPIO,网络中断(net),系统滴答中断(tick)等 软件中断有:定时器,tasklet等 内核中的软中断: 该数组里面有个action成员,该成员是个函数,函数会调

    2024年02月14日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包