三十八.进入自己的控制台LCD

来源:互联网 发布:java 微秒 编辑:程序博客网 时间:2024/05/21 11:59

1.ARM系统中LCD体系架构


其中LCD驱动芯片和LCD显示器是连接在LCD模块上的,而LCD控制器则是在ARM处理器上的。

2.液晶工作原理:
液晶分子为长棒子状,通过分子的电流不一样, 他们会发生不同程度的偏转,从而对背光灯的光线产生不同程度的反射和折射,进而使得显示的像素呈现出不同的色彩。每个分子对应一个像素,很多像素构成一幅图像。

3.液晶屏分类:常见的有STN的,就是玩单片机用到的12864还有1602等,以及GF,而我们现在说的大都是TFT的。


4.LCD驱动芯片:为液晶分子的偏转提供电压,从而达到控制LCD的效果。相当于神经网络。

5.LCD控制器:为LCD驱动芯片提供必要的数据和控制信号。这是相当于大脑,LCD显示器就相当于器官。REGBANK里有寄存器组,调色板内存。LCDCDMA则是用来控制帧缓存(内存)里的数据到LCD显示器,不需要CPU干预。VIDPRCS则是像素数据,TIMEGEN则是控制时序的,与REGBANK密切相关。

6.显示过程


7.时序信号


8.各信号含义:

9.简要概括

10.引脚初始化,找到原理图VD对应的引脚,然后在datasheet里面找到相应的GPIO寄存器区写入初值,让这些引脚工作在LCD数据传输模式。

11时序初始化:
(1)找出需要初始化什么时序信号
(2)找到初始化这些信号的寄存器(LCDCON1,LCDCON2,LCDCON3,LCDCON4)
(3)根据datashhet确定初始化的值


12.帧缓冲初始化:
(1)分配空间,分辨率的两倍,每个像素用两个字节来描述。一般静态分配,用二维数组来分配,数组元素类型是描述颜色的位数对应的类型。但不一定是两倍,即不是只能用16位描述一个像素,位数越多颜色越丰富。

(2)告知地址:由DMA来搬运数据,不需要CPU干预。所以DMA首先要知道数据在内存中的地址,即帧缓存。(LCDSADDR1,2,3)起始地址,结束地址,是否间隔,多少半字单位。


13.杂项初始化:
(1)选择什么屏
(2)选择控制像素的位数
(3)是否打开LCD
(4)选择颜色控制格式(LCDCON5)
(5)选择所用LCD的HSYNC以及VSYNC的极性,即是否选择反转。默认三星的是高电平的极性。(LCDCON5)
(6)打开半字转换(LCDCON5),后来我发现打不打开都可以,这里表示有疑问???
(7)关闭临时调色板(TPAL)
(8)打开电源引脚功能(LCD_PWR,引脚复用,LCDCON5打卡电源允许)
(9)使能LCD控制器(LCDCON1)

14.画点函数:
(1)定义坐标,与帧缓存里面的数组的行列注意对应关系。
(2)颜色转换。根据datasheet将24位转换为16为数据,再赋值。
(3)建议大家初始化的时候不要使能LCD的数据输出,不然会花屏,建议大家用这个画点的思想,在最初上电的时候,进行一个清屏操作,根据自己想要的颜色来做。虽然老师说过这种方法比较傻,不如调色板好用,但是我试验了,用调色板清屏以后就不能在画图,具体原因还没弄清楚。所以为了避免一开机就花屏,建议大家用循环的方式不断往帧缓存里面写入相同的颜色值。这里不是纯粹的调用画点函数,那样的话效率很低,每次都要做移位运算。建议这样写,会加速清屏时间。
void lcd_clear_init(U32 color){U32 x,y;U32 red,green,blue;U16 temp;red = ((color >> 19) & 0x1f);green = ((color >> 10) & 0x3f);blue = ((color >> 3) & 0x1f);temp = (U16)((red << 11) | (green < 5) | blue);for(y = 0;y < 272;y++){for(x = 0;x < 480;x++)buf[y][x] = temp;}}


15.画线画图:利用画点函数,学会使用取模软件,单色显示要用到调色板(TPAL)。
我想实现一个函数,在任意两点之间画一条直线,但是由于像素是一个个小方格,不是直接连起来的圆点,目前还未实现,希望大家提出想法一起探讨。争取找一个好算法。

16.我用mini2440板子,用的tq4.3的液晶,不是迷你自带的LCD 
代码如下:
(1)宏定义和全局变量定义部分
#define VSPW 9#define VBPD 1#define LINEVAL 271#define VFPD 1#define HSPW 40#define HBPD 1#define HOZVAL 479#define HFPD 1#define CLKVAL4 #define U32unsigned int #define U16unsigned short #define U8unsigned char unsigned short buf[272][480];

这些参数是根据这张表和时序信号图以及LCDCON1的描述得到的




(2)引脚初始化
void lcd_port_init(){GPCCON = 0xAAAAAAAA;GPDCON = 0xAAAAAAAA;}

(3)时序初始化
void lcd_time_init(){LCDCON1 = (CLKVAL<<8);LCDCON2 = (VBPD << 24)| (LINEVAL << 14) | (VFPD << 6) | (VSPW);LCDCON3 = (HBPD << 19) | (HOZVAL << 8) | (HFPD << 0);LCDCON4 = (HSPW << 0);}

(4)帧缓存初始化
void lcd_frame_init(){LCDSADDR1 = ((U32)(((U32)buf >> 22)<<21)) | ((U32)(((U32)buf >> 1) & 0x1fffff) << 0);LCDSADDR2 = (U32)(((((U32)buf + 272*480*2) >> 1) & 0x1fffff) << 0);LCDSADDR3 = ((U32)(0 <<11)) | ((U32)(480<<0));}
(5)杂项初始化
void lcd__others_init(){LCDCON1 |= (3 << 5) | (0xc << 1) | (0 << 0);LCDCON5 = (1 << 11) | (1 << 9) | (1 << 8) | (1 << 0);TPAL = 0;GPGCON |=  (3 << 8);LCDCON5 |= (1 << 3);LCDCON1 |= (1 << 0);}

(6)总的初始化
void lcd_init(){lcd_port_init();lcd_time_init();lcd_frame_init();lcd__others_init();lcd_clear_init(0x0000CD);Delay(500000);}

(7)画点函数
void lcd_point(U16 x, U16 y,U32 color){U32 red,green,blue;red = ((color >> 19) & 0x1f);green = ((color >> 10) & 0x3f);blue = ((color >> 3) & 0x1f);buf[y][x] = (U16)((red << 11) | (green < 5) | blue);}

(8)用调色板清屏函数
void lcd_clear(U32 color){TPAL = (1<<24)|(color&0xffffff);}

(9)画”十字架“函数
void lcd_line(){U32 x,y;for(x = 0; x < 480;x++){lcd_point(x,136,0xFF0000);}for(y = 0; y < 272;y++){lcd_point(240,y,0x54FF9F);}}


(10)画一张预存好的图片函数
extern const U8 pic[85928];void lcd_picture(U16 x_start,U16 y_start,U16 x_size,U16 y_size,const U8* pic){U32 y = 0,x = 0;U16 temp = 0;U32 p = 0;for(y = y_start; y < y_start + y_size;y++){for(x = x_start; x < x_start + x_size;x++){temp = ((U16)pic[p]) | (((U16)pic[p + 1]) << 8);if(x < 480 && y < 272){buf[y][x] = temp;}p += 2;}}}

(11)开机使用的清屏函数
void lcd_clear_init(U32 color){U32 x,y;U32 red,green,blue;U16 temp;red = ((color >> 19) & 0x1f);green = ((color >> 10) & 0x3f);blue = ((color >> 3) & 0x1f);temp = (U16)((red << 11) | (green < 5) | blue);for(y = 0;y < 272;y++){for(x = 0;x < 480;x++)buf[y][x] = temp;}}

(12)延时函数
void Delay(U32 time){while(time--);}

(13)测试函数
void lcd_tes(){lcd_line();Delay(500000);lcd_picture(0,0,240,179,pic);Delay(500000);}

6410代码

/****************************@File:lcd.c@@Tiny6410裸机下学期代码@LCD配置文件@Author:小君君@****************************/#include "common.h"void lcd_init(){/*1.配置GPIO*/(vi GPECON) = 0x00011111;(vi GPEDAT) = 0x00000001;(vi GPFCON) = 0x96AAAAAA;(vi GPFDAT) = 0x00002000;(vi GPICON) = 0xAAAAAAAA;(vi GPJCON) = 0x00AAAAAA;/*2.设置MOFPCON为normal mode*/(vi MIFPCON) &= ~(1<<3);/*3.设置SPCON,选择RGB/IF style*/(vi SPCON) &= ~(0x3);(vi SPCON) |= 1;/*4.设置VIDCONx,选择接口类型,输出格式,时钟,极性,使能LCD控制器*//*ENVID_F = 1,当前帧结束后使能 LCD 控制器;ENVID = 1,使能 LCD 控制器;CLKSEL_F = 0, 选择时钟源为 HCLK;CLKDIR = 1, 选择需要分频;VCLKFREE = 0,选择 normal mode;CLKVAL_F = 10, 分频系数为 9,即 VCLK = 133 / (9+1) = 13MHz;CLKVALUP = 0,总是选择 CLKVAL_F 来更新时序控制;RGSPSEL = 0,RGB 并行;VIDOUT=0,使用 RGB 接口;*/(vi VIDCON0) = (0<<26)|(0<<17)|(0<<16)|(10<<6)|(0<<5)|(1<<4)|(0<<2)|(3<<0);(vi VIDCON1) |= 1<<5 | 1<<6;/*5.设置VIDTCONx,选择时序和分辨率*/(vi VIDTCON0) = VBPD<<16 | VFPD<<8 | VSPW<<0;(vi VIDTCON1) = HBPD<<16 | HFPD<<8 | HSPW<<0;(vi VIDTCON2) = (LINEVAL << 11) | (HOZVAL << 0);/*6.设置WINCON0,设置window0的数据格式*//*Enable the video output and the VIDEO control signal.*//*1011 = unpacked 24 BPP (non-palletized R:8-G:8-B:8 ) */(vi WINCON0) |= 1<<0;(vi WINCON0) &= ~(0xf << 2);(vi WINCON0) |= 0xB<<2;/*7.配置VIDOSDOA/B/C,设置window0坐标*//*结合LCD的Data Input Format可知宽480,高272像素*//*所以左上角坐标(0,0),右下角(479,271)*/(vi VIDOSD0A) = (LeftTopX<<11) | (LeftTopY << 0);(vi VIDOSD0B) = (RightBotX<<11) | (RightBotY << 0);(vi VIDOSD0C) = (LINEVAL + 1) * (HOZVAL + 1);/*8.设置VIDWOOADD0B0以及VIDWOOADD1B0,设置framebuffer的地址*/(vi VIDW00ADD0B0) = FRAME_BUFFER;(vi VIDW00ADD1B0) = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);}// 描点void lcd_draw_pixel(int row, int col, int color){unsigned long * pixel = (unsigned long  *)FRAME_BUFFER;*(pixel + row * COL + col) = color;}// 清屏void lcd_clear_screen(int color){int i, j;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++)lcd_draw_pixel(i, j, color);}// 划横线void lcd_draw_hline(int row, int col1, int col2, int color){int j;// 描第row行,第j列for (j = col1; j <= col2; j++)lcd_draw_pixel(row, j, color);}// 划竖线void lcd_draw_vline(int col, int row1, int row2, int color){int i;// 描第i行,第col列for (i = row1; i <= row2; i++)lcd_draw_pixel(i, col, color);}// 划十字void lcd_draw_cross(int row, int col, int halflen, int color){lcd_draw_hline(row, col-halflen, col+halflen, color);lcd_draw_vline(col, row-halflen, row+halflen, color);}// 绘制同心圆void lcd_draw_circle(void){int x,y;int color;unsigned char red,green,blue,alpha;int xsize = ROW;int ysize = COL;for (y = 0; y < ysize; y++)for (x = 0; x < xsize; x++){color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;red   = (color/8) % 256;green = (color/4) % 256;blue  = (color/2) % 256;alpha = (color*2) % 256;color |= ((int)alpha << 24);color |= ((int)red   << 16);color |= ((int)green << 8 );color |= ((int)blue       );lcd_draw_pixel(x,y,color);}}

/****************************@File:common.h@@Tiny6410裸机下学期代码@常用头文件定义@Author:小君君@****************************/#ifndef __COMMON_H__#define __COMMON_H__#define  vi   *( volatile unsigned long * ) #define ulong unsigned long/*取消使用mmu*///#define MMU_ENABLE 1/*LED初始化*/#ifndef MMU_ENABLE#define LED_CON 0x7F008800#define LED_DAT  0x7F008808#else#define LED_CON 0xA0008800#define LED_DAT  0xA0008808#endifvoid mmu_init();void led_init();void led_on();void led_off();void led1_on();void led2_on();void led3_on();void led4_on();void led5_on();void led6_on();void led7_on();void led8_on();/*按键相关初始化*/#define KEYCON  0x7f008830#define KEYCON1 0x7f008814#define K1_MSK (3 << 0)#define K2_MSK (3 << 2)#define K3_MSK (3 << 4)#define K4_MSK (3 << 6)#define K5_MSK (3 << 8)#define K6_MSK (3 << 10)#define K7_MSK (0xF << 12)#define K8_MSK (0xF << 16)#define K1_OK (2 << 0)#define K2_OK (2 << 2)#define K3_OK (2 << 4)#define K4_OK (2 << 6)#define K5_OK (2 << 8)#define K6_OK (2 << 10)#define K7_OK (0x3 << 12)#define K8_OK (0x3 << 16)void button_init();/*中断控制器相关的寄存器地址*/#define EXT_INT_0_CON       0x7f008900   #define EXT_INT_1_CON       0x7f008904  #define EXT_INT_0_MASK      0x7f008920 #define EXT_INT_0_PEND      0x7f008924     #define VIC0INTENABLE       0x71200010   #define VIC1INTENABLE       0x71300010#define EINT0_VECTADDR      0x71200100 /*每个中断源有一个寄存器存放相应的中断处理函数的地址,共32+32 = 64个*/#define EINT1_VECTADDR      0x71200104#define EINT2_VECTADDR      0x71200108#define EINT3_VECTADDR      0x7120010C#define EINT4_VECTADDR      0x71200110#define EINT5_VECTADDR      0x71200114/*以上是VIC0,见6410datasheet的P414*/#define EINT19_VECTADDR     0x71300100     #define EINT20_VECTADDR     0x71300104 /*以上是VIC1*/#define VIC0ADDRESS         0x71200f00   #define VIC1ADDRESS         0x71300f00void irq_init();/*nandflash相关寄存器定义*/#define NFCONF  0x70200000 #define NFCONT  0x70200004 #define NFCMMD  0x70200008 #define NFADDR  0x7020000C #define NFDATA  0x70200010 #define NFDATA8 (*(volatile unsigned char *)0x70200010) #define NFSTAT  0x70200028int nand_erase(unsigned int block_addr);int Nand_PageWrite(unsigned long start_addr,char *buf);/*UART相关寄存器定义*/#define UARTCON     0x7F008000#define ULCON0      0x7F005000#define UCON0       0x7F005004#define UFCON0      0x7F005008#define UMCON0      0x7F00500C#define UTRSTAT0    0x7F005010#define UFSTAT0     0x7F005018#define UTXH0      (*((volatile unsigned char *)0x7F005020))//注意是char类型的#define URXH0      (*((volatile unsigned char *)0x7F005024))#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))//注意是short类型的#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))#define UART_FIFO_ENABLE 1  //最好使用FIFO模式,就是必须有这个宏定义void uart_init();#ifdefUART_FIFO_ENABLEchar getchar(void);void putchar(char c);void send_string(char* str);#elseunsigned char getchar(void);void putchar(unsigned char c);void send_string(unsigned char* str);#endif/*DMA相关定义*/#define UTXH0_DMA 0x7F005020#define DMA_BASE 0x75000000#define DMACC0SrcAddr  (DMA_BASE + 0x100)#define DMACC0DestAddr (DMA_BASE + 0x104)#define DMACC0Control0 (DMA_BASE + 0x10C)#define DMACC0Control1 (DMA_BASE + 0x110)#define DMACC0Configuration (DMA_BASE + 0x114)#define DMACC0ConfigurationExp (DMA_BASE + 0x118)#define DMACC0LLI (DMA_BASE + 0x108)#define DMACEnbldChns (DMA_BASE + 0x01C)#define DMACConfiguration (DMA_BASE + 0x030)#define DMACSync (DMA_BASE + 0x034)#define DMA_SEL 0x7E00F110void dma_init();void dma_start();/*LCD相关寄存器定义*/#define GPECON  0x7F008080#define GPEDAT  0x7F008084#define GPEPUD  0x7F008088#define GPFCON  0x7F0080A0#define GPFDAT  0x7F0080A4#define GPFPUD  0x7F0080A8#define GPICON  0x7F008100#define GPIPUD  0x7F008108#define GPJCON  0x7F008120#define GPJPUD  0x7F008128/* display controller */#define MIFPCON  0x7410800C#define SPCON        0x7F0081A0#define VIDCON0      0x77100000#define VIDCON1      0x77100004#define VIDTCON0     0x77100010#define VIDTCON1     0x77100014#define VIDTCON2     0x77100018#define WINCON0      0x77100020#define VIDOSD0A      0x77100040#define VIDOSD0B      0x77100044#define VIDOSD0C      0x77100048#define VIDW00ADD0B0    0x771000A0#define VIDW00ADD1B0    0x771000D0#define VIDW00ADD2      0x77100100#define DITHMODE        0x77100170#define FRAME_BUFFER   0x54000000#define ROW272#define COL480#define HSPW (2)#define HBPD (40- 1)#define HFPD (5 - 1)#define VSPW(2)#define VBPD (8 - 1)#define VFPD (9 - 1)#define LINEVAL (271)#define HOZVAL(479)#define LeftTopX     0#define LeftTopY     0#define RightBotX   479#define RightBotY   271void lcd_init();void lcd_draw_pixel(int row, int col, int color);void lcd_clear_screen(int color);void lcd_draw_hline(int row, int col1, int col2, int color);void lcd_draw_vline(int col, int row1, int row2, int color);void lcd_draw_cross(int row, int col, int halflen, int color);void lcd_draw_circle(void);#define WIDTHEIGHT480#define HEIGHT272#endif

/****************************@File:main.c@@Tiny6410裸机下学期代码@LCD测试文件@Author:小君君@****************************/#include "common.h"int main(void){int num = 1000;//mmu_init();//MMU初始化,这里不使用MMUled_init();//LED的GPIO初始化button_init();//按键初始化irq_init();//中断初始化led_on();//点亮4颗LEDuart_init();//串口初始化putchar('a');putchar('\r');putchar('\n');putchar('b');putchar('\r');putchar('\n');dma_init();//DMA初始化dma_start();//启动DMA发送数据到串口uart_init();//串口再次初始化,使得串口恢复中断或者轮询模式lcd_init();lcd_clear_screen(0xFFFFFF);while(1){printf("=================================================\n\r");printf("===================JUN-BOOT======================\n\r");printf("0.Send the ARP to get yhe host's MAC address\n\r");printf("1.Download the linux kernel from tftp\n\r");printf("2.Boot linux OS from SDRAM\n\r");printf("3.Junjun is a houmorous\n\r");printf("=================================================\n\r");printf("===================LCD_TEST======================\n\r");printf("4.清屏\n\r");printf("5.画横线\n\r");printf("6.画竖线\n\r");printf("7.画十字架\n\r");printf("8.画同心圆\n\r");printf("                                                   \n\r");printf("请输入0-8任意一个数字:\n\r");scanf("%d",&num);switch(num){case 0:printf("请支持成都国嵌\n\r");break;case 1:printf("国嵌学院=====打造你的嵌入式人生\n\r");break;case 2:printf("学ARM,学Linux,学C++,学安卓,学嵌入式,就到成都国嵌学院\n\r");break;case 3:printf("只要你肯努力,你的明天就会等你!!\n\r");break;case 4:lcd_clear_screen(0x000000);break;case 5:lcd_clear_screen(0x000000);lcd_draw_hline(HEIGHT/2, 100, WIDTHEIGHT-100, 0xff0000);break;case 6:lcd_clear_screen(0x000000);lcd_draw_vline(WIDTHEIGHT/2, 50, HEIGHT-50, 0xff0000);break;case 7:lcd_clear_screen(0x000000);lcd_draw_cross(HEIGHT/2, WIDTHEIGHT/2, 20, 0x777777);break;case 8:lcd_clear_screen(0x000000);lcd_draw_circle();break;default:printf("只要你肯努力,你的明天就会等你!!\n\r");break;}}return 0;}


0 0
原创粉丝点击