你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
smallcsduck 发布时间:2018-6-12 02:47
本帖最后由 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。




收藏 6 评论14 发布时间:2018-6-12 02:47

举报

14个回答
zhjb1 回答时间:2018-6-12 09:34:34
拜读了,非常感谢!我也可以试试,手头的LCD屏多了去了,谢谢!
wolfgang 回答时间:2018-6-12 10:05:45
GOOD!
Bowen 回答时间:2018-6-12 10:16:45
学习下。我也可以试试。多谢分享~
MrJiu 回答时间:2018-6-12 10:28:21
看着不错。。。但是有几个问题需要问清楚,最好也解答清楚。。。首先是ram和flash的占用情况,用到12864这类显示屏,肯定是ram和flash不会很多,芯片也不会很高档,其次,ST的I2C硬件不太好用,不过SPI倒是非常不错!!!
smallcsduck 回答时间: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总线上 工作很正常。
你可以看一下。
chrome777 回答时间:2018-6-13 09:15:00
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗
smallcsduck 回答时间:2018-6-13 13:31:59
morphlings2014 发表于 2018-6-13 09:15
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗 ...

就是电子纸 没电还能保持显示的
http://www.good-display.cn/
某宝上我就看到一家
smallcsduck 回答时间:2018-6-13 13:35:00
本帖最后由 smallcsduck 于 2018-6-13 13:36 编辑
morphlings2014 发表于 2018-6-13 09:15
卧槽。。。EVAL。。。壕无人性啊。
话说第一张图的LCD,可以分享在资料或者购买链接吗 ...

百度 good-display电子纸  就是没电了还能保持显示的
baitiandesinian 回答时间:2018-6-13 18:20:19

谢谢分享
chrome777 回答时间:2018-6-14 08:47:02
smallcsduck 发表于 2018-6-13 13:31
就是电子纸 没电还能保持显示的
http://www.good-display.cn/
某宝上我就看到一家 ...

好的,谢谢。
SimonLuk 回答时间:2018-6-26 22:12:58
哟,好,mark一下
SimonLuk 回答时间:2018-6-26 22:52:31
但是补充一下,用keil mdk自带的emWin,就有spage驱动了
sunonly 回答时间:2018-7-6 19:10:43
感谢分享!下来学习学习
steve_zhang 回答时间:2020-10-12 16:12:53
照着你的搞,没有显示任何东西。你的源码好像有个问题。
1 你OLED的写命令,写数据函数,都没有和EMWIN的 GUIDVR_Lin 驱动模块建立任何连接,不可能显示东西的,不知道你的结果是真的还是假的。

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版