61-DMA-LCM液晶屏接口测试,STC32G144K246实验箱演示程序
61-DMA-LCM液晶屏接口测试,STC32G144K246实验箱演示程序LCD1602显示程序-硬件M6800并行接口+DMA刷新,主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/*---------------------------------------------------------------------*/
/************* 功能说明 **************
本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。
LCM1602字符液晶模块,8位数据,全部由LCM DMA驱动,节省CPU时间(LCD1602用IO方式访问速度很慢!)。
使用3.3V的LCD1602模块。
请先别修改程序, 直接下载"LCD1602.hex"测试.
下载时, 选择时钟 48MHz (用户可自行修改频率).
*******************************************/
#include "..\..\comm\STC32G144K246.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/****************用户定义宏****************/
#define MAIN_Fosc 48000000UL //定义主时钟
/****************IO口定义******************/
sfr LCD_DATA = 0xa0; //P0--0x80,P1--0x90,P2--0xa0,P3--0xb0
sbit LCD_B7= P2^7; //Pin 14 B3--Pin 10 LED+ -- Pin 15
//Pin 13 B2--Pin 9 LED- -- Pin 16
//Pin 12 B1--Pin 8 Vo -- Pin 3
//Pin 11 B0--Pin 7 VDD-- Pin 2 VSS -- Pin 1
sbit LCD_ENA = P4^4; //Pin 6
sbit LCD_RW= P4^2; //Pin 5//LCD_RS R/W DB7--DB0 FOUNCTION
sbit LCD_RS= P4^5; //Pin 4// 0 0 INPUT write the command to LCD model
// 0 1 OUTPUT read BF and AC pointer from LCD model
// 1 0 INPUT write the data to LCDmodel
// 1 1 OUTPUT read the data from LCD model
/****************本地常量声明**************/
const u8text1[] = {" LCD1602 8-DATA "};
const u8text2[] = {" STC32G144K246"};
const u8text3[] = {"2025-12-25 18:59"};
const u8text4[] = {" www.STCAI.com"};
/****************本地变量声明**************/
u16 LCM_TxCnt; //LCM DMA触发发送次数, 一次16字节, 一共64次
bit B_LCM_DMA_busy; //LCM DMA忙标志, 1标志LCM-DMA忙,LCM DMA中断中清除此标志,使用LCM DMA前要确认此标志为0
bit B_TxCmd; //已发送命令标志
u8xdata CmdTmp; //命令缓冲
u8xdata DisTmp1;//第一行显示缓冲,将要显示的内容放在显存里,启动DMA即可.
u8xdata DisTmp2;//第二行显示缓冲,将要显示的内容放在显存里,启动DMA即可.
/****************本地函数声明**************/
/******************************************************************************
HD44780U LCD_MODUL DRIVE PROGRAMME
*******************************************************************************
total 2 lines, 16x2= 32
first line address:0~15
second line address: 64~79
total 2 lines, 20x2= 40
first line address:0~19
second line address: 64~83
total 2 lines, 40x2= 80
first line address:0~39
second line address: 64~103
*/
#define C_CLEAR 0x01 //clear LCD
#define C_HOME 0x02 //cursor go home
#define C_CUR_L 0x04 //cursor shift left after input
#define C_RIGHT 0x05 //picture shift right after input
#define C_CUR_R 0x06 //cursor shift right after input
#define C_LEFT 0x07 //picture shift left after input
#define C_OFF 0x08 //turn off LCD
#define C_ON 0x0C //turn onLCD
#define C_FLASH 0x0D //turn onLCD, flash
#define C_CURSOR 0x0E //turn onLCD and cursor
#define C_FLASH_ALL 0x0F //turn onLCD and cursor, flash
#define C_CURSOR_LEFT 0x10 //single cursor shift left
#define C_CURSOR_RIGHT 0x10 //single cursor shift right
#define C_PICTURE_LEFT 0x10 //single picture shift left
#define C_PICTURE_RIGHT 0x10 //single picture shift right
#define C_BIT8 0x30 //set the data is 8 bits
#define C_BIT4 0x20 //set the data is 8 bits
#define C_L1DOT7 0x30 //8 bits,one line 5*7dots
#define C_L1DOT10 0x34 //8 bits,one line 5*10 dots
#define C_8bitL2DOT7 0x38 //8 bits,tow lines 5*7 dots
#define C_4bitL2DOT7 0x28 //4 bits,tow lines 5*7 dots
#define C_CGADDRESS0 0x40 //CGRAM address0 (addr=40H+x)
#define C_DDADDRESS0 0x80 //DDRAM address0 (addr=80H+x)
//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注: 由于芯片使能了Cache功能,软件延时时间可能不太准确
//========================================================================
void delay_ms(u16 ms)
{
u16 i;
do{
i = MAIN_Fosc / 6000;
while(--i);
}while(--ms);
}
//******************** LCD40 Module END ***************************
//========================================================================
// 函数: void LCM_Config(void)
// 描述: LCM配置函数。ST7920 @540KHz,清屏指令典型时间为1.6ms,读忙信号0us, 写入、读出数据、命令72us. 本例子DMA刷新时间84ms @24MHz.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
//LCMIFCFG(7EFE50H) TFT彩屏接口配置寄存器
#define LCMIFIE (0<<7) //TFT彩屏接口中断使能控制位(bit7), 1->允许中断,0->禁止
#define LCMIFIP (0<<4) //TFT彩屏接口中断优先级控制位(bit5~bit4), (最低)0~3(最高).
#define LCMIFDPS (0<<2) //TFT彩屏接口数据脚选择位(bit3~bit2), D18_D8=0: 0或2->8位数据在P2, D18_D8=1: 0: P2-高字节, P0低字节, 2: P2-高字节,低字节P0 P4.7 P4.6 P4.3 P4.1.
#define LCM_D16_D8 (0<<1) //TFT彩屏接口数据宽度控制位(bit1), 0: 8位数据,1:16位数据
#define LCM_M68_I80 1 //TFT彩屏接口数据模式选择位(bit0), 0: I8080模式,1:M6800模式
//LCMIFCFG2(7EFE51H) TFT彩屏接口配置寄存器2
#define LCMIFCPS (0<<5) //TFT彩屏接口控制脚选择位(bit6~bit5), RS RD(E) WR(RW), 0->P4.5 P4.4 P4.2,1->P4.5 P3.7 P3.6, 2->P4.0 P4.4 P4.2, 3->P4.0 P3.7 P3.6
#define LCMSETUPT (4<<2) //TFT彩屏接口数据建立时间控制位(bit4~bit2), 0~7, 对应1~8个LCMIF时钟, 对于6800模式就是E高电平时间, 至少20us.
#define LCMHOLDT 3 //TFT彩屏接口数据保持时间控制位(bit1~bit0), 0~3, 对应1~4个LCMIF时钟
//LCMIFCR(7EFE52H) TFT彩屏接口控制寄存器
#define ENLCMIF (1<<7) //TFT彩屏接口使能控制位(bit7), 1->允许TFT彩屏接口功能, 0->禁止
#define LCM_WRCMD 4 //TFT彩屏接口触发命令(bit2~bit0), 4->写命令
#define LCM_WRDAT 5 //TFT彩屏接口触发命令(bit2~bit0), 5->写数据
#define LCM_RDCMD 6 //TFT彩屏接口触发命令(bit2~bit0), 6->读命令/状态
#define LCM_RDDAT 7 //TFT彩屏接口触发命令(bit2~bit0), 7->读数据
void LCM_Config(void)
{
LCMIFCFG= LCMIFIE| LCMIFIP | LCMIFDPS | LCM_D16_D8 | LCM_M68_I80;
LCMIFCFG2 = LCMIFCPS | LCMSETUPT | LCMHOLDT; //RS:P45,E:P44,RW:P42; Setup Time,HOLD Time
LCMIFSTA= 0x00; //TFT彩屏接口中断请求标志,软件清0
LCMIFPSCR = (u8)(MAIN_Fosc/250000UL-1); //TFT彩屏接口时钟预分频0~255, LCMIF时钟频率 = SYSclk/(LCMIFPSCR+1), LCD1602速度慢,最快250KHz
LCMIFCR = ENLCMIF;
}
void CheckBusy(void) //检测忙标志
{
LCMIFSTA = 0; //清除完成标志
do
{
LCMIFCR = ENLCMIF | LCM_RDCMD; //读状态
while((LCMIFSTA & 1) == 0); //等待读完成
LCMIFSTA = 0; //清除完成标志
LCD_ENA = 0;
}while(LCMIFDATL & 0x80); //bit7==0则空闲
}
/**********************************************/
void IniSendCMD(u8 cmd) //write the command to LCD
{
LCMIFDATL = cmd;
LCMIFCR = ENLCMIF | LCM_WRCMD; //写命令
while((LCMIFSTA & 1) == 0); //等待写完成
LCMIFSTA = 0; //清除完成标志
}
/**********************************************/
void Write_CMD(u8 cmd)//write the command to LCD
{
CheckBusy(); //检测忙
LCMIFDATL = cmd;
LCMIFCR = ENLCMIF | LCM_WRCMD; //写命令
while((LCMIFSTA & 1) == 0); //等待写完成
LCMIFSTA = 0; //清除完成标志
}
/********* 初始化函数 **************************/
void Initialize_LCD(void) //intilize LCD, input none, output none
{
LCD_ENA = 0;
LCD_RS= 0;
LCD_RW= 0;
delay_ms(100);
IniSendCMD(C_BIT8); //set the data is 4 bits
delay_ms(10);
IniSendCMD(C_BIT8); //set the data is 4 bits
delay_ms(10);
IniSendCMD(C_8bitL2DOT7); //tow lines 5*7 dots
delay_ms(6);
Write_CMD(C_CLEAR); //clear LCD RAM
Write_CMD(C_CUR_R); //Curror Shift Right
Write_CMD(C_ON); //turn onLCD
}
//========================================================================
// 函数: void DMA_Config(u8 xdata *pic)
// 描述: LCM DMA配置函数。
// 参数: *pic: 数据首地址.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
//DMA_LCM_CR (7EfA71H) LCM_DMA控制寄存器
#define DMA_ENLCM (1<<7) // LCM DMA功能使能控制位, bit7, 0:禁止LCM DMA功能,1:允许LCM DMA功能。
#define LCM_TRIGWC (1<<6) // LCM DMA触发写命令,bit6, 0:写0无效, 1:写1开始LCM DMA开始写命令。
#define LCM_TRIGWD (1<<5) // LCM DMA触发写数据,bit5, 0:写0无效, 1:写1开始LCM DMA开始写数据。
#define LCM_TRIGRC (1<<4) // LCM DMA触发读命令,bit4, 0:写0无效, 1:写1开始LCM DMA开始读命令。
#define LCM_TRIGRD (1<<3) // LCM DMA触发读数据,bit3, 0:写0无效, 1:写1开始LCM DMA开始读数据。
#define LCM_CLRFIFO 0 // 清除LCM DMA接收FIFO控制位,bit0, 0:写0无效,1:写1复位FIFO指针。
//DMA_LCM_CFG(7EfA70H) LCM_DMA配置寄存器
#define DMA_LCMIE (1<<7) // LCM DMA中断使能控制位,bit7, 0:禁止SPI DMA中断, 1:允许中断。
#define DMA_LCMIP (0<<2) // LCM DMA中断优先级控制位,bit3~bit2, (最低)0~3(最高).
#define DMA_LCMPTY 0 // LCM DMA数据总线访问优先级控制位,bit1~bit0, (最低)0~3(最高).
//DMA_LCM_STA(7EfA72) LCM_DMA状态寄存器
#define LCM_TXOVW (1<<1) // LCM DMA数据覆盖标志位,bit1, 软件清0.
#define DMA_LCMIF 1 // LCM DMA中断请求标志位,bit0, 软件清0.
void LCM_DMA_Trig(void)
{
DMA_LCM_STA= 0x00;
DMA_LCM_CFG= DMA_LCMIE | DMA_LCMIP | DMA_LCMPTY;;
DMA_LCM_ITVH = 0; //设置传输间隔时间(高8位),对应N+1个LCMIF时钟(1~65536个LCMIF时钟)
DMA_LCM_ITVL = 9-1; //设置传输间隔时间(低8位)
B_TxCmd = 0; //已发送命令标志
LCM_TxCnt = 0; //LCM DMA触发发送次数, 一次16字节, 一共64次
B_LCM_DMA_busy = 1; //标志LCM-DMA忙,LCM DMA中断中清除此标志,使用LCM DMA前要确认此标志为0
DMA_LCM_STA = DMA_LCMIF; //软件触发LCM DMA中断,启动发送
}
//========================================================================
// 函数: void LCMIF_DMA_ISR(void) interrupt DMA_LCM_VECTOR
// 描述: LCM DMA中断函数。中断处理时间:2.3us @24MHz. 刷新时间:84ms @24MHz.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
void LCMIF_DMA_ISR(void) interrupt DMA_LCM_VECTOR
{
if(DMA_LCM_STA & DMA_LCMIF)
{
if(LCM_TxCnt >= 2) //判断发送是否完毕
{
DMA_LCM_CR = 0;
B_LCM_DMA_busy = 0; //清除LCM-DMA忙标志,LCM DMA中断中清除此标志,使用LCM DMA前要确认此标志为0
}
else //仍有数据要发送
{
if(!B_TxCmd) //还没有发设置地址命令,则先发设置地址命令
{
B_TxCmd = 1; //指示已发地址命令
if(LCM_TxCnt == 0) //第一行地址设置命令
{
LCD_RS = 0; //写命令
LCD_RW = 0;
CmdTmp = 0x80; //第一行AC地址
}
else if(LCM_TxCnt == 1) //第二行地址设置命令
{
LCD_RS = 0; //写命令
LCD_RW = 0;
CmdTmp = 0x80 | 64;//第二行AC地址
}
DMA_LCM_TXAH = (u8)((u16)CmdTmp >> 8);//LCM DMA发送命令首地址
DMA_LCM_TXAL = (u8)CmdTmp;
DMA_LCM_AMTH = 0; //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_LCM_AMT= 1-1; //设置传输总字节数(低8位).
DMA_LCM_CR = DMA_ENLCM | LCM_TRIGWC; //启动LCM DMA发送命令
}
else //写数据
{
LCD_RS = 1; //写显示数据
LCD_RW = 0;
B_TxCmd = 0; //清除已发地址命令
if(LCM_TxCnt == 0) //第一行显示缓冲地址
{
DMA_LCM_TXAH = (u8)((u16)DisTmp1 >> 8); //LCM DMA发送数据首地址
DMA_LCM_TXAL = (u8)DisTmp1;
}
else //if(LCM_TxCnt == 1) //第二行显示缓冲地址
{
DMA_LCM_TXAH = (u8)((u16)DisTmp2 >> 8); //LCM DMA发送数据首地址
DMA_LCM_TXAL = (u8)DisTmp2;
}
DMA_LCM_AMTH = 0; //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_LCM_AMT= 16-1; //设置传输总字节数(低8位).
DMA_LCM_CR = DMA_ENLCM | LCM_TRIGWD;//启动LCM DMA发送数据
LCM_TxCnt++; //发送行数+1
}
}
}
DMA_LCM_STA = 0;
}
/*************** 主函数 *******************************/
void main(void)
{
u16 i;
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 1; //避免 DMA 与 CPU 同时访问 xdata 时产生总线冲突
P4M0 |= 0x34; //RS,WR,RD设置成推挽输出
P4M1 &= ~0x34;
P5M0 |= 0x02; //RST设置成推挽输出
P5M1 &= ~0x02;
P2BP &= ~0xff; //使能LCM的D8~D15数据脚硬件自动设置端口模式
delay_ms(100); //等待一下,等LCD讲入工作状态
LCM_Config();
Initialize_LCD(); //初始化LCD
EA = 1;
while (1)
{
if(!B_LCM_DMA_busy) //DMA空闲
{
for(i=0; i<16; i++) //将要显示的文本装载到显存
{
DisTmp1= text1;//加载第一行显存
DisTmp2 = text2; //加载第二行显存
}
LCM_DMA_Trig(); //启动DMA,显示文本
}
delay_ms(2000);
if(!B_LCM_DMA_busy) //DMA空闲
{
for(i=0; i<16; i++) //将要显示的文本装载到显存
{
DisTmp1 = text3; //加载第一行显存
DisTmp2 = text4; //加载第二行显存
}
LCM_DMA_Trig(); //启动DMA,显示文本
}
delay_ms(2000);
}
}
61-DMA-LCM液晶屏接口测试,STC32G144K246实验箱演示程序
TFT320240显示程序-硬件I8080并行接口+DMA刷新,主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/*---------------------------------------------------------------------*/
/*************功能说明 **************
本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
LCM接口+DMA驱动液晶屏程序
16bit I8080模式, P0口接D0~D7, P2口接D8~D15
sbit LCD_RS = P4^5;
sbit LCD_WR = P4^2;
sbit LCD_RD = P4^4;
sbit LCD_RESET = P5^1;
DMA设置长度2048字节,通过中断方式判断传输完成
下载时, 选择IRC频率 48MHz,主时钟使用 PLL 90MHz 时钟频率.
******************************************/
#include "..\..\comm\STC32G144K246.h"
#include "font.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/****************用户定义宏****************/
#define SEL_HPLL1 1
#define SEL_HPLL2 2
#define HPLL_SEL SEL_HPLL2
#if(HPLL_SEL==SEL_HPLL1)
#define MAIN_Fosc 120000000L //定义主时钟(超频)
#else
#define MAIN_Fosc 90000000L//定义主时钟
#endif
/****************IO口定义******************/
sbit LCD_RS = P4^5;
sbit LCD_WR = P4^2;
sbit LCD_RD = P4^4;
sbit LCD_RESET = P5^1;
#define LCD_CS_H()P9SETB= 0x08//P93 = 1
#define LCD_CS_L()P9CLRB= 0x08//P93 = 0
//IO连接
//#defineLCD_DataPortH P2 //高8位数据口,8位模式下只使用高8位
//#defineLCD_DataPortL P0 //低8位数据口,8位模式下低8位可以不接线
/****************本地常量声明**************/
//支持横竖屏快速定义切换
#define USE_HORIZONTAL 3 //定义液晶屏顺时针旋转方向 0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
//定义LCD的尺寸
#define LCD_W 240
#define LCD_H 320
#define DMA_AMT_LEN2047//n+1
/****************本地变量声明**************/
u16 POINT_COLOR=0x0000; //画笔颜色
u16 index;
u16 xdata Color;
bit DmaFlag;
bit LcmFlag;
typedef struct
{
u16 width; //LCD 宽度
u16 height; //LCD 高度
u16 id; //LCD ID
u8dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
u8 wramcmd; //开始写gram指令
u8 rramcmd; //开始读gram指令
u8 setxcmd; //设置x坐标指令
u8 setycmd; //设置y坐标指令
}_lcd_dev;
_lcd_dev lcddev;
/****************本地函数声明**************/
void HPLL_config(void);
void delay_ms(u16 ms);
void GPIO_Init(void);
void LCM_Config(void);
void DMA_Config(void);
void LCD_Init(void);
void Test_Color(void);
void LCD_WR_DATA_16Bit(u16 Data);
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);
void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode);
void LCD_direction(u8 direction);
/**********************************************/
void main(void)
{
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 1; //避免 DMA 与 CPU 同时访问 xdata 时产生总线冲突
HPLL_config();
GPIO_Init();
LCM_Config();
DMA_Config();
EA = 1;
LCD_Init(); //LCM初始化
while(1)
{
Test_Color();
}
}
//========================================================================
// 函数: void HPLL_config(void)
// 描述: PLL时钟配置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注:
//========================================================================
void HPLL_config(void)
{
#if(HPLL_SEL==SEL_HPLL2)
WTST = 2; //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:360MHz/2/2=90MHz, 读Flash速度:90MHz/(1+2)=30MHz
HPLLCR |= 0x80; //使能HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)
//首先需要将HIRC主频调节到48MHz
HPLL2CR &= ~0x10; //选择HPLL2输入时钟源为HIRC
// HPLL2CR |= 0x10; //选择HPLL2输入时钟源为IRCM
HPLL2PDIV = 8; //设置HPLL2输入时钟预分频为8(HPLL输入频率必须为6MHz)
// HPLL2CR |= 0x00; //HPLL2=6MHz*52=312MHz
// HPLL2CR |= 0x01; //HPLL2=6MHz*54=324MHz
// HPLL2CR |= 0x02; //HPLL2=6MHz*56=336MHz
// HPLL2CR |= 0x03; //HPLL2=6MHz*58=348MHz
HPLL2CR |= 0x04; //HPLL2=6MHz*60=360MHz
// HPLL2CR |= 0x05; //HPLL2=6MHz*62=372MHz
// HPLL2CR |= 0x06; //HPLL2=6MHz*64=384MHz
// HPLL2CR |= 0x07; //HPLL2=6MHz*66=396MHz
// HPLL2CR |= 0x08; //HPLL2=6MHz*68=408MHz
// HPLL2CR |= 0x09; //HPLL2=6MHz*70=420MHz
// HPLL2CR |= 0x0a; //HPLL2=6MHz*72=432MHz
// HPLL2CR |= 0x0b; //HPLL2=6MHz*74=444MHz
// HPLL2CR |= 0x0c; //HPLL2=6MHz*76=456MHz
// HPLL2CR |= 0x0d; //HPLL2=6MHz*78=468MHz
// HPLL2CR |= 0x0e; //HPLL2=6MHz*80=480MHz
// HPLL2CR |= 0x0f; //HPLL2=6MHz*82=492MHz
HPLL2CR |= 0x20; //高速外设时钟选择 HPLL2/2
HPLL2CR |= 0x80; //使能HPLL2
HPLLCR &= ~0x80; //关闭HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)
CLKDIV = 2; //系统时钟 = 主时钟源/2 = HPLL2/2/2 = 90MHz
CLKSEL = 0x08; //选择HPLL2/2作为主时钟源
#else
WTST = 3; //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:480MHz/2/2=120MHz, 读Flash速度:120MHz/(1+3)=30MHz
//首先需要将HIRC主频调节到48MHz
HPLLCR &= ~0x10; //选择HPLL输入时钟源为HIRC
// HPLLCR |= 0x10; //选择HPLL输入时钟源为IRCM
HPLLPDIV = 8; //设置HPLL输入时钟预分频为8(HPLL输入频率必须为6MHz)
// HPLLCR |= 0x00; //HPLL=6MHz*52=312MHz
// HPLLCR |= 0x01; //HPLL=6MHz*54=324MHz
// HPLLCR |= 0x02; //HPLL=6MHz*56=336MHz
// HPLLCR |= 0x03; //HPLL=6MHz*58=348MHz
// HPLLCR |= 0x04; //HPLL=6MHz*60=360MHz
// HPLLCR |= 0x05; //HPLL=6MHz*62=372MHz
// HPLLCR |= 0x06; //HPLL=6MHz*64=384MHz
// HPLLCR |= 0x07; //HPLL=6MHz*66=396MHz
// HPLLCR |= 0x08; //HPLL=6MHz*68=408MHz
// HPLLCR |= 0x09; //HPLL=6MHz*70=420MHz
// HPLLCR |= 0x0a; //HPLL=6MHz*72=432MHz
// HPLLCR |= 0x0b; //HPLL=6MHz*74=444MHz
// HPLLCR |= 0x0c; //HPLL=6MHz*76=456MHz
// HPLLCR |= 0x0d; //HPLL=6MHz*78=468MHz
HPLLCR |= 0x0e; //HPLL=6MHz*80=480MHz
// HPLLCR |= 0x0f; //HPLL=6MHz*82=492MHz
HPLL2CR &= ~0x60; //高速外设时钟选择 HPLL/2
HPLLCR |= 0x80; //使能HPLL
CLKDIV = 2; //系统时钟=主时钟源/2 = HPLL/2/2 = 120MHz
CLKSEL = 0x04; //选择HPLL/2作为主时钟源
#endif
// P5M0 |= 0x10; P5M1 &= ~0x10;//设置P5.4口为推挽输出
// P5SR &= ~0x10; //设置P5.4口为快速模式
// HIRCCR |= 0x10; //输出系统时钟
// MCLKOCR = 10; //系统时钟 10 分频到P5.4
}
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{
u16 i,j;
u16 width=ex-sx+1; //得到填充的宽度
u16 height=ey-sy+1; //高度
LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口
for(j=0,i=0;i<=DMA_AMT_LEN;i++)
{
Color= color;
}
index = 75; //(320 * 240 * 2) / 2048 = 75
LCD_CS_L();
DmaFlag = 1;
DMA_LCM_CR = 0xa0; //Write dat
while(DmaFlag);
}
void Test_Color(void)
{
u8 buf = {0};
LCD_Fill(0,0,lcddev.width,lcddev.height,WHITE);
Show_Str(20,30,BLUE,YELLOW,"LCM Test",16,1);delay_ms(800);
LCD_Fill(0,0,lcddev.width,lcddev.height,RED);
Show_Str(20,30,BLUE,YELLOW,"RED ",16,1);delay_ms(800);
LCD_Fill(0,0,lcddev.width,lcddev.height,GREEN);
Show_Str(20,30,BLUE,YELLOW,"GREEN ",16,1);delay_ms(800);
LCD_Fill(0,0,lcddev.width,lcddev.height,BLUE);
Show_Str(20,30,RED,YELLOW,"BLUE ",16,1);delay_ms(800);
}
//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-11-01
// 备注: 由于芯片使能了Cache功能,软件延时时间可能不太准确
//========================================================================
void delay_ms(u16 ms)
{
u16 i;
do{
i = MAIN_Fosc / 6000;
while(--i);
}while(--ms);
}
/*****************************************************************************
* @name :void LCD_WR_REG(u16 Reg)
* @date :2018-08-09
* @function :Write an 16-bit command to the LCD screen
* @parameters :data:Command value to be written
* @retvalue :None
******************************************************************************/
void LCD_WR_REG(u16 Reg)
{
LCMIFDATH = Reg>>8;
LCMIFDATL = Reg;
LCD_CS_L();
LCMIFCR = 0x84; //Enable interface, write command out
while(!LCMIFSTA);
LCMIFSTA = 0x00;
LCD_CS_H();
}
/*****************************************************************************
* @name :void LCD_WR_DATA(u16 Data)
* @date :2018-08-09
* @function :Write an 16-bit data to the LCD screen
* @parameters :data:data value to be written
* @retvalue :None
******************************************************************************/
void LCD_WR_DATA(u16 Data)
{
LCMIFDATH = Data>>8;
LCMIFDATL = Data;
LCD_CS_L();
LCMIFCR = 0x85; //Enable interface, write data out
while(!LCMIFSTA);
LCMIFSTA = 0x00;
LCD_CS_H();
}
/*****************************************************************************
* @name :void LCD_WR_DATA_16Bit(u16 Data)
* @date :2018-08-09
* @function :Write an 16-bit command to the LCD screen
* @parameters :Data:Data to be written
* @retvalue :None
******************************************************************************/
void LCD_WR_DATA_16Bit(u16 Data)
{
LCD_WR_DATA(Data);
}
/*****************************************************************************
* @name :void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
* @date :2018-08-09
* @function :Write data into registers
* @parameters :LCD_Reg:Register address
LCD_RegValue:Data to be written
* @retvalue :None
******************************************************************************/
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}
/*****************************************************************************
* @name :void LCD_WriteRAM_Prepare(void)
* @date :2018-08-09
* @function :Write GRAM
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
LCD_WR_REG(lcddev.wramcmd);
}
/*****************************************************************************
* @name :void LCD_DrawPoint(u16 x,u16 y)
* @date :2018-08-09
* @function :Write a pixel data at a specified location
* @parameters :x:the x coordinate of the pixel
y:the y coordinate of the pixel
* @retvalue :None
******************************************************************************/
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetWindows(x,y,x,y);//设置光标位置
LCD_WR_DATA_16Bit(POINT_COLOR);
}
/*****************************************************************************
* @name :void GPIO_Init(void)
* @date :2018-11-13
* @function :Set the gpio to push-pull mode
* @parameters :None
* @retvalue :None
******************************************************************************/
void GPIO_Init(void)
{
P4M0 |= 0x34; //RS,WR,RD设置成推挽输出
P4M1 &= ~0x34;
P5M0 |= 0x02; //RST设置成推挽输出
P5M1 &= ~0x02;
P9M0 |= 0x08; //CS设置成推挽输出
P9M1 &= ~0x08;
P0BP &= ~0xff; //使能LCM的D0~D7 数据脚硬件自动设置端口模式
P2BP &= ~0xff; //使能LCM的D8~D15数据脚硬件自动设置端口模式
}
/*****************************************************************************
* @name :void LCM_Config(void)
* @date :2025-12-25
* @function :Config LCM
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCM_Config(void)
{
LCMIFCFG = 0x02; //16位模式
LCMIFCFG2 = 0x0d;
LCMIFSTA = 0x00;
}
/*****************************************************************************
* @name :void DMA_Config(void)
* @date :2025-12-09
* @function :Config DMA
* @parameters :None
* @retvalue :None
******************************************************************************/
void DMA_Config(void)
{
DMA_LCM_AMT = (u8)DMA_AMT_LEN; //设置传输总字节数(低8位):n+1
DMA_LCM_AMTH = (u8)(DMA_AMT_LEN>>8); //设置传输总字节数(高8位):n+1
DMA_LCM_TXAH = (u8)((u16)&Color >> 8);
DMA_LCM_TXAL = (u8)((u16)&Color);
// DMA_LCM_RXAH = (u8)((u16)&Buffer >> 8);
// DMA_LCM_RXAL = (u8)((u16)&Buffer);
DMA_LCM_STA = 0x00;
DMA_LCM_CFG = 0x82;
DMA_LCM_CR = 0x00;
}
/*****************************************************************************
* @name :void LCDReset(void)
* @date :2018-08-09
* @function :Reset LCD screen
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCDReset(void)
{
LCD_CS_H();
delay_ms(50);
LCD_RESET=0;
delay_ms(150);
LCD_RESET=1;
delay_ms(50);
}
/*****************************************************************************
* @name :void LCD_Init(void)
* @date :2018-08-09
* @function :Initialization LCD screen
* @parameters :None
* @retvalue :None
******************************************************************************/
void LCD_Init(void)
{
LCDReset(); //初始化之前复位
// delay_ms(150); //根据不同晶振速度可以调整延时,保障稳定显示
//*************3.2inch ILI9341初始化**********//
LCD_WR_REG(0xCF);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xD9); //0xC1
LCD_WR_DATA(0X30);
LCD_WR_REG(0xED);
LCD_WR_DATA(0x64);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0X12);
LCD_WR_DATA(0X81);
LCD_WR_REG(0xE8);
LCD_WR_DATA(0x85);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x7A);
LCD_WR_REG(0xCB);
LCD_WR_DATA(0x39);
LCD_WR_DATA(0x2C);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x34);
LCD_WR_DATA(0x02);
LCD_WR_REG(0xF7);
LCD_WR_DATA(0x20);
LCD_WR_REG(0xEA);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA(0x1B); //VRH
LCD_WR_REG(0xC1); //Power control
LCD_WR_DATA(0x12); //SAP;BT 0x01
LCD_WR_REG(0xC5); //VCM control
LCD_WR_DATA(0x08); //30
LCD_WR_DATA(0x26); //30
LCD_WR_REG(0xC7); //VCM control2
LCD_WR_DATA(0XB7);
LCD_WR_REG(0x36); // Memory Access Control
LCD_WR_DATA(0x08);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x55);
LCD_WR_REG(0xB1);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x1A);
LCD_WR_REG(0xB6); // Display Function Control
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0xA2);
LCD_WR_REG(0xF2); // 3Gamma Function Disable
LCD_WR_DATA(0x00);
LCD_WR_REG(0x26); //Gamma curve selected
LCD_WR_DATA(0x01);
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x1D);
LCD_WR_DATA(0x1A);
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x49);
LCD_WR_DATA(0X66);
LCD_WR_DATA(0x3B);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x09);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x04);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x18);
LCD_WR_DATA(0x1D);
LCD_WR_DATA(0x02);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x36);
LCD_WR_DATA(0x13);
LCD_WR_DATA(0x4C);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x13);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x2E);
LCD_WR_DATA(0x2F);
LCD_WR_DATA(0x05);
LCD_WR_REG(0x2B);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x3f);
LCD_WR_REG(0x2A);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xef);
LCD_WR_REG(0x11); //Exit Sleep
delay_ms(120);
LCD_WR_REG(0x29); //display on
//设置LCD属性参数
LCD_direction(USE_HORIZONTAL);//设置LCD显示方向
}
/*****************************************************************************
* @name :void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
* @date :2018-08-09
* @function :Setting LCD display window
* @parameters :xStar:the bebinning x coordinate of the LCD display window
yStar:the bebinning y coordinate of the LCD display window
xEnd:the endning x coordinate of the LCD display window
yEnd:the endning y coordinate of the LCD display window
* @retvalue :None
******************************************************************************/
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA((u8)(xStar>>8));
LCD_WR_DATA((u8)(0x00FF&xStar));
LCD_WR_DATA((u8)(xEnd>>8));
LCD_WR_DATA((u8)(0x00FF&xEnd));
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA((u8)(yStar>>8));
LCD_WR_DATA((u8)(0x00FF&yStar));
LCD_WR_DATA((u8)(yEnd>>8));
LCD_WR_DATA((u8)(0x00FF&yEnd));
LCD_WriteRAM_Prepare(); //开始写入GRAM
}
/*****************************************************************************
* @name :void LCD_direction(u8 direction)
* @date :2018-08-09
* @function :Setting the display direction of LCD screen
* @parameters :direction:0-0 degree
1-90 degree
2-180 degree
3-270 degree
* @retvalue :None
******************************************************************************/
void LCD_direction(u8 direction)
{
lcddev.setxcmd=0x2A;
lcddev.setycmd=0x2B;
lcddev.wramcmd=0x2C;
lcddev.rramcmd=0x2E;
switch(direction){
case 0:
lcddev.width=LCD_W;
lcddev.height=LCD_H;
LCD_WriteReg(0x36,(1<<3));
break;
case 1:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(1<<5)|(1<<6));
break;
case 2:
lcddev.width=LCD_W;
lcddev.height=LCD_H;
LCD_WriteReg(0x36,(1<<3)|(1<<4)|(1<<6)|(1<<7));
break;
case 3:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5)|(1<<4));
break;
default:break;
}
}
/*****************************************************************************
* @name :void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode)
* @date :2018-08-09
* @function :Display a single English character
* @parameters :x:the beginning x coordinate of the Character display position
y:the beginning y coordinate of the Character display position
fc:the color value of display character
bc:the background color of display character
num:the ascii code of display character(0~94)
size:the size of display character
mode:0-no overlying,1-overlying
* @retvalue :None
******************************************************************************/
void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode)
{
u8 temp;
u8 pos,t;
u16 colortemp=POINT_COLOR;
num=num-' ';//得到偏移后的值
LCD_SetWindows(x,y,x+size/2-1,y+size-1);//设置单个文字显示窗口
if(!mode) //非叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206;//调用1206字体
else temp=asc2_1608; //调用1608字体
for(t=0;t<size/2;t++)
{
if(temp&0x01)LCD_WR_DATA_16Bit(fc);
else LCD_WR_DATA_16Bit(bc);
temp>>=1;
}
}
}
else//叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206;//调用1206字体
else temp=asc2_1608; //调用1608字体
for(t=0;t<size/2;t++)
{
POINT_COLOR=fc;
if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//画一个点
temp>>=1;
}
}
}
POINT_COLOR=colortemp;
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏
}
/*****************************************************************************
* @name :void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
* @date :2018-08-09
* @function :Display Chinese and English strings
* @parameters :x:the beginning x coordinate of the Chinese and English strings
y:the beginning y coordinate of the Chinese and English strings
fc:the color value of Chinese and English strings
bc:the background color of Chinese and English strings
str:the start address of the Chinese and English strings
size:the size of Chinese and English strings
mode:0-no overlying,1-overlying
* @retvalue :None
******************************************************************************/
void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
{
u16 x0=x;
u8 bHz=0; //字符或者中文
while(*str!=0)//数据未结束
{
if(!bHz)
{
if(x>(lcddev.width-size/2)||y>(lcddev.height-size))
return;
if(*str>0x80) bHz=1;//中文
else //字符
{
if(*str==0x0D)//换行符号
{
y+=size;
x=x0;
str++;
}
else
{
if(size>16)//字库中没有集成12X24 16X32的英文字体,用8X16代替
{
LCD_ShowChar(x,y,fc,bc,*str,16,mode);
x+=8; //字符,为全字的一半
}
else
{
LCD_ShowChar(x,y,fc,bc,*str,size,mode);
x+=size/2; //字符,为全字的一半
}
}
str++;
}
}
else//中文
{
// if(x>(lcddev.width-size)||y>(lcddev.height-size))
// return;
// bHz=0;//有汉字库
// if(size==32)
// GUI_DrawFont32(x,y,fc,bc,str,mode);
// else if(size==24)
// GUI_DrawFont24(x,y,fc,bc,str,mode);
// else
// GUI_DrawFont16(x,y,fc,bc,str,mode);
str+=2;
x+=size;//下一个汉字偏移
}
}
}
/*****************************************************************************
* @name :void LCM_Interrupt(void)
* @date :2025-12-25
* @function :None
* @parameters :None
* @retvalue :
******************************************************************************/
void LCM_Interrupt(void) interrupt LCM_VECTOR
{
if(LCMIFSTA & 0x01)
{
LCMIFSTA = 0x00;
LcmFlag = 0;
}
}
void LCM_DMA_Interrupt(void) interrupt DMA_LCM_VECTOR
{
if(DMA_LCM_STA & 0x01)
{
index--;
if(index == 0)
{
DMA_LCM_CR = 0;
DmaFlag = 0;
LCD_CS_H();
}
else
{
DMA_LCM_CR = 0xa0; //Write dat
}
DMA_LCM_STA = 0;
}
}
页:
[1]