STM32学习之ILI9341控制显示屏输出(一)

本实验工具:

STM32F407ZGT6                    液晶显示屏2.8寸                 显示屏控制芯片:ILI9341

本液晶显示屏内部包含一个ILI9341液晶控制芯片。其内部结构如下所示:

其中最核心的部分为GRAM,可以称为显存,每一个存储单元都对应着液晶面板的一个像素点。下图右侧的模块共同作用吧GRAM存储单元的数据转化为液晶面板的控制信号,使像素点呈现特定的颜色,而像素点组合起来就成为一幅完整的图像。框图的左上角为芯片的主要控制信号和配置引脚,根据其不同的状态设置可以使芯片工作在不同的模式,如每个像素点的位数,6位、18位、16位等。本实验采用STM32的FSMC模拟8080时序与液晶屏通讯。

 

FSMC的地址映射:

FSMC连接好外部存储器并初始化后,就可以直接通过访问地址读写数据,这种地址访问与I2CEEPROM、SPI Flash的不一样,使用FSMC外接存储器时,其存储单元是映射到STM32的内部寻址空间;在程序里,第一一个指向这些地址的指针,然后就可以通过指针直接修改该存储单元的内容,FSMC外设会自动完成数据访问过程,读写命令之类的操作不需要程序控制。

NOR Flash存储器时序结构体

控制FSMC使用NOR Flash存储器时主要是配置时序寄存器以及控制寄存器,利用ST标准库的时序结构体以及初始化结构体。

NOR Flash时序结构体FSMC_NORSRAMTimingInitTypeDef结构体



typedef struct
{
uint32_t FSMC_AddressSetupTime; //用于定义地址建立时间,范围:0~0xF个周期,一个周期一般
                                //为1/HSCLK。
uint32_t FSMC_AddressHoldTime;  //用于设置地址保持时间:0~0xF个周期。
uint32_t FSMC_DataSetupTime;    //地址建立时间,0~0xF个周期,
uint32_t FSMC_BusTurnAroundDuration; //总线转换时间,0~0xF个周期;
uint32_t FSMC_CLKDivision;      //时钟分频因子,0~0xF,若控制异步存储器,本参数无效;
uint32_t FSMC_DataLatency;      //数据延迟时间,若控制异步存储器,本参数无效;
uint32_t FSMC_AccessMode;       //设置访问模式;

}FSMC_NORSRAMTimingInitTypeDef; 

FSMC初始化结构体:用于控制NOR Flash相关的结构体,

NORSRAMInitTypeDef结构体

typedef struct
{
 uint32_t FSMC_Bank;   //设置需要控制的区域;
uint32_t  FSMC_DataAddressMux; //设置地址总线与数据总线是否复用;
uint32_t FSMC_MemoryType;  //设置存储器类型;
uint32_t FSMC_MemoryDataWidth; //设置存储器的宽度;
uint32_t FSMC_BurstAccessMode; //设置是否支持突发模式,只支持同步类型的存储器;
uint32_t FSMC_AsynchronousWait; //设置是否使能在同步传输中时的等待信号;
uint32_t FSMC_WaitSignalPolarity; //设置等待信号的极性;
uint32_t FSMC_WrapMode;         //设置是否支持对其的突发模式;
uint32_t FSMC_WaitSignalActive; //设置等待信号在等待前有效还是等待期间有效;
uint32_t FSMC_WriteOperation;  //设置是否写使能;
uint32_t FSMC_WaitSignal;     //设置是否使能等待状态插入;
uint32_t FSMC_ExtendedMode;  //设置是否使能扩展模式;
uint32_t FSMC_WriteBurst;   //设置是否使能突发模式;
//当不设置扩展模式时,本参数用于设置读写时序,否则用于配置读时序;
FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;
//当使用扩展模式时,本参数用于配置写时序;
FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;
}FSMC_NORSRAMInitTypeDef

以上是使用库函数需要配置的结构体,具体程序代码请见下一章节;

STM32F4芯片上使用ILI9341显示汉字需要涉及到汉字的编码问题和字库的存储问题。以下是一个简单的代码示例,可以输出“张翼鹏”这三个汉字。 1. 字库存储 将汉字的字库存储到外部FLASH或SD卡中,然后通过读取字库数据进行汉字的显示。这里我们假设字库数据已经存储在外部FLASH中,首先需要将字库数据读取到内存中。 ```c #define FONT_SIZE 24 // 汉字字库大小 #define FONT_ADDR 0x08040000 // 外部FLASH中存储字库的地址 uint8_t font_buf[FONT_SIZE * 2]; // 存储读取到的字库数据 void read_font(uint16_t index) { uint32_t addr = FONT_ADDR + index * FONT_SIZE * 2; for (int i = 0; i < FONT_SIZE * 2; i += 2) { uint16_t data = *(volatile uint16_t *)addr; font_buf[i] = data & 0xFF; // 取低8位 font_buf[i + 1] = data >> 8; // 取高8位 addr += 2; } } ``` 2. 汉字编码 汉字编码采用Unicode编码,每个汉字用两个字节表示。在Unicode编码中,“张翼鹏”这三个汉字分别对应的编码为0x5f20、0x7ffc和0x9e1f。需要注意的是,在STM32F4芯片上使用的是小端模式,因此需要将高位字节放在前面,低位字节放在后面。 ```c uint16_t utf8_to_unicode(uint8_t *utf8_str) { uint16_t unicode = 0; if ((utf8_str[0] & 0x80) == 0x00) { // 单字节编码 unicode = utf8_str[0]; } else if ((utf8_str[0] & 0xE0) == 0xC0) { // 双字节编码 unicode = ((utf8_str[0] & 0x1F) << 6) | (utf8_str[1] & 0x3F); } else if ((utf8_str[0] & 0xF0) == 0xE0) { // 三字节编码 unicode = ((utf8_str[0] & 0x0F) << 12) | ((utf8_str[1] & 0x3F) << 6) | (utf8_str[2] & 0x3F); } return unicode; } uint16_t get_unicode(uint8_t *str) { uint16_t unicode = 0; if (str[0] == 0xE5 && str[1] == 0xBC && str[2] == 0xA0) { // 张 unicode = 0x5f20; } else if (str[0] == 0xE7 && str[1] == 0xBF && str[2] == 0xBC) { // 翼 unicode = 0x7ffc; } else if (str[0] == 0xE9 && str[1] == 0xB9 && str[2] == 0x9F { // 鹏 unicode = 0x9e1f; } return unicode; } ``` 3. 汉字绘制 使用ILI9341显示屏输出汉字需要将字库数据写入到ILI9341的GRAM中,然后设置GRAM中每个像素的颜色值,最后通过SPI接口将GRAM中的数据发送给ILI9341。以下是一个简单的代码示例,可以输出“张翼鹏”这三个汉字。 ```c #define LCD_WIDTH 240 // 显示屏宽度 #define LCD_HEIGHT 320 // 显示屏高度 #define LCD_CS_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_4) #define LCD_CS_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_4) #define LCD_DC_LOW() GPIO_ResetBits(GPIOA, GPIO_Pin_3) #define LCD_DC_HIGH() GPIO_SetBits(GPIOA, GPIO_Pin_3) void lcd_write_cmd(uint8_t cmd) { LCD_CS_LOW(); LCD_DC_LOW(); SPI_I2S_SendData(SPI1, cmd); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); LCD_CS_HIGH(); } void lcd_write_data(uint8_t data) { LCD_CS_LOW(); LCD_DC_HIGH(); SPI_I2S_SendData(SPI1, data); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); LCD_CS_HIGH(); } void lcd_set_pos(uint16_t x, uint16_t y) { lcd_write_cmd(0x2A); lcd_write_data(x >> 8); lcd_write_data(x & 0xFF); lcd_write_data((x + FONT_SIZE - 1) >> 8); lcd_write_data((x + FONT_SIZE - 1) & 0xFF); lcd_write_cmd(0x2B); lcd_write_data(y >> 8); lcd_write_data(y & 0xFF); lcd_write_data((y + FONT_SIZE - 1) >> 8); lcd_write_data((y + FONT_SIZE - 1) & 0xFF); lcd_write_cmd(0x2C); } void lcd_draw_char(uint16_t x, uint16_t y, uint8_t *str) { uint16_t unicode = utf8_to_unicode(str); uint16_t index = (unicode - 0x4E00) * FONT_SIZE; // 计算字库数据的偏移量 read_font(index); lcd_set_pos(x, y); for (int i = 0; i < FONT_SIZE; i++) { uint8_t data = font_buf[i]; for (int j = 0; j < 8; j++) { uint16_t color = (data & 0x80) ? 0xFFFF : 0x0000; // 根据字库数据设置颜色值 lcd_write_data(color >> 8); lcd_write_data(color & 0xFF); data <<= 1; } } } void lcd_draw_string(uint16_t x, uint16_t y, uint8_t *str) { while (*str) { uint16_t unicode = get_unicode(str); if (unicode) { lcd_draw_char(x, y, str); x += FONT_SIZE; } str += 3; } } int main(void) { // 初始化SPI和GPIO // ... lcd_write_cmd(0x36); lcd_write_data(0x48); // RGB旋转180度 lcd_write_cmd(0x3A); lcd_write_data(0x05); // 16位色深 lcd_write_cmd(0x29); // 开始显示 lcd_draw_string(0, 0, "张翼鹏"); while (1); } ``` 上述代码仅供参考,具体实现还需要根据具体情况进行调整。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值