×
单片机 > 单片机程序设计 > 详情

S3C2440 字符设备驱动程序之LED驱动程序_操作LED(四)

发布时间:2024-05-10 发布时间:
|

第12课第2.3节 字符设备驱动程序之LED驱动程序_操作LED(四)


写一个点LED的驱动:


一、框架


二、完善、硬件的操作:


a.看原理图、确定引脚;


b.看2440手册;


c.写代码:


单片机:操作物理地址


驱动:用ioremap函数来映射虚拟地址


★★★

void *ioremap(unsigned long phys_addr, unsigned long size)


phys_addr:要映射的物理地址


size:要映射的长度,单位是字节


ioremap是以页为单位进行映射,你的长度写为4,16,32等等,都会映射到4096字节的空间。


★★★


下面的代码中:


gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);

gpfdat = gpfcon + 1;


①先映射GPFCON为虚拟地址。F寄存器为GPFCON:0x56000050,GPFDAT:0x56000054,GPFUP:0x56000058,Reserved:0x5600005c共4个,2440为32位CPU,所以4个4字节为16字节,故这里映射16字节。


②gpfdat=gpfcon+1;这里指针加1是以上面"unsigned long "为单位的。unsigned long的字节数是4个字节。


驱动程序first_drv.c


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static struct class *firstdrv_class; //一个类

static struct class_device *firstdrv_class_dev; //一个类里面再建立一个设备

volatile unsigned long *gpfcon = NULL;

volatile unsigned long *gpfdat = NULL;

static int first_drv_open(struct inode *inode, struct file *file)

{

//printk("first_drv_openn");

/* 配置GPF4,5,6为输出 */

*gpfcon &= ~((0x3<

*gpfcon |= ((0x1<

return 0;

}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

int val;

//printk("first_drv_writen");

//用户程序传进来的值,怎样才能取得到,用户空间-》内核空间

copy_from_user(&val, buf, count); // copy_to user()

if (val == 1)

{

//点灯

*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));

}

else

{

//灭灯

*gpfdat |= (1<<4) | (1<<5) | (1<<6);

}

return 0;

}

static struct file_operations first_drv_fops = {

.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open = first_drv_open,

.write = first_drv_write,

};

int major;

/*

在VFS(虚拟文件系统)中实际是用一个数组来管理文件,而这个数组就是以主设备号作为索引

在注册驱动的时候,register_chrdev函数会按照major作为索引在对应位置填入file_operation

*/

int first_drv_init(void)

{

//第一个参数写0:让系统给我们自动分配,在数组中找个空缺,返回主设备号

major = register_chrdev(0, "first_drv", &first_drv_fops); //注册驱动程序,告诉内核

/* 下面这两条信息就会在sys目录下,建立firstdrv这个类,再firstdrv这个类下,会创建xyz这个设备 */

/* 然后mdev就会创建/dev/xyz这个节点 */

//创建一个类

firstdrv_class = class_create(THIS_MODULE, "firstdrv");

//在这个类下面再创建一个设备

firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz");

//映射:物理地址->虚拟地址

gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); //指向的是虚拟地址,第一个参数是物理开始地址,第二个是长度(字节)

gpfdat = gpfcon + 1; //加1,实际加4个字节

return 0;

}

void first_drv_exit(void)

{

unregister_chrdev(major, "first_drv"); //卸载驱动

class_device_unregister(firstdrv_class_dev);

class_destroy(firstdrv_class);

iounmap(gpfcon);

}

module_init(first_drv_init);

module_exit(first_drv_exit);

MODULE_LICENSE("GPL");




用户程序firstdevtest.c


#include

#include

#include

#include

/* firstdrvtest on 打开

* firstdrvtest off 熄灯

*/

int main(int argc, char **argv)

{

int fd;

int val = 1;

fd = open("/dev/xyz", O_RDWR);

if (fd < 0)

{

printf("can't open!n");

}

//argc:传进来参数的个数

if (argc != 2)

{

printf("Usage :n"); //Usage用法不对

//在linux,<>尖括号表示参数不能省略,|或符号表示任选一个(on或者off)

printf("%s n",argv[0]);

return 0;

}

//第二个参数 等于 on

if (strcmp(argv[1], "on") == 0)

{

val = 1;

}

else

{

val = 0;

}

write(fd, &val, 4);

return 0;

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32 USB HID 键盘