【FPGA黑金开发板】NIOSII那些事儿--LCD驱动及图片显示(二十二)
声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。
简介
这一节,我们来讲解与点阵LCD相关的内容,主要介绍硬件结构及其驱动编写。
做我们这行的,我相信很少有人不知道点阵LCD的,就算没用过也应该见过(俗话说,没吃过猪肉还没见过猪跑啊,呵呵)。不用我多说,大家也知道这东西是做什么用的。不过可能很多人对他的结构还不是很熟悉。通常我们所见到的LCD模块具有LCM(玻璃)、背光、PCB板。其实这三样只有一样是必须要有的,那就是LCM(玻璃)。大家就有点疑问了,没有背光无所谓了,那没有PCB板,就一块玻璃有啥用啊。大家接着听我说,点阵的LCD模块按驱动控制器的集成方式,分为两种:COB和COG,COG就是将驱动控制芯片集成到了玻璃里面,我们只需要在电路板上加上无法集成的电容电阻就可以了;而COB是那种需要将驱动芯片焊接在LCD模块后面的PCB板上的。这回大家应该明白为什么只有一块玻璃就能显示了吧。
在我们黑金开发板上使用的LCD就是128*64的COG液晶,它将驱动控制IC集成到了LCM上,这样就省去了PCB底板,给我们节省了很大的空间。下面,我简单介绍一下这款液晶的一些参数,如下图所示,它的驱动芯片为ST7565P。支持三种接口方式,我们采用的是串行时序方式,接口简单,使用方便,相比其他两种,也节省了很多的管脚。

下图为LCD的串行接口原理图,大家可以看到,仅四根线就可以搞定了。

对于LCD而言,需要清楚的了解驱动控制IC的显存与LCD上的点的对应关系,这一点非常重要。通过下图,我们可以了解到,LCD的显存中存在8(page)*8+1行,即65行,s0-s131,即132列,而液晶只有64*128个点。因此显存上的一些数据是不能显示的。通过实验测试得知,最后一行(page8中的D0)和最后三列(ADC为正常时,s129、s130、s131;ADC为反向时,s0、s1、s2)是不能显示的,而显存上其他数据与LCD上的点一一对应。如下图的红圈处所示的区域。

显示屏上的每一个点都对应有控制器片内的显示缓存RAM中的一个位, 显示屏上64*128个点分别对应着显示RAM的8个Page, 每一个Page有128个byte的空间对应,如下表所示

大家如要点亮 LCD 屏上的某一个点时,实际上就是对该点所对应的显示 RAM 区中的某一个位进行置 1 操作;所以就要确定该点所处的行地址、列地址。从上图中可以看出,液晶的行地址实际上就是 Page 的信息,每一个 Page应有 8 行;而列地址则表示该点的横坐标,在屏上为从左到右排列,Page 中的一个 Byte 对应的是一列(8行,即 8 个点) ,达 128列。 可以根据这样的关系在程序中控制 LCD显示屏的显示。
硬件设置
下面我们来看,如果如何在NIOS下驱动液晶屏。首先,我们需要在软核中四个PIO口,分别对应LCD的四个引脚。如下图所示,四个PIO模块全部为输出。

建好以后,自动分配地址,中断,编译…
然后,我们回到Quartus中,通过TCL脚本分配好管脚疑惑,LCD部分如下图示是

接着又是编译,完成以后,硬件部分的设置就结束了。
软件开发
接下来,我们打开NIOS IDE软件。
第一步做的还是需要进行一次完全编译,Ctrl+b,漫长的等待…
编译完成后,我们进入system.h,查看是否有我们想要得到的LCD部分,如下表所示
| 02 | * LCD_SI configuration |
| 06 | #define LCD_SI_NAME "/dev/LCD_SI" |
| 07 | #define LCD_SI_TYPE "altera_avalon_pio" |
| 08 | #define LCD_SI_BASE 0x000018b0 |
| 11 | * LCD_A0 configuration |
| 15 | #define LCD_A0_NAME "/dev/LCD_A0" |
| 16 | #define LCD_A0_TYPE "altera_avalon_pio" |
| 17 | #define LCD_A0_BASE 0x000018c0 |
| 20 | * LCD_SCL configuration |
| 24 | #define LCD_SCL_NAME "/dev/LCD_SCL" |
| 25 | #define LCD_SCL_TYPE "altera_avalon_pio" |
| 26 | #define LCD_SCL_BASE 0x000018d0 |
| 29 | * LCD_CS configuration |
| 33 | #define LCD_CS_NAME "/dev/LCD_CS" |
| 34 | #define LCD_CS_TYPE "altera_avalon_pio" |
| 35 | #define LCD_CS_BASE 0x000018e0 |
接下来,我们需要在sopc.h中添加LCD部分的代码
| 03 | unsigned long int DATA; |
| 04 | unsigned long int DIRECTION; |
| 05 | unsigned long int INTERRUPT_MASK; |
| 06 | unsigned long int EDGE_CAPTURE; |
| 13 | #define LCD_CS ((PIO_STR *) LCD_CS_BASE) |
| 14 | #define LCD_SCL ((PIO_STR *) LCD_SCL_BASE) |
| 15 | #define LCD_A0 ((PIO_STR *) LCD_A0_BASE) |
| 16 | #define LCD_SI ((PIO_STR *) LCD_SI_BASE) |
接下来,我们根据LCD串行方式的时序图来编写LCD的驱动,时序图如下图所示

我们需要在工程目录中的driver下建立lcd.c文件,代码如下
| 002 | * ================================================================= |
| 008 | * Compiler: Nios II 9.0 IDE |
| 010 | * Email: avic633@gmail.com |
| 011 | * ================================================================== |
| 014 | /*------------------------------------------------------------------- |
| 016 | *-----------------------------------------------------------------*/ |
| 019 | #include "../inc/sopc.h" |
| 021 | /*------------------------------------------------------------------ |
| 023 | *-----------------------------------------------------------------*/ |
| 026 | /*-- 宽度x高度=128x64 --*/ |
| 027 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 028 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 029 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 030 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 031 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 032 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 033 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 034 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 035 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0xF0, |
| 036 | 0xF0,0x78,0x38,0x38,0x38,0x78,0xF0,0xF0,0xE0,0x80,0x00,0x00,0xE0,0xF0,0xF8,0x38, |
| 037 | 0x38,0x38,0x38,0x78,0xF0,0xF0,0xC0,0x00,0x00,0xF8,0xF8,0xF8,0x00,0x00,0x00,0x00, |
| 038 | 0x00,0xF8,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xF8,0xF8,0x38, |
| 039 | 0x38,0x38,0x38,0x38,0x38,0x38,0x00,0x00,0xF8,0xF8,0xF8,0x38,0x38,0x38,0x38,0x78, |
| 040 | 0xF8,0xF0,0xE0,0x00,0x00,0x80,0xE0,0xF0,0xF0,0x78,0x38,0x38,0x38,0x38,0x78,0xF0, |
| 041 | 0xF0,0x40,0x00,0x00,0x00,0x00,0xC0,0xF8,0xF8,0x38,0xF8,0xF8,0xC0,0x00,0x00,0x00, |
| 042 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 043 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x7F,0xFF, |
| 044 | 0xF0,0xE0,0xC0,0xC0,0xC0,0xE0,0xF0,0xFF,0x7F,0x1F,0x00,0x00,0x31,0xF3,0xF7,0xE7, |
| 045 | 0xC7,0xC6,0xCE,0xCE,0xFC,0xFC,0x78,0x00,0x00,0xFF,0xFF,0xFF,0x07,0x07,0x07,0x07, |
| 046 | 0x07,0xFF,0xFF,0xFF,0x00,0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x00,0xFF,0xFF,0xFF,0x07, |
| 047 | 0x07,0x07,0x07,0x07,0x07,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x0E,0x0E,0x0E,0x0E,0x0F, |
| 048 | 0x0F,0x07,0x03,0x00,0x00,0x1F,0x7F,0xFF,0xF0,0xE0,0xC0,0xC0,0xDC,0xDC,0xDC,0xFC, |
| 049 | 0xFC,0x7C,0x00,0x80,0xF0,0xFE,0x7F,0x3F,0x39,0x38,0x39,0x3F,0x7F,0xFE,0xF0,0x80, |
| 050 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 051 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 052 | 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, |
| 053 | 0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00, |
| 054 | 0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00, |
| 055 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, |
| 056 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00, |
| 057 | 0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01, |
| 058 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 059 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 060 | 0x00,0x00,0x00,0x00,0x00,0xF8,0xF8,0x28,0xE8,0xC8,0xF8,0xF8,0xC8,0x68,0x28,0xF8, |
| 061 | 0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0x60,0x38,0x38,0x60,0xC0,0x80, |
| 062 | 0x80,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0xF0,0xF0,0x10,0x10,0x10,0xF0, |
| 063 | 0xF0,0x10,0x10,0x10,0x10,0x00,0x00,0x80,0xF0,0xF0,0x80,0x80,0xF8,0xF8,0x80,0x90, |
| 064 | 0xB0,0xE0,0xE0,0x80,0x80,0x80,0x00,0x80,0x80,0x80,0xF8,0xF8,0x80,0x80,0xF0,0xF0, |
| 065 | 0x10,0x10,0x18,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 066 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 067 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 068 | 0x00,0x00,0x00,0x20,0xA0,0xA9,0x29,0xA9,0xA9,0x29,0x3F,0xBF,0xA9,0x29,0x29,0x29, |
| 069 | 0xA9,0xA0,0x20,0x00,0x02,0x02,0x13,0x11,0x53,0xD2,0x92,0xFE,0xFE,0x12,0xD2,0xD2, |
| 070 | 0x13,0x13,0x03,0x01,0x00,0x02,0x02,0x02,0x82,0xE2,0x7F,0x1F,0x02,0x02,0x02,0xFF, |
| 071 | 0xFF,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x81,0xC1,0x78,0x3F,0x3F,0x74,0xC4,0xC4, |
| 072 | 0x7C,0x3C,0x00,0x00,0x00,0x00,0x00,0x20,0x38,0x1E,0xFF,0xFF,0x8E,0xFC,0x7F,0x0F, |
| 073 | 0x8F,0xDD,0x71,0xFD,0x8F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 074 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 075 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 076 | 0x00,0x00,0x00,0x02,0x03,0x01,0x00,0x00,0x03,0x03,0x00,0x00,0x03,0x03,0x00,0x00, |
| 077 | 0x00,0x03,0x03,0x00,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x02, |
| 078 | 0x02,0x02,0x02,0x02,0x00,0x00,0x02,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x03, |
| 079 | 0x03,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x01,0x04,0x04,0x06,0x02,0x03,0x01,0x01, |
| 080 | 0x01,0x03,0x06,0x06,0x02,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x02,0x03, |
| 081 | 0x01,0x00,0x00,0x01,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 082 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 083 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 084 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 085 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 086 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 087 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 088 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 089 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 090 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 |
| 092 | //-----------------Function Prototype--------------------// |
| 093 | void initialize_lcd(void); |
| 094 | void draw_screen(unsigned char *p); |
| 096 | void write_data(unsigned char dat); |
| 097 | void data_send(unsigned char dat); |
| 098 | void write_command(unsigned char com); |
| 101 | * === FUNCTION ================================================== |
| 103 | * Description: 发送一个字节数据 |
| 104 | * ================================================================= |
| 106 | void data_send(unsigned char dat) |
| 114 | if(dat&0x80)LCD_SI->DATA=1; |
| 128 | * === FUNCTION =================================================== |
| 129 | * Name: write_command |
| 130 | * Description: A0为低时,写命令字, |
| 131 | * ================================================================= |
| 133 | void write_command(unsigned char com) |
| 141 | * === FUNCTION =================================================== |
| 143 | * Description: A0为高时,写数据 |
| 144 | * ================================================================= |
| 146 | void write_data(unsigned char dat) |
| 153 | * === FUNCTION =================================================== |
| 156 | * ================================================================= |
| 158 | void set_x(unsigned char x) |
| 160 | write_command(x>>4|0x10); |
| 161 | write_command(x&0xf); |
| 164 | * === FUNCTION =================================================== |
| 166 | * Description: 设置页地址 一共8页 |
| 167 | * ================================================================= |
| 169 | void set_y(unsigned char y) |
| 171 | write_command(y|0xb0); |
| 174 | * === FUNCTION =================================================== |
| 177 | * ================================================================= |
| 184 | for(page=0;page<8;page++) { |
| 185 | set_y(page);//设置页地址,一共8页 |
| 186 | set_x(0x00);//设置列地址为0 |
| 188 | for(seg=0;seg<128;seg++){ |
| 194 | * === FUNCTION =================================================== |
| 196 | * Description: 显示一张128*64的图片 |
| 197 | * ================================================================= |
| 199 | void draw_screen(unsigned char *p) |
| 204 | for(page=0;page<8;page++) { |
| 205 | set_y(page);//设置页地址,一共8页 |
| 206 | set_x(0x00);//设置列地址为0 |
| 208 | for(seg=0;seg<128;seg++){ |
| 214 | * === FUNCTION =================================================== |
| 215 | * Name: initialize_lcd |
| 216 | * Description: LCD初始化,初始化函数由厂商提供,相关设置请查询datasheet |
| 217 | * ================================================================= |
| 219 | void initialize_lcd(void) |
| 221 | write_command(0xaf); //ON DISPLAY |
| 222 | write_command(0x40); //STAR DISPLAY |
| 223 | write_command(0xa0); //ADC NORMAL |
| 224 | write_command(0xa6); //Display Normal |
| 225 | write_command(0xa4); //CLEAR |
| 226 | write_command(0xa2); //1/9BIAS |
| 227 | write_command(0xc8); //COMMON OUTPUT DIRECTION |
| 228 | write_command(0x2f); //POWER CONTROL |
| 229 | write_command(0x24); //RESISTER RATIO |
| 230 | write_command(0x81); //VOLUM MODE SET |
| 231 | write_command(0x24); //RESISTER RATIO |
写好驱动以后,我们还需要在工程目录的inc下建立lcd.h函数,代码如下:
| 02 | * ================================================================= |
| 08 | * Compiler: Nios II 9.0 IDE |
| 10 | * Email: avic633@gmail.com |
| 11 | * ================================================================= |
| 17 | extern void initialize_lcd(void); |
| 18 | extern void draw_screen(unsigned char *p); |
| 19 | extern void clear(void); |
| 20 | extern unsigned char buf[]; |
接下来,需要做的就是写个测试函数,在main.c中添加如下代码
| 02 | * ================================================================= |
| 04 | * Description: LCD试验,在LCD上打印128*64图片 |
| 08 | * Compiler: Nios II 9.0 IDE |
| 10 | * Email: avic633@gmail.com |
| 11 | * ================================================================= |
| 14 | /*------------------------------------------------------------------ |
| 16 | *-----------------------------------------------------------------*/ |
| 17 | #include "../inc/lcd.h" |
| 20 | * === FUNCTION =================================================== |
| 23 | * ================================================================= |
OK,代码就全部写好了。编译之后将程序下载进去,我们就可以看出效果了,如下图所示,显示的效果还是很不错的。

上面涉及到了一个放置图片的数组,这个数组是通过点阵液晶取模软件生成的。我下面简单介绍一下它的使用方法。
首先打开点阵液晶取模软件,如下图所示

如果想显示128*64的图片,首先就要有一个分辨率为128*64的图片,然后按打开图像图标,如下图所示红圈处,将图片载入

然后按下图所示红圈1,点击取模方式。然后点击红圈2,这时在红圈3处就会生成我们需要的16进制的代码了。操作很简单,软件里面还有很多功能,大家可以自行研究一下。

好了,这一节我们就讲完了。下一节,我们将在这一节的基础上,研究有关中文显示和英文变宽字体显示的方法,敬请期待…
阅读(1608) | 评论(0) | 转发(0) |