828|0

504

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【得捷电子Follow me第4期】入门任务之二-液晶驱动 [复制链接]

  本帖最后由 qinyunti 于 2024-2-15 22:15 编辑

二.液晶驱动

2.1参考

1.adafruit-sharp-memory-display-breakout.pdf

2.LS013B4DN04-3V_FPC-204284.pdf

 

2.2接线

电源只需要3.3V接VIN,接GND。

信号使用3个输出引脚接CS,DI,CLK

 

 

2.3显存映射

分辨率144x168,注意这里不要搞反了否则显示会不对。

 

V垂直方向对应Line地址144x168就是168.

H水平方向对应P,一个字节对应8列,144列需要144/8个字节。

需要显存大小是144*168/8字节。

 

Line地址如下映射,注意对应二进制从1开始,以下示例是96行,我们这里实际是168行:

 

2.4时序

操作参考1文档的6.5章节。

 

两个重点参数帧率1~60HZ,时钟频率最大1MHz。

 

其他重点时序参数

tsSCS最小6uS  SCS建立时间

thSCS最小2uS    SCS保持时间

tsSI最小380nS   数据建立时间

thSI最小440nS   数据保持时间

twSCLKL 最低450nS 时钟低时间

twSCLKL 最低450nS 时钟高时间

 

SCS高有效,SCLK低时准备数据,上升沿设备采样数据。

 

关注以下操作,显示单行,多行和清除显示,只需要这几个操作即可,前者将存在控制器的显存刷新到液晶显示,后者清除显示为白色。

 

 

 

2.4.1显示单行6-5-1 Data update mode (1 line)

 

 

2.4.2显示多行6-5-2 Data Update Mode (Multiple Lines)

 

 

2.4.3清除显示6-5-4 All Clear Mode

 

2.5驱动

2.5.1 数据结构和接口

定义基本的IO操作接口

typedef void (*ls013_io_cs_set)(uint8_t level);    /**< CS输出接口  */

typedef void (*ls013_io_di_set)(uint8_t level);    /**< DI输出接口  */

typedef void (*ls013_io_clk_set)(uint8_t level);   /**< SCK输出接口 */

typedef void (*ls013_io_delay)(uint32_t ns);       /**< 延时接口    */

typedef void (*ls013_io_init)(void);               /**< 初始化      */

typedef void (*ls013_io_deinit)(void);             /**< 解除初始化      */

 

/** \struct ls013_dev_st

 * 设备接口结构体

 */

typedef struct

{

    ls013_io_cs_set cs_set;    /**< CS输出接口  */

    ls013_io_di_set di_set;    /**< DI输出接口  */

    ls013_io_clk_set clk_set;  /**< SCK输出接口 */

    ls013_io_delay delay;      /**< 延时接口    */

    ls013_io_init init;        /**< 初始化      */

    ls013_io_deinit deinit;    /**< 解除初始化      */

} ls013_dev_st;

定义对外接口

/**

 * \fn ls013_dis

 * 显示一帧

 * \param[in]  dev \ref ls013_dev_st 设备指针

 * \param[in]  buffer 帧缓存

 * \param[in] h 水平像素点

 * \param[in] v 垂直像素点

*/

void ls013_dis(ls013_dev_st* dev, uint8_t* buffer, uint8_t h, uint8_t v);

 

/**

 * \fn ls013_clr

 * 清除显示

 * \param[in]  dev \ref ls013_dev_st 设备指针

*/

void ls013_clr(ls013_dev_st* dev);

 

/**

 * \fn ls013_init

 * 初始化

 * \param[in]  dev \ref ls013_dev_st 设备指针

*/

void ls013_init(ls013_dev_st* dev);

 

/**

 * \fn ls013_deinit

 * 解除初始化

 * \param[in]  dev \ref ls013_dev_st 设备指针

*/

void ls013_deinit(ls013_dev_st* dev);

 

定时参数宏

/**

 * 时序宏定义

 * tsSCS最小6uS  SCS建立时间

 * thSCS最小2uS    SCS保持时间

 * tsSI最小380nS   数据建立时间

 * thSI最小440nS   数据保持时间

 * twSCLKL 最低450nS 时钟低时间

 * twSCLKL 最低450nS 时钟高时间

 * twSCSL 最低2uS    SCS低时间

 * twSCSH 最低24/136uS    SCS高时间

*/

#define TSSCS    6000

#define THSCS    2000

#define TSSI     380

#define THSI     440

#define TWSCLKL  450

#define TWSCLKH  450

#define TWSCSL  2000

#define TWSCSH  24000

 

/**

 * 命令宏定义

 * M2-M1-M0的组合

*/

#define CMD_ALL_CLR 0x04  /* M2 */

#define CMD_NO_CLR 0x00

#define CMD_VCOM_H 0x02   /* M1 */

#define CMD_VCOM_L 0x00

#define CMD_MODE_UPDATE 0x01 /* M0 */

#define CMD_MODE_DISPLAY 0x00

 

 

发送字节实现

/**

 * \fn ls013_write_byte

 * 发送一个字节

*/

static void ls013_write_byte(ls013_dev_st* dev, uint8_t val)

{

    /* 默认SCLK为0 */

    dev->clk_set(0);

 

    for(int i=0; i<8; i++)

    {

        if((val & 0x01) != 0)

        {

            dev->di_set(1);

        }

        else

        {

            dev->di_set(0);  

        }

        if(dev->delay != 0)

        {

            dev->delay(TWSCLKL); /* 足够数据建立时间 TWSCLKL>TSSI */

        }

        dev->clk_set(1);      /* SCK上升沿触发对方采样 */

        if(dev->delay != 0)

        {

            dev->delay(TWSCLKH); /* 足够数据保持时间 TWSCLKH>THSI */

        }

        /* 恢复SCLK为0 */

        dev->clk_set(0);

        val >>= 1; /* 准备下一位, 低位在前发送 */

    }

}

 

 

2.5.2设置模式实现

/**

 * \fn ls013_set_mode

 * 设置m2-m1-m0

 * \param[in] dev \ref ls013_dev_st 设备指针

 * \param[in] mode m2-m1-m0的组合

*/

static void ls013_set_mode(ls013_dev_st* dev, uint8_t mode)

{

    if(dev == 0)

    {

        return;

    }

    if((dev->clk_set == 0) || (dev->cs_set == 0) || (dev->di_set == 0))

    {

        return;

    }

    dev->cs_set(1);  /* 拉高SCS */

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待TSSCS */

    }

    ls013_write_byte(dev,mode);  /* M2-M1-M0 */

    ls013_write_byte(dev,0x00);  /* dummy */

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待THSCS */

    }

    dev->cs_set(0);  /* 拉低SCS */

    if(dev->delay != 0)

    {

        dev->delay(TWSCSL); /* 等待TWSCSL */

    }

}

 

2.5.3单行显示

void ls013_dis_line(ls013_dev_st* dev, uint8_t* buffer, uint8_t h, uint8_t line)

{

    uint32_t index = 0;

 

    dev->cs_set(1);  /* 拉高SCS */

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待TSSCS */

    }

 

    ls013_write_byte(dev,CMD_NO_CLR | CMD_VCOM_L | CMD_MODE_UPDATE);  /* M2-M1-M0 */

    ls013_write_byte(dev,line+1);  /* line地址,从1开始 */

    for(int j=0; j<h/8; j++)

    {

        ls013_write_byte(dev,buffer[index++]);  /* 数据 */

    }

 

    ls013_write_byte(dev,0);  /* 最后16个CLK dummy */

    ls013_write_byte(dev,0);

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待THSCS */

    }

    dev->cs_set(0);  /* 拉低SCS */

    if(dev->delay != 0)

    {

        dev->delay(TWSCSL); /* 等待TWSCSL */

    }

}

 

2.5.4多行显示

基于单行更新实现,或者直接使用多行更新。

void ls013_dis(ls013_dev_st* dev, uint8_t* buffer, uint8_t h, uint8_t v)

{

#if 1

    uint8_t index = 0;

    if(dev == 0)

    {

        return;

    }

    if((dev->clk_set == 0) || (dev->cs_set == 0) || (dev->di_set == 0))

    {

        return;

    }

    dev->cs_set(1);  /* 拉高SCS */

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待TSSCS */

    }

 

    for(int i=0; i<v; i++)

    {

        if(i==0)

        {

            ls013_write_byte(dev,CMD_NO_CLR | CMD_VCOM_L | CMD_MODE_UPDATE);  /* M2-M1-M0 */

        }

        else

        {

            ls013_write_byte(dev,0);

        }

        ls013_write_byte(dev,i+1);  /* line地址,从1开始 */

        for(int j=0; j<h/8; j++)

        {

            ls013_write_byte(dev,buffer[index++]);  /* 数据 */

        }

    }

    ls013_write_byte(dev,0);  /* 最后16个CLK dummy */

    ls013_write_byte(dev,0);

    if(dev->delay != 0)

    {

        dev->delay(TSSCS); /* 等待THSCS */

    }

    dev->cs_set(0);  /* 拉低SCS */

    if(dev->delay != 0)

    {

        dev->delay(TWSCSL); /* 等待TWSCSL */

    }

 

    //ls013_set_mode(dev, CMD_NO_CLR | CMD_VCOM_L | CMD_MODE_DISPLAY);

#else

    for(int i=0; i<v; i++)

    {

        ls013_dis_line(dev, buffer+i*(h/8), h, i);

    }

#endif

}

 

逻辑分析仪测试如下

 

 

 

2.5.5清除显示

void ls013_clr(ls013_dev_st* dev)

{

    ls013_set_mode(dev, CMD_ALL_CLR | CMD_VCOM_L | CMD_MODE_DISPLAY);

}

 

 

逻辑分析测量如下

 

 

 

2.5.6初始化解除初始化

void ls013_init(ls013_dev_st* dev)

{

    if(dev == 0)

    {

        return;

    }

    if(dev->init == 0)

    {

        return;

    }

    dev->init();

}

 

void ls013_deinit(ls013_dev_st* dev)

{

    if(dev == 0)

    {

        return;

    }

    if(dev->deinit == 0)

    {

        return;

    }

    dev->deinit();

 

}

 

2.5.7 测试

实现ls013_lcd.h

#ifndef LS013_LCD_H

#define LS013_LCD_H

 

#ifdef __cplusplus

    extern "C"{

#endif

 

#define LCD_H (uint8_t)144

#define LCD_V (uint8_t)168

 

void lcd_init(void);

void lcd_deinit(void);

void lcd_sync(void);

void lcd_fill(uint8_t val);

void lcd_set_pixel(uint8_t x, uint8_t y, uint8_t val);

uint8_t lcd_get_pixel(uint8_t x, uint8_t y);

 

#ifdef __cplusplus

    }

#endif

 

#endif

 

实现ls013_lcd.c

#include "ls013.h"

#include "ls013_lcd.h"

#include "pico/stdlib.h"

#include <string.h>

 

uint8_t lcd_buffer[LCD_V*LCD_H/8];

 

void ls013_port_init(void)

{

    gpio_init(2);

    gpio_set_dir(2, GPIO_OUT);

    gpio_put(2, 0);

 

    gpio_init(3);

    gpio_set_dir(3, GPIO_OUT);

    gpio_put(3, 0);

 

    gpio_init(4);

    gpio_set_dir(4, GPIO_OUT);

    gpio_put(4, 0);

}

 

void ls013_port_deinit(void)

{

 

}

 

void ls013_port_cs_set(uint8_t val)

{

    if(val == 0)

    {

        gpio_put(2, 0);

    }

    else

    {

        gpio_put(2, 1);

    }

}

 

void ls013_port_di_set(uint8_t val)

{

    if(val == 0)

    {

        gpio_put(3, 0);

    }

    else

    {

        gpio_put(3, 1);

    }

}

 

void ls013_port_clk_set(uint8_t val)

{

    if(val == 0)

    {

        gpio_put(4, 0);

    }

    else

    {

        gpio_put(4, 1);

    }

}

 

void ls013_port_delay(uint32_t ns)

{

    sleep_us((ns+999)/1000);

}

 

ls013_dev_st ls013_dev =

{

    .cs_set = ls013_port_cs_set,

    .di_set = ls013_port_di_set,

    .clk_set = ls013_port_clk_set,

    .delay = ls013_port_delay,

    .init = ls013_port_init,

    .deinit = ls013_port_deinit,

};

 

void lcd_init(void)

{

    memset(lcd_buffer,0,sizeof(lcd_buffer));

    ls013_init(&ls013_dev);

    ls013_clr(&ls013_dev);

}

 

void lcd_deinit(void)

{

    ls013_deinit(&ls013_dev);

}

 

void lcd_sync(void)

{

    ls013_dis(&ls013_dev, lcd_buffer, LCD_H, LCD_V);

}

 

void lcd_fill(uint8_t val)

{

    memset(lcd_buffer,val,sizeof(lcd_buffer));

    ls013_dis(&ls013_dev, lcd_buffer, LCD_H, LCD_V);

}

 

void lcd_set_pixel(uint8_t x, uint8_t y, uint8_t val)

{

    uint8_t byte;

    uint8_t offset;

    byte = x>>3;

    offset = x&0x07;

    if(val != 0)

    {

        lcd_buffer[y*(LCD_H/8)+byte] |= ((uint8_t)1<<offset);

    }

    else

    {

        lcd_buffer[y*(LCD_H/8)+byte] &= ~((uint8_t)1<<offset);

    }

}

 

uint8_t lcd_get_pixel(uint8_t x, uint8_t y)

{

    uint8_t byte;

    uint8_t offset;

    byte = x>>3;

    offset = x&0x07;

 

    return ((lcd_buffer[y*(LCD_H/8)+byte] & ((uint8_t)1<<offset)) == 0) ? 0 : 1;

 

}

 

测试代码如下,黑白刷屏

    lcd_init();

    while (true) {

        for(int i=0; i<LCD_H; i++)

        {

            for(int j=0; j<LCD_V; j++)

            {

                lcd_set_pixel(i,j,1);

            }

        }

        lcd_sync();

        //lcd_fill(0xFF);

        sleep_ms(1000);

        for(int i=0; i<LCD_H; i++)

        {

            for(int j=0; j<LCD_V; j++)

            {

                lcd_set_pixel(i,j,0);

            }

        }

        lcd_sync();

        //lcd_fill(0);

        sleep_ms(1000);

    }

 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表