1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban
本章将介绍使用APM32E103驱动TFTLCD(MCU屏)进行显示。通过本章的学习,读者将学习到EMMC(外部存储器控制器)中SMC(静态存储控制器)的使用。
本章分为如下几个小节:
25.1硬件设计
25.2 程序设计
25.3 下载验证
25.1 硬件设计
25.1.1 例程功能
图25.1.3.1 TFTLCD模块与MCU的连接原理图
从上图中可以看到,TFTLCD模块连接至SMC的存储块1的区域块4,并且使用了地址线A10作为TFTLCD模块命令或数据的选择信号,结合《APM32E103xCxE用户手册》,便可计算出配置好SMC后,TFTLCD模块的命令访问地址被映射到0x6C00007E,TFTLCD模块的数据访问地址被映射到0x6C000080。
25.2 程序设计
25.2.1 Geehy标准库的SMC驱动
本章实验通过SMC驱动8080并口的TFTLCD模块,通过SMC可以将TFTLCD模块的命令和数据寄存器映射为两个地址,往这两个地址写入或读取数据就可直接与TFTLCD模块进行通讯,因此需要对SMC做相应的配置,,具体的步骤如下:
①:配置SMC存储块1的区域块4
②:使能SMC存储块1的区域块4
在Geehy标准库中对应的驱动函数如下:
①:配置SMC存储块1的区域块
该函数用于配置SMC存储块1的区域块,其函数原型如下所示:
void SMC_ConfigNORSRAM(SMC_NORSRAMConfig_T* smcNORSRAMConfig);
该函数的形参描述,如下表所示:
形参 描述
smcNORSRAMConfig 指向SMC存储块1区域块配置结构体的指针
需自行定义,并根据SMC存储块1区域块的配置参数填充结构体中的成员变量
表25.2.1.1 函数SMC_ConfigNORSRAM()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表25.2.1.2 函数SMC_ConfigNORSRAM()返回值描述
该函数使用SMC_NORSRAMConfig_T类型的结构体变量传入SMC存储块1区域块的配置参数,该结构体的定义如下所示:
typedef enum
{
SMC_BANK1_NORSRAM_1, /* SMC存储块1区域块1 */
SMC_BANK1_NORSRAM_2, /* SMC存储块1区域块2 */
SMC_BANK1_NORSRAM_3, /* SMC存储块1区域块3 */
SMC_BANK1_NORSRAM_4 /* SMC存储块1区域块4 */
} SMC_BANK1_NORSRAM_T;
typedef enum
{
SMC_DATA_ADDRESS_MUX_DISABLE, /* 禁止数据地址总线复用 */
SMC_DATA_ADDRESS_MUX_ENABLE /* 使能数据地址总线复用 */
} SMC_DATA_ADDRESS_MUX_T;
typedef enum
{
SMC_MEMORY_TYPE_SRAM, /* SRAM */
SMC_MEMORY_TYPE_PSRAM, /* PSRAM */
SMC_MEMORY_TYPE_NOR /* NORFlash */
} SMC_MEMORY_TYPE_T;
typedef enum
{
SMC_MEMORY_DATA_WIDTH_8BIT, /* 8位数据宽度 */
SMC_MEMORY_DATA_WIDTH_16BIT /* 16位数据宽度 */
} SMC_MEMORY_DATA_WIDTH_T;
typedef enum
{
SMC_BURST_ACCESS_MODE_DISABLE, /* 禁用突发访问模式 */
SMC_BURST_ACCESS_MODE_ENABLE /* 使能突发访问模式 */
} SMC_BURST_ACCESS_MODE_T;
typedef enum
{
SMC_ASYNCHRONOUS_WAIT_DISABLE, /* 禁用异步等待 */
SMC_ASYNCHRONOUS_WAIT_ENABLE /* 使能异步等待 */
} SMC_ASYNCHRONOUS_WAIT_T;
typedef enum
{
SMC_WAIT_SIGNAL_POLARITY_LOW, /* 低电平有效 */
SMC_WAIT_SIGNAL_POLARITY_HIGH /* 高电平有效 */
} SMC_WAIT_SIGNAL_POLARITY_T;
typedef enum
{
SMC_WRAP_MODE_DISABLE, /* 禁止非对齐的突发访问 */
SMC_WRAP_MODE_ENABLE /* 使能非对齐的突发访问 */
} SMC_WRAP_MODE_T;
typedef enum
{
SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE, /* 在等待前有效 */
SMC_WAIT_SIGNAL_ACTIVE_DURING_WAIT_STATE /* 在等在阶段有效 */
} SMC_WAIT_SIGNAL_ACTIVE_T;
typedef enum
{
SMC_WRITE_OPERATION_DISABLE, /* 禁止写操作 */
SMC_WRITE_OPERATION_ENABLE /* 使能写操作 */
} SMC_WRITE_OPERATION_T;
typedef enum
{
SMC_WAITE_SIGNAL_DISABLE, /* 禁止等待信号 */
SMC_WAITE_SIGNAL_ENABLE /* 使能等待信号 */
} SMC_WAITE_SIGNAL_T;
typedef enum
{
SMC_EXTENDEN_MODE_DISABLE, /* 禁止扩展模式 */
SMC_EXTENDEN_MODE_ENABLE /* 使能扩展模式 */
} SMC_EXTENDEN_MODE_T;
typedef enum
{
SMC_WRITE_BURST_DISABLE, /* 禁止突发写 */
SMC_WRITE_BURST_ENABLE /* 使能突发写 */
} SMC_WRITE_BURST_T;
typedef enum
{
SMC_ACCESS_MODE_A, /* 访问模式A */
SMC_ACCESS_MODE_B, /* 访问模式B */
SMC_ACCESS_MODE_C, /* 访问模式C */
SMC_ACCESS_MODE_D /* 访问模式D */
} SMC_ACCESS_MODE_T;
typedef struct
{
uint8_t addressSetupTime; /* 地址建立时间 */
uint8_t addressHodeTime; /* 地址保持时间 */
uint8_t dataSetupTime; /* 数据建立时间 */
uint8_t busTurnaroundTime; /* 总线恢复时间 */
uint8_t clockDivision; /* 时钟分频系数 */
uint8_t dataLatency; /* 数据保持时间 */
SMC_ACCESS_MODE_T accessMode; /* 访问模式 */
} SMC_NORSRAMTimingConfig_T;
typedef struct
{
SMC_BANK1_NORSRAM_T bank; /* SMC存储块1区域块 */
SMC_DATA_ADDRESS_MUX_T dataAddressMux; /* 数据地址总线复用 */
SMC_MEMORY_TYPE_T memoryType; /* 存储器类型 */
SMC_MEMORY_DATA_WIDTH_T memoryDataWidth; /* 数据宽度 */
SMC_BURST_ACCESS_MODE_T burstAcceesMode; /* 突发访问模式 */
SMC_ASYNCHRONOUS_WAIT_T asynchronousWait; /* 异步等待 */
SMC_WAIT_SIGNAL_POLARITY_T waitSignalPolarity; /* 等待信号极性 */
SMC_WRAP_MODE_T wrapMode; /* 非对齐的突发访问 */
SMC_WAIT_SIGNAL_ACTIVE_T waitSignalActive; /* 等待时序 */
SMC_WRITE_OPERATION_T writeOperation; /* 写操作 */
SMC_WAITE_SIGNAL_T waiteSignal; /* 等待信号 */
SMC_EXTENDEN_MODE_T extendedMode; /* 扩展模式 */
SMC_WRITE_BURST_T writeBurst; /* 突发写 */
SMC_NORSRAMTimingConfig_T *readWriteTimingStruct; /* 读写时序 */
SMC_NORSRAMTimingConfig_T *writeTimingStruct; /* 写时序 */
} SMC_NORSRAMConfig_T;
该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_smc.h"
void example_fun(void)
{
SMC_NORSRAMConfig_T smc_norsram_init_struct;
SMC_NORSRAMTimingConfig_T smc_read_timing_struct;
SMC_NORSRAMTimingConfig_T smc_write_timing_struct;
/* 配置SMC读时序 */
smc_read_timing_struct.addressSetupTime = 0x0F;
smc_read_timing_struct.addressHodeTime = 0x00;
smc_read_timing_struct.dataSetupTime = 0x3C;
smc_read_timing_struct.busTurnaroundTime = 0;
smc_read_timing_struct.clockDivision = 0;
smc_read_timing_struct.dataLatency = 0;
smc_read_timing_struct.accessMode = SMC_ACCESS_MODE_A;
/* 配置SMC写时序 */
smc_write_timing_struct.addressSetupTime = 0x09;
smc_write_timing_struct.addressHodeTime = 0x00;
smc_write_timing_struct.dataSetupTime = 0x09;
smc_write_timing_struct.busTurnaroundTime = 0;
smc_write_timing_struct.clockDivision = 0;
smc_write_timing_struct.dataLatency = 0;
smc_write_timing_struct.accessMode = SMC_ACCESS_MODE_A;
/* 配置SMC存储块1区域块1 */
smc_norsram_init_struct.bank = SMC_BANK1_NORSRAM_1;
smc_norsram_init_struct.dataAddressMux = SMC_DATA_ADDRESS_MUX_DISABLE;
smc_norsram_init_struct.memoryType = SMC_MEMORY_TYPE_SRAM;
smc_norsram_init_struct.memoryDataWidth = SMC_MEMORY_DATA_WIDTH_16BIT;
smc_norsram_init_struct.burstAcceesMode = SMC_BURST_ACCESS_MODE_DISABLE;
smc_norsram_init_struct.asynchronousWait = SMC_ASYNCHRONOUS_WAIT_DISABLE;
smc_norsram_init_struct.waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
smc_norsram_init_struct.wrapMode = SMC_WRAP_MODE_DISABLE;
smc_norsram_init_struct.waitSignalActive =
SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
smc_norsram_init_struct.writeOperation = SMC_WRITE_OPERATION_ENABLE;
smc_norsram_init_struct.waiteSignal = SMC_WAITE_SIGNAL_DISABLE;
smc_norsram_init_struct.extendedMode = SMC_EXTENDEN_MODE_ENABLE;
smc_norsram_init_struct.writeBurst = SMC_WRITE_BURST_DISABLE;
smc_norsram_init_struct.readWriteTimingStruct = &smc_read_timing_struct;
smc_norsram_init_struct.writeTimingStruct = &smc_write_timing_struct;
SMC_ConfigNORSRAM(&smc_norsram_init_struct);
}
②:使能SMC存储块1的区域块
该函数用于使能SMC存储块1的区域块,其函数原型如下所示:
void SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_T bank);
该函数的形参描述,如下表所示:
形参 描述
bank SMC存储块1的区域块
例如:SMC_BANK1_NORSRAM_1、SMC_BANK1_NORSRAM_2等(在apm32e10x_smc.h文件中有定义)
表25.2.1.3 函数SMC_EnableNORSRAM()形参描述
该函数的返回值描述,如下表所示:
返回值 描述
无 无
表25.2.1.4 函数SMC_EnableNORSRAM()返回值描述
该函数的使用示例,图下所示:
#include "apm32e10x.h"
#include "apm32e10x_smc.h"
void example_fun(void)
{
/* 使能SMC存储块1区域块1 */
SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_1);
}
25.2.2 TFTLCD驱动
本章实验的TFTLCD驱动主要负责向应用层提供TFTLCD的初始化和各种TFTLCD显示的操作函数。本章实验中,TFTLCD的驱动代码包括lcd.c、lcd_ex.c、lcd.h和字体文件lcdfont.h四个文件。
由于TFTLCD模块需要使用到打量的GPIO引脚,因此对于GPIO的相关定义,请读者自行查看lcd.c和lcd.h这两个文件。
TFTLCD驱动中,TFTLCD的初始化函数,如下所示:
/**
* @brief 初始化LCD
* @param 无
* @retval 无
*/
void lcd_init(void)
{
GPIO_Config_T gpio_init_struct;
SMC_NORSRAMConfig_T smc_norsram_init_struct;
SMC_NORSRAMTimingConfig_T smc_read_timing_struct;
SMC_NORSRAMTimingConfig_T smc_write_timing_struct;
/* 使能时钟 */
LCD_WR_GPIO_CLK_ENABLE(); /* 使能SMC_NWE引脚端口时钟 */
LCD_RD_GPIO_CLK_ENABLE(); /* 使能SMC_NOE引脚端口时钟 */
LCD_BL_GPIO_CLK_ENABLE(); /* 使能LCD_BL引脚端口时钟 */
LCD_CS_GPIO_CLK_ENABLE(); /* 使能SMC_NE4引脚端口时钟 */
LCD_RS_GPIO_CLK_ENABLE(); /* 使能SMC_A6引脚端口时钟 */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_SMC); /* 使能EMMC时钟 */
/* 使能SMC_D0/1/2/3/13/14/15引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
/* 使能SMC_D4/5/6/7/8/9/10/11/12引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
/* 配置SMC_NWE引脚 */
gpio_init_struct.pin = LCD_WR_GPIO_PIN; /* SMC_NWE引脚 */
gpio_init_struct.mode = GPIO_MODE_AF_PP; /* 复用功能模式 */
gpio_init_struct.speed = GPIO_SPEED_50MHz; /* 高速 */
GPIO_Config(LCD_WR_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NWE引脚 */
/* 配置SMC_NOE引脚 */
gpio_init_struct.pin = LCD_RD_GPIO_PIN; /* SMC_NOE引脚 */
GPIO_Config(LCD_RD_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NOE引脚 */
/* 配置SMC_NEx引脚 */
gpio_init_struct.pin = LCD_CS_GPIO_PIN; /* SMC_NEx引脚 */
GPIO_Config(LCD_CS_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NEx引脚 */
/* 配置SMC_Ay引脚 */
gpio_init_struct.pin = LCD_RS_GPIO_PIN; /* SMC_Ay引脚 */
GPIO_Config(LCD_RS_GPIO_PORT, &gpio_init_struct);/* 配置SMC_Ay引脚 */
/* 配置SMC_Dn引脚 */
gpio_init_struct.pin = GPIO_PIN_14 | /* SMC_D0 */
GPIO_PIN_15 | /* SMC_D1 */
GPIO_PIN_0 | /* SMC_D2 */
GPIO_PIN_1 | /* SMC_D3 */
GPIO_PIN_8 | /* SMC_D13 */
GPIO_PIN_9 | /* SMC_D14 */
GPIO_PIN_10; /* SMC_D15 */
GPIO_Config(GPIOD, &gpio_init_struct); /* 配置SMC_Dn引脚 */
gpio_init_struct.pin = GPIO_PIN_7 | /* SMC_D4 */
GPIO_PIN_8 | /* SMC_D5 */
GPIO_PIN_9 | /* SMC_D6 */
GPIO_PIN_10 | /* SMC_D7 */
GPIO_PIN_11 | /* SMC_D8 */
GPIO_PIN_12 | /* SMC_D9 */
GPIO_PIN_13 | /* SMC_D10 */
GPIO_PIN_14 | /* SMC_D11 */
GPIO_PIN_15; /* SMC_D12 */
GPIO_Config(GPIOE, &gpio_init_struct); /* 配置SMC_Dn引脚 */
/* 配置LCD_BL引脚 */
gpio_init_struct.pin = LCD_BL_GPIO_PIN; /* LCD_BL引脚 */
gpio_init_struct.mode = GPIO_MODE_OUT_PP; /* 通用输出模式 */
GPIO_Config(LCD_BL_GPIO_PORT, &gpio_init_struct);/* 配置LCD_BL引脚 */
/* 配置SMC读时序 */
smc_read_timing_struct.addressSetupTime = 1; /* 地址建立时间 */
smc_read_timing_struct.addressHodeTime = 0; /* 地址保持时间 */
smc_read_timing_struct.dataSetupTime = 26; /* 数据建立时间 */
/* 访问模式 */
smc_read_timing_struct.accessMode = SMC_ACCESS_MODE_A;
/* 配置SMC写时序 */
smc_write_timing_struct.addressSetupTime = 1; /* 地址建立时间 */
smc_write_timing_struct.addressHodeTime = 0; /* 地址保持时间 */
smc_write_timing_struct.dataSetupTime = 3; /* 数据建立时间 */
/* 访问模式 */
smc_write_timing_struct.accessMode = SMC_ACCESS_MODE_A;
/* 配置SMC */
smc_norsram_init_struct.bank = SMC_BANK1_NORSRAM_4;/* 使用SMC_NE4 */
/* 禁止数据、地址总线复用 */
smc_norsram_init_struct.dataAddressMux = SMC_DATA_ADDRESS_MUX_DISABLE;
/* SRAM类型 */
smc_norsram_init_struct.memoryType = SMC_MEMORY_TYPE_SRAM;
/* 16位数据宽度 */
smc_norsram_init_struct.memoryDataWidth = SMC_MEMORY_DATA_WIDTH_16BIT;
/* 禁止突发访问 */
smc_norsram_init_struct.burstAcceesMode = SMC_BURST_ACCESS_MODE_DISABLE;
/* 禁止异步传输期间的等待信号 */
smc_norsram_init_struct.asynchronousWait = SMC_ASYNCHRONOUS_WAIT_DISABLE;
/* 配置等待信号极性,仅在突发访问模式下有效 */
smc_norsram_init_struct.waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
/* 禁止非对齐的突发访问 */
smc_norsram_init_struct.wrapMode = SMC_WRAP_MODE_DISABLE;
/* 配置等待时序 */
smc_norsram_init_struct.waitSignalActive = SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
/* 使能写存储器 */
smc_norsram_init_struct.writeOperation = SMC_WRITE_OPERATION_ENABLE;
/* 禁止等待信号 */
smc_norsram_init_struct.waiteSignal = SMC_WAITE_SIGNAL_DISABLE;
/* 使能扩展模式 */
smc_norsram_init_struct.extendedMode = SMC_EXTENDEN_MODE_ENABLE;
/* 使能突发写 */
smc_norsram_init_struct.writeBurst = SMC_WRITE_BURST_DISABLE;
/* 读时序 */
smc_norsram_init_struct.readWriteTimingStruct = &smc_read_timing_struct;
/* 写时序 */
smc_norsram_init_struct.writeTimingStruct = &smc_write_timing_struct;
/* 配置SMC */
SMC_ConfigNORSRAM(&smc_norsram_init_struct);
/* 使能存储块1区域块4 */
SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_4);
delay_ms(50);
/* 尝试9341 ID的读取 */
lcd_wr_regno(0xD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0x00 */
lcddev.id = lcd_rd_data(); /* 读取93 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取41 */
if (lcddev.id != 0x9341) /* 不是 9341 , 尝试看看是不是 ST7789 */
{
lcd_wr_regno(0x04);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0x85 */
lcddev.id = lcd_rd_data(); /* 读取0x85 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data();/* 读取0x52 */
if (lcddev.id == 0x8552) /* 将8552的ID转换成7789 */
{
lcddev.id = 0x7789;
}
if (lcddev.id != 0x7789) /* 也不是ST7789, 尝试是不是 NT35310 */
{
lcd_wr_regno(0xD4);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0x01 */
lcddev.id = lcd_rd_data(); /* 读回0x53 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 这里读回0x10 */
if (lcddev.id != 0x5310) /* 也不是NT35310,尝试看看是不是ST7796 */
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X00 */
lcddev.id = lcd_rd_data(); /* 读取0X77 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X96 */
if (lcddev.id != 0x7796) /* 也不是ST7796,尝试看看是不是NT35510 */
{
/* 发送密钥(厂家提供) */
lcd_write_reg(0xF000, 0x0055);
lcd_write_reg(0xF001, 0x00AA);
lcd_write_reg(0xF002, 0x0052);
lcd_write_reg(0xF003, 0x0008);
lcd_write_reg(0xF004, 0x0001);
lcd_wr_regno(0xC500); /* 读取ID低八位 */
lcddev.id = lcd_rd_data(); /* 读回0x80 */
lcddev.id <<= 8;
lcd_wr_regno(0xC501); /* 读取ID高八位 */
lcddev.id |= lcd_rd_data(); /* 读回0x00 */
delay_ms(5); /* 等待5ms, 因为0XC501指令对1963来说就是软件复位指 令, 等待5ms让1963复位完成再操作 */
if (lcddev.id != 0x5510)/*也不是NT5510,尝试看看是不是ILI9806*/
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0X00 */
lcddev.id = lcd_rd_data(); /* 读回0X98 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0X06 */
/* 也不是ILI9806,尝试看看是不是SSD1963 */
if (lcddev.id != 0x9806)
{
lcd_wr_regno(0xA1);
lcddev.id = lcd_rd_data();
lcddev.id = lcd_rd_data(); /* 读回0x57 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0x61 */
/* SSD1963读回的ID是5761H,为方便区分,我们强制设置为1963 */
if (lcddev.id == 0x5761) lcddev.id = 0x1963;
}
}
}
}
}
}
if (lcddev.id == 0x7789)
{
lcd_ex_st7789_reginit(); /* 执行ST7789初始化 */
}
else if (lcddev.id == 0x9341)
{
lcd_ex_ili9341_reginit(); /* 执行ILI9341初始化 */
}
else if (lcddev.id == 0x5310)
{
lcd_ex_nt35310_reginit(); /* 执行NT35310初始化 */
}
else if (lcddev.id == 0x7796)
{
lcd_ex_st7796_reginit();
}
else if (lcddev.id == 0x5510)
{
lcd_ex_nt35510_reginit(); /* 执行NT35510初始化 */
}
else if (lcddev.id == 0x9806)
{
lcd_ex_ili9806_reginit();
}
else if (lcddev.id == 0x1963)
{
lcd_ex_ssd1963_reginit(); /* 执行SSD1963初始化 */
lcd_ssd_backlight_set(100); /* 背光设置为最亮 */
}
lcd_display_dir(0); /* 默认设置为竖屏 */
LCD_BL(1); /* 点亮背光 */
lcd_clear(WHITE); /* 清屏 */
}
从上的代码中可以看出,本章实验的TFTLCD驱动是兼容了正点原子的多款TFTLCD模块的,因此在初始化完SMC后,会与TFTLCD进行通讯,确定TFTLCD的型号,然后根据型号针对性地对TFTLCD模块进行配置。
TFTLCD驱动中与TFTLCD模块通讯的函数,如下所示:
/**
* @brief LCD写数据
* @param data: 要写入的数据
* @retval 无
*/
void lcd_wr_data(volatile uint16_t data)
{
data = data;
LCD->LCD_RAM = data;
}
/**
* @brief LCD写寄存器编号或地址
* @param regno: 寄存器编号或地址
* @retval 无
*/
void lcd_wr_regno(volatile uint16_t regno)
{
regno = regno;
LCD->LCD_REG = regno;
}
/**
* @brief LCD写寄存器
* @param regno: 寄存器编号
* @param data : 要写入的数据
* @retval 无
*/
void lcd_write_reg(uint16_t regno, uint16_t data)
{
LCD->LCD_REG = regno;
LCD->LCD_RAM = data;
}
/**
* @brief LCD读数据
* @param 无
* @retval 读取到的数据
*/
static uint16_t lcd_rd_data(void)
{
volatile uint16_t ram;
ram = LCD->LCD_RAM;
return ram;
}
从上面的代码中可以看出,与TFTLCD的通讯都是通过LCD这一结构体对象来完成的,对于LCD结构体的相关定义,如下所示:
#define LCD_SMC_NEX 4
#define LCD_SMC_AX 10
typedef struct
{
volatile uint16_t LCD_REG;
volatile uint16_t LCD_RAM;
} LCD_TypeDef;
从LCD结构体的相关定义中可以看出,与TFTLCD模块的通讯地址是与TFTLCD连接的SMC存储块1的区域块和TFTLCD模块命令、数据选择信号所连接的SMC地址线是有关的。通过上面宏定义的计算,可以算出LCD_BASE宏定义的值为0x6C00007E,因此访问LCD->LCD_REG就是访问0x6C00007E这一地址,访问LCD->LCD_RAM就是访问0x6C000080这一地址,这两个地址也就是通过SMC映射的TFTLCD命令和数据寄存器的访问地址。
通过上面介绍的驱动函数就能够与TFTLCD模块进行通讯了,而在TFTLCD模块的显示屏上显示出特定的图案或字符或设置TFTLCD模块的显示方向等等的操作都是能够通过TFTLCD模块规定的特定命令来完成的,想深究的读者可以产看正点原子TFTLCD模块的用户手册或查看实际使用的TFTLCD模块的相关文档。
25.2.3 实验应用代码
本实验的应用代码,如下所示:
int main(void)
{
uint8_t x = 0;
uint8_t lcd_id[12];
NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4); /* 设置中断优先级分组为组4 */
sys_apm32_clock_init(15); /* 配置系统时钟 */
delay_init(120); /* 初始化延时功能 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
/* 显示LCD屏ID信息 */
sprintf((char *)lcd_id, "LCD ID: %04X", lcddev.id);
while (1)
{
switch (x)
{
case 0:
{
lcd_clear(WHITE);
break;
}
case 1:
{
lcd_clear(BLACK);
break;
}
case 2:
{
lcd_clear(BLUE);
break;
}
case 3:
{
lcd_clear(RED);
break;
}
case 4:
{
lcd_clear(MAGENTA);
break;
}
case 5:
{
lcd_clear(GREEN);
break;
}
case 6:
{
lcd_clear(CYAN);
break;
}
case 7:
{
lcd_clear(YELLOW);
break;
}
case 8:
{
lcd_clear(BRRED);
break;
}
case 9:
{
lcd_clear(GRAY);
break;
}
case 10:
{
lcd_clear(LGRAY);
break;
}
case 11:
{
lcd_clear(BROWN);
break;
}
}
lcd_show_string(10, 40, 240, 32, 32, "APM32", RED);
lcd_show_string(10, 80, 240, 24, 24, "TFTLCD TEST", RED);
lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(10, 130, 240, 16, 16, (char *)lcd_id, RED);
x++;
if (x == 12)
{
x = 0;
}
LED0_TOGGLE();
delay_ms(1000);
}
}
从上面的代码中可以看出,在初始化完LCD后,便在LCD上显示一些本实验的相关信息,随后便每间隔1000毫秒就更换一次LCD屏幕显示的背景色。