目录:
一、引言
二、LCD接口说明
三、并行接口说明
四、接口连接说明
五、控制程序接口说明
六、实例说明
一 引言:
1.1编写目的
为了在产品开发过程中更好的了解有关LCD和PARALLEL部分的相关知识,更快的对使用LCD和PARALLELL组件进行开发,特此编写此文档。
1.2背景
目前的软硬件结合的专用系统越来越多的使用LCD显示其状态,这不仅有助于用户了解系统的情况,同时更加方便的对用户的操作进行指示,也为维护人员提供直接的基本的参考。而且,具备LCD组件的设备也可以让整体系统在视觉上感觉较好,是侧面划分产品档次可开发实力的依据。
字符型LCD目前发展已经比较成熟,接口已经十分规范化、标准化,其成本很低,投入较低的成本即可获得良好的效果。
1.3关键字
1)LCD:
2)PARALLEL接口:
3)Linux:
4)线路图:
5)PCB:
6)高/低电平:1为高电平、0为低电平
7)1602:字符型液晶模块,是一种用5x7点阵图形来显示字符的液晶显示器,显示的容量为2行16个字,俗称16X2。还有1行16个字(1601)和2行20个字(2002)等等。
8)CGROM:字符发生存储器
9)DDRAM:Display Data RAM
1.4参考资料
1)相应LCD生产厂家的产品资料
2)并行口标准
3)Linux Port I/O Howto
二 LCD接口说明:
2.1字符型1602类接口
此处使用常见的1602型LCD模块作为实例进行说明。这一类模块接口具有14根主要引脚,8根数据线,6根控制线。一般还具有15和16脚,为背光供电线路。一般不具有第17引脚,如果有17脚的可以接到3脚VLc上。
2.1.1物力特性
第1脚:VSS为地电源
第2脚:VDD接5V正电源
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度
第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。如果需要采用4位传送数据,应该采用DB4-DB7来传送数据
第15脚:B+,背光正极
第16脚:B-,背光负极
第17脚:LCD,
2.1.2指令系统
1602的指令系统源自日立公司的HD44780控制器指令,这已经成为默认标准,绝大多数的模块都兼容。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如表所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”
(1602字符编码表)
1602液晶模块内部的控制器共有11条控制指令,如表所示
序号 |
指令 |
RS |
R/W |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
1 |
清显示 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
2 |
光标返回 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
* |
3 |
置输入模式 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
I/D |
S |
4 |
显示开/关控制 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
D |
C |
B |
5 |
光标或字符移位 |
0 |
0 |
0 |
0 |
0 |
1 |
S/C |
R/L |
* |
* |
6 |
置功能 |
0 |
0 |
0 |
0 |
1 |
DL |
N |
F |
* |
* |
7 |
置字符发生存储器地址 |
0 |
0 |
0 |
1 |
字符发生存储器地址(AGG) |
8 |
置数据存储器地址 |
0 |
0 |
1 |
显示数据存储器地址(ADD) |
9 |
读忙标志或地址 |
0 |
1 |
BF |
计数器地址(AC) |
10 |
写数到CGRAM或DDRAM |
1 |
0 |
要写的数 |
11 |
从CGRAM或DDRAM读数 |
1 |
1 |
读出的数据 |
(1602控制指令表)
LCD的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符 (有些模块是 DL:高电平时为8位总线,低电平时为4位总线)
指令7:字符发生器RAM地址设置
指令8:DDRAM地址设置
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据
指令11:读数据
下表是内部显示地址:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
|
00 |
01 |
02 |
03 |
04 |
05 |
06 |
07 |
08 |
09 |
0A |
0B |
0C |
0D |
0E |
0F |
第一行 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
4A |
4B |
4C |
4D |
4E |
4F |
第二行 |
(1602显示地址表)
2.1.3 4线通信模式
1602支持4位和8位两种总线,我们一般使用8位总线模式。
采用4线并口通信(命令:0x28),可以减少对微控制器IO的需求,当设计产品过程中微控制器的IO资源紧张的时候可以考虑使用此种方法。4线通信是采用DB4-DB7与微控制器进行通信,先传送数据或者命令的高4位,然后再传送低4位。
在程序的编制过程中需要注意的几个方面:
1)LCD初始话中需要对命令0x28多操作几次,同时要有相应的延时。
2)先发送四位数据,应该采用这种方式:
LCDIO=command&0xf0;(LCDIO: P1口)
低四位数据时为:
LCDIO=(command&0x0f)<<4;
三 并行接口说明:
并行接口的分类: SPP(标准并行接口) ,EPP(增强型并行接口),ECP(扩展型并行端口)
标准并行端口(SPP)也是最早的端口定义,主要功能如下,1:并行端口提供了8个数据线以进行并行的字节传输,2:计算机能够通过数据线向打印机发送选能信号,以通知打印机已经准备好接收数据,3:打印机招收到数据后,向计算机发送一个回应信号(NACK)。其各位信号线所代表的意义详见下表。
增强型并行端口(EPP)的出现提供了一种更高性能的连接方式,并东路向下兼容所有在此之前存在的并行接口及外设。与SPP不同之处在于原来17个信号中的重新定义,在这17个信号中,EPP使用了其中的14个信号进行传输,握手和选通,剩下的3个信号可以由外设设计者有来自定义。
并行口一般有25个引脚,其中包括8位数据线,5位打印机状态线,4位控制线.下面将对这些引脚予以详细说明:
(注:1:>出,表示由计算机发向打印机;入,表示由打印机发向计算机,
2:>低电平有效信号用上划线或星号表示(如S7*),高电平有效信号则没有上划线或星号)
引脚号 |
名称 |
数据位 |
寄存器 |
数据方向 |
定义 |
1 |
/STROBE |
C0* |
Control |
出/入 |
选通信号,低电平有效信号,表明线上有数据到达 |
2 |
D0 |
DATA1 |
Data |
出/入 |
八位数据线,只有在SPP指令下才有能输出数据 |
3 |
D1 |
DATA2 |
Data |
出/入 |
4 |
D2 |
DATA3 |
Data |
出/入 |
5 |
D3 |
DATA4 |
Data |
出/入 |
6 |
D4 |
DATA5 |
Data |
出/入 |
7 |
D5 |
DATA6 |
Data |
出/入 |
8 |
D6 |
DATA7 |
Data |
出/入 |
9 |
D7 |
DATA8 |
Data |
出/入 |
10 |
/ACK |
S6 |
Status |
入 |
应答,以插入低电平的形式出现,表明最后一个字符已招收完毕 |
11 |
BUSY |
S7* |
Status |
入 |
繁忙通知,以插入高电平的方式出现,表明打印机处于忙状态不能再接收数据 |
12 |
PE |
S5 |
Status |
入 |
没有打印机纸 |
13 |
SELECT |
S4 |
Status |
入 |
选择输入,以插入高电平的方式出现,表明打印机处于在线待命状态 |
14 |
AUTO FEED |
C1* |
Control |
出/入 |
自动馈送,低电平有效信号民,通知打印机对于每遇到一个回车进行自动换行 |
15 |
/ERROR |
S3 |
Status |
入 |
错误,该信号由打印机发向计算机,表明打印机处于错误状态 |
16 |
/INIT |
C2 |
Control |
出/入 |
初始化,低电平有效信号,该信号用来对打印机进行复位 |
17 |
/SELIN |
C3* |
Control |
出/入 |
选择输入,低电平有效信号,表明已经选中的打印机 |
18 |
GND |
|
|
--- |
信号接地 |
19 |
GND |
|
|
--- |
信号接地 |
20 |
GND |
|
|
--- |
信号接地 |
21 |
GND |
|
|
--- |
信号接地 |
22 |
GND |
|
|
--- |
信号接地 |
23 |
GND |
|
|
--- |
信号接地 |
24 |
GND |
|
|
--- |
信号接地 |
25 |
GND |
|
|
--- |
信号接地 |
(标准并行端口物理特性定义-表)
四 接口连接说明:
电路的接法比较简单,并口的2~9针对应液晶的7~14针,是8位并行双向数据接口;并口的18~25这8根数据地线针连到一起再接到电源的地线;剩下3条控制线从并口的1、 14、16对应的接到液晶屏的6(E:使能端)、5(R/W:读/写状态控制)、4(RS:数据/指令输入控制)。液晶和背光共用一套供电和地线分别接+ 5V和电源地线,液晶的3号脚Vee是显示对比度控制,接地表示取最大对比度,一般可以满足使用的要求。如果个别液晶屏发生字符过黑的情况,可以用 500Ω电位器取0~5V之间的一个合适电压输入Vee,找到合适的对比度。
通常不接LCD的背光,因为采用背光的话,需要的电流太大,从而会造成稳压管发热特别厉害。
五 控制程序接口说明:
5.1几点注意
1)液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
2)要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符。
3)我们使用PC并口进行LCD控制,而不是直接使用单片机,由于I/O转换电路(或者是其他的)原因,在程序中置1会产生实际信号为低电平现象,一般是由于此引脚定义为低电平有效,而程序中认为置1此引脚有效。
5.2LCD指令说明和延迟(中文参考2.1.2)
Instruction Code: RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
Description Execution
time**
Clear display 0 0 0 0 0 0 0 0 0 1
Clears display and returns cursor to the home position (address 0)。
1。64mS
Cursor home 0 0 0 0 0 0 0 0 1 *
Returns cursor to home position (address 0)。 Also returns display being shifted to the original position。 DDRAM contents remains unchanged。
1。64mS
Entry mode set 0 0 0 0 0 0 0 1 I/D S
Sets cursor move direction (I/D), specifies to shift the display (S)。 These operations are performed during data read/write。 I/D = 0 --> cursor is in decrement position。 I/D = 1 --> cursor is in increment position。 S = 0 --> Shift is invisible。 S = 1 --> Shift is visible
40uS
Display On/Off control 0 0 0 0 0 0 1 D C B
Sets On/Off of all display (D), cursor On/Off (C) and blink of cursor position character (B)。 D = 0 --> Display off。 D = 1 --> Displan on。 C = 0 --> Cursor off。 C = 1 --> Cursor on。 B = 0 --> Cursor blink off。 B = 1 --> Cursor blink on。
40uS
Cursor/display shift 0 0 0 0 0 1 S/C R/L * *
Sets cursor-move or display-shift (S/C), shift direction (R/L)。 DDRAM contents remains unchanged。 S/C = 0 --> Move cursor。 S/C = 1 --> Shift display。 R/L = 0 --> Shift left。 R/L = 1 --> Shift right
40uS
Function set 0 0 0 0 1 DL N F * *
Sets interface data length (DL), number of display line (N) and character font(F)。 DL = 0 --> 4 bit interface。 DL = 1 --> 8 bit interface。 N = 0 --> 1/8 or 1/11 Duty (1 line)。 N = 1 --> 1/16 Duty (2 lines)。 F = 0 --> 5x7 dots。 F = 1 --> 5x10 dots。
40uS
Set CGRAM address 0 0 0 1 CGRAM address
Sets the CGRAM address。 CGRAM data is sent and received after this setting。
40uS
Set DDRAM address 0 0 1 0 DDRAM address
Sets the DDRAM address。 DDRAM data is sent and received after this setting。
40uS
Read busy-flag and address counter 0 1 BF CGRAM/DDRAM address
Reads Busy-flag (BF) indicating internal operation is being performed and reads CGRAM or DDRAM address counter contents (depending on previous instruction)。 I used some delay functions in my code which are ThreadSleep if you don't want to use these you can check the Busy Flag and make your LCD speedy。 BF = 0 --> Can accept instruction。 BF = 1 --> Internal operation in progress no additional operation can be accepted。
0uS
Write to CGRAM or DDRAM 1 0 write data
Writes data to CGRAM or DDRAM
40uS
Read from CGRAM or DDRAM 1 1 read data
Reads data from CGRAM or DDRAM。
40uS
* = Not important, Can be "1" or "0"
** = Execution Time is a time needed which the LCD needs for the operation。
CGRAM is character generator RAM, this ram can hold user defined graphic characters。 This capability gains these modules popularity because of this you can make bargraphs and your own language's special characters(Maybe Chinese, Korean, Turkish, Greek, etc。)。
DDRAM is the Display Data RAM for these modules which represents the hexadecimal Display data adresses。 See 显示地址表。
5.3Linux端口控制编程说明
5.3.1系统对端口操作的支持
由于Linux的开放性和高度的用户自定义性,要让Linux支持该端口,以并口为例,首先要让Linux的内核支持并口。设置系统内核时选择上"Parallel port support"这个选项。我们就预定义了宏CONFIG_PARPORT,编译器就被通知到要把并口支持部分代码给编进内核当中去。也可以用命令insmod、rmmod操作parport.o、parport_pc.o等来加载、去除并口支持功能。
在确定Linux内核支持并口功能后,我们就可以用系统接口对端口进行操作。Linux禁止用户进程直接对硬件端口访问(用户空间程序不允许访问内核空间中的内容)。
首先,用C语言操作并口,本身就存在两种方法
一种是:ioperm inb outb
另外一种是:open read write ioctl
第一种方法是直接端口操作
第二种方法是对文件描述符操作
5.3.2直接端口操作
我们常用/usr/include/io.h或者内核源代码中的linux/linux/asm-i386/io.h中提供的方法来访问I/O接口,要在程序里使用这些方法,你指需要在你的程序的开始部分加上
由于gcc的限制,你可能需要使用优化选项,像这样:gcc -01(或更高),来编译你的代码,或者在#include前面加上#define extern static,然后加上#undef extern
为了除错方便,如果你用的是新版本的gcc,你可以使用gcc -g -0,但优化后的代码在除错时可能会遇到许多不必要的麻烦,所以你可以将进行I/O操作的那些代码放到另外的文件中使用优化选项进行编译,然后再和其他不直接使用I/O操作的部分连接。
操作权限:
当你访问某些端口时,你必须让你的程序获得足够的权限,你可以通过使用函数ioperm()来实现(包含在unistd.h中,而且在内核中有定义),在你进行I/O操作之前,你需要先使用此函数得到访问某些端口的权限,使用的方法是ioperm(from,num,turn_on),其中from是需要操作的首个端口地址,num表示需要操作的后面几个端口的数目,例如ioperm(0x300,5,1)代表将使用从0x300到0x304共5个端口,最后参数是一个布尔值(1代表true),1表示给程序申请权限,0表示收回访问权限,如果你需要操作多段不连续的端口,你可以多次使用这个函数,详细操作请查看ioperm(2)的man手册。
要使用ioperm()函数的话你需要拥有root权限,所以你需要用root用户运行此程序,或者获得root的权限,当你调用ioperm()取得权限后你就可以放弃root权限了,但你不必在程序的最后使用ioperm(,,0)回收权限,因为程序结束后相应I/O操作权限会被系统自动回收。
当你切换到普通用户时,程序的I/O操作权限不会被回收,但是如果你使用fork()创造一个新进程的话,由于新进程没有获得权限,所以系统会拒绝执行新创建的子进程中的I/O操作。
ioperm()只能获得从0x000到0x3ff的I/O接口的权限,对于其他的端口,需要使用iopl(),这个函数可以获得所有I/O端口的访问权限,同样在使用此函数前你需要root权限,现在你可以使用参数3来获得所有I/O接口的操作,ioperm(3),但是要小心,由于取得了系统中所有端口的操作权限,你的错误的操作可能会造成难以预料的后果。
开始操作端口:
使用inb( <端口号> )来从端口输入一个字节(8个比特),这个函数的返回值就是从这个端口输入的数据。
outb( <数值> , <端口号> )函数用来向端口送出数值。
inw( <起始端口号> )从连续的两个读入一个字的数据(16个比特)。
outw( <一个字长的数值> , <起始端口号> )向连续的两个端口打入一个字节的数据。
如果你不能确定应该使用字节还是字,保守起见,你可以只使用inb()和outb(),大多数设备都可以支持端口的字节操作,每次端口操作都会占用至少一毫秒的时间。
宏inb_p(),out_p(),inw_p()和outw_p()和上面介绍的函数功能相同,但会在端口操作后有大概1微秒的延时,你可以在 #include前面加上#define REALLY_SLOW_IO来延时4微秒,这些宏用通过向端口0x80写入数据的方法实现延时,延时的时间就是向0x80写入数据的时间(我们再后面会提到这个端口),所以你必须在你的程序中使用ioperm()得到此端口的操作权限,但是如果你使用#define SLOW_IO_BY_JUMPING,就可以使用另外的方法而不用向0x80端口写数据,但此方法可能会导致错误。
关于以上所提到的所有函数和宏定义已经在新版本的man手册中给出了详细资料。
5.3.3访问端口的另外一种方法:/dev/port
访问I/O接口的另外一种方法是使用open()函数来打开设备文件/dev/port,然后使用lseek()函数将指针移动到此文件的适当位置,例如位置0处就是端口0x00,位置1就是端口0x01,等等,然后你就可以向里面用read()或write()函数写入或读出一个字节或者一个字。
当然,进行上述操作需要你对/dev/port文件的读写权限,而且这种方法的运行效率相对要慢一些,但是此方法不需要编译器的优化选项和ioperm()函数,而且也不需要root权限,只要你有操作/dev/port的权限就可以了。
你可以给所有用户对/dev/port的操作权限,这样就能使他们都能够调试I/O接口。但这会对系统安全造成一定的隐患,因为他们可以使用/dev/port文件来对硬盘,网卡等设备进行I/O操作,从而造成系统数据被窃听或者破坏。
你不可以使用select()或者poll()来读/dev/port文件,如果数据被改变,系统上的硬件并不能通知CPU数据出错。
5.4直接操作并行端口地址
为了简化并口访问,Linux又提供了一个Helper Function,这就是ioperm。这个函数可以告诉内核:给出一定的控制权与用户进程,当用户程序结束后,再把控制权给收回来。如果我们不事先调用ioperm的话,访问并口的程序也可以编译成功,但在运行时会出错,一般会在屏幕上出现"Segment Failure"的出错提示。
使用到的3个函数原型如下:
#include
int ioperm(unsigned long from, unsigned long num, int turn_on);
void outb(unsigned char byte, unsigned port);
char inb(unsigned port);
ioperm是让从from开始,直到num个字节,这段范围内的I/O映射地址可以为普通用户程序访问。上述行为是在当turn_on参数为"真"(非零)时允许的。当为"假"时,就禁止这种行为。这可以在程序完成,不再要访问硬件端口时调用。
下面给出Linux下访问并口的示例代码:
... ...
ioperm(0x000,0x3FF,1); //把0x000~0x3FF之间空间开放给用户程序
//这段范围对访问并口而言,已经足够了。
outb(0xFF,0x378); //向并口数据位写数据。这里是将8个数据位全置为1
... ...
ioperm(0x000,0x3FF,0); //收回控制权,用户程序在这之后就不再可以
//访问内核空间内容了。
5.5文件描述符操作并行端口
用操作文件描述符的方法主要问题在于ioctl函数上,这个函数实在是变化无穷,第一个参数是文件描述符,但是该文件描述符是如何获得的,将直接影响第二个参数用什么,而第二个参数又直接影响第三个参数的指针类型
总之,就第二个参数而言,其针对串口,并口,socket,普通文件等等是各有一套定义的,而且分别存放在不同的.h中的,如果用错了(假如把socket的用到并口上),编译的时候不会有问题,但是运行的时候,肯定会告诉你参数无效的。
对于并口来说,首先你的系统就要支持并口的那种,如果各位裁减内核的时候把这个东西裁掉了,那么,你用open 打开/dev/lp0的时候会告诉你没有这个设备,昨天我下午曾经一度陷入了这个设备中/dev/parport0,这也是个并口,但是不对应硬件,我不敢肯定的说他可能是个虚拟的并口(希望研究比较明白的人给个答案),对于这个并口的操作,我们必须用到
#include
#include
这两个头文件,这里的名字和路径,我再强调一下,是Red Hat Linux上的,其它平台应该会有少许差别。这两个头文件里是什么东西呢,只要看了,就会明白,其实这里定义了ioctl中第二个参数可以用哪些,以及对应第三个参数是什么类型的指针,包括各种并口状态位的宏定义,以及并口的模式标准(EPP,IEEE1284等)等等,但是问题在于这个设备对应的不是打印机口,所以虽然可以操作了,但是也没用,操作这个东东的ioctl函数的第二个参数可谓十分丰富,只是跟下面将要说的/dev/lp0比起来,/dev/lp0提供给ioctl函数的第二个参数就少得可怜了。
六 实例说明:
6.1LCD与并行端口连接的线路图
其中LCD端口的5脚(R/W)是直接连接到地线的,因为如果只是简单的控制输出的话不会用到此引脚高电平状态,可以根据需要选择连接到parport的16脚(INIT)或17脚(SELEIN),通过程序控制实现完整的LCD指令操作。
6.2并行端口编程的基础
并行端口/dev/lp0的基地址(下文称做BASE)是0x3bc,/dev/lp1是0x378,/dev/lp2是0x278,如果你只是想通过并口操纵打印机的话,请参看Printing-HOWTO。
并行端口也可以通过ECP或EPP等扩展模式,实现数据双向传输,有关这方面的信息请参看和~cpeacock/parallel.htm。
需要注意的是,在用户模式下你不可以使用中断和DMA,如果你需要使用ECP或EPP,你必须编写一个驱动程序。
可能是操作系统的原因,我通过BIOS设置CMOS中的并行口地址为0x378,使用时/dev/lp0的地址是0x378,可以正常操作
状态端口:
0x379 |
(S7)11 忙 |
(S6)10应答 |
(S5)12缺纸 |
(S4)13联机 |
(S3)15错误 |
S2 |
S1 |
S0 |
端口BASE+1是只读的,它指示出并行接口的状态,下面便是它各个位表示的意义:
第0,1位 被保留
第2位 IRQ 中断状态
第3位 ERROR 错误显示位 (1有效)
第4位 SLCT (1有效)
第5位 PE (1有效)
第6位 ACK (1有效)
第7位 -BUSY 忙信号 (0有效)
标记为S7的信号表示最高位,SO表示为最低位,只有S3-S7五个信号才是真正有用的信号。他们的具体信号功能解释如下:
S7*(busy):打印机使用该信号表示打印机正处于忙状态,不能再接收数据。需要强调的是,该信号通过适配器板时,进行了反相处理,因此连接器上的低电平到微处理器时就变成了高电平。
S6(nAck):当适配器发出选通信号时,打印机就会产生该信号作为响应。通常情况下,该信号是高电平,选通打印机之后,打印机首先把该信号设为低电平,然后再返回高电平。
S5(PE):当打印机缺纸时,它就会产生一个这样的信号,通常情况下,该信号由打印机保持为低电平,打印机纸使用完之后,该信号就会变成高电平。
S4(SELECT):当打印机恢复正常操作时,它就会插入一个高电平的该信号。当打印机处于无效状态时,访信号就会变成低电平。
S3(NERROR):当打印机出现错误时就会产生这种邮错信号。产生出错的原因很多,如打印纸堵了或产生了内部错误。产生错误时该信号就会设置成低电平。
控制端口:
0x379 |
1 |
1 |
输入
控制 |
中断 |
17线 |
16线 |
14线 |
1线 |
端口BASE+2是控制端口,你可以向其中写入控制信息,对这个端口的读操作会返回最近一次写入的数据,各个位的意义如下:
第0位 -STROBE (0有效)
第1位 -AUTO_FEED_XT (0有效)
第2位 INIT (1有效)
第3位 -SLCT_IN (0有效)
第4位 当这位置1时允许中断(ACK的上升沿表示中断)
第5位 控制扩展模式的方向,0表示写,1表示读,而且只能向这位写数据,不可以读数据
第6,7位 被保留
两高位(7和8)没什么用,第6位写1表示可以向并口输出数据。第五位中断信号(IRQ EN),利用此信号线,驱动程序可以在STATUS端口信号(nAck)的帮助下,使用该信号对中断信号的产生与否进行控制。第3,2,1,0位分别控制第17线,第16线,第14线和第1线。
注意:机器在打开的状态下向并行接口连接设备可能会烧毁并行口,如果你需要反复实验的话你可以购买一块I/O卡,将它连接道电脑上后将卡上的并行接口的I/O地址调到一个空闲的地址。如果你不需要使用中断的话,IRQ的设置你可以不必关心。
6.3直接端口操作例程
我倾向于直接对端口的地址进行操作,这样只要了解了端口的基础知识,使用起来可以十分的随意,我写的程序采用此方法,具体实例如下:
Lcdctrl.c
6.4通过文件访问端口操作例程
操作lp0得源码,强调一下,虽然有了
#include
#include
这两个头文件中定义的那么多的东东,很可惜他们全都不能用到lp0上,否则告诉你参数无效,要操作lp0关键在于下面的头文件,上面两个可以不要
#include
源码如下:
#include
#include
#include
#include
#include
#include
#include
int CheckParPortState(int fd, int m_bits)
{
int status;
/* Get Par Port State */
if (ioctl(fd, LPGETSTATUS, (char*)&status) < 0)
{
return (0);
}
if (m_bits != 0x20) return ( status & m_bits );
else return( !(status & m_bits) );
}
main()
{
int fd;
if ( (fd = open("/dev/lp0", O_WRONLY , 0)) < 0)
{
perror("/dev/lp0 error");
exit(-1);
};
if (!CheckParPortState(fd, LP_PBUSY))
printf("printer is busy \n");
if (!CheckParPortState(fd, LP_PACK))
printf("printer answer \n");
if (!CheckParPortState(fd, LP_POUTPA))
printf("printer paper out \n");
if (!CheckParPortState(fd, LP_PERRORP))
printf("printer error \n");
close(fd);
}
附CGROM和CGRAM中字符代码与字符图形对应关系
|
0000 |
0010 |
0011 |
0100 |
0101 |
0110 |
0111 |
1010 |
1011 |
1100 |
1101 |
1110 |
1111 |
××××0000 |
CGRAM(1) |
|
0 |
ə |
P |
\ |
p |
|
一 |
タ |
三 |
α |
P |
××××0001 |
(2) |
! |
1 |
A |
Q |
a |
q |
□ |
ァ |
チ |
ム |
ä |
q |
××××0010 |
(3) |
” |
2 |
B |
R |
b |
r |
r |
ィ |
川 |
メ |
β |
θ |
××××0011 |
(4) |
# |
3 |
C |
S |
c |
s |
⌡ |
ゥ |
テ |
モ |
ε |
∞ |
××××0100 |
(5) |
$ |
4 |
D |
T |
d |
t |
\ |
ェ |
ト |
ャ |
μ |
|
××××0101 |
(6) |
% |
5 |
E |
U |
e |
u |
ロ |
ォ |
ナ |
ュ |
B |
0 |
××××0110 |
(7) |
& |
6 |
F |
V |
f |
v |
テ |
ヵ |
ニ |
ョ |
P |
∑ |
××××0111 |
(8) |
> |
7 |
G |
W |
g |
w |
ア |
キ |
ヌ |
ラ |
g |
x |
××××1000 |
(1) |
( |
8 |
H |
X |
h |
x |
イ |
ク |
ネ |
リ |
∫ |
X |
××××1001 |
(2) |
) |
9 |
I |
Y |
i |
y |
ウ |
ケ |
ノ |
ル |
-1 |
y |
××××1010 |
(3) |
· |
: |
J |
Z |
j |
z |
エ |
コ |
リ |
レ |
j |
千 |
××××1011 |
(4) |
+ |
; |
K |
[ |
k |
〈 |
オ |
サ |
ヒ |
ロ |
x |
万 |
××××1100 |
(5) |
フ |
< |
L |
¥ |
l |
| |
ヤ |
シ |
フ |
ワ |
¢ |
缺 |
××××1101 |
(6) |
- |
= |
M |
] |
m |
〉 |
ュ |
ス |
ヘ |
ゾ |
缺 |
十 |
1110 |
(7) |
. |
> |
N |
^ |
n |
- |
ヨ |
セ |
ホ |
ハ |
缺 |
|
××××1111 |
(8) |
/ |
? |
O |
— |
0 |
缺 |
ツ |
ソ |
缺 |
ロ |
ö |
|