本文使用FSMC驱动LCD显示,关于建议先看之前的7、STM32 FSMC驱动SRAM一文
硬件连接:
一、CubeMx配置FSMC驱动LCD ILI93xx
此章只为快速使用LCD,不涉及原理、指令说明
显示屏驱动文件参考正点探索者
1、CubeMx图形配置
此处的时序还可以调整,配置的满足要求,没细究
生成工程…
2、添加文件至工程
文件可以在下面工程中获取
注意:文件中操作的是FSMC对应的NE4相应地址,
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线
//注意设置时STM32内部会右移一位对其! 111 1110=0X7E
#define LCD_BASE ((uint32_t)(0x6C000000 | 0x0000007E))
#define TFT_LCD ((LCD_TypeDef *) LCD_BASE)
2、LCD代码编写
A、ILI93xx.h修改背光引脚宏
B、main.c文件添加编写串口printf所需函数、stdio.h、初始化LCD、字符串显示
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "fsmc.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ILI93xx.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/****************************************************
@function:串口重定义
@param:void
@return:void
@date:2023.2.14
@note:使用printf时需要此函数,并在Keil魔术棒中勾选User MicroLIB库
****************************************************/
int fputc(int ch,FILE *f)
{
uint8_t data = ch;
HAL_UART_Transmit(&huart1,&data,1,1);
return(ch);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FSMC_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
TFTLCD_Init();
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(30,50,200,16,16,"STM32F4 FSMC LCD");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3、文件下载:
部分文件:
链接:https://pan.baidu.com/s/1b-GrxnUoKsuabGLw4vK1Pw
提取码:vm16
完成工程:
链接:https://pan.baidu.com/s/1NrQoqWxm4E5wkiq_9IUPxQ
提取码:9utl
二、LCD 任意偶数大小字体中英文显示 带字库
要实现任意文字显示,若都去取模,那么单片机的RAM是放不下的,此时需要制作字库放置在外部,比如SD卡、W25Qxx
取模软件下载地址:
链接:https://pan.baidu.com/s/1CAz_wyaNULfqws6VgsS5uA
提取码:brbw
本文章将字库写入在W25Q128中,需要使用SD卡 FATFS系统
1、字符取模小解释 + 字库制作方法
首先先设置一种取模方式 阴码 逐行 顺向 32*32
这是生成的数据
1(0)
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x80,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80},
{0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0xC0,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",0*/
这个数据就是按照32*16出的数据,
0x00,0x00,
0x00,0x00,
0x00,0x00,
…
0x00,0x00
打点的时候按此还原即可呈现出字符
for(y = 0;y < 32;y++)
{
x = 0;
data = buf[HByte]<<8 | buf[LByte];
for(x = 0;x < 16;x++)
{
if(data & 0x8000){LCD(x,y,显示点)}
else {LCD(x,y,不显示点)}
x++;
}
}
选择所需要制作的字库文件,此处选用GBK字库(完整的字库文件)
如此就可得到32*32的字库文件
2、字库烧录至W25Q128
本次直接使用野火做好的字库文件,并烧录
srcdata文件下载:
链接:https://pan.baidu.com/s/1Hf-ks3jgLo9MI_pIpsfx4g
提取码:xk6e
把srcdata文件夹放到SD卡根目录
主要部分实现代码:
/****************************************************
@function:向FLASH写入文件(写到非文件系统部分)
@param: dat:要写入的文件数据的信息
file_num:要写入的文件个数
@return:正常返回FR_OK
@date:2023.3.1
@note:
****************************************************/
static FRESULT burn_file_sd2flash(Aux_Data_Typedef *dat,uint8_t file_num)
{
FRESULT result;
UINT bw;/* File R/W count */
uint32_t write_addr=0,j=0;
uint8_t tempbuf[256],flash_buf[256],i = 0;
char filename[150] = {0};
for(i=0;i<file_num;i++)
{
if(dat[i].burn_option == DO_NOT_UPDATE)continue;
BURN_INFO("-------------------------------------");
BURN_INFO("准备烧录内容:%s",dat[i].description);
memset(filename,0,sizeof(filename));
sprintf(filename,"%s%s",SDPath,dat[i].filename);printf("文件名:%s\r\n",filename);
result = f_open(&SDFile,(const char*)filename,FA_OPEN_EXISTING | FA_READ);
if(result != FR_OK)
{
BURN_ERROR("打开文件失败!");
return result;
}
BURN_INFO("正在擦除要使用的FLASH空间...");
write_addr = dat[i].start_addr;
for(j=0;j < dat[i].length/4096 ;j++)//擦除扇区,起始位置710*4096共2116KB
{
W25Qxx_SectorErase(write_addr+j*4096);
}
BURN_INFO("正在向FLASH写入内容...");
write_addr = dat[i].start_addr;
while(result == FR_OK)
{
result = f_read( &SDFile, tempbuf, 256, &bw);//读取数据
if(result!=FR_OK)//执行错误
{
BURN_ERROR("读取文件失败!");
return result;
}
W25Qxx_PageWrite(tempbuf,write_addr,256); //拷贝数据到外部flash上
write_addr+=256;
if(bw !=256)break;
}
BURN_INFO("内容写入完毕,开始校验数据...");
//校验数据
write_addr = dat[i].start_addr;
f_lseek(&SDFile,0);
while(result == FR_OK)
{
result = f_read( &SDFile, tempbuf, 256, &bw);//读取数据
if(result!=FR_OK) //执行错误
{
BURN_ERROR("读取文件失败!");
return result;
}
W25Qxx_BufferRead(flash_buf,write_addr,bw); //从FLASH中读取数据
write_addr+=bw;
for(j=0;j<bw;j++)
{
if(tempbuf[i] != flash_buf[i])
{
BURN_ERROR("数据校验失败!");
return FR_INT_ERR;
}
}
if(bw !=256)break;//到了文件尾
}
BURN_INFO("数据校验成功!");
BURN_INFO("文件:%s 写入完成",filename);
BURN_INFO("-------------------------------------");
f_close(&SDFile);
}
BURN_INFO("************************************");
BURN_INFO("所有文件均已烧录成功!(非文件系统部分)");
return FR_OK;
}
其实就是通过SD卡读出文件,将数据写入W25Qxx
if(KeyPressFlag[eKeyCode1])//按下按键进行烧录
{
KeyPressFlag[eKeyCode1] = 0;
Burn_FontLibraryToW25Qxx();
}
如何显示字符时读取的呢?
//字库使用文件为:字模GB2312_H3232 conslons字体,阴码点阵格式,逐行顺向取模 32*32
//存储在W25Q128中,中文字库存储在FLASH的起始地址:GBKCODE_START_ADDRESS
#define GBKCODE_START_ADDRESS 1254*4096
#define FONTS_WIDTH 32//字库字形宽度
#define FONTS_HEIGHT 32//字库字形高度
/****************************************************
@function:获取FLASH中文显示字库数据
@param: pBuffer:存储字库矩阵的缓冲区
c:要获取的文字
@return:void
@note:使用前需要确保W25Qxx能读写,并已烧录字库
****************************************************/
static void GetGBKCode_from_EXFlash( uint8_t * pBuffer, uint16_t c)
{
unsigned char High8bit = 0,Low8bit = 0;
unsigned int pos = 0;
High8bit= c >> 8; /* 取高8位数据 */
Low8bit= c & 0x00FF; /* 取低8位数据 */
/*GB2312 公式*/
pos = ((High8bit-0xa1)*94+Low8bit-0xa1)*FONTS_WIDTH*FONTS_HEIGHT/8;
W25Qxx_BufferRead(pBuffer,GBKCODE_START_ADDRESS+pos,FONTS_WIDTH*FONTS_HEIGHT/8); //读取字库数据
}
GBKCODE_START_ADDRESS这个和烧录时写入地址相同
完整代码看后面下载链接
2、显示中英文字符串
此程序参考野火
需要ILI93xx.h开启自己写的宏
#define LCD_EnableFontLibrary_W25Qxx//使能W25Qxx字库,可以使用字库中的中文,和相关显示函数
//LCD_DispString_EN_CH(0,0,"残梦箍CanMeng");
// LCD_DisplayStringEx(0,1*48,48,48,(uint8_t *)"野火BH",0);//显示48大小的字体
// LCD_DisplayStringEx(0,2*56,56,56,(uint8_t *)"野火BH",1);
// LCD_DisplayStringEx(0,3*56,24,24,(uint8_t *)"野火BH",1);
3、完整工程下载
链接:https://pan.baidu.com/s/1NiBKUR9AzwOZzJ7IA4JkMQ
提取码:p57d