【方法】Ilitek ILI9325、ILI9341 LCD TFT彩屏利用Memory Read指令读取屏幕上显示的内容

【ILI9325】

ILI9325可以通过0号寄存器读出来0x9325,代表芯片就是ILI9325。如果读出来是0,则说明芯片可能不是ILI9325,而有可能是ILI9341。

程序下载地址:https://blog.csdn.net/ZLK1214/article/details/107327515

ILI9325读取屏幕内容的代码如下:

#define ILI9325_CMD (*(volatile uint16_t *)0x60000000)
#define ILI9325_DATA (*(volatile uint16_t *)0x60020000)

#define ILI9325_CMD_HORIZONTAL_GRAM_ADDRESS_SET 0x20
#define ILI9325_CMD_VERTICAL_GRAM_ADDRESS_SET 0x21
#define ILI9325_CMD_MEMORY_WRITE 0x22
#define ILI9325_CMD_MEMORY_READ 0x22

/* 读取指定区域的屏幕显示内容 */
void ILI9325_GetPixelsInRect(void *pixels, uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
  int i, j;
  uint16_t *p = pixels;
  
  for (i = 0; i < height; i++)
  {
    for (j = 0; j < width; j++)
    {
      // 手册上有这句话: The address counter is not automatically updated when read data from the internal GRAM
      // 也就是说读数据的时候光标不能自己移动
      ILI9325_SetPos(x + j, y + i);
      ILI9325_CMD = ILI9325_CMD_MEMORY_READ;
      ILI9325_DATA; // dummy read
      *p++ = ILI9325_DATA;
    }
  }
}

/* 设置绘图位置 */
void ILI9325_SetPos(uint16_t x, uint16_t y)
{
  ILI9325_CMD = ILI9325_CMD_HORIZONTAL_GRAM_ADDRESS_SET;
  ILI9325_DATA = x;
  ILI9325_CMD = ILI9325_CMD_VERTICAL_GRAM_ADDRESS_SET;
  ILI9325_DATA = y;
}

测试代码:

#include 
#include 
#include 
#include "common.h"
#include "images.h"
#include "ILI9325.h"
#include "XPT2046.h"

static void check_display(const void *image, int x, int y, int width, int height)
{
  int i, j, curr;
  int err = 0, count = 0;
  uint16_t pixels[50];
  
  for (i = 0; i < height; i++)
  {
    for (j = 0; j < width; j += curr)
    {
      curr = _countof(pixels);
      if (curr > width - j)
        curr = width - j;
      
      ILI9325_GetPixelsInRect(pixels, x + j, y + i, curr, 1);
      if (memcmp(pixels, (uint16_t *)image + i * width + j, curr * sizeof(uint16_t)) != 0)
        err++;
      count++;
    }
  }
  if (err == 0)
    printf("Display OK!\n");
  else
  {
    // 使用杜邦线连接彩屏时, 有可能会有个别字节传输出错
    // 将FSMC的AddressHoldTime和DataSetupTime改大可以降低错误率
    printf("Display error! err/count=%d/%d\n", err, count);
  }
}

int main(void)
{
  int x, y;
  
  HAL_Init();
  
  clock_init();
  usart_init(115200);
  printf("STM32F407VE FSMC ILI9325\n");
  printf("SystemCoreClock=%u\n", SystemCoreClock);
  
  ILI9325_Init(); // 初始化彩屏
  ILI9325_Clear(ILI9325_COLOR_RED); // 背景色刷为红色
  
  XPT2046_Init(); // 初始化触控
  
  // 彩屏的坐标轴方向: 短边为x轴, 长边为y轴
  // 图片myimage是逆时针旋转了90度后转换成数组的
  HAL_Delay(1000);
  ILI9325_DrawImage(myimage, 0, 36, _countof(myimage[0]), _countof(myimage)); // 在屏幕上显示一张图片
  check_display(myimage, 0, 36, _countof(myimage[0]), _countof(myimage)); // 检查是否显示正确
  
  while (1)
  {
    // 每按一下, 触发一次中断
    if (XPT2046_GetITStatus())
    {
      XPT2046_ReadPosition(&x, &y);
      printf("(%d,%d)\n", x, y);
      ILI9325_SetPixel(x, y, 0x4010);
    }
  }
}

【ILI9341】

网上很多彩屏例程都通过0号命令(有时也称为0号寄存器)读取彩屏的ID号,以此来判断彩屏的芯片型号,然而ILI9341芯片的0号命令是一个空操作(No Operation),无法得到器件ID。

【方法】Ilitek ILI9325、ILI9341 LCD TFT彩屏利用Memory Read指令读取屏幕上显示的内容_第1张图片
4号命令和0xda~0xdc命令虽然是读取ID的命令,但是读出来的ID全都是0。这会不会是STM32 FSMC的时序配置问题?或者STM32的FSMC根本就不支持这款液晶的读操作?到底是STM32的时序问题,还是芯片的器件ID本来就为0?
通过Memory Read(0x2e)命令可以发现,即使把FSMC的时序值配置为最小值,STM32也能通过FSMC正确读取到屏幕上显示的像素点的颜色值,这说明FSMC的读时序配置没有问题,可以产生正确的读时序。是这款液晶的器件ID本来就为0。
此外,Memory Read命令还可以用来实现屏幕截图,将屏幕上显示的内容以位图的格式保存到存储器中。

在下面的程序中,我们先将图片显示到屏幕上,然后将屏幕显示内容的前120行读出来,和原来的图像数据比较,看是否一样。如果一样,则说明读操作没有问题。

程序下载地址:https://blog.csdn.net/ZLK1214/article/details/107144250

#include 
#include 
#include 
#include "common.h"
#include "images.h"
#include "ILI9341.h"
 
#define RGB888TO565(color) ((((color) >> 8) & 0xf800) | (((color) >> 5) & 0x7e0) | (((color) >> 3) & 0x1f))
 
static void ILI9341_GetPixels(uint16_t *pixels, int count)
{
  int i = 0;
  uint16_t data[3];
  uint16_t rgb565[2];
  uint32_t rgb888[2];
  
  ILI9341_CMD = 0x2e;
  ILI9341_DATA; // dummy read
  while (i < count)
  {
    // 读两个像素, 每个像素3字节
    // 每字节表示一个分量, 分量在字节中是左对齐的
    data[0] = ILI9341_DATA; // 0xr1g1 (高字节为第一个像素的红色分量, 低字节为第一个像素的绿色分量)
    data[1] = ILI9341_DATA; // 0xb1r2 (高字节为第一个像素的蓝色分量, 低字节为第二个像素的红色分量)
    data[2] = ILI9341_DATA; // 0xg2b2 (高字节为第二个像素的绿色分量, 低字节为第二个像素的蓝色分量)
    
    // 转换成RGB888
    rgb888[0] = (data[0] << 8) | (data[1] >> 8);
    rgb888[1] = ((data[1] & 0xff) << 16) | data[2];
    //printf("#%06X #%06X => ", rgb888[0], rgb888[1]);
    
    // 再转换成RGB565
    rgb565[0] = RGB888TO565(rgb888[0]);
    rgb565[1] = RGB888TO565(rgb888[1]);
    //printf("0x%04x 0x%04x\n", rgb565[0], rgb565[1]);
    
    // 保存颜色值
    pixels[i++] = rgb565[0];
    if (i < count)
      pixels[i++] = rgb565[1];
  }
}
 
static void ILI9341_GetPixelsInRect(void *pixels, uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
  ILI9341_SetRegion(x, y, x + width - 1, y + height - 1);
  ILI9341_GetPixels(pixels, width * height);
}
 
int main(void)
{
  static uint16_t pixels[120][239];
  
  HAL_Init();
  
  clock_init();
  usart_init(115200);
  printf("STM32F103VE FSMC ILI9341\n");
  printf("SystemCoreClock=%u\n", SystemCoreClock);
  
  ILI9341_Init();
  ILI9341_Clear(ILI9341_COLOR_BLUE);
  ILI9341_Enable(1);
  
  ILI9341_DrawImage(image1, 0, 36, 239, 248); // 在屏幕上显示一张图片
  ILI9341_GetPixelsInRect(pixels, 0, 36, 239, 120); // 读取屏幕上的图像内容
  if (memcmp(pixels, image1, sizeof(pixels)) == 0) // 和原图比较
    printf("same\n"); // 相同
  else
    printf("different\n"); // 不相同
  
  while (1)
  {
  }
}

程序运行结果为:

STM32F103VE FSMC ILI9341
SystemCoreClock=72000000
same

所以,读操作没有问题。

你可能感兴趣的:(CubeMX,STM32,STM32,ILI9341,TFTLCD,ILI9325,ILI9328)