本帖最后由 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*300的ELINK墨水屏,使用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(); //数据发送到显示屏
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设置
SSD1306的oled的GUIDRV_Lin设置也是一样的。 设置数据缓存128*64/8bit=1024。说明一下我使用两个I2C接口同时控制两块SSD1306的OLED所以数据缓存是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(); 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传输。你可以使用硬件的 I2C的DM传输减少cpu占用 }
SSD1306传输的显示缓存数据形式很特别。
所以需要把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设置 最后说一下: 使用stenwin必须要打开芯片上的crc外设。另外#define GUI_NUMBYTES 这个数字要足够,不然会出现某些层不工作的情况,而且不会有任何提示,让你搞不清问题在哪里。另外就是显示最大的层数好像只能是2层。我原来准备用多个层控制多个的显示屏。试了好久,发现大于2个层的内容他就不处理了,不知道是不是stemwin的库做了限制。 此外我发现很多人喜欢使用模拟的SPI和I2C接口,我实在想不明白是为什么。有硬件的SPI和I2C为什么不用呢?不但减少CPU处理量,还可以减少传输错误,加快传输速度,还能使用中断和DMA方式传输。I2C这种信号都是有超时时间的,模拟操作IO口中被其他处理任务打断了很容易造成I2C总线被锁死,需要重启。我看到过有人说STM32的I2C接口有问题,我用了这么久是从来没有发现过的。我在一个I2C总线上挂了3、4个设备都全速使用都没有问题。 本人水平有限,以上如有错误之处,敬请指出。 转载请注明出处http://smallcsduck.blog.163.com
源码工程地址: https://pan.baidu.com/s/1dkLXGWfkrAT6hComZVEibw oled6是ELINK的407vg工程。 oled7是12864oled的407vg工程。整个编译出得程序,flash用了50k,ram用了8k。
|