请选择 进入手机版 | 继续访问电脑版
搜索
查看: 12879|回复: 14

[原创] 12864类显示屏使用STemwin库的方法(源码已上传)

[复制链接]

该用户从未签到

14

主题

50

帖子

29

蝴蝶豆

中级会员

最后登录
2018-8-25
发表于 2018-6-12 02:47:00 | 显示全部楼层 |阅读模式
本帖最后由 smallcsduck 于 2018-6-12 18:31 编辑

  这里说的12864类显示屏主要指单色的,内部有显示缓存的显示屏。显存数据组织方式是1位代表1个像素。显示芯片没有限制,分辨率没有限制,显示屏控制接口也没有限制。
     emwin里面不是有个GUIDRV_SPage驱动么?这个驱动可以支持这些显示屏。没错emwin是有了很多现成的驱动,不过那都是要钱的,1千多欧元一个。ST专用版emwin里面并没有这些个驱动。那怎么办呢? stemwin附带了GUIDRV_Lin这个驱动,其实这个驱动可以算是万能驱动,可以用来适配各种控制芯片。
   简单来说,GUIDRV_Lin,这个驱动所有的绘图结果都是放在指定的一块内存中,你只需要把这块内存数据传输到显示芯片的内置显示缓存中就可以把图像显示出来了。
    下面用两个屏幕做例子。一个是ssd1306显示芯片的oled屏幕,分辨率是128*64,使用I2c接口。一个是400*300ELINK墨水屏,使用spi接口,控制芯片是IL0398
     ELINK的墨水屏的GUIDRV_Lin设置 。内存需要400*300/8bit=15000.这个屏幕有两个显示缓存,一个输出黑色,一个输出红色。那在驱动里也需要设置2个数据块。
uint8_t elinkbuff1[15000]
uint8_t elinkbuff2[15000]
  设置驱动工作模式,颜色转换程序。
  GUI_DEVICE_CreateAndLink(GUIDRV_LIN_1,GUICC_1, 0, 0);
  GUI_DEVICE_CreateAndLink(GUIDRV_LIN_1,GUICC_1, 0, 1);
  设置显示分辨率,设置缓存地址。
LCD_SetSizeEx (0, 400, 300);
LCD_SetSizeEx (1, 400, 300);
LCD_SetVRAMAddrEx(0, (void *)elinkbuff1);
LCD_SetVRAMAddrEx(1, (void *)elinkbuff2);
  这样墨水屏的显示驱动就设置完了。剩下需要做的就是绘图程序结束以后,按照IL0398的要求传输序列把这两个数组写到显示芯片的数据缓存中。需要注意的是这个墨水屏背景色要设置成白色,前景色要设置成黑色。

    GUI_Init();
    GUI_UC_SetEncodeUTF8();
    GUI_SetLayerAlphaEx(1,0x00);
    GUI_SelectLayer(0);                                //黑色层
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    GUI_SetColor(GUI_BLACK);                        
    GUI_FillRect(7,0,100,80);
    GUI_FillCircle(180,100,60);
    GUI_SetFont(&GUI_Fontyahei60);
    GUI_DispStringAt("温度1234567890",0,200);
    GUI_SelectLayer(1);                                //红色层
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    GUI_SetColor(GUI_BLACK);
    GUI_FillRect(300,100,400,200);
    GUI_SetFont(&GUI_Fontyahei60);
    GUI_DispStringAt("测试ABCDEFG",0,250);
    ELINKDisplay();                                          //数据发送到显示屏
3309.jpg

void ELINKDisplay(void)
{
    uint8_t temp[4];
    ELINKCOM(0x06);
    temp[0]=0x17;
    temp[1]=0x17;
    temp[2]=0x17;
    ELINKDATA(temp,3);
    ELINKCOM(0x04);
    ELINKCK();
    ELINKCOM(0x00);
    temp[0]=0x0f;
    ELINKDATA(temp,1);
    ELINKCOM(0x10);
    ELINKDATA(elinkbuff1,15000);                //传输显示缓存
    ELINKCOM(0x13);
    ELINKDATA(elinkbuff2,15000);                //传输显示缓存
    ELINKCOM(0x12);
    HAL_Delay(100);
    ELINKCK();
    ELINKCOM(0x50);
    temp[0]=0xf7;
    ELINKDATA(temp,1);
    ELINKCOM(0x02);
    ELINKCK();
    ELINKCOM(0x07);
    temp[0]=0xA5;
    ELINKDATA(temp,1);   
}
void ELINKCOM(uint8_t INIT_COM)
{

    HAL_GPIO_WritePin(SPICD_GPIO_Port,SPICD_Pin,GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1,&INIT_COM,1,100);
//硬件的spi传输,可以使用DMA传输减少cpu占用

}


void ELINKDATA(uint8_t* INIT_DATA,int num)
{

    HAL_GPIO_WritePin(SPICD_GPIO_Port,SPICD_Pin,GPIO_PIN_SET);
    HAL_SPI_Transmit(&hspi1,INIT_DATA,num,100);
//硬件的spi传输,可以使用DMA传输减少cpu占用

}

   Spi接口的STM32CubeMX设置
s1.png
s2.png
s3.png
s4.png


     SSD1306oledGUIDRV_Lin设置也是一样的。
   设置数据缓存128*64/8bit=1024。说明一下我使用两个I2C接口同时控制两块SSD1306OLED所以数据缓存是uint8_t oledbuff[64][32];一个OLED屏幕的缓存是uint8_t oledbuff[64][16];
    设置驱动模式和颜色转换。
     GUI_DEVICE_CreateAndLink(GUIDRV_LIN_1,GUICC_1, 0, 0);
     设置显示分辨率,设置缓存地址。
LCD_SetSizeEx (0, 128, 64);
LCD_SetVRAMAddrEx(0, (void *)&oledbuff[0][0]);
  绘图结束后把数据传输给显示屏就可以显示了。x坐标小于128是显示在第一块oled上,x坐标大于128是显示在第二块屏幕上。        背景是黑色,前景色是白色。
GUI_Init();
           GUI_UC_SetEncodeUTF8();
GUI_SelectLayer(0);
      GUI_SetBkColor(GUI_BLACK);
      GUI_Clear();
      GUI_SetColor(GUI_WHITE);
      GUI_SetFont(&GUI_Fontyahei30);
      GUI_DispStringAt("温度:",0,0);
      GUI_GotoXY(0,32);
      GUI_DispFloatFix(sht31.temper,5,2);
      GUI_DispStringAt("湿度:",64,0);
      GUI_GotoXY(64,32);
      GUI_DispFloatFix(sht31.humidity,5,2);
      GUI_DispStringAt("12345678:",128,0);
      OLEDshow();
      OLED1show();
221.jpg
void OLEDshow(void)
{
    OLEDalgorit();
    uint8_t *temp;
    temp=(uint8_t*)&i2cbuff[0][0];
    uint8_t buff[1025];                //在栈里的临时数组,栈大小要设置大于1K
    buff[0]=0x40                        ;//0x40表示后面传输的都是数据
    memcpy((buff+1),temp,1024);

    HAL_I2C_Master_Transmit(&hi2c1,OLEDADD,buff,1025,100);
//硬件I2C传输。你可以使用硬件的        I2CDM传输减少cpu占用        
}   

    SSD1306传输的显示缓存数据形式很特别。
111.png

  所以需要把emwin产生的显示缓存数据转换一下。

void OLEDalgorit(void)
{
    memset((void*)&i2cbuff[0][0],0,1024);

    uint16_t temp;
    uint8_t t[64][16];                //需要栈大小在1k以上
    memset((void*)&t[0][0],0,1024);
    for(int a=0;a<64;a++)   
    {
        for(int b=0;b<16;b++)
        {
        temp=0;
        temp=oledbuff[a];
        temp=temp<<8;
            for(int i=0;i<8;i++)
            {
                temp|=(temp&(0x100<<i))>>(2*i+1);
            }
            t[a]=temp;         
        }
    }
    for(int n=0;n<128;n++)
    {
        for(int i=0;i<8;i++)
        {
            for(int m=0;m<8;m++)
            {
               i2cbuff[n]|=(((t[i*8+m][n/8])&(1<<(n%8)))>>(n%8))<<m;

       }   
        }
     }

}

I2C接口的STM32CubeMX设置
i1.png
i2.png
     最后说一下:
  使用stenwin必须要打开芯片上的crc外设。另外#define GUI_NUMBYTES 这个数字要足够,不然会出现某些层不工作的情况,而且不会有任何提示,让你搞不清问题在哪里。另外就是显示最大的层数好像只能是2层。我原来准备用多个层控制多个的显示屏。试了好久,发现大于2个层的内容他就不处理了,不知道是不是stemwin的库做了限制。
  此外我发现很多人喜欢使用模拟的SPII2C接口,我实在想不明白是为什么。有硬件的SPII2C为什么不用呢?不但减少CPU处理量,还可以减少传输错误,加快传输速度,还能使用中断和DMA方式传输。I2C这种信号都是有超时时间的,模拟操作IO口中被其他处理任务打断了很容易造成I2C总线被锁死,需要重启。我看到过有人说STM32I2C接口有问题,我用了这么久是从来没有发现过的。我在一个I2C总线上挂了34个设备都全速使用都没有问题。

   本人水平有限,以上如有错误之处,敬请指出。

   转载请注明出处http://smallcsduck.blog.163.com


源码工程地址:

https://pan.baidu.com/s/1dkLXGWfkrAT6hComZVEibw

oled6是ELINK的407vg工程。

oled7是12864oled的407vg工程。整个编译出得程序,flash用了50k,ram用了8k。




回复

使用道具 举报

该用户从未签到

82

主题

718

帖子

121

蝴蝶豆

版主

最后登录
2021-1-2
发表于 2018-6-12 09:34:34 | 显示全部楼层
拜读了,非常感谢!我也可以试试,手头的LCD屏多了去了,谢谢!
回复 支持 反对

使用道具 举报

该用户从未签到

74

主题

1442

帖子

194

蝴蝶豆

版主

最后登录
2023-10-26
发表于 2018-6-12 10:05:45 | 显示全部楼层
GOOD!
回复

使用道具 举报

该用户从未签到

7

主题

1437

帖子

42

蝴蝶豆

论坛元老

最后登录
2023-6-20
发表于 2018-6-12 10:16:45 | 显示全部楼层
学习下。我也可以试试。多谢分享~
回复 支持 反对

使用道具 举报

该用户从未签到

3

主题

1002

帖子

363

蝴蝶豆

版主

最后登录
2021-4-15
发表于 2018-6-12 10:28:21 | 显示全部楼层
看着不错。。。但是有几个问题需要问清楚,最好也解答清楚。。。首先是ram和flash的占用情况,用到12864这类显示屏,肯定是ram和flash不会很多,芯片也不会很高档,其次,ST的I2C硬件不太好用,不过SPI倒是非常不错!!!
回复 支持 反对

使用道具 举报

该用户从未签到

14

主题

50

帖子

29

蝴蝶豆

中级会员

最后登录
2018-8-25
 楼主| 发表于 2018-6-12 18:37:01 | 显示全部楼层
MrJiu 发表于 2018-6-12 10:28
看着不错。。。但是有几个问题需要问清楚,最好也解答清楚。。。首先是ram和flash的占用情况,用到12864这 ...

我看了一下。
12864oled两个屏幕一起,ram用了8k,flash用了50k 。
103c8都应该是可以用的。
flash主要是看中文字库有多少字。
你哪个I2C的设备用硬件I2C有问题呢?我可以帮你看看。
我的工程里面sht31和oled屏幕都挂在一个硬件i2c总线上 工作很正常。
你可以看一下。
回复 支持 反对

使用道具 举报

该用户从未签到

2

主题

747

帖子

98

蝴蝶豆

论坛元老

最后登录
2021-4-1
发表于 2018-6-13 09:15:00 | 显示全部楼层
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗
回复 支持 反对

使用道具 举报

该用户从未签到

14

主题

50

帖子

29

蝴蝶豆

中级会员

最后登录
2018-8-25
 楼主| 发表于 2018-6-13 13:31:59 | 显示全部楼层
morphlings2014 发表于 2018-6-13 09:15
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗 ...

就是电子纸 没电还能保持显示的
http://www.good-display.cn/
某宝上我就看到一家
回复 支持 反对

使用道具 举报

该用户从未签到

14

主题

50

帖子

29

蝴蝶豆

中级会员

最后登录
2018-8-25
 楼主| 发表于 2018-6-13 13:35:00 | 显示全部楼层
本帖最后由 smallcsduck 于 2018-6-13 13:36 编辑
morphlings2014 发表于 2018-6-13 09:15
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗 ...

百度 good-display电子纸  就是没电了还能保持显示的
回复 支持 反对

使用道具 举报

该用户从未签到

0

主题

11

帖子

0

蝴蝶豆

新手上路

最后登录
2020-11-6
发表于 2018-6-13 18:20:19 | 显示全部楼层

谢谢分享
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-3-29 15:58 , Processed in 1.224204 second(s), 46 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表