前天写了ARM9的LED和按键的裸机程序,今天把它用驱动实现。但是真的不好写,搞了一个晚上,不过真算OK啦。
我的这个驱动,实现的功能就是提供一个菜单给你选择,只要在总端输入数字选着LED运行模式就可以。
并且我用KI按键,实现了可以返回菜单另选另一种模式的功能。最后一个,就是应用层序是一个死循环,我还提供一个选择,退出死循环。但是另选模式后,要执行完本次才执行重选的模式。图如下:
1.进入主菜单:
2.有六种模式:选着相应模式就可运行:
3.由于是死循环,所以必须要通过按键1来返回主菜单,在选着其他模式。
4.选着7键来推出菜单,但是退出时得运行本次才退出,如下:
驱动程序如下:
//头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPIO_LED_MAJOR 97
#define LED_1_ON 1
#define LED_2_ON 2
#define LED_3_ON 3
#define LED_4_ON 4
#define LED_OFF 5
#define KEY_READ 6
#define ctl_GPIO_LED1 1
int GPIO_open(struct inode *inode, struct file *file)
{
printk("Open successfully!\n\n");
//初始化引脚,GPB输出GPF7输入
__raw_writel(__raw_readl(S3C2410_GPBCON)|(1<<(2*5))|(1<<(2*6))|(1<<(2*7))|(1<<(2*8)),S3C2410_GPBCON);
__raw_writel(__raw_readl(S3C2410_GPBDAT)|(0xf<<5),S3C2410_GPBDAT);
__raw_writel(__raw_readl(S3C2410_GPFCON)&~(3<<(2*7)),S3C2410_GPFCON);
printk("Initialization of LED and Button!\n\n");
return 0;
}
int GPIO_release(struct inode *inode, struct file *filp)
{
printk("Close successfully!\n\n");
return 0;
}
//读按键值
ssize_t GPIO_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
int value;
value=__raw_readl(S3C2410_GPFDAT);
if(!access_ok(VERIFY_WRITE,buf,1))
return -EFAULT;
if(copy_to_user(buf,&value,1))
{
return -EFAULT;
}
return count;
}
ssize_t GPIO_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
return count;
}
//执行LED运行模式
int GPIO_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long org)
{
switch(cmd)
{
case LED_1_ON:
{
__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(0x1<<5),S3C2410_GPBDAT);
printk("LED_1 light!\n");
break;
}
case LED_2_ON:
{
__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(0x1<<6),S3C2410_GPBDAT);
printk("LED_2 light!\n");
break;
}
case LED_3_ON:
{
__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(0x1<<7),S3C2410_GPBDAT);
printk("LED_3 light!\n");
break;
}
case LED_4_ON:
{
__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(0x1<<8),S3C2410_GPBDAT);
printk("LED_4 light!\n");
break;
}
case LED_OFF:
{
__raw_writel(__raw_readl(S3C2410_GPBDAT)|(0xf<<5),S3C2410_GPBDAT);
printk("LED OFF!\n");
break;
}
default:
{
printk("led control:no cmd run \n");
return -EINVAL;
}
return 0;
}
}
struct file_operations GPIO_LED_ctl_ops={
.owner =THIS_MODULE,
.open =GPIO_open,
.read =GPIO_read,
.write =GPIO_write,
.ioctl =GPIO_ioctl,
. release =GPIO_release,
};
static int GPIO_init(void)
{
int ret=-ENODEV;
printk("-----------------\n\n");
ret=register_chrdev(GPIO_LED_MAJOR,"gpio_led_ctl",&GPIO_LED_ctl_ops);
if(ret<0)
{
return ret;
}
else
{
}
return ret;
}
static int __init s3c2440_led_init()
{
int ret=-ENODEV;
ret=GPIO_init();
if(ret)
return ret;
return 0;
}
static void s3c2440_led_exit(void)
{
unregister_chrdev(GPIO_LED_MAJOR,"gpio_led_ctl");
}
module_init(s3c2440_led_init);
module_exit(s3c2440_led_exit);
MODULE_LICENSE("Dual BSD/GPL");
应用层序:
#include
#include
#include
#include
#include
#define LED_1_ON 1
#define LED_2_ON 2
#define LED_3_ON 3
#define LED_4_ON 4
#define LED_OFF 5
#define KEY_READ 6
void delay();
int menu();
void key1();
void key2();
void key3();
void key4();
void key5();
void key6();
int fd,value;
void delay()
{
sleep(1);
int result;
read(fd,&result,1);
if(!(result&(1<<7)))
{
result=0xffff;
value=menu();
}
}
int menu()
{
int result;
printf("******************************************\n");
printf("******************************************\n");
printf("the number decide the mode pf LED running\n\n");
printf("the button 1 decede you return to menu\n\n");
printf("Please input a number that must be between 1-7:");
scanf("%d",&result);
return result;
}
void key1()
{
int count;
ioctl(fd,LED_OFF);
for(count=1;count<5;count++)
{
ioctl(fd,count);
delay();
ioctl(fd,LED_OFF);
delay();
}
}
void key2()
{
int count;
ioctl(fd,LED_OFF);
for(count=4;count>0;count--)
{
ioctl(fd,count);
delay();
ioctl(fd,LED_OFF);
delay();
}
}
void key3()
{
int count;
ioctl(fd,LED_OFF);
for(count=1;count<3;count++)
{
ioctl(fd,count);
ioctl(fd,5-count);
delay();
ioctl(fd,LED_OFF);
delay();
}
}
void key4()
{
int count;
ioctl(fd,LED_OFF);
for(count=2;count>0;count--)
{
ioctl(fd,count);
ioctl(fd,5-count);
delay();
ioctl(fd,LED_OFF);
delay();
}
}
void key5()
{
ioctl(fd,LED_1_ON);
ioctl(fd,LED_2_ON);
ioctl(fd,LED_3_ON);
ioctl(fd,LED_4_ON);
delay();
ioctl(fd,LED_OFF);
delay();
}
void key6()
{
key1();
delay();
key2();
delay();
key3();
delay();
key4();
delay();
key5();
delay();
}
int main()
{
int ret;
char *i;
printf("\nstart gpio_led_driver test\n\n");
fd=open("/dev/gpio_led_ctl",O_RDWR);
if(fd==-1)
{
printf("open device error\n");
return ;
}
value=menu();
while(1)
{
if((value>0)&&(value<8))
{
switch(value)
{
case 1:key1();break;
case 2:key2();break;
case 3:key3();break;
case 4:key4();break;
case 5:key5();break;
case 6:key6();break;
case 7:goto out;
default:ioctl(fd,LED_OFF);break;
}
}
}
out:
ret=close(fd);
printf("close gpio_led+driver test\n");
return 0;
}
后言:其实linux已经自带了LED子系统,这个研究起来有点麻烦,以后再研究
遇到的问题:
1.编译模块时候,板级相关文件没有找到,重新编译内核,记得在make menuconfig时候保存配置文件即可。
2编译时候,出现错误:/home/long/led/led.c:20: error: ‘GPIO_open’ undeclared here (not in a function)
只要把file_operations数据结构放到具体实现函数后面即可。
3.把应用程序通过超级终端发到班上,运行时候说没存在该文件,该一下文件名,估计是由于文件名和.ko前缀文件名一样且在同一目录就不行。
4.在超级终端无法卸载模块,解决方法就是在lib目录下创建modules/*****就可以。