stm32F1显示器实验学习笔记

本文详细介绍了STM32与LCD显示屏的连接、8080时序、常用驱动芯片如ILI9341和ST7789的控制指令,包括读ID、访问控制、坐标设置和数据传输。还提供了示例代码,展示了如何用STM32进行LCD的基本操作,以及ASCII字库的制作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LCD简介

在这里插入图片描述

LCD驱动原理

LCD屏(MCU接口)驱动的核心是:驱动LCD驱动芯片(ILI9341)
LCD驱动基本知识:
1,8080时序,LCD驱动芯片一般使用8080时序控制,实现数据写入/读取
2,初始化序列(数组),屏厂提供,用于初始化特定屏幕,不同屏幕厂家不完全相同!
3,画点函数、读点函数(非必需),基于这两个函数可以实现各种绘图功能!
在这里插入图片描述

8080时序简介

在这里插入图片描述
8080写时序
在这里插入图片描述
8080读时序
在这里插入图片描述

LCD驱动芯片简介(通常是ILI9341,ST7789型号芯片)

一般我们只需要:6条指令即可完成对LCD的基本使用(以9341为例,ST7789的读ID质量为0XD4)

在这里插入图片描述

读ID指令(0XD3)

获取LCD控制器型号,通过型号可以执行不同LCD驱动芯片的初始化
在这里插入图片描述

访问控制指令(0XD3)

实现GRAM读写方向控制,即:控制GRAM自增方向,从而控制显示方向
在这里插入图片描述

MX,MY,MV:共同控制GRAM自增方向(扫描方向)
BGR位:可以控制RGB、BGR顺序
八种扫描方向
在这里插入图片描述

X坐标设置指令(0X2A)

在这里插入图片描述

Y坐标设置指令(0X2B)

写GRAM指令(0X2C)

在这里插入图片描述

读GRAM指令(0X2E)

发送该指令后,数据线变成16位,可以开始读取GRAM数据,支持地址自增
在这里插入图片描述

LCD基本驱动实现(掌握)

目标:用最简单代码,点亮开发板LCD屏,实现任意位置画点和读点
在这里插入图片描述

硬件IO连接关系(MINI)

在这里插入图片描述

实验源码

lcd.c

#include "stdlib.h"
#include "./BSP/LCD/lcd.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LCD/lcd_ex.c"
#include "./BSP/LCD/lcdfont.h"

/* 设置画笔和背景颜色 */
uint32_t g_point_color = 0XF800;    /* 画笔颜色*/
uint32_t g_back_color  = 0XFFFF;    /* 背景颜色*/

/* 管理LCD的重要参数*/
_lcd_dev lcddev;

/* LCD重要参数,声明在lcd.h中 */
typedef struct
{
    uint16_t width;     /* LCD 宽度 */
    uint16_t height;    /* LCD ¸高度*/
    uint16_t id;        /* LCD ID */
    uint8_t dir;        /* 0是竖屏,1是横屏 */
    uint16_t wramcmd;   /* 写指令 */
    uint16_t setxcmd;   /* 设置x指令 */
    uint16_t setycmd;   /*设置y指令 */
} _lcd_dev;

/* 8080 写数据,WR上升沿发送数据*/
void lcd_wr_data (uint16_t data)
{
    LCD_RS(1);          /* 操作数据 */
    LCD_CS(0);          /* 片选选中*/
    LCD_DATA_OUT(data); /* 数据 */
    LCD_WR(0);          /* WR低电平 */
    LCD_WR(1);          /* WR¸高电平*/
    LCD_CS(1);          /* 释放片选 */
}

/* 8080 写命令 ,WR上升沿发送数据*/
void lcd_wr_regno(uint16_t regno)
{
    LCD_RS(0);          /* RS=0,表示写寄存器 */
    LCD_CS(0);          /* Ñ¡ÖÐ */
    LCD_DATA_OUT(regno);/* ÃüÁî */
    LCD_WR(0);          /* WRµÍµçƽ */
    LCD_WR(1);          /* WR¸ßµçƽ */
    LCD_CS(1);          /* ÊÍ·ÅÆ¬Ñ¡ */
}

/* 往寄存器写值*/
void lcd_write_reg(uint16_t regno, uint16_t data)
{
    lcd_wr_regno(regno);    /* дÈëҪдµÄ¼Ä´æÆ÷ÐòºÅ */
    lcd_wr_data(data);      /* дÈëÊý¾Ý */
}

static void lcd_opt_delay(uint32_t i)
{
    while(i--);
}

/* LCD读数据 */
uint16_t lcd_rd_data(void)
{
    volatile uint16_t ram;  /* ·ÀÖ¹±»ÓÅ»¯ */
    
    GPIO_InitTypeDef gpio_init_struct;
    /* LCD_DATA 引脚模式设置使用GPIOB接收数据,上拉输入,准备接收数据*/
    gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_INPUT;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct); 

    LCD_RS(1);              /* RS=1,表示操作数据 */
    LCD_CS(0);
    LCD_RD(0);
    lcd_opt_delay(2);
    ram = LCD_DATA_IN;      /* 读取数据,实际上上是读取GPIOB寄存器IDR的值*/
    LCD_RD(1);
    LCD_CS(1);
     
    /* LCD_DATA设置引脚模式,恢复输出状态 */
    gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);   

    return ram;
}

/* 准备写GRAM */
void lcd_write_ram_prepare(void)
{
    lcd_wr_regno(lcddev.wramcmd);
}

/* 设置坐标 */
void lcd_set_cursor(uint16_t x, uint16_t y)
{
    lcd_wr_regno(lcddev.setxcmd);
    lcd_wr_data(x >> 8);
    lcd_wr_data(x & 0xFF);
    lcd_wr_regno(lcddev.setycmd);
    lcd_wr_data(y >> 8);
    lcd_wr_data(y & 0xFF);
}

/* 画点 */
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
    lcd_set_cursor(x, y);
    lcd_write_ram_prepare();
    lcd_wr_data(color);
}

/* 读点 */
uint16_t  lcd_read_point (uint16_t x, uint16_t y)
{
    uint16_t r = 0, g = 0, b = 0;   /* ¶¨Òå±äÁ¿ */
    
    lcd_set_cursor(x, y);           /* 设置坐标 */
    lcd_wr_regno(0X2E);             /* ·发送读命令 */
    r = lcd_rd_data();              /* 假读 */
    r = lcd_rd_data();              /* 读rg*/
    b = lcd_rd_data();              /* 读 b */
    g = r & 0XFF;                   /* 得到g的值 */
    return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11));
}

//显示字符函数

void lcd_show_char(uint16_t x, uint16_t y, char chr, uint8_t size, uint8_t mode, uint16_t color)
{
    uint8_t t, t1, temp;
    uint8_t *pfont = NULL;
	//»ñÈ¡×Ö·ûµÄ×Ü×Ö½ÚÊý
    uint8_t csize = (size / 8+((size % 8) ? 1 : 0)) * (size / 2);
    chr = chr - ' ';
    uint16_t y0 = y;
    
    switch(size)
    {
        case 12:
            pfont = (uint8_t *)asc2_1206[chr];  /* µ÷ÓÃ1206×ÖÌå */
            break;

        case 16:
            pfont = (uint8_t *)asc2_1608[chr];  /* µ÷ÓÃ1608×ÖÌå */
            break;

        case 24:
            pfont = (uint8_t *)asc2_2412[chr];  /* µ÷ÓÃ2412×ÖÌå */
            break;

        case 32:
            pfont = (uint8_t *)asc2_3216[chr];  /* µ÷ÓÃ3216×ÖÌå */
            break;

        default:
            return ;
    }
    
    for (t = 0; t < csize; t++)
    {
        temp = pfont[t];
        
        for (t1 = 0; t1 < 8; t1++)
        {
            if (temp & 0x80)
            {
                lcd_draw_point(x, y, color);
            }
            else if (mode == 0)
            {
                lcd_draw_point(x, y, g_back_color);
            }
            
            temp <<= 1;
            y++;
            
            if ((y - y0) == size)
            {
                y = y0;
                x++;
                break;
            }
        }
        
    }

}


void lcd_clear(uint16_t color)
{
    uint32_t index = 0;
    uint32_t totalpoint = lcddev.width;
    
    totalpoint *= lcddev.height;    /* 得到屏幕的像素点 */
    lcd_set_cursor(0, 0);   /* 设置坐标 */
    lcd_write_ram_prepare();        /* 写GRAM命令发送 */

    LCD_RS(1);                      /* RS=1,表示写数据 */
    LCD_CS(0);
    
    for (index = 0; index < totalpoint; index++)
    {
        LCD_DATA_OUT(color);        /*将屏幕清为color颜色*/
        LCD_WR(0);
        LCD_WR(1);
    }
    
    LCD_CS(1);
}

/* 初始化¯LCD */
void lcd_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    LCD_BL_GPIO_CLK_ENABLE();   /* LCD_BL脚时钟使能 */
    LCD_CS_GPIO_CLK_ENABLE();   /* LCD_CS脚时钟使能 */
    LCD_WR_GPIO_CLK_ENABLE();   /* LCD_WR脚时钟使能*/
    LCD_RD_GPIO_CLK_ENABLE();   /* LCD_RD脚时钟使能 */
    LCD_RS_GPIO_CLK_ENABLE();   /* LCD_RS脚时钟使能 */
    LCD_DATA_GPIO_CLK_ENABLE(); /* LCD_DATA脚时钟使能 */
    //以上时钟使能是在lcd.h中实现的。
    __HAL_RCC_AFIO_CLK_ENABLE();
    __HAL_AFIO_REMAP_SWJ_NOJTAG(); /*禁止JTAG,使能SWD,释放PB3,PB4两个引脚做普通IO用 */
    
    gpio_init_struct.Pin = LCD_BL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽复用输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉­ */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* ¸高速 */
    HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct);     /* LCD_BL引脚模式设置(推挽输出) */

    gpio_init_struct.Pin = LCD_CS_GPIO_PIN;
    HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_CS引脚 */

    gpio_init_struct.Pin = LCD_WR_GPIO_PIN;
    HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct);     /* 初始化¯LCD_WR引脚 */

    gpio_init_struct.Pin = LCD_RD_GPIO_PIN;
    HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RD引脚*/

    gpio_init_struct.Pin = LCD_RS_GPIO_PIN;
    HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct);     /* 初始化LCD_RS引脚 */

    gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /*推挽输出*/
    HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);   /* LCD_DATA引脚模式设置 */
    
    LCD_WR(1);                  /* WR ĬÈÏ¸ßµçÆ½ */
    LCD_RD(1);                  /* RD ĬÈÏ¸ßµçÆ½ */
    LCD_CS(1);                  /* CS ĬÈÏ¸ßµçÆ½ */
    LCD_RS(1);                  /* RS ĬÈÏ¸ßµçÆ½ */
    LCD_DATA_OUT(0XFFFF);       /* DATA ĬÈÏ¸ßµçÆ½ */

    /*读取IO */
    lcd_wr_regno(0xD3);
    lcddev.id = lcd_rd_data();  /* 假读 */
    lcddev.id = lcd_rd_data();  /* 00 */
    lcddev.id = lcd_rd_data();  /* 93 */
    lcddev.id <<= 8;
    lcddev.id |= lcd_rd_data();  /* 41 */
    
    printf("lcddev_id:%#x \r\n", lcddev.id);    
    /* 初始化外设显示器中的芯片 */
    if (lcddev.id == 0x9341)
        lcd_ex_ili9341_reginit();//³õʼ»¯ÍâÉèÏÔʾÆ÷ÖеÄоƬ¡£
    else
        lcd_ex_st7789_reginit();
    
    /* 对lcd控制结构体赋值 */
    lcddev.width = 240;
    lcddev.height = 320;
    lcddev.setxcmd = 0x2A;
    lcddev.setycmd = 0x2B;
    lcddev.wramcmd = 0x2C;
    
    lcd_wr_regno(lcddev.setxcmd);
    lcd_wr_data(0);
    lcd_wr_data(0);
    lcd_wr_data((lcddev.width - 1) >> 8);
    lcd_wr_data((lcddev.width - 1) & 0XFF);
    lcd_wr_regno(lcddev.setycmd);
    lcd_wr_data(0);
    lcd_wr_data(0);
    lcd_wr_data((lcddev.height - 1) >> 8);
    lcd_wr_data((lcddev.height - 1) & 0XFF);
    
    /* 设置扫描方向*/
    lcd_write_reg(0x36, 1 << 3);
    
    /* 点亮背光*/
    LCD_BL(1);
    
    /* lcd_clear */
    lcd_clear(0xFFFF);
}

main.c

   uint16_t point_value = 0;
    uint8_t x = 0;
    
    HAL_Init();                         /* HAL¿â³õʼ»¯ */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* ÉèÖÃʱÖÓ, 72Mhz */
    delay_init(72);                     /* ÑÓʱ³õʼ»¯ */
    usart_init(115200);                 /* ´®¿Ú³õʼ»¯Îª115200 */
  //  led_init();                         /* ³õʼ»¯LED */
    lcd_init();
    
    lcd_draw_point(0, 0, RED);
    lcd_draw_point(0, 1, RED);
    lcd_draw_point(100, 100, RED);
    
    /* 0xF800 */
    point_value = lcd_read_point(100, 100);
    printf("point_value:%#x \r\n",point_value);

    lcd_show_char(0, 0, 'A', 16, 1, RED);
    lcd_show_char(100, 100, 'B', 24, 1, RED);

代码运行结果图

在这里插入图片描述

ASCII字库制作(16*16)

使用PCtoLCD2002.exe软件制作ASCII字库!

  1. 设置字体大小
    在这里插入图片描述
    第2步,设置字模选项
    在这里插入图片描述
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值