用AI8051,直接驱动480*272分辨率,RGB接口屏,
屏幕是标准40pin的RGB接口屏,频率22.1184Mhz,用DE模式驱动,本来单纯想学学这种屏幕的时序,没想到显示个汉字啥的,还能接受,因为是用24位RGB,所以用的32bit模式,8位対long的兼容不好,程序写的不好,希望大家指正。为了显示汉字,数字之类的,实在不知道怎么写这个函数,因为每次都要全屏刷新像素,就用了最粗暴的方式,建立整屏缓存,然后把需要显示的汉字或者数字数组,替换掉全屏缓存内对应的字节。
#include <AI8051U.H>
#include "intrins.h"
// 引脚定义
sbit CLK = P5^7;
sbit DE = P4^0;
//sbit DISP= P1^5;
sbit LED = P5^6;
#define port_r P1
#define port_g P0
#define port_b P2
// 屏幕参数
#define H_ACTIVE 480 // 水平有效像素
#define V_ACTIVE 272 // 垂直有效行数
#define H_BLANK 45 // 水平消隐期(前廊+同步+后廊)
#define V_BLANK 14 // 垂直消隐期(前廊+同步+后廊)
#define H_TOTAL (H_ACTIVE + H_BLANK)
#define V_TOTAL (V_ACTIVE + V_BLANK)
#define FOSC 22118400UL
#define BRT (65536 - FOSC / 115200 / 4)
#define bai 0xffffff
#define hong 0xff0000
#define lv 0x00ff00
#define huang 0xffff00
#define hei 0x000000
#define qianhuang 0xffffbe
#define lan 0x0000ff
unsigned char xdata full={0};
unsigned char xdata shan={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x10,0x18,0x00, /* 0 */
0x0f,0xf8,0x18,0x00,0x0c,0x30,0x18,0x00,0x0c,0x20,0x18,0x60,0x0c,0x67,0xff,0xf0,
0x0c,0x40,0x18,0x00,0x04,0x40,0x18,0x00,0x04,0x82,0x18,0xc0,0x04,0x83,0x10,0xc0,
0x04,0x83,0x10,0x80,0x04,0x41,0x91,0x00,0x04,0x21,0x91,0x00,0x04,0x11,0x12,0x00,
0x04,0x10,0x10,0x10,0x04,0x1f,0xff,0xf8,0x04,0x18,0x34,0x00,0x04,0x18,0x34,0x00,
0x07,0xf0,0x24,0x00,0x04,0xe0,0x62,0x00,0x0c,0x00,0x43,0x00,0x0c,0x00,0xc1,0x00,
0x0c,0x01,0x81,0xc0,0x0c,0x03,0x00,0xe0,0x0c,0x06,0x00,0x78,0x0c,0x18,0x00,0x30,
0x08,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
unsigned char xdata xi={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20, /* 1 */
0x1f,0xff,0xff,0xf0,0x00,0x0c,0x30,0x00,0x00,0x0c,0x30,0x00,0x00,0x0c,0x30,0x00,
0x00,0x0c,0x30,0x00,0x04,0x0c,0x30,0x40,0x07,0xff,0xff,0xf0,0x06,0x0c,0x30,0x60,
0x06,0x0c,0x30,0x60,0x06,0x0c,0x30,0x60,0x06,0x0c,0x30,0x60,0x06,0x08,0x30,0x60,
0x06,0x08,0x30,0x60,0x06,0x18,0x30,0x60,0x06,0x10,0x31,0x60,0x06,0x30,0x1f,0xe0,
0x06,0x20,0x00,0x60,0x06,0x40,0x00,0x60,0x06,0x80,0x00,0x60,0x06,0x00,0x00,0x60,
0x07,0xff,0xff,0xe0,0x06,0x00,0x00,0x60,0x06,0x00,0x00,0x60,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
unsigned char xdata sheng={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x80,0x00, /* 2 */
0x00,0x41,0x00,0x00,0x00,0x71,0x03,0x80,0x00,0xc1,0x00,0xc0,0x01,0x81,0x0c,0x70,
0x01,0x81,0x1c,0x30,0x03,0x01,0x30,0x30,0x06,0x02,0xe0,0x10,0x08,0x01,0xc0,0x00,
0x10,0x03,0x00,0x00,0x00,0x0e,0x01,0x00,0x00,0x3f,0xff,0x80,0x00,0x70,0x03,0x00,
0x00,0xe0,0x03,0x00,0x07,0x20,0x03,0x00,0x08,0x3f,0xff,0x00,0x00,0x20,0x03,0x00,
0x00,0x20,0x03,0x00,0x00,0x20,0x03,0x00,0x00,0x3f,0xff,0x00,0x00,0x20,0x03,0x00,
0x00,0x20,0x03,0x00,0x00,0x3f,0xff,0x00,0x00,0x20,0x03,0x00,0x00,0x20,0x03,0x00,
0x00,0x20,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
unsigned char xdata shuzi1632[] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xc0,0x0e,0x60,0x1c,0x70, /* 0 */
0x38,0x38,0x38,0x38,0x38,0x18,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,
0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x30,0x18,0x38,0x38,0x38,0x38,0x1c,0x70,
0x0e,0x60,0x07,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0xc0,0x0f,0xc0, /* 1 */
0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,
0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,0x01,0xc0,
0x01,0xe0,0x0f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xe0,0x0c,0x78,0x18,0x38, /* 2 */
0x30,0x1c,0x30,0x1c,0x38,0x1c,0x38,0x1c,0x00,0x1c,0x00,0x38,0x00,0x30,0x00,0x70,
0x00,0xe0,0x01,0xc0,0x03,0x80,0x07,0x00,0x0e,0x00,0x0c,0x0c,0x18,0x0c,0x30,0x1c,
0x3f,0xfc,0x3f,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xc0,0x18,0xf0,0x38,0x70, /* 3 */
0x38,0x38,0x38,0x38,0x38,0x38,0x00,0x38,0x00,0x70,0x00,0xe0,0x03,0xc0,0x00,0x70,
0x00,0x38,0x00,0x18,0x00,0x1c,0x00,0x1c,0x38,0x1c,0x38,0x1c,0x38,0x1c,0x38,0x38,
0x18,0x70,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x70,0x00,0xf0, /* 4 */
0x00,0xf0,0x01,0xf0,0x03,0x70,0x03,0x70,0x06,0x70,0x0e,0x70,0x0c,0x70,0x18,0x70,
0x18,0x70,0x30,0x70,0x60,0x70,0x7f,0xfe,0x00,0x70,0x00,0x70,0x00,0x70,0x00,0x70,
0x00,0x70,0x03,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xfc,0x1f,0xfc,0x18,0x00, /* 5 */
0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1b,0xe0,0x1e,0x78,0x1c,0x38,
0x00,0x1c,0x00,0x1c,0x00,0x1c,0x00,0x1c,0x38,0x1c,0x38,0x1c,0x30,0x38,0x30,0x38,
0x1c,0x70,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe0,0x0e,0x38,0x1c,0x38, /* 6 */
0x18,0x38,0x38,0x00,0x30,0x00,0x30,0x00,0x70,0x00,0x77,0xe0,0x7e,0x70,0x78,0x38,
0x78,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x38,0x1c,0x38,0x18,0x1c,0x38,
0x1e,0x70,0x07,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xfc,0x1f,0xfc,0x38,0x18, /* 7 */
0x30,0x30,0x30,0x30,0x00,0x60,0x00,0x60,0x00,0xc0,0x00,0xc0,0x01,0x80,0x01,0x80,
0x01,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x07,0x00,
0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xe0,0x1c,0x70,0x38,0x38, /* 8 */
0x70,0x1c,0x70,0x1c,0x70,0x1c,0x78,0x1c,0x3c,0x38,0x1e,0x30,0x0f,0xe0,0x0f,0xe0,
0x18,0xf0,0x38,0x78,0x70,0x3c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x38,0x38,
0x1c,0x70,0x0f,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xc0,0x1c,0x70,0x38,0x30, /* 9 */
0x38,0x38,0x70,0x18,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x1c,0x70,0x3c,0x38,0x3c,
0x3c,0xfc,0x0f,0xdc,0x00,0x1c,0x00,0x38,0x00,0x38,0x00,0x38,0x38,0x70,0x38,0x70,
0x38,0xe0,0x1f,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
void Delayms(unsigned int x) //@22.1184MHz
{
unsigned long edata i;
while(x--)
{
_nop_();
i = 5528UL;
while (i) i--;
}
}
void UartInit() //定时器1(模式0)做串口1波特率发生器
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器时钟1T模式
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设置定时器模式
TL1 =BRT; //设置定时初始值
TH1 = BRT >> 8; //设置定时初始值
ET1 = 0; //禁止定时器中断
TR1 = 1; //定时器1开始计时
ES = 1; //打开串口中断
EA = 1; //打开总中断
}
void UartSend(unsigned char dat) //单片机发送一个字节
{
SBUF = dat;
while(TI==0);
TI=0;
}
void CheckCustomCmd(unsigned char dat) //检测命令序列:"@STCISP#"
{
unsigned char bStage;
switch (bStage++)
{
default:
L_Check1st:
case 0: //检测命令头
bStage = (dat == '@');
break;
case 1:
if (dat != 'S') goto L_Check1st;
break;
case 2:
if (dat != 'T') goto L_Check1st;
break;
case 3:
if (dat != 'C') goto L_Check1st;
break;
case 4:
if (dat != 'I') goto L_Check1st;
break;
case 5:
if (dat != 'S') goto L_Check1st;
break;
case 6:
if (dat != 'P') goto L_Check1st;
break;
case 7:
if (dat != '#') goto L_Check1st;
Delayms(5); //检测到正确的命令序列后复位到系统区,此处的延时可省去
IAP_CONTR = 0x60; //复位到系统区
break;
}
}
void UartSendStr(unsigned char *p)//单片机发送字符串
{
while (*p)
{
UartSend(*p++);
}
}
void Delayus(unsigned int x) //@20.000MHz
{
unsigned long edata i;
while(x--)
{
_nop_();
_nop_();
_nop_();
i = 3UL;
while (i) i--;
}
}
void Full_RGB_Display(unsigned long color)
{
unsigned int line, pixel;
for(line = 0; line < V_ACTIVE; line++) // 逐行显示 272
{
DE = 1;// 行有效期开始
for(pixel = 0; pixel < H_ACTIVE; pixel++) // 生成一行像素时钟 480
{
// Delayus(100);
port_r=color>>16;
port_g=color>>8;
port_b=color;
CLK = 1;
CLK = 0;
}
DE = 0;// 行有效期结束
for(pixel = 0; pixel < H_BLANK; pixel++) // 行消隐期
{
CLK = 1;
CLK = 0;
}
}
// 帧消隐期
for(line = 0; line < V_BLANK; line++)
{
for(pixel = 0; pixel < H_TOTAL; pixel++)
{
CLK = 1;
CLK = 0;
}
}
}
void Simple_RGB_Display(unsigned long x,unsigned long y) //竖向条文
{
unsigned int line, pixel;
unsigned char i;
for(line = 0; line < V_ACTIVE; line++) // 逐行显示 272
{
DE = 1;// 行有效期开始
for(pixel = 0; pixel < 10; pixel++) // 生成一行像素时钟 480
{
for(i = 0; i < 24; i++)
{
port_r=x>>16;
port_g=x>>8;
port_b=x;
CLK = 1;
CLK = 0;
}
for(i = 0; i < 24; i++)
{
port_r=y>>16;
port_g=y>>8;
port_b=y;
CLK = 1;
CLK = 0;
}
}
DE = 0;// 行有效期结束
for(pixel = 0; pixel < H_BLANK; pixel++) // 行消隐期
{
CLK = 1;
CLK = 0;
}
}
// 帧消隐期
for(line = 0; line < V_BLANK; line++)
{
for(pixel = 0; pixel < H_TOTAL; pixel++)
{
CLK = 1;
CLK = 0;
}
}
}
void pic480272(unsigned long x,unsigned long y) //图片
{
unsigned int line, pixel;
unsigned char a,b,i;
for(line = 0; line < V_ACTIVE; line++) // 逐行显示 272
{
DE = 1;// 行有效期开始
for(pixel = 0; pixel < 60; pixel++) // 生成一行像素时钟 480
{
a=full;
for(i=0;i<8;i++)
{
b=a&0x80;
if(b==0)
{
port_r=y>>16;
port_g=y>>8;
port_b=y;
CLK = 1;
CLK = 0;
}
else
{
port_r=x>>16;
port_g=x>>8;
port_b=x;
CLK = 1;
CLK = 0;
}
a=a<<1;
}
}
DE = 0;// 行有效期结束
for(pixel = 0; pixel < H_BLANK; pixel++) // 行消隐期
{
CLK = 1;
CLK = 0;
}
}
// 帧消隐期
for(line = 0; line < V_BLANK; line++)
{
for(pixel = 0; pixel < H_TOTAL; pixel++)
{
CLK = 1;
CLK = 0;
}
}
}
//void display_3232 (unsigned char x,unsigned char y,unsigned char *p,unsigned long bfcolor, unsigned long bhcolor) //x的范围0-272 y的范围0-60
void display_3232 (unsigned char y,unsigned char x,unsigned char *p)
{
unsigned char i,j;
for(i=0;i<32;i++) //一行480/8个字节
{
for(j=0;j<4;j++) //32*32汉字,汉字一行32/4个字节
{
full[(y*60+x)+(j+i*60)]=p;
}
}
// pic480272(bfcolor,bhcolor);
}
void displayNum_1632 (unsigned char y,unsigned char x,unsigned char a)
{
unsigned char i,j;
unsigned char num;
num=a/100;
for(i=0;i<32;i++) //一行480/8个字节
{
for(j=0;j<2;j++) //16*32数字,数字一行16/82个字节
{
full[(y*60+x)+(j+i*60)]=shuzi1632;
}
}
x=x+2;
num=(a % 100) / 10;
for(i=0;i<32;i++) //一行480/8个字节
{
for(j=0;j<2;j++) //16*32数字,数字一行16/82个字节
{
full[(y*60+x)+(j+i*60)]=shuzi1632;
}
}
x=x+2;
num=a%10;
for(i=0;i<32;i++) //一行480/8个字节
{
for(j=0;j<2;j++) //16*32数字,数字一行16/82个字节
{
full[(y*60+x)+(j+i*60)]=shuzi1632;
}
}
// pic480272(bfcolor,bhcolor);
}
// 主函数
void main(void)
{
unsigned char a;
// P0P1P2口推挽输出
P0M0 = 0xff; //不推挽输出也行
P0M1 = 0x00;
P1M0 = 0xff;
P1M1 = 0x00;
P2M0 = 0xff;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0xc0;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
UartInit();
Delayms(5);
// DISP = 1;// 打开显示直接接3.3v的时候,可以不要这句
while(1)
{
// 主循环空闲,所有工作由中断处理
// 可以在这里添加其他功能
Full_RGB_Display(hong);
Delayms(300); //整屏显示后,大概可以维持800ms,等待时间再长图像就失真了
Full_RGB_Display(huang); //刷一次屏大概170ms
Delayms(300);
Full_RGB_Display(lan);
Delayms(300);
for(a=0;a<25;a++)
{
display_3232 (10,10,shan);
display_3232 (10,10+4,xi);
display_3232 (10,10+4+4,sheng);
displayNum_1632(10,10+4+4+4,a);
pic480272(huang,hei);
}
LED=~LED;
}
}
void UartIsr() interrupt 4 //串口1中断函数
{
// unsigned char i=0;
if (RI) //接收
{
RI = 0;
CheckCustomCmd(SBUF); //检测串口为指定命令函数
}
// if (TI)
// {
// TI = 0;
// }
}现在有个问题:为啥22MHz左右的频率可以正常显示,30Mhz以上频率就花屏,感觉clk翻转是不是太快了,我在clk=1和clk=0中加入延时,还是不行。
955 你这段代码和描述已经非常贴近底层驱动开发了,尤其是在使用国产AI8051芯片(可能是基于增强型8051内核的国产MCU)直接驱动RGB接口的480x272分辨率液晶屏,这种做法在资源受限的MCU平台上具有一定的挑战性。以下是对你的代码和开发思路的专业性分析与优化建议。
一、整体架构分析
你使用的是DE模式驱动RGB接口的TFT液晶屏,这是一种较为常见的驱动方式,适用于没有VSYNC/HSYNC信号的液晶屏,通过DE(Data Enable)信号来判断当前是否处于有效显示区域。
你定义了以下关键参数:
水平分辨率:480
垂直分辨率:272
水平总周期:HACTIVE + HBLANK = 480 + 45 = 525
垂直总周期:VACTIVE + VBLANK = 272 + 14 = 286
主频:22.1184 MHz
RGB接口为24位,使用32位模式兼容
你采用的是一种全屏缓存+像素级替换的方式进行字符显示,这在资源有限的8位MCU上是一种比较常见但效率较低的方式,适用于静态或低帧率显示。
二、关于RGB接口与8051的适配问题
你提到“8位对long的兼容不好”,这可能是指你在进行像素数据拼接时,使用的是unsigned long类型来表示RGB数据(例如RGB888),但在8位MCU上操作32位数据效率较低,容易造成性能瓶颈。
建议:
使用结构体或联合体来处理RGB数据,提高可读性和可移植性;
避免频繁的32位运算,可以将RGB颜色值预处理为数组或常量;
若使用的是RGB565格式(16位),可考虑将颜色数据压缩为16位,降低内存和带宽压力。
三、关于全屏缓存与字符显示的优化
你提到“建立整屏缓存,替换对应字节”的方式,这种方式虽然简单直接,但在8位MCU上会带来以下问题:
1. 内存占用大:480x272x3 = 391,680字节(RGB888),对于片内RAM有限的MCU来说,必须使用外部SRAM或显存;
2. 刷新效率低:每次刷新都要遍历整个缓存,效率低下;
3. 字体渲染方式原始:缺乏字体缓存、区域更新等机制。
建议优化方案:
1. 使用帧缓存压缩(如RGB565)
RGB565格式占用内存为480x272x2 = 261,120字节,节省约1/3内存;
可以通过宏定义或函数实现RGB888到RGB565的转换。
2. 实现字符绘制函数
你提到“不知道怎么写这个函数”,其实可以按如下方式实现一个简单的字符绘制函数:
```c
void DrawChar(int x, int y, char c, unsigned short color) {
const unsigned char font = GetFont(c); // 获取字符点阵数据
for (int row = 0; row < FONTHEIGHT; row++) {
for (int col = 0; col < FONTWIDTH; col++) {
if (font & (1
[本文内容由国芯人工智能辅助生成,仅供参考] 第一次传视频,为啥我传的视频这么大{:fadai:}
页:
[1]