打印
[PIC®/AVR®/dsPIC®产品]

【CuriosityNano测评报告】+墨水屏的显示驱动

[复制链接]
10687|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#
AVR64DD32 CuriosityNano是一款小巧的开发板,为这款开发板配上一款1.54寸的墨水屏是一个不错的选择。
目前以PIC的产品对墨水屏的支持并不多,为此决定将它移植到AVR64DD32开发板。
比较有意思的是,与常规的显示器件不同,墨水屏在写入显示内容后,在移除电源后会保持显示的内容,这也是为什么墨水屏被用于做电子标签的主要原因。可谓是省电没商量,一旦拥有恒久流传。

图1 显示效果
该墨水屏共有8个引脚,它与开发板的连接关系如下:
SCL---PD7
SDA---PD6
RST---PD3
DC ---PD2
CS ---PD1
BUSY ---PF4
在这8个引脚中,除BUSY引脚外均以输出模式使用,而BUSY则是以输入模式使用,故相关的语句定义为:
#define EPD_CLK_init() do { PORTD.OUTSET = PIN7_bm; PORTD.DIRSET = PIN7_bm; } while (0)
#define EPD_MOSI_init() do { PORTD.OUTSET = PIN6_bm; PORTD.DIRSET = PIN6_bm; } while (0)
#define EPD_RST_init() do { PORTD.OUTSET = PIN3_bm; PORTD.DIRSET = PIN3_bm; } while (0)
#define EPD_DC_init() do { PORTD.OUTSET = PIN2_bm; PORTD.DIRSET = PIN2_bm; } while (0)
#define EPD_CS_init() do { PORTD.OUTSET = PIN1_bm; PORTD.DIRSET = PIN1_bm; } while (0)

#define GetValue() (VPORTF.IN & (0x1 << 4))
#define SetPullUp() do { PORTF_PIN4CTRL  |= PORT_PULLUPEN_bm; } while(0)
#define SetDigitalInput() do { PORTF_DIRCLR = 0x10; } while(0)


由于该显示屏的分辨率为200*200像素点,故其几何的参数定义为:
#define EPD_1IN54_WIDTH        200
#define EPD_1IN54_HEIGHT    200
相关引脚输出高低电平的语句定义为:
#define EPD_CLK_0   do { PORTD.OUTCLR = PIN7_bm; } while (0)    //CLK
#define EPD_CLK_1   do { PORTD.OUTSET = PIN7_bm; } while (0)
#define EPD_MOSI_0   do { PORTD.OUTCLR = PIN6_bm; } while (0)   //DIN
#define EPD_MOSI_1   do { PORTD.OUTSET = PIN6_bm; } while (0)

#define EPD_RST_0   do { PORTD.OUTCLR = PIN3_bm; } while (0)    //RST
#define EPD_RST_1   do { PORTD.OUTSET = PIN3_bm; } while (0)
#define EPD_DC_0    do { PORTD.OUTCLR = PIN2_bm; } while (0)    //DC
#define EPD_DC_1    do { PORTD.OUTSET = PIN2_bm; } while (0)

#define EPD_CS_0    do { PORTD.OUTCLR = PIN1_bm; } while (0)    //C S
#define EPD_CS_1    do { PORTD.OUTSET = PIN1_bm; } while (0)
显示屏的复位函数为:
void EPD_1IN54_Reset(void)
{
    EPD_RST_1;
    DEV_Delay_ms(200);
    EPD_RST_0;
    DEV_Delay_ms(20);
    EPD_RST_1;
    DEV_Delay_ms(200);
}
判别显示屏是否处于忙的状态的函数为:
void EPD_1IN54_ReadBusy(void)
{
    while(GetValue()==1) {
       DEV_Delay_ms(100);
    }
}
进入和退出墨水屏工作模式的函数为:
int DEV_Module_Init(void)
{
    EPD_DC_0;
    EPD_CS_0;
    EPD_RST_1;
    return 0;
}

void DEV_Module_Exit(void)
{
    EPD_DC_0;
    EPD_CS_0;
    EPD_RST_0;
}
以GPIO口模拟SPI发送发送字节数据的函数为:
void DEV_SPI_WriteByte(unsigned char value)
{
    u8 i;
    for(i=0; i<8;i++)
    {
        EPD_CLK_0;
        if(value & 0x80)
        EPD_MOSI_1;
        else
        EPD_MOSI_0;
        EPD_CLK_1;
        value = (value << 1);
    }
    EPD_CLK_0;
}
向墨水屏发送指令和数据的函数为:
void EPD_1IN54_SendCommand(u8 Reg)
{
    EPD_DC_0;
    EPD_CS_0;
    DEV_SPI_WriteByte(Reg);
    EPD_CS_1;
    delay_us(4);
}

void EPD_1IN54_SendData(u8 Data)
{
    EPD_DC_1;
    EPD_CS_0;
    DEV_SPI_WriteByte(Data);
    EPD_CS_1;
    delay_us(4);
}
墨水屏的初始化函数为:
void EPD_1IN54_Init(u8 Mode)
{
    u16 i;
    EPD_1IN54_Reset();
    EPD_1IN54_SendCommand(0x01);
    EPD_1IN54_SendData((EPD_1IN54_HEIGHT - 1) & 0xFF);
    EPD_1IN54_SendData(((EPD_1IN54_HEIGHT - 1) >> 8) & 0xFF);
    EPD_1IN54_SendData(0x00);
    EPD_1IN54_SendCommand(0x0C);
    EPD_1IN54_SendData(0xD7);
    EPD_1IN54_SendData(0xD6);
    EPD_1IN54_SendData(0x9D);
    EPD_1IN54_SendCommand(0x2C);
    EPD_1IN54_SendData(0xA8);
    EPD_1IN54_SendCommand(0x3A);
    EPD_1IN54_SendData(0x1A);
    EPD_1IN54_SendCommand(0x3B);
    EPD_1IN54_SendData(0x08);
    EPD_1IN54_SendCommand(0x11);
    EPD_1IN54_SendData(0x03);
    EPD_1IN54_SendCommand(0x32);
    if(Mode == EPD_1IN54_FULL){
        for ( i = 0; i < 30; i++) {
           EPD_1IN54_SendData(EPD_1IN54_lut_full_update[i]);
        }
    }else if(Mode == EPD_1IN54_PART){
        for ( i = 0; i < 30; i++) {
           EPD_1IN54_SendData(EPD_1IN54_lut_partial_update[i]);
        }
    }else{
   
    }
}
开启墨水屏显示的函数为:
void EPD_1IN54_TurnOnDisplay(void)
{
    EPD_1IN54_SendCommand(0x22);
    EPD_1IN54_SendData(0xC4);
    EPD_1IN54_SendCommand(0x20);
    EPD_1IN54_SendCommand(0xFF);
    EPD_1IN54_ReadBusy();
}
至此,前面的努力是否会奏效呢?
方法就是先去验证一下,如果无效,恐怕前面的工作就算交学费。
怎么验证呢?
用清屏函数,通常情况下清屏函数是为清除屏幕内容服务的,这里是反其道而行之,就是让它在屏上留下一些痕迹来判别驱动程序是是否有效。

为此,需将清屏函数改造为一个绘制直线的函数,其内容如下:
void EPD_1IN54_Clear(void)
{
    u16 Width, Height,i,j;
    Width = (EPD_1IN54_WIDTH%8== 0)? (EPD_1IN54_WIDTH/8):(EPD_1IN54_WIDTH/8+1);
    Height = EPD_1IN54_HEIGHT;
    EPD_1IN54_SetWindow(0, 0, EPD_1IN54_WIDTH, EPD_1IN54_HEIGHT);
    for (j = 0; j < Height; j++) {
        EPD_1IN54_SetCursor(0, j);
        EPD_1IN54_SendCommand(0x24);
        for (i = 0; i < Width; i++) {
            EPD_1IN54_SendData(0XFE);
        }
    }
    EPD_1IN54_TurnOnDisplay();
}
经程序的编译与下载,其运行效果如图2所示。这说明驱动是有效的,前期的工作没白费!
图2 绘制直线
有了清屏函数的基础,只需将固定的清屏数据改为图像数据就可以显示图片了。此外,在显示图像时还需选取绘图模式,其函数为:
void Paint_SelectImage(u8 *image)
{
    Paint.Image = image;
}
进行图像绘制的函数为:
void Paint_DrawBitMap(const unsigned char* image_buffer)
{
    unsigned short  int x, y;
    u32 Addr = 0;
    for (y = 0; y < Paint.HeightByte; y++) {
        for (x = 0; x < Paint.WidthByte; x++) {
            Addr = x + y * Paint.WidthByte;
            Paint.Image[Addr] = (unsigned char)image_buffer[Addr];
        }
    }
}
在配以主程序的情况下,即可进行显示图片的测试,其主程序的内容为:
u8 BlackImage[5000];
int main(void) {
    EPD_CLK_init();
    EPD_MOSI_init();
    EPD_RST_init();
    EPD_DC_init();
    EPD_CS_init();
    SetDigitalInput();
    SetPullUp();
    DEV_Module_Init();
    EPD_1IN54_Init(EPD_1IN54_FULL);
    //EPD_1IN54_Clear();
    Paint_NewImage(BlackImage, EPD_1IN54_WIDTH, EPD_1IN54_HEIGHT, 270, WHITE);
    Paint_SelectImage(BlackImage);
    Paint_DrawBitMap(gImage_1in54);
    EPD_1IN54_Display(BlackImage);
    DEV_Delay_ms(2000);
    EPD_1IN54_Sleep();
    DEV_Delay_ms(2000);
    while(1);
}
经编译下载,其测试效果就是图1的显示内容,证明绘图函数也成功了!

在添加图形绘制函数的情况下,可绘制点、直线、矩形及圆等并可以进行填充处理。此外,在配置字库的条件下,可实现字符和中文的显示,其实现的效果如图3和图4所示。
图3 绘制图形
图4 显示字符及数值

实现显示效果的主程序为:
int main(void) {
    EPD_CLK_init();
    EPD_MOSI_init();
    EPD_RST_init();
    EPD_DC_init();
    EPD_CS_init();
    SetDigitalInput();
    SetPullUp();
    DEV_Module_Init();
    EPD_1IN54_Init(EPD_1IN54_FULL);
    Paint_NewImage(BlackImage, EPD_1IN54_WIDTH, EPD_1IN54_HEIGHT, 270, WHITE);
    Paint_SelectImage(BlackImage);
    Paint_DrawBitMap(gImage_1in54);
    Paint_Clear(WHITE);
    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, WHITE, 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);
   
    EPD_1IN54_Display(BlackImage);
    DEV_Delay_ms(2000);
    EPD_1IN54_Sleep();
    DEV_Delay_ms(2000);
    while(1);
}

这样在PIC的产品上,墨水屏也可以焕发出光彩了!

使用特权

评论回复
评论
jinglixixi 2022-12-19 23:43 回复TA
@lulugl :没尝试在线刷线 
lulugl 2022-12-19 11:34 回复TA
可以在线刷新吗,我原来用mps430就是刷新很慢。 
沙发
南来之风| | 2022-11-10 14:27 | 只看该作者
IO模拟SPI?

使用特权

评论回复
板凳
jinglixixi|  楼主 | 2022-11-10 16:34 | 只看该作者

是的,没错。

使用特权

评论回复
地板
xu@xupt| | 2022-12-8 23:37 | 只看该作者
厉害啦

使用特权

评论回复
5
jinglixixi|  楼主 | 2022-12-9 00:14 | 只看该作者

岂敢岂敢

使用特权

评论回复
6
feiyinglala| | 2022-12-18 15:10 | 只看该作者
楼主,目前的刷新频率怎么样?

使用特权

评论回复
7
jinglixixi|  楼主 | 2022-12-18 23:13 | 只看该作者
feiyinglala 发表于 2022-12-18 15:10
楼主,目前的刷新频率怎么样?

没具体测,一眨眼的功夫。

使用特权

评论回复
8
lzbf| | 2022-12-22 19:11 | 只看该作者
墨水瓶的刷新速度是不是有限?              

使用特权

评论回复
9
bestwell| | 2022-12-22 19:20 | 只看该作者
这个不错,怎么才能实现远程更新呢?

使用特权

评论回复
10
jinglixixi|  楼主 | 2022-12-23 00:07 | 只看该作者
bestwell 发表于 2022-12-22 19:20
这个不错,怎么才能实现远程更新呢?

那只能和有WiFi功能或以太网传输功能的开发板相配合来实现了,或是采用串口与WiFi通讯。

使用特权

评论回复
11
vivilyly| | 2022-12-24 20:20 | 只看该作者
墨水屏价格贵吗              

使用特权

评论回复
12
jinglixixi|  楼主 | 2022-12-25 10:22 | 只看该作者

小贵于OLED屏

使用特权

评论回复
13
小明的同学| | 2024-7-27 17:51 | 只看该作者
SPI的IO模拟时许。

使用特权

评论回复
14
幸福小强| | 2024-7-27 21:00 | 只看该作者
IO模拟各种串行时序很在行。

使用特权

评论回复
15
xuanhuanzi| | 2024-7-29 21:58 | 只看该作者
SPI接口。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

455

主题

2756

帖子

38

粉丝