《LINUX设备驱动程序》学习之与硬件通信(并行接口)实例
2012-11-26 16:22
381 查看
注意:
在学习这一节内容时,我根据书本写了一个并口驱动程序,然后用一个LED发光二极管、一个电阻以及一些导线和电脑主机的并口连接了一条回路,最后通过测试程序控制LED灯的开启、关闭,验证了并口驱动程序的正确性。整个过程没出现什么意外状况,但是有网友指出,这个实验是非常危险的,所以如果你想尝试,得足够了解可能会出现的意外情况。
1. 并行接口(并口)简介
并行接口是常见的一种I/O接口,通常主机上是25针D型接口。其引脚如下:
为操作并行口,SPP(Standard Parallel Port标准并行接口)定义了寄存器,并映射到PC机的I/O空间。寄存器包括了以并口地址为基址的3块连续 的寄存器,并口地址常见为3BCH、378H和278H,其中都包括数据、状态和控制寄存器,分别对应数据、状态和控制信号线操作,通常称为数据端口、状 态端口和控制端口。打印机卡1的地址常为378H,其中数据口0378H、状态口0379H、控制口037AH;打印机卡2的地址常为278H,其中数据 口0278H、状态口0279H、控制口027AH。支持新的IEEE 1284标准的并口,使用8到16个寄存器,地址为378H or 278H,即插即用(Plug and Play)兼容的的并口适配器也可以重新加载。
并行接口输出的是TTL标准逻辑电平,其中,标准TTL为+5V,低压TTL 为+3.3V。一般情况下,小于0.8V是低电平,大于2V是高电平。
2. 驱动程序
2.1 驱动程序源码
2. 2 Makefile源码
2.3 安装驱动程序步骤
3. 测试程序
4. 连接电路
在并口上的 2 脚和 25 脚分别引出两根引线,2 脚接 LED 灯的长脚,25 脚接 LED 灯的短脚,再在电路上串联一个500欧左右的电阻,电路图如下:
5. 测试
在应用程序中,使用 read() 系统调用不断尝试读取并口设备状态寄存器。如果并口上没有外接设备,则会打印信息:
当通过引线将13脚和25脚短接,则13引脚有低电平输入,这时候输出:
然后,通过调用 write() 函数向并口设备数据寄存器写数据,使 LED 灯开灯、关灯10次,最后关闭设备文件并退出。
在学习这一节内容时,我根据书本写了一个并口驱动程序,然后用一个LED发光二极管、一个电阻以及一些导线和电脑主机的并口连接了一条回路,最后通过测试程序控制LED灯的开启、关闭,验证了并口驱动程序的正确性。整个过程没出现什么意外状况,但是有网友指出,这个实验是非常危险的,所以如果你想尝试,得足够了解可能会出现的意外情况。
1. 并行接口(并口)简介
并行接口是常见的一种I/O接口,通常主机上是25针D型接口。其引脚如下:
为操作并行口,SPP(Standard Parallel Port标准并行接口)定义了寄存器,并映射到PC机的I/O空间。寄存器包括了以并口地址为基址的3块连续 的寄存器,并口地址常见为3BCH、378H和278H,其中都包括数据、状态和控制寄存器,分别对应数据、状态和控制信号线操作,通常称为数据端口、状 态端口和控制端口。打印机卡1的地址常为378H,其中数据口0378H、状态口0379H、控制口037AH;打印机卡2的地址常为278H,其中数据 口0278H、状态口0279H、控制口027AH。支持新的IEEE 1284标准的并口,使用8到16个寄存器,地址为378H or 278H,即插即用(Plug and Play)兼容的的并口适配器也可以重新加载。
并行接口输出的是TTL标准逻辑电平,其中,标准TTL为+5V,低压TTL 为+3.3V。一般情况下,小于0.8V是低电平,大于2V是高电平。
2. 驱动程序
2.1 驱动程序源码
/*ParaPortDEV.c*/ /*Created by Chung-shu on November 26th, 2012*/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/fcntl.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/ioport.h> #define DEV_NAME "ParaPortDEV" #define PARA_PORT_DATA_REGISTER_ADDR 0x0378 #define PARA_PORT_STATUS_REGISTER_ADDR 0x0379 MODULE_LICENSE ("GPL"); int para_port_open(struct inode *inode, struct file *filp); int para_port_release(struct inode *inode, struct file *filp); ssize_t para_port_read(struct file *filp, char *buf, size_t count, loff_t *f_pos); ssize_t para_port_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos); int dev_major=240; int dev_minor=0; struct file_operations para_port_fops = { .owner = THIS_MODULE, .read = para_port_read, .write = para_port_write, .open = para_port_open, .release = para_port_release, }; int para_port_init(void) { int result; result = register_chrdev(dev_major, DEV_NAME, ¶_port_fops); if (result < 0) { printk("register character device error!\n"); return result; } if(request_region(PARA_PORT_DATA_REGISTER_ADDR, 3, DEV_NAME)==NULL) { printk("register IO port error!\n"); exit(1); } return 0; } void para_port_exit(void) { release_region(PARA_PORT_DATA_REGISTER_ADDR, 3); unregister_chrdev(dev_major, DEV_NAME); } int para_port_open(struct inode *inode, struct file *filp) { return 0; } int para_port_release(struct inode *inode, struct file *filp) { return 0; } ssize_t para_port_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { unsigned char status; int i; for (i = 0; i <count; i++) { status = inb(PARA_PORT_STATUS_REGISTER_ADDR); rmb(); put_user(status, (char *)(buf+i)); } return count; } ssize_t para_port_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { unsigned char data; int i; for (i = 0; i < count; i++) { get_user(data, (char *)(buf+i)); outb(data, PARA_PORT_DATA_REGISTER_ADDR); wmb(); } return count; } module_init(para_port_init); module_exit(para_port_exit);
2. 2 Makefile源码
obj-m:=ParaPortDEV.o #KERNELDIR:=/lib/modules/2.6.38.8/build KERNELDIR:=/usr/src/linux-headers-2.6.38-8-generic PWD:=$(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -f *.o
2.3 安装驱动程序步骤
~/linux_study/para_port$ make ~/linux_study/para_port$ sudo insmod ParaPortDEV.ko ~/linux_study/para_port$ sudo mknod /dev/ParaPortDEV c 240 0 ~/linux_study/para_port$ sudo chgrp staff /dev/ParaPortDEV ~/linux_study/para_port$ sudo chmod 664 /dev/ParaPortDEV
3. 测试程序
/*test_para_port_dev.c*/ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #define DEV_NAME "/dev/ParaPortDEV" int main(void) { int i, dev; char buff[10]; dev=open(DEV_NAME, O_RDWR|O_NDELAY); if(dev==-1) { printf("open error: %s.\n", strerror(errno)); return -1; } printf("read from para port:\n"); for(i=0; i<10; i++) { if(read(dev, buff+i, 1)==-1) { printf("%dth read error: %s.\n", i, strerror(errno)); break; } sleep(1); printf("data = %0X\n", buff[i]); } printf("write to para port:\n"); for(i=0; i<10; i++) { /*turn the light on*/ buff[i] = 0xFF; if(write(dev, buff+i, 1)==-1) { printf("%dth write error: %s.\n", i, strerror(errno)); break; } printf("light on\n"); sleep(1); /*turn the light off*/ buff[i] = 0x00; if(write(dev, buff+i, 1)==-1) { printf("%dth write error: %s.\n", i, strerror(errno)); break; } printf("light off\n"); sleep(1); } close(dev); return 0; }
4. 连接电路
在并口上的 2 脚和 25 脚分别引出两根引线,2 脚接 LED 灯的长脚,25 脚接 LED 灯的短脚,再在电路上串联一个500欧左右的电阻,电路图如下:
5. 测试
~/linux_study/para_port$ sudo ./test_para_port_dev
在应用程序中,使用 read() 系统调用不断尝试读取并口设备状态寄存器。如果并口上没有外接设备,则会打印信息:
read from para port: data = 7F data = 7F data = 7F data = 7F data = 7F data = 7F data = 7F data = 7F data = 7F data = 7F
当通过引线将13脚和25脚短接,则13引脚有低电平输入,这时候输出:
read from para port: data = 6F data = 6F data = 6F data = 6F data = 6F data = 6F data = 6F data = 6F data = 6F data = 6F
然后,通过调用 write() 函数向并口设备数据寄存器写数据,使 LED 灯开灯、关灯10次,最后关闭设备文件并退出。
相关文章推荐
- 《LINUX设备驱动程序》学习之与硬件通信(并行接口)实例
- 【原创】《Linux设备驱动程序》学习之循序渐进 --- 与硬件通信
- 【原创】《Linux设备驱动程序》学习之循序渐进 --- 与硬件通信
- Linux设备驱动程序第三版学习(12)- 与硬件通信
- Linux设备驱动程序第三版学习(12)- 与硬件通信
- Socket通信学习实例一之TCP通信
- Linux设备驱动程序学习(9)-与硬件通信
- 《Linux设备驱动程序》——硬件通信
- java学习之路——基于UDP的Socket网络通信实例
- linux设备驱动程序学习(9) 与硬件通信
- Linux设备驱动程序学习(9)-与硬件通信
- 某科学的超 Java网络编程:Socket通信原理及实例学习
- unix学习笔记---------自己写的管道实例----父子进程通信
- 《LINUX设备驱动程序》学习之信号量实例
- Linux设备驱动程序第三版学习(12)- 与硬件通信
- Socket通信学习实例二之即时通信
- WCF学习笔记(五)契约双工通信、多契约绑定及对数据库增删改查等综合实例
- Linux设备驱动程序学习-与硬件通信
- ldd3学习之九:与硬件通信
- Windows Workflow Foundation (wwf) 在宿主中使用参数与实例通信 --学习笔记(二)