墨水屏卡片 ePaper_card

简介:一个小巧的墨水屏卡片,向虚拟U盘存储bmp图,通过按键即可实现墨水屏显示墨水屏。

开源协议: Public Domain

发布时间:2021-09-01 15:37:31
  • 1.7k
  • 12
  • 26
描述

众所周知,墨水屏卡片是最近非常火的一个词。那么墨水屏卡片到底是什么梗呢?相信大家对墨水屏卡片都很熟悉,墨水屏卡片就是我们每天都会经常遇到的,但是墨水屏卡片是怎么回事呢?下面就让小编带大家一起了解一下墨水屏卡片是怎么回事吧。 其实之前并没有太多人知道墨水屏卡片,但是最近由于热度的上升,墨水屏卡片受到了大家的关注。大家可能会感到很惊讶,墨水屏卡片为什么是这样的?墨水屏卡片究竟为什么火起来了呢?但事实就是这样,小编也感到非常惊讶。 希望小编精心整理的这篇内容能够帮助到你,本期教学结束了,如果大家喜欢,可以点赞表示对小编的支持。欢迎在下方评论和小编一起讨论喔~


咳咳,,,

演示视频:https://www.bilibili.com/video/BV1MT4y1f7yF

为什么有这个项目

屏幕截图 2021-09-29 142238.png很久之前就很留意野生钢铁侠的这个NFC名片项目了(视频链接),可惜一直没有足够的知识储备已经原材料,项目一直停留在新建文件夹这一步(说白了就是懒~)

然后,几天前在老王家买来了一些还不错的墨水屏,成色如图,感觉还可以,买了6片亮了3片,投资成功率五五开:

image.png

驱动板在开源平台找的,作为学习平台。

异同

原本打算是实现稚晖君的NFC卡片的100%功能的:模拟门禁卡,NFC上传数据等。可惜NFC传输数据实在找不到好的学习资料(有相关资料的大佬欢迎在评论区留言,共同学习,感谢!),NFC功能是实现不了了,这可咋整,怎么上传图片数据?

几番思考后,决定还是做一款不同于稚晖君的墨水屏卡片,放弃NFC方案,使用单片机虚拟U盘,将要显示的图片放入U盘内(FLASH),单片机读取bmp图像数据并显示在墨水屏上。

电路板设计

确定了需求,那么电路图也是胸有成竹了。

单片机

驱动墨水屏和FLASH都需要SPI,我这里用了两路SPI,为了防止数据传输有干扰,后面发现其实可以在编程上稍加注意,两路数据传输不会干扰,所以大家也可以只使用一路SPI,用两个CS脚分别控制就行,不再赘述:

image.png

墨水屏

墨水屏驱动电路参考这个链接,感谢大佬!

image.png

这个方案还是比较成熟的。

电源

不同于稚晖君的纽扣电池,我这里选择了锂电池供电方案,搭配IP2312充电芯片,效果还是非常的棒。给U盘传输数据同时还可以给电池充电:

image.png

FLASH

不赘述,可以参考我上一个开源工程:功率计power-X

其他

其他LED,按键什么的不赘述。

焊接 组装

用solidworks设计了一个外壳,还是非常的nice,三围尺寸比稚晖君的要小:

image.png

电路板图:

image.pngimage.png组装好后:

image.png

程序编写

烧录文件和最关键的bmp读取文件我放在附件,有需自取,欢迎纠错、指正!

下面稍微讲解一哈:

首先我们要了解bmp的格式,最关键就是:8位图用1个bytes存储一个像素,表示灰度值;24位图用3个bytes存储一个像素,按照BGR顺序存储。

下面两个函数首先读取bmp图,包括验证图片属性,读取图片位深,图片长宽等:

uint8_t ImgReadHeader(BITMAPFILEHEADER*Header, FIL* fp)
void ImgReadInfo(BMP_INFOHEADER* INFO, FIL* fp)

稚晖君选择的是黑白双色墨水屏,我这里稍加改进,改为了黑白红三色墨水屏,缺点是不能局部刷新(快),只能全局刷新(很慢),但考虑到这个屏幕尺寸很小,一天也就刷新几次,刷新慢可以接受。

那么问题来了,如何将一张图片显示在3色屏上呢,由于墨水屏每一个"微胶囊"(显示的每一个小像素点)只能显示一种颜色:要么黑要么红要么白,所以我们有必要将一种图片分为两种颜色,,,这个我研究了老半天,尝试了很多方案:

Q:bmp不是储存BGR三种颜色的值嘛,红色的R值肯定比较大,比如说定R>200为红色不就好了吗?

A :确实,bmp储存是rgb,但是墨水屏显示不是rgb,准确来说是CMYK,类似于打印机,具体可以看这篇博文,如果之前没有了解过可能有点绕,仔细想想就明白了。所以,纯红和纯白的R值都是255,照你这么判断,他们都是“红色“了,存在bug。

Q:害,我举个例子嘛,改进一下,比如说 R>200 && G<50 && B<50 (这里看不懂可以仔细想一想),不就好了吗!

A:某些图片显示确实可以,但是遇到一些比较复杂的图片就不堪入目了,这样的阈值无法解决红到白的渐变图,明显可以看到分割线两边不均匀。

Q:。。。

几番尝试,效果依然不理想,主要是RGB颜色空间里对红色的约束不清晰,最终我决定使用HSV颜色空间来解决这个问题(因为HSV对红色有着比较清晰的区分),使用到RGB转HSV函数:

void RGB2HSV(uint8_t R, uint8_t G, uint8_t B,float * H, float * S, float * V)
{
    float max, min, delta=0;
    float r = R/255.0;
    float g = G/255.0;
    float b = B/255.0;

    max = max3(r, g, b);
    min = min3(r, g, b);
    delta = (max - min);

    if (fabs(delta)&lt;1e-3) {
        *H = 0;
    } else {
        if (fabs(r-max)&lt;1e-3) {
            *H = ((g-b)/delta)*60;
        } else if (fabs(g-max)&lt;1e-3) {
            *H = 120+(((b-r)/delta)*60);
        } else if (fabs(b-max)&lt;1e-3) {
            *H = 240 + (((r-g)/delta)*60);
        }
        if (*H &lt; 0)
            *H += 360;
    }

    if (fabs(max)&lt;1e-3)
        *S = 0;
    else
        *S = (float)(delta/max);
    *V = max;
}

判断函数:

if( ((H>=0&amp;&amp;H&lt;=10)||(H>=156&amp;&amp;H&lt;=180)) &amp;&amp; S>=43 &amp;&amp; S&lt;=255 &amp;&amp; V>=46 &amp;&amp; V&lt;=255 )

因为我这一款墨水屏没有灰阶,所以我决定使用稚晖君同款抖动函数,opencv源代码图片:

image.png

感谢我的队友把它移植到了一下:

uint8_t saturated_add(uint8_t val1, int8_t val2)
{
    int16_t val1_int = val1;
    int16_t val2_int = val2;
    int16_t tmp = val1_int + val2_int;

    if (tmp > 255)
    {
        return 255;
    }
    else if (tmp &lt; 0)
    {
        return 0;
    }
    else
    {
        return tmp;
    }
}

void dither(BMP_8 bmp8[][IMG_WIDTH])
{
    int err;
    int8_t a, b, c, d;
    for (int i = 0; i &lt; IMG_HEIGHT; i++)
    {
        for (int j = 0; j &lt; IMG_WIDTH; j++)
        {
            if (bmp8[i][j].gray_val > 127)
            {
                err = bmp8[i][j].gray_val - 255;
                bmp8[i][j].gray_val = 255;
            }
            else
            {
                err = bmp8[i][j].gray_val - 0;
                bmp8[i][j].gray_val = 0;
            }

            a = (err * 7) / 16;
            b = (err * 1) / 16;
            c = (err * 5) / 16;
            d = (err * 3) / 16;

            if ((i != (IMG_HEIGHT - 1)) &amp;&amp; (j != 0) &amp;&amp; (j != (IMG_WIDTH - 1)))
            {
                bmp8[i+0][j+1].gray_val = saturated_add(bmp8[i+0][j+1].gray_val , a);
                bmp8[i+1][j+1].gray_val  = saturated_add(bmp8[i+1][j+1].gray_val, b);
                bmp8[i+1][j+0].gray_val = saturated_add(bmp8[i+1][j+0].gray_val , c);
                bmp8[i+1][j-1].gray_val  = saturated_add( bmp8[i+1][j-1].gray_val, d);
            }
        }
    }
}

还有取模函数,相当于我们使用的取模软件:

image.png

void img2LCD(BMP_8 img_bmp8[IMG_HEIGHT][IMG_WIDTH],unsigned char gImage[]){
    uint16_t num=0;
    uint8_t data[8];
    uint8_t out;
    for (int i = 0; i &lt; IMG_HEIGHT; i++) {
        for (int j = 0; j &lt; IMG_WIDTH; ) {
            for(int k=0;k&lt;8;k++){
                if(img_bmp8[i][j].gray_val>128)
                    data[k]=1;
                else
                    data[k]=0;
                j++;
            }
            for(int k=0;k&lt;8;k++)
                out=out&lt;&lt;1|data[k];
            gImage[num]=out;
            num++;
            out=0;
        }
    }
}

这么一来,我们就仅仅需要把图片放入虚拟U盘内,让单片机自动读取,抖动,取模,非常nice,不用关心其他。

然后是移植FATFS,这个不赘述,也可以参考我上一个开源工程:功率计power-X

这么一来,整个流程就很清晰了:

image.png


至此,项目完结~

整个项目和稚晖君的有不少不同,但是灵感来自于他,感谢大佬。然后放弃NFC使用FASH储存也有好处:实现简单,并且可以同时储存多张图片,一个4Mb的flash就可以储存上百张152*152的bmp图。

最后,还是希望有NFC的好的资料的同学可以在评论区交流,共同学习,感谢观看!



ZERO. 2021.9.29

设计图
ID Name Designator Footprint Quantity
1 1uF C1,C4,C5,C6,C7,C10,C11,C13,C14 C0603 9
2 4.7uF C2,C16 C0603 2
3 100nF C3 C0603 1
4 15pF C8,C9 C0603 2
5 100nF C12,C15,C28,C29,C30 C0603 5
6 1u C17,C18 C0603 2
7 10uF C20,C21,C23 C0805 3
8 10uF C22 C0603 1
9 22uF C24,C25,C26 C0805 3
10 MBR0530 D4,D5,D6 SOD-123 3
11 IP2312 IP2312 SOP-8_L4.9-W3.9-P1.27-LS6.0-BL-EP 1
12 HDR-M-2.54_1x4 J1 HDR-M-2.54_1X4 1
13 HDR-M-2.54_1x2 J2,J3 HDR-M-2.54_1X2 2
14 1uH L1 IND-SMD_L4.4-W4.2 1
15 68uH L2 IND-SMD_L3.5-W3.0 1
16 E6C1204QBAC1UDA LED1,LED2,LED3,LED4 LED-SMD_L3.2-W1.0-R-RD 4
17 FPC-0.5MM-LSSJ-H2.0-24P P3 FPC-0.5MM-LSSJ-H2.0-24P 1
18 MOSFET-N+SI1304BDL Q1 SOT-323 1
19 10K R1,R8,R13 R0603 3
20 0.47 R2 R0603 1
21 1K R3,R4 R0603 2
22 5.1k R5,R6 R0603 2
23 22 R14,R15 R0603 2
24 1K RD1,RD2,RTST1 R0603 3
25 2 RIN1 R0603 1
26 CR0603F51K0P05Z RNTC1 R0603 1
27 0.5 ROUT1 R0603 1
28 TM-2023 SW1 SW-SMD_TM-2023-1 1
29 SK-3296S-01-L3 SW2 SW-SMD_SK-3296S-01-L3 1
30 STM32F401CCU6 U1 UFQFPN-48_L7.0-W7.0-P0.50-BL-EP 1
31 RT9013-33GB U3 SOT-23-5_L3.0-W1.7-P0.95-LS2.8-BR 1
32 W25Q32JVSSIQ U4 SOIC-8_L5.3-W5.3-P1.27-LS8.0-BL 1
33 TYPE-C-31-M-14 USBC1 USB-C-SMD_12P-P0.50-H-F_TYPE-C-31-M-14 1
34 25MHz X2 OSC-SMD_4P-L3.2-W2.5-BL 1

展开

工程成员

服务时间

周一至周五 9:00~18:00
  • 153 6159 2675

服务时间

周一至周五 9:00~18:00
  • 立创EDA微信号

    easyeda

  • QQ交流群

    664186054

  • 开源平台公众号

    oshwhub