ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

NUC980的GPIO驱动程序

2019-08-26 22:03:21  阅读:717  来源: 互联网

标签:LED 驱动程序 int timer define IOCTL GPIO include NUC980


<NUC980的GPIO驱动程序>
GPIO为字符型设备的代表,先设计一个点灯的程序。
先写一点程序设计的要求
1、能够操作GPIO,包括可以输出高和输出低,能够加载驱动和卸载驱动
2、能够设置一个可以闪烁的程序

1、驱动程序头文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

/*时间和定时器相关的文件,如果不使用sleep和mdelay等,可以去掉delay函数,如果不*使用定时器,可以去掉定时器相关函数
*/
#include <linux/delay.h>
#include<linux/timer.h>
#include<linux/jiffies.h>
/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
#include <linux/device.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>
/*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>

2.宏定义

#define LED_MAGIC 'k'
#define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int)
#define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int)
#define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int)
#define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int)
#define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int)
#define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int)
/*
由宏定义组成的一组32位数据
bit31~bit30 2位为 “区别读写” 区,作用是区分是读取命令还是写入命令。
bit29~bit15 14位为 "数据大小" 区,表示 ioctl() 中的 arg 变量传送的内存大小。
bit20~bit08  8位为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
bit07~bit00   8位为 "区别序号" 区,是区分命令的命令顺序序号。

_IO (魔数, 基数);
_IOR (魔数, 基数, 变量型)
_IOW  (魔数, 基数, 变量型)
一般情况下用于作为CMD指令的参量,第一个魔数,可以设定一个字母,第二个为指令的值,第三个直接写int数据类型即可,只要在主程序将上述代码添加,然后使用宏定义,即可操作字符设备的函数
*/
#define TIMER_SET (200*HZ)/1000 /*设定定时器的定时值,亮灭都为0.2HZ*/

3.变量定义

static int major;	/*定义一个用于保存major的值,可以指定值,也可以自由分配*/
static struct class *jt_gpio_class;	/*定义一个class,用于注册设备*/
static struct device *jt_gpio_device; /*将device自动加入到设备列表中,方便操作*/
static struct timer_list test_timer;	/*定时器,用于定时*/
unsigned char ledflag = 1;		/*是否闪烁的flag,可以使用其他名称*/
MODULE_LICENSE("Dual BSD/GPL");	/*常规描述*/
MODULE_AUTHOR("TOPEET");/*常规描述*/

4.定时器定义

/*
*定时器处理函数,用于处理定时器相关中断,需要定义到定时器之前
*/
static void sec_timer_handler(unsigned long arg)
{
	int num;
	mod_timer(&test_timer,jiffies+TIMER_SET);	/*重新初始化定时器*/
	if(ledflag > 0)
	{
		gpio_set_value(NUC980_PB8, 0);
		ledflag  = 0;
	}
	else
	{
		gpio_set_value(NUC980_PB8, 1);
		ledflag  = 1;
	}	

//	atomic_inc(&led_devp->sec_counter);		//原子变量的值加一,不可被打断
//	num = atomic_read(&led_devp->sec_counter);	//原子变量的值读取,不可被打断
//	printk(KERN_INFO "sec_count:%d\n",num);		
}
/**
*初始化相关的定时器数值,保证定时器运行,需依赖相应的头文件
*/
static int led_shun(void)
{
//	struct timer_list *timer;
//	timer = &test_timer;
	
	printk(KERN_INFO "timer init \n");
	test_timer.function = sec_timer_handler;
	test_timer.expires = jiffies + TIMER_SET;		  //计时频率为HZ HZ一般为100,所以此处可以加速闪烁
	printk(KERN_INFO "timer HZ \n");

	init_timer(&test_timer);  /*初始化一定要放到赋值函数的后面,否则会出现错误,此处可以增加错误处理函数*/
	add_timer(&test_timer); /*将设定好的timer加入到列表中,可增加错误处理函数*/ 
	return 0;
}

5.基本操作函数定义

/*操作函数*/
static long gpio_PB8_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
   
	printk("cmd is %d,arg is %d \n",cmd,(unsigned int)(arg));
    
	switch(cmd){
		case IOCTL_LED_ON:{
			del_timer(&test_timer);
			gpio_set_value(NUC980_PB8, 0);	
			break;
		}
		case IOCTL_LED_OFF:{
			del_timer(&test_timer);
			gpio_set_value(NUC980_PB8, 1);	
			break;
		}
		case IOCTL_LED_RUN:{
			/*for (i=0;i<arg;i++)
				for (j=0;j<4;j++) {
					gpio_set_value(NUC980_PB8, 0);	
					msleep(400); //delay 400ms
					gpio_set_value(NUC980_PB8, 1);	
					msleep(400); //delay 400ms
				}  
				*/
				led_shun();
		}
		default:
			break;
	}    
    return 0;
}
/*释放函数*/
static int gpio_PB8_release(struct inode *inode, struct file *file){
    printk(KERN_EMERG "gpio_PB8 release\n");
    return 0;
}
/*打开函数*/
static int gpio_PB8_open(struct inode *inode, struct file *file){
    printk(KERN_EMERG "gpio_PB8 open\n");
    return 0;
}
/*ops结构体,存储相关的操作函数*/
static struct file_operations gpio_PB8_ops = {
    .owner					= THIS_MODULE,
    .open						= gpio_PB8_open,
    .release				= gpio_PB8_release,
    .unlocked_ioctl = gpio_PB8_ioctl,
};

static int gpio_PB8_init(void)
{
    int DriverState;
    int ret;
   	
    printk(KERN_EMERG "module 20190824 !\n");
    ret = gpio_request(NUC980_PB8,"NUC980_PB8");
    if(ret < 0){
        printk(KERN_EMERG "gpio_request NUC980_PB8 failed!\n");
        return ret;
    }
    gpio_direction_output(NUC980_PB8,1);
    gpio_set_value(NUC980_PB8, 0);
		major = register_chrdev(0, "gpio_PB8_gpio", &gpio_PB8_ops);  
		
		jt_gpio_class = class_create(THIS_MODULE, "jt_gpio_class");
    if (!jt_gpio_class) {
        printk(KERN_INFO "jt_gpio class_create fail\n");
        return -1;
    }
    jt_gpio_device = device_create(jt_gpio_class, NULL, MKDEV(major, 0), NULL, "gpio_PB8_gpio");
    if (!jt_gpio_device) {
        printk(KERN_INFO "jt_gpio device_create fail\n");
        return -1;
    }

    printk(KERN_EMERG "DriverState is %d\n",DriverState);
    return 0;
}

static void gpio_PB8_exit(void)
{
    printk(KERN_EMERG "module 20190824 exit!\n");
    
    unregister_chrdev(major,"gpio_PB8_gpio");  
    gpio_free(NUC980_PB8);
    device_unregister(jt_gpio_device);
    class_destroy(jt_gpio_class); 
	del_timer(&test_timer);    
}

6.用于操作module的函数

module_init(gpio_PB8_init);
module_exit(gpio_PB8_exit); 

7.主程序头文件

#include <stdio.h>	/*标准的输入输出函数库*/
#include <stdlib.h>	/*标准的输入输出函数库*/
#include <unistd.h> /*对于read和write等函数的支持*/
#include <sys/ioctl.h> /*IO指令流函数,如cmd等,除了打开函数之外,其他的函数定义*/

8.主程序宏定义

#define LED_MAGIC 'k'
#define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int)
#define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int)
#define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int)
#define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int)
#define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int)
#define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int)

9.主程序函数定义

void usage(char *exename)
{
    printf("Usage:\n");
    printf("    %s <led_no> <on/off>\n", exename);
    printf("    led_no = 1, 2, 3 or 4\n");
}    
int main(int argc, char **argv)
{
    unsigned int led_no;
    int fd = -1;
    unsigned int count=10;
    
    if (argc > 3 || argc == 1)
        goto err;
        
    fd = open("/dev/gpio_PB8_gpio", 0);  // 打开设备
    if (fd < 0) {
        printf("Can't open /dev/gpio_PB8_gpio\n");
        return -1;    
    }    
    
	printf("argc = %d\n",argc);
    if (argc == 2) {
        if (!strcmp(argv[1], "on")) {
			printf("argc[1] = on\n");
            ioctl(fd, IOCTL_LED_ON, count);    // 点亮它
        } 
		else if (!strcmp(argv[1], "off")) {
			printf("argc[1] = off\n");
            ioctl(fd, IOCTL_LED_OFF, count);   // 熄灭它
        } 
		else if (!strcmp(argv[1], "run")) {
            ioctl(fd, IOCTL_LED_RUN, count);   //运行跑马灯
                } 
        } 
	else {
            goto err;
        }        
    close(fd);
	return 0;        
err:
    if (fd > 0) 
        close(fd);
    usage(argv[0]);
    return -1;        
}

10.终端设备输入定义
终端设备输入使用./函数名 <函数参数个数> <函数参数1> <函数参数2>实现,函数名称计算到参数个数内,如./app 2 on,<./app>作为一个参数,作为一个参数,因此需要写作2,真正需要判断的argv则为argv[1]。
其他暂时先不说了

标签:LED,驱动程序,int,timer,define,IOCTL,GPIO,include,NUC980
来源: https://blog.csdn.net/weixin_43828795/article/details/100086790

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有