正点原子的开发板是相对电子爱好者学习STM32的理想工具,因为它学习资料非常细致和完整,从教程、视频、例程到开发工具等一应俱全。
自己就有一块STM32探索者V3的开发板,由于没有随机配备显示屏,便打算利用手头的显示屏来实现显示功能。
1.显示驱动
与常规显示屏不同的是,该开发板所采用的显示屏是一款MCU屏,属16位8080并口驱动,其接口电路如图1所示。
图1 显示屏接口
而现在所用的显示屏多是SPI接口的,因此与该显示接口无法匹配。
那该如何来解决呢?
方法不外乎两个,一个最简单的方法是直接买一个与其完全配备的显示屏,另一个就是就地取材利用已有显示屏来解决。
对于从事技术工作的人来说当然是迎难而上,去锻炼技术的提高和成长。
经查找,有一块MDM-2802显示模块恰与该显示接口能兼容,其接口如图2所示。
该显示屏为2.2寸显示屏,其驱动IC为ILI9341,以SPI方式进行驱动。
图2 MDM-2802接口
为此,对显示驱动需要进行全新地改写。
MDM-2802显示模块与开发板的连接关系为:
CS ----PG12
RS ----PF12 (GND)
WR ----PD5
RD ----PD4 (GND)
RST ----RST
SDA ----PF11
BKL ----PB15
为了以GPIO口模拟SPI,对高低电平输出的语句定义为:
#define CLR_CLK() HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_RESET)
#define SET_CLK() HAL_GPIO_WritePin(GPIOD,GPIO_PIN_5,GPIO_PIN_SET) //CLK
#define CLR_SDA() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_11,GPIO_PIN_RESET)
#define SET_SDA() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_11,GPIO_PIN_SET) //DIN
#define CLR_CS() HAL_GPIO_WritePin(GPIOG,GPIO_PIN_12,GPIO_PIN_RESET)
#define SET_CS() HAL_GPIO_WritePin(GPIOG,GPIO_PIN_12,GPIO_PIN_SET) //CS
#define CLR_BKL() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET)
#define SET_BKL() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET) //BKL
#define CLR_RS() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_12,GPIO_PIN_RESET)
#define SET_RS() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_12,GPIO_PIN_SET) //RS
#define CLR_RD() HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_RESET)
#define SET_RD() HAL_GPIO_WritePin(GPIOD,GPIO_PIN_4,GPIO_PIN_SET) //RD
对所用引脚的配置函数为:
void LCD_Init(void)
{
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_1;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_15;
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_5| GPIO_PIN_12;
HAL_GPIO_Init(GPIOD, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_11| GPIO_PIN_12;
HAL_GPIO_Init(GPIOF, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_12;
HAL_GPIO_Init(GPIOG, &gpio_init_struct);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
}
模拟SPI方式实现字节数据发送的函数为:
void send_byte(uint8_t data)
{
uint8_t count;
for(count = 0; count < 8; count++)
{
CLR_CLK();
if(data & 0x80)
{
SET_SDA();
}
else
{
CLR_SDA();
}
data <<= 1;
SET_CLK();
}
}
为了以最小的成本来检测驱动效果,可通过清屏函数来进行。
以色彩清除屏幕的函数为:
void ili9341_clear(int c)
{
uint32_t index=0;
set_cursor(0x00, 0x0000);
gram_prepare();
for(index = 0; index < (320*240); index++)
{
write_data(c >> 8);
write_data(c);
}
}
经测试,其驱动程序有效可以对原设计功能加以逐步地替换和改造。
2.界面功能的恢复
在实现数码相框功能前,首要地任务是恢复原界面的提示功能以便了解运行的状态和操作方法。
为简化替换的工作量,可暂时构建一个字符库来实现信息提示的作用。
其实现字符串显示的函数为:
void LCD_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/lcd_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
GUI_DispChar(' ', x+8*t, y);
continue;
}
else enshow=1;
}
GUI_DispChar(temp+'0', x+8*t, y);
}
}
至此,就具备了恢复原界面提示功能的基础,其测试效果如图3所示。
图3 测试效果
为了便于后续的处理,应将新的驱动程序以tft.c和tft.h的文件形式保存并放入原LCD驱动程序所在的目录。
在文件tft.h中所包含的函数有:
此外,要将原来的显示函数及相关调用进行屏蔽和更换。
3. 检测TF卡读取功能
对于数码相框来讲,其显示图片的存地是TF卡。为测试对TF卡的读取能力,在恢复其图像显示功能前,可通过显示图片文件名来进行验证,其语句为:
piclib_ai_load_picfile(pname, 0, 0, 240,320, 1); /* 获取图片文件名 */
LCD_ShowString(20,12,(char *)pname); /*显示图片文件名 */
经测试,其显示效果如图4所示,说明TF卡读写功能有效。
图4 显示文件名
4.图片类型及显示
探索者V3开发板所支持的图片类型有: BMP、GIF及JPG
是通过文件的后缀来调用不同的解码处理,其判别结构如下:
caseT_BMP:
res = stdbmp_decode(filename);
break;
caseT_JPG:
caseT_JPEG:
res = jpg_decode(filename, fast);
break;
caseT_GIF:
res = gif_decode(filename, x, y, width, height);
break;
对BMP文件来说,它是一种非压缩式图片格式,因此要显示BMP文件,只需调用画点函数即可。
对应的画点函数为:
void ili9341_draw_pixel(uint16_t c, uint16_t x, uint16_t y)
{
set_cursor(x,y);
gram_prepare();
write_data(c >> 8);
write_data(c);
}
所替代的原函数为:
voidlcd_draw_point(uint16_t x, uint16_t y, uint32_t color);
在替代后,所实现的显示效果如图5所示。
图5 显示位图
对GIF及JPG文件来说,其采用的是压缩式图片格式,在恢复图片显示时,要调用画点函数、画线及填充函数,其形式如下:
pic_phy.draw_point((uint16_tx0, uint16_t y0, uint16_t *pencolor); /* 画点 */
pic_phy.draw_hline(uint16_tx0, uint16_t y0, uint16_t color); /* 画水平线 */
pic_phy.fillcolor(uint16_t x0, uint16_t y0, uint16_t width, uint16_t height, uint16_t pencolor); /*颜色填充*/
所配置的画线与填充函数为:
void ili9341_line(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t * color)
{
uint16_t j=0;
uint16_t c=* color;
set_cursor(x0, y0);
gram_prepare();
for(j = 0; j < x1; j++)
{
write_data(c >> 8);
write_data(c);
}
}
void ili9341_fill(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t c)
{
uint16_t i,j=0;
for(i = 0; i < y1; i++)
{
set_cursor(x0, y0);
gram_prepare();
for(j = 0; j < x1; j++)
{
write_data(c >> 8);
write_data(c);
}
y0=y0+1;
}
}
经测试,其GIF动画的显示效果如图6所示,而对于JPG文件来说,其显示效果则如图7所示。
图6 GIF动画
图7 显示JPG图片
这样,就利用开发板上的显示接口,为其配接了兼容的显示屏并实现了数码相框的功能。
虽然这里介绍的内容是针对STM32探索者V3的,但这种处理方式对其它需要进行类似处理的问题是有较好地借鉴和参考意义的。
---------------------
作者:jinglixixi
链接:https://bbs.21ic.com/icview-3300926-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。