使用AI8051U和SPI驱动ST7796的问题
之前用ESP32S3的TFT-ESPI和LVGL驱动过这块屏幕,使用STM32F4、以及配合LVGL也驱动过这块屏幕。但是这几天学习AI8051U时,我使用AI8051U和普通SPI驱动ST7796一直没有亮屏,按照官方视频和有关代码。
现有一般都是DMA+SPI或者是高速SPI点屏,正常来说使用最基础的方式也能够驱动啊,但屏幕就还只是白色(BL亮),展示不了其他东西。
我的硬件没有PSRAM和SPIFLASH,就只是简单的驱动点屏。源代码上传了,请大佬给指导指导。
示波器或逻辑分析仪看看信号正常不 DebugLab 发表于 2024-11-27 18:27
示波器或逻辑分析仪看看信号正常不
业余玩家没有{:5_276:} 又改了一个多小时,还是没办法点亮。是支持不了SPI的ST7796吗?
AI8051U的SPI驱动屏有点难搞,还是要必须配合DMA和PSRAM使用才可以?
谁有这个屏,寄2块给我们,我们来帮忙测试下
或者告诉我们在哪买,我们买了来测试下
AI8051U可能驱动不了 SPI的4寸ST7796显示屏。
同样使用试验箱程序包的第76号文件,尝试驱动了2.8寸7789和4寸7796显示屏。
同样的代码,连屏幕分辨率都没改变,只是两者驱动部分改变了(7796的驱动代码在stm可以正常驱动),结果是7789可以驱动,7796无显示。
/*************功能说明 **************
本例程基于AI8051U为主控芯片的实验箱V1.1版本进行编写测试。
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
彩色SPI接口TFT LCD240x240的显示程序,通过SPI DMA将3200字节的图片数据送到彩屏,传送时不占用CPU时间。
显示图形,汉字,英文,数字. TFT LCD240X240使用中景园的液晶屏,主控IC型号为ST7789V3。
其中图形显示发送命令使用SPI查询方式(11字节),图片数据使用SPI DMA操作,本例运行于40MHz, 每次SPI DMA传输总时间1.52ms. 整屏刷新55mms.
将要显示的内容放在1024字节的显存中,启动DMA传输即可。
下载时, 选择时钟 40MHz (用户可自行修改频率后重新编译即可).
******************************************/
#define FOSC 40000000UL
#include "AI8051U.h"
#include "LCD.h"
#include "lcdfont.h"
#include "pic.h"
//-----------------LCD端口定义----------------
/* 定义接口 */
//GND AI8051U实验箱 V1.1
//VCC 3~5V
//sbit P_LCD_CLK = P3^2; //D0 SPI or II2 的时钟脚
//sbit P_LCD_SDA = P3^3; //D1 SPI or II2 的数据脚
//sbit P_LCD_RST = P4^7; //RES 复位脚, 低电平复位
//sbit P_LCD_DC = P1^1; //DC 数据或命令脚
//sbit P_LCD_CS = P3^5; //CS 片选脚
sbit P_LCD_CLK = P1^7; //D0 SPI or II2 的时钟脚
sbit P_LCD_SDA = P1^5; //D1 SPI or II2 的数据脚
sbit P_LCD_RST = P4^7; //RES 复位脚, 低电平复位
sbit P_LCD_DC = P1^1; //DC 数据或命令脚
sbit P_LCD_CS = P1^4; //CS 片选脚
// 显示定义
#define USE_HORIZONTAL 3 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#define LCD_W 320
#define LCD_H 240
//-----------------变量定义----------------
bit B_SPI_DMA_busy; //SPI DMA忙标志, 1标志SPI-DMA忙,SPI DMA中断中清除此标志,使用SPI DMA前要确认此标志为0
u16 SPI_TxAddr; //SPI DMA要发送数据的首地址
u8 xdata DisTmp; //显示缓冲,将要显示的内容放在显存里,启动DMA即可. 由于LCM DMA有4字节对齐问题,所以这里定位对地址为4的倍数
//N ms延时函数
void delay_ms(u16 ms) // 1~65535 ms
{
u16 i;
do
{
i = FOSC / 6000; //STC32系列
while(--i) ;
}while(--ms);
}
//========================================================================
// 函数: voidSPI_Config(u8 SPI_io, u8 SPI_speed)
// 描述: SPI初始化函数。
// 参数: io: 切换到的IO, SSMOSI MISO SCLK
// 0: 切换到 P1.4 P1.5 P1.6 P1.7
// 1: 切换到 P2.4 P2.5 P2.6 P2.7
// 2: 切换到 P4.0 P4.1 P4.2 P4.3
// 3: 切换到 P3.5 P3.4 P3.3 P3.2
// SPI_speed: SPI的速度, 0: fosc/4,1: fosc/8,2: fosc/16,3: fosc/2
// 返回: none.
// 版本: VER1.0
// 日期: 2024-8-13
// 备注:
//========================================================================
voidSPI_Config(u8 SPI_io, u8 SPI_speed)
{
SPI_io &= 3;
SPCTL = SPI_speed & 3; //配置SPI 速度, 这条指令先执行, 顺便Bit7~Bit2清0
SSIG = 1; //1: 忽略SS脚,由MSTR位决定主机还是从机 0: SS脚用于决定主机还是从机。
SPEN = 1; //1: 允许SPI, 0:禁止SPI,所有SPI管脚均为普通IO
DORD = 0; //1:LSB先发, 0:MSB先发
MSTR = 1; //1:设为主机 0:设为从机
CPOL = 1; //1: 空闲时SCLK为高电平, 0:空闲时SCLK为低电平
CPHA = 1; //1: 数据在SCLK前沿驱动,后沿采样. 0: 数据在SCLK前沿采样,后沿驱动.
// SPR1 = 0; //SPR1,SPR0 00: fosc/4, 01: fosc/8
// SPR0 = 0; // 10: fosc/16, 11: fosc/2
P_SW1 = (P_SW1 & ~0x0c) | ((SPI_io<<2) & 0x0c); //切换IO
HSCLKDIV = 1; //HSCLKDIV主时钟分频
SPI_CLKDIV = 1; //SPI_CLKDIV主时钟分频
SPSTAT = 0x80 + 0x40; //清0 SPIF和WCOL标志
if(SPI_io == 0)
{
P1n_standard(0xf0); //切换到 P1.4(SS) P1.5(MOSI) P1.6(MISO) P1.7(SCLK), 设置为准双向口
PullUpEnable(P1PU, 0xf0); //设置上拉电阻 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P1n_push_pull(Pin7+Pin5); //MOSI SCLK设置为推挽输出
SlewRateHigh(P1SR, Pin7+Pin5); //MOSI SCLK端口输出设置为高速模式 PxSR, 要设置的端口对应位为1. 高速模式在3.3V供电时速度可以到13.5MHz(27MHz主频,SPI速度2分频)
}
else if(SPI_io == 1)
{
P2n_standard(0xf0); //切换到P2.4(SS) P2.5(MOSI) P2.6(MISO) P2.7(SCLK), 设置为准双向口
PullUpEnable(P2PU, 0xf0); //设置上拉电阻 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P2n_push_pull(Pin7+Pin5); //MOSI SCLK设置为推挽输出
SlewRateHigh(P2SR, Pin7+Pin5); //MOSI SCLK端口输出设置为高速模式 PxSR, 要设置的端口对应位为1. 高速模式在3.3V供电时速度可以到13.5MHz(27MHz主频,SPI速度2分频)
}
else if(SPI_io == 2)
{
P4n_standard(0x0f); //切换到P4.0(SS) P4.1(MOSI) P4.2(MISO) P4.3(SCLK), 设置为准双向口
PullUpEnable(P4PU, 0x0f); //设置上拉电阻 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P4n_push_pull(Pin3+Pin1); //MOSI SCLK设置为推挽输出
SlewRateHigh(P4SR, Pin3+Pin1); //MOSI SCLK端口输出设置为高速模式 PxSR, 要设置的端口对应位为1. 高速模式在3.3V供电时速度可以到13.5MHz(27MHz主频,SPI速度2分频)
}
else if(SPI_io == 3)
{
P3n_standard(0x3C); //切换到P3.5(SS) P3.4(MOSI) P3.3(MISO) P3.2(SCLK), 设置为准双向口
PullUpEnable(P3PU, 0x3c); //设置上拉电阻 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P3n_push_pull(Pin4+Pin2); //MOSI SCLK设置为推挽输出
SlewRateHigh(P3SR, Pin4+Pin2); //MOSI SCLK端口输出设置为高速模式 PxSR, 要设置的端口对应位为1. 高速模式在3.3V供电时速度可以到13.5MHz(27MHz主频,SPI速度2分频)
}
}
//========================================================================
// 描述: 写SPI一个字节函数
// 参数: 无.
// 返回: 无
//========================================================================
void LCD_SendByte(u8 dat)
{
SPDAT = dat; //发送一个字节
while(SPIF == 0) ; //等待发送完成
SPSTAT = 0x80 + 0x40; //清0 SPIF和WCOL标志
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值:无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
P_LCD_CS = 0;
LCD_SendByte(dat);
P_LCD_CS = 1;
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值:无
******************************************************************************/
void LCD_WR_DATA16(u16 dat)
{
P_LCD_CS = 0;
LCD_SendByte((u8)(dat>>8));
LCD_SendByte((u8)dat);
P_LCD_CS = 1;
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值:无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
P_LCD_DC = 0;//写命令
P_LCD_CS = 0;
LCD_SendByte(dat);
P_LCD_CS = 1;
P_LCD_DC = 1;//写数据
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值:无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
if(USE_HORIZONTAL == 1)
{
y1 += 80;
y2 += 80;
}
else if(USE_HORIZONTAL == 3)
{
x1 += 80;
x2 += 80;
}
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA16(x1);
LCD_WR_DATA16(x2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA16(y1);
LCD_WR_DATA16(y2);
LCD_WR_REG(0x2c);//储存器写
}
/******************************************************************************
函数说明:LCD初始化函数
入口数据:无
返回值:无
******************************************************************************/
void LCD_Init(u8 LCDdriver)
{
P_LCD_CLK = 1;//SCLK
P_LCD_SDA = 1;//MOSI
P_LCD_RST = 1;//RES
P_LCD_DC= 1;//DC
P_LCD_CS= 1;//CS
P_LCD_RST = 0;
delay_ms(100);
P_LCD_RST = 1;
delay_ms(100);
if(LCDdriver==0)
{
LCD_WR_REG(0x11); //Sleep out 退出睡眠
delay_ms(120); //Delay 120ms
LCD_WR_REG(0x36); //显存访问控制
if(USE_HORIZONTAL == 0) LCD_WR_DATA8(0x00);
else if(USE_HORIZONTAL == 1) LCD_WR_DATA8(0xC0);
else if(USE_HORIZONTAL == 2) LCD_WR_DATA8(0x70);
else LCD_WR_DATA8(0xA0);
LCD_WR_REG(0x3A); //接口格式
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0x35);
LCD_WR_REG(0xBB);
LCD_WR_DATA8(0x20); //2b
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x2C);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x18); //VDV, 0x20:0v
LCD_WR_REG(0xC6);
LCD_WR_DATA8(0x13); //0x13:60Hz
LCD_WR_REG(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xD6);
LCD_WR_DATA8(0xA1); //sleep in后,gate输出为GND
//---------------ST7789V gamma setting-------------//
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0xE1); //Set Gamma
LCD_WR_DATA8(0xF0);
LCD_WR_DATA8(0x02);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x21);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x38);
LCD_WR_DATA8(0x12);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x31);
LCD_WR_REG(0xE4);
LCD_WR_DATA8(0x1D); //使用240根gate(N+1)*8
LCD_WR_DATA8(0x00); //设定gate起点位置
LCD_WR_DATA8(0x00); //当gate没有用完时,bit4(TMG)设为0
LCD_WR_REG(0x20);
LCD_WR_REG(0x29); //开启显示
}
else
{
/**** ST7796S IPS初始化 ****/
LCD_WR_REG(0x11); //Sleep out 退出睡眠
delay_ms(120); //Delay 120ms
LCD_WR_REG(0x36); //显存访问控制
LCD_WR_DATA8(0x48);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x55); //LCD_WR_DATA8(0x66);
LCD_WR_REG(0xF0); // Command Set Control
LCD_WR_DATA8(0xC3);
LCD_WR_REG(0xF0);
LCD_WR_DATA8(0x96);
LCD_WR_REG(0xB4);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0xC6);
//LCD_WR_REG(0xB9);
//LCD_WR_DATA8(0x02);
//LCD_WR_DATA8(0xE0);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x80);
LCD_WR_DATA8(0x45);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0x13); //18//00
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0xA7);
LCD_WR_REG(0xC5);
LCD_WR_DATA8(0x0A);
LCD_WR_REG(0xE8);
LCD_WR_DATA8(0x40);
LCD_WR_DATA8(0x8A);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x19);
LCD_WR_DATA8(0xA5);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x0F);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x47);
LCD_WR_DATA8(0x17);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2B);
LCD_WR_DATA8(0x31);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x2F);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x47);
LCD_WR_DATA8(0x38);
LCD_WR_DATA8(0x15);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x32);
LCD_WR_REG(0xF0);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xF0);
LCD_WR_DATA8(0x69);
delay_ms(120);
LCD_WR_REG(0x20);
LCD_WR_REG(0x29);
P1M0 |= 0x01; //BL推挽输出
P1M1 &= ~0x01;
P10=1;
}
}
/******************************************************************************
函数说明:在指定区域填充颜色
入口数据:xsta,ysta 起始坐标
xend,yend 终止坐标
color 要填充的颜色
返回值:无
******************************************************************************/
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
{
u16 i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA16(color);
}
}
}
/******************************************************************************
函数说明:在指定位置画点
入口数据:x,y 画点坐标
color 点的颜色
返回值:无
******************************************************************************/
void LCD_DrawPoint(u16 x,u16 y,u16 color)
{
LCD_Address_Set(x,y,x,y);//设置光标位置
LCD_WR_DATA16(color);
}
/******************************************************************************
函数说明:显示单个12x12汉字
入口数据:x,y显示坐标
*s 要显示的汉字
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChinese12x12(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
u8 i,j,m=0;
u16 k;
u16 HZnum;//汉字数目
u16 TypefaceNum;//一个字符所占字节大小
u16 x0=x;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
HZnum=sizeof(tfont12)/sizeof(typFNT_GB12); //统计汉字数目
for(k=0;k<HZnum;k++)
{
if((tfont12.Index==*(s))&&(tfont12.Index==*(s+1)))
{
LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
for(i=0;i<TypefaceNum;i++)
{
for(j=0;j<8;j++)
{
if(!mode)//非叠加方式
{
if(tfont12.Msk&(0x01<<j)) LCD_WR_DATA16(fc);
else LCD_WR_DATA16(bc);
m++;
if(m%sizey==0)
{
m=0;
break;
}
}
else//叠加方式
{
if(tfont12.Msk&(0x01<<j)) LCD_DrawPoint(x,y,fc);//画一个点
x++;
if((x-x0)==sizey)
{
x=x0;
y++;
break;
}
}
}
}
}
continue;//查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
/******************************************************************************
函数说明:显示单个16x16汉字
入口数据:x,y显示坐标
*s 要显示的汉字
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChinese16x16(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
u8 i,j,m=0;
u16 k;
u16 HZnum;//汉字数目
u16 TypefaceNum;//一个字符所占字节大小
u16 x0=x;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
HZnum=sizeof(tfont16)/sizeof(typFNT_GB16); //统计汉字数目
for(k=0;k<HZnum;k++)
{
if ((tfont16.Index==*(s))&&(tfont16.Index==*(s+1)))
{
LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
for(i=0;i<TypefaceNum;i++)
{
for(j=0;j<8;j++)
{
if(!mode)//非叠加方式
{
if(tfont16.Msk&(0x01<<j)) LCD_WR_DATA16(fc);
else LCD_WR_DATA16(bc);
m++;
if(m%sizey==0)
{
m=0;
break;
}
}
else//叠加方式
{
if(tfont16.Msk&(0x01<<j)) LCD_DrawPoint(x,y,fc);//画一个点
x++;
if((x-x0)==sizey)
{
x=x0;
y++;
break;
}
}
}
}
}
continue;//查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
/******************************************************************************
函数说明:显示单个24x24汉字
入口数据:x,y显示坐标
*s 要显示的汉字
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChinese24x24(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
u8 i,j,m=0;
u16 k;
u16 HZnum;//汉字数目
u16 TypefaceNum;//一个字符所占字节大小
u16 x0=x;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
HZnum=sizeof(tfont24)/sizeof(typFNT_GB24); //统计汉字数目
for(k=0;k<HZnum;k++)
{
if ((tfont24.Index==*(s))&&(tfont24.Index==*(s+1)))
{
LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
for(i=0;i<TypefaceNum;i++)
{
for(j=0;j<8;j++)
{
if(!mode)//非叠加方式
{
if(tfont24.Msk&(0x01<<j)) LCD_WR_DATA16(fc);
else LCD_WR_DATA16(bc);
m++;
if(m%sizey==0)
{
m=0;
break;
}
}
else//叠加方式
{
if(tfont24.Msk&(0x01<<j)) LCD_DrawPoint(x,y,fc);//画一个点
x++;
if((x-x0)==sizey)
{
x=x0;
y++;
break;
}
}
}
}
}
continue;//查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
/******************************************************************************
函数说明:显示单个32x32汉字
入口数据:x,y显示坐标
*s 要显示的汉字
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChinese32x32(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
u8 i,j,m=0;
u16 k;
u16 HZnum;//汉字数目
u16 TypefaceNum;//一个字符所占字节大小
u16 x0=x;
TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
HZnum=sizeof(tfont32)/sizeof(typFNT_GB32); //统计汉字数目
for(k=0;k<HZnum;k++)
{
if ((tfont32.Index==*(s))&&(tfont32.Index==*(s+1)))
{
LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
for(i=0;i<TypefaceNum;i++)
{
for(j=0;j<8;j++)
{
if(!mode)//非叠加方式
{
if(tfont32.Msk&(0x01<<j)) LCD_WR_DATA16(fc);
else LCD_WR_DATA16(bc);
m++;
if(m%sizey==0)
{
m=0;
break;
}
}
else//叠加方式
{
if(tfont32.Msk&(0x01<<j)) LCD_DrawPoint(x,y,fc);//画一个点
x++;
if((x-x0)==sizey)
{
x=x0;
y++;
break;
}
}
}
}
}
continue;//查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
}
/******************************************************************************
函数说明:显示单个字符
入口数据:x,y显示坐标
num 要显示的字符
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode)
{
u8 temp,sizex,t,m=0;
u16 i,TypefaceNum;//一个字符所占字节大小
u16 x0=x;
sizex=sizey/2;
TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
num=num-' '; //得到偏移后的值
LCD_Address_Set(x,y,x+sizex-1,y+sizey-1);//设置光标位置
for(i=0;i<TypefaceNum;i++)
{
if(sizey==12)temp=ascii_1206; //调用6x12字体
else if(sizey==16)temp=ascii_1608; //调用8x16字体
else if(sizey==24)temp=ascii_2412; //调用12x24字体
else if(sizey==32)temp=ascii_3216; //调用16x32字体
else return;
for(t=0;t<8;t++)
{
if(!mode)//非叠加模式
{
if(temp&(0x01<<t)) LCD_WR_DATA16(fc);
else LCD_WR_DATA16(bc);
m++;
if(m%sizex==0)
{
m=0;
break;
}
}
else//叠加模式
{
if(temp&(0x01<<t))LCD_DrawPoint(x,y,fc);//画一个点
x++;
if((x-x0)==sizex)
{
x=x0;
y++;
break;
}
}
}
}
}
/******************************************************************************
函数说明:显示汉字串
入口数据:x,y显示坐标
*s 要显示的汉字串
fc 字的颜色
bc 字的背景色
sizey 字号 可选 16 24 32
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowChinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
{
while(*s!=0)
{
if(sizey==12) LCD_ShowChinese12x12(x,y,s,fc,bc,sizey,mode);
else if(sizey==16) LCD_ShowChinese16x16(x,y,s,fc,bc,sizey,mode);
else if(sizey==24) LCD_ShowChinese24x24(x,y,s,fc,bc,sizey,mode);
else if(sizey==32) LCD_ShowChinese32x32(x,y,s,fc,bc,sizey,mode);
else return;
s+=2;
x+=sizey;
}
}
/******************************************************************************
函数说明:显示字符串
入口数据:x,y显示坐标
*p 要显示的字符串
fc 字的颜色
bc 字的背景色
sizey 字号
mode:0非叠加模式1叠加模式
返回值:无
******************************************************************************/
void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode)
{
while(*p!='\0')
{
LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
x+=sizey/2;
p++;
}
}
/******************************************************************************
函数说明:显示数字
入口数据:m底数,n指数
返回值:无
******************************************************************************/
u32 mypow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
/******************************************************************************
函数说明:显示整数变量
入口数据:x,y显示坐标
num 要显示整数变量
len 要显示的位数
fc 字的颜色
bc 字的背景色
sizey 字号
返回值:无
******************************************************************************/
void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc,u8 sizey)
{
u8 t,temp;
u8 enshow=0;
u8 sizex=sizey/2;
for(t=0;t<len;t++)
{
temp = (num/mypow(10, (u8)(len-t-1)))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+t*sizex,y,' ',fc,bc,sizey,0);
continue;
}else enshow=1;
}
LCD_ShowChar(x+t*sizex,y, (u8)(temp+48),fc,bc,sizey,0);
}
}
/******************************************************************************
函数说明:显示两位小数变量
入口数据:x,y显示坐标
num 要显示小数变量
len 要显示的位数
fc 字的颜色
bc 字的背景色
sizey 字号
返回值:无
******************************************************************************/
void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey)
{
u8 t,temp,sizex;
u16 num1;
sizex=sizey/2;
num1=num*100;
for(t=0;t<len;t++)
{
temp=(num1/mypow(10, (u8)(len-t-1)))%10;
if(t==(len-2))
{
LCD_ShowChar(x+(len-2)*sizex,y,'.',fc,bc,sizey,0);
t++;
len+=1;
}
LCD_ShowChar(x+t*sizex,y,(u8)(temp+48),fc,bc,sizey,0);
}
}
/******************************************************************************
函数说明:显示图片
入口数据:x,y起点坐标
length 图片长度
width图片宽度
pic[]图片数组
返回值:无
******************************************************************************/
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width, u8 xdata *pic)
{
LCD_Address_Set(x,y,x+length-1,y+width-1);
SPI_DMA_TRIG(pic); //触发SPI DAM发送一个图片
while(B_SPI_DMA_busy); //等待图片发送完毕
}
//DMA_SPI_CR SPI_DMA控制寄存器
#define DMA_ENSPI (1<<7) // SPI DMA功能使能控制位, bit7, 0:禁止SPI DMA功能,1:允许SPI DMA功能。
#define SPI_TRIG_M (1<<6) // SPI DMA主机模式触发控制位,bit6, 0:写0无效, 1:写1开始SPI DMA主机模式操作。
#define SPI_TRIG_S (0<<5) // SPI DMA从机模式触发控制位,bit5, 0:写0无效, 1:写1开始SPI DMA从机模式操作。
#define SPI_CLRFIFO 1 // 清除SPI DMA接收FIFO控制位,bit0, 0:写0无效, 1:写1复位FIFO指针。
//DMA_SPI_CFG SPI_DMA配置寄存器
#define DMA_SPIIE (1<<7) // SPI DMA中断使能控制位,bit7, 0:禁止SPI DMA中断, 1:允许中断。
#define SPI_ACT_TX (1<<6) // SPI DMA发送数据控制位,bit6, 0:禁止SPI DMA发送数据,主机只发时钟不发数据,从机也不发. 1:允许发送。
#define SPI_ACT_RX (0<<5) // SPI DMA接收数据控制位,bit5, 0:禁止SPI DMA接收数据,主机只发时钟不收数据,从机也不收. 1:允许接收。
#define DMA_SPIIP (0<<2) // SPI DMA中断优先级控制位,bit3~bit2, (最低)0~3(最高).
#define DMA_SPIPTY 0 // SPI DMA数据总线访问优先级控制位,bit1~bit0, (最低)0~3(最高).
//DMA_SPI_CFG2 SPI_DMA配置寄存器2
#define SPI_WRPSS (0<<2) // SPI DMA过程中使能SS脚控制位,bit2, 0: SPI DMA传输过程不自动控制SS脚。1:自动拉低SS脚。
#define SPI_SSS 3 // SPI DMA过程中自动控制SS脚选择位,bit1~bit0, 0: P1.4,1:P2.4,2: P4.0,3:P3.5。
//DMA_SPI_STA SPI_DMA状态寄存器
#define SPI_TXOVW (1<<2) // SPI DMA数据覆盖标志位,bit2, 软件清0.
#define SPI_RXLOSS (1<<1) // SPI DMA接收数据丢弃标志位,bit1, 软件清0.
#define DMA_SPIIF 1 // SPI DMA中断请求标志位,bit0, 软件清0.
//HSSPI_CFG高速SPI配置寄存器
#define SS_HOLD (0<<4) //高速模式时SS控制信号的HOLD时间, 0~15, 默认3. 在DMA中会增加N个系统时钟,当SPI速度为系统时钟/2时执行DMA,SS_HOLD、SS_SETUP和SS_DACT都必须设置大于2的值.
#define SS_SETUP 3 //高速模式时SS控制信号的SETUP时间,0~15, 默认3. 在DMA中不影响时间, 当SPI速度为系统时钟/2时执行DMA,SS_HOLD、SS_SETUP和SS_DACT都必须设置大于2的值.
//HSSPI_CFG2高速SPI配置寄存器2
#define SPI_IOSW (1<<6) //bit6:交换MOSI和MISO脚位,0:不交换,1:交换
#define HSSPIEN (0<<5) //bit5:高速SPI使能位,0:关闭高速模式,1:使能高速模式
#define FIFOEN (1<<4) //bit4:高速SPI的FIFO模式使能位,0:关闭FIFO模式,1:使能FIFO模式,使能FIFO模式在DMA中减少13个系统时间。
#define SS_DACT 3 //bit3~0:高速模式时SS控制信号的DEACTIVE时间,0~15, 默认3, 不影响DMA时间.当SPI速度为系统时钟/2时执行DMA,SS_HOLD、SS_SETUP和SS_DACT都必须设置大于2的值.
void SPI_DMA_TRIG(u8 xdata *TxBuf)
{
//@40MHz, Fosc/4, 200字节258us,100字节130us,50字节66us,N个字节耗时 N*1.280+2 us, 51T一个字节,其中状态机19T, 传输耗时32T.
//@40MHz, Fosc/2, 200字节177us,100字节 89.5us,50字节46us,N个字节耗时 N*0.875+2 us, 35T一个字节,其中状态机19T, 传输耗时16T.
//@40MHz, Fosc/2, SPI DMA传输一个字节, FIFO=1, HOLD=0,耗时16+3=19T(0.475us), HOLD=3,耗时16+6=22T(0.55us).
//@40MHz, Fosc/4, SPI DMA传输一个字节, FIFO=1, HOLD=0,耗时32+3=35T(0.875us), HOLD=3,耗时32+6=38T(0.95us).
HSSPI_CFG= SS_HOLD | SS_SETUP; //SS_HOLD会增加N个系统时钟, SS_SETUP没有增加时钟。驱动OLED 40MHz时SS_HOLD可以设置为0,
HSSPI_CFG2 = SPI_IOSW | FIFOEN | SS_DACT; //FIFOEN允许FIFO会减小13个时钟.
P_LCD_DC= 1; //写数据
P_LCD_CS= 0; //片选
B_SPI_DMA_busy = 1; //标志SPI-DMA忙,SPI DMA中断中清除此标志,使用SPI DMA前要确认此标志为0
SPI_TxAddr = (u16)TxBuf; //要发送数据的首地址
DMA_SPI_TXAH = (u8)(SPI_TxAddr >> 8); //发送地址寄存器高字节
DMA_SPI_TXAL = (u8)SPI_TxAddr; //发送地址寄存器低字节
DMA_SPI_AMTH = (u8)((3200-1)/256); //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_SPI_AMT= (u8)(3200-1); //设置传输总字节数(低8位).
DMA_SPI_ITVH = 0;
DMA_SPI_ITVL = 0;
DMA_SPI_STA= 0x00;
DMA_SPI_CFG= DMA_SPIIE | SPI_ACT_TX | SPI_ACT_RX | DMA_SPIIP | DMA_SPIPTY;
DMA_SPI_CFG2 = SPI_WRPSS | SPI_SSS;
DMA_SPI_CR = DMA_ENSPI | SPI_TRIG_M | SPI_TRIG_S | SPI_CLRFIFO; //启动SPI DMA发送命令
}
//========================================================================
// 函数: void SPI_DMA_ISR (void) interrupt DMA_SPI_VECTOR
// 描述:SPI_DMA中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-1-5
//========================================================================
void SPI_DMA_ISR (void) interrupt DMA_SPI_VECTOR
{
DMA_SPI_CR = 0; //关闭SPI DMA
B_SPI_DMA_busy = 0; //清除SPI-DMA忙标志,SPI DMA中断中清除此标志,使用SPI DMA前要确认此标志为0
SPSTAT = 0x80 + 0x40; //清0 SPIF和WCOL标志
HSSPI_CFG2 = SPI_IOSW | SS_DACT; //使用SPI查询或中断方式时,要禁止FIFO
P_LCD_CS = 1;
DMA_SPI_STA = 0; //清除中断标志
}
void main(void)
{
u16 i;
u8 j;
float t=0;
EAXFR = 1; //允许访问扩展寄存器
WTST= 0;
CKCON = 0;
P0M1 = 0; P0M0 = 0; //设置为准双向口
P1M1 = 0; P1M0 = 0; //设置为准双向口
P2M1 = 0; P2M0 = 0; //设置为准双向口
P3M1 = 0; P3M0 = 0; //设置为准双向口
P4M1 = 0; P4M0 = 0; //设置为准双向口
P5M1 = 0; P5M0 = 0; //设置为准双向口
P6M1 = 0; P6M0 = 0; //设置为准双向口
P7M1 = 0; P7M0 = 0; //设置为准双向口
//==================== SPI初始化 ==================================
SPI_Config(0, 3); //(SPI_io, SPI_speed), 参数: SPI_io: 切换IO(SS MOSI MISO SCLK), 0: 切换到P1.4 P1.5 P1.6 P1.7,1: 切换到P2.4 P2.5 P2.6 P2.7, 2: 切换到P4.0 P4.1 P4.2 P4.3,3: 切换到P3.5 P3.4 P3.3 P3.2,
// SPI_speed: SPI的速度, 0: fosc/4,1: fosc/8,2: fosc/16,3: fosc/2
// HSSPI_CFG2 = 0x40; //交换MOSI MISO, P3.3是MOSI
P1n_standard(Pin1); //SPI引脚设置为准双向口, SPI和控制信号
PullUpEnable(P1PU, Pin1); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P3n_standard(0x2c); //SPI引脚设置为准双向口, SPI和控制信号
PullUpEnable(P3PU, 0x2c); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
P4n_standard(Pin7); //SPI引脚设置为准双向口, SPI和控制信号
PullUpEnable(P4PU, Pin7); // 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1
//=================================================================
LCD_Init(0);//LCD初始化
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
EA = 1;
while(1)
{
// LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
LCD_ShowChinese(0,0,"深圳国芯人工智能",RED,WHITE,24,0);
// LCD_ShowString(0,40,"LCD_W:",RED,WHITE,16,0);
// LCD_ShowIntNum(48,40,LCD_W,3,RED,WHITE,16);
// LCD_ShowString(80,40,"LCD_H:",RED,WHITE,16,0);
// LCD_ShowIntNum(128,40,LCD_H,3,RED,WHITE,16);
// LCD_ShowString(80,40,"LCD_H:",RED,WHITE,16,0);
// LCD_ShowString(0,70,"Increaseing Nun:",RED,WHITE,16,0);
LCD_ShowFloatNum1(128,70,t,4,RED,WHITE,16);
t+=0.11;
delay_ms(3000); // 1~65535 ms
// for(i=0; i<3200; i++) DisTmp = Image_1; //将图片装载到显存
// for(j=0; j<6; j++) //6行图片, 整屏36个图片 @40MHz FIFOEN=1, SS_HOLD=0时55ms @2T
// {
// for(i=0; i<6; i++) //一行6个图片
// {
// LCD_ShowPicture(40*i, j*40, 40, 40, DisTmp); //触发SPI DMA显示一个图片, 3200字节 1.52ms @40MHz
// }
// }
// delay_ms(3000); // 1~65535 ms
// for(i=0; i<3200; i++) DisTmp = Image_2; //将图片装载到显存
// for(j=0; j<6; j++) //6行图片, 整屏36个图片 @40MHz FIFOEN=1, SS_HOLD=0时55ms @2T
// {
// for(i=0; i<6; i++) //一行6个图片
// {
// LCD_ShowPicture(40*i, j*40, 40, 40, DisTmp); //触发SPI DMA显示一个图片, 3200字节 1.52ms @40MHz
// }
// }
// delay_ms(3000);
}
}
为什么呢???
明天抽空用STM驱动试试,再排除下是不是硬件问题 272761180 发表于 2024-12-1 21:02
AI8051U可能驱动不了 SPI的4寸ST7796显示屏。
频率搞小点,延时搞长点试试 楼主你试过楼上这位大佬说的方法了吗? 会不会和频率和延时有关呢?我之前搞过其他,就在这里出的问题。
页:
[1]
2