linux驱动(GPIO驱动 & 定时器驱动)

  • GPIO点灯-MCIMX93开发板
#include <linux/module.h>                                 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>

/* 初始化设备号,定义设备名*/
int Major = 0;
#define CNAME "MyGpio"

/*
 * LED基地址,以及虚拟弟子
 */
#define LED_OUTPUT 0x43810040
#define LED_MODE 0x43810054
unsigned int * LedOutPut = NULL;
unsigned int * LedMode = NULL;

struct class * Cls1;
struct device * Dev1;
/*
 * 存储向应用从发送的数据
 */
char KBuf = 0;

ssize_t GpioWrite(struct file *file, const char __user *ubuf, size_t size, loff_t *offs)
{
	int ret;
	/*
	 * 调用函数将灯熄灭
	 */
	*(LedOutPut) &= ~(1<<4);
	*(LedOutPut) &= ~(1<<12);
	*(LedOutPut) &= ~(1<<13);

    printk("this is write\n");
    ret = copy_from_user(&KBuf,ubuf,1);
    if(ret){
        printk("copyfrom user error\n");
        return -EINVAL;
    }

	printk("Kbuf:%c\n",KBuf);

    switch(KBuf)
    {
        case '0':    
            *(LedOutPut) |= 1<<4;
            break;
        case '1':
            *(LedOutPut) |= 1<<12;
			break;
		case '2':
            *(LedOutPut) |= 1<<13;
			break;
		case '3':
        	*(LedOutPut) &= ~(1<<4);
        	*(LedOutPut) |= ~(1<<12);
        	*(LedOutPut) |= ~(1<<13);
			break;
    }
	return size;
}

ssize_t ReadLed(struct file *file, char __user *ubuf,size_t  size, loff_t *offs) 
{
    int ret;
    char send[36]="\0";
    
	sprintf(send,"green:%d blune:%d read:%d\n",(*LedOutPut & (1<<4)),(*LedOutPut & (1<<12)),(*LedOutPut & (1<<13)));

    ret = copy_to_user(ubuf,send,size);
    if(ret){
        printk("copy  to user error\n");
        return -EINVAL;
    }                                                        
    return size;
}


const struct file_operations GPIO_LED = {
	.write   = GpioWrite,
	.read  = ReadLed,
};

static int __init GpioInit(void)
{
    printk("LED start\n");

    /*
	 * 注册自发设备驱动
	 */
	Major = register_chrdev(Major,CNAME,&GPIO_LED);
	if(Major < 0){
		printk("LED error\n");
		return Major;
	}

    Cls1 = class_create(THIS_MODULE,CNAME);
	if(IS_ERR(Cls1)){
        printk("class_create err");
		return PTR_ERR(Cls1);
	}
	Dev1 = device_create(Cls1,NULL,MKDEV(Major,0),NULL,CNAME);
	if(IS_ERR(Dev1)){
        printk("device create error\n");
		return PTR_ERR(Dev1);
	}

    /* 
	 * 物理地址转换为虚拟地址
	 */
    LedOutPut = ioremap(LED_OUTPUT,64);
	if(LedOutPut == NULL){//转换失败提示
		printk("red output error\n");
		return -ENOMEM;
	}

    LedMode = ioremap(LED_MODE,64);
	if(LedMode == NULL){//转换失败提示
		printk("red mode error\n");
		return -ENOMEM;
	}

    /*
	 * 将GPIO设置为输出
	 */
	*(LedMode) |= 1<<4;
	*(LedMode) |= 1<<12;
	*(LedMode) |= 1<<13;

	/*
	 * 使GPIO输出高电平
	 */
	*(LedOutPut) |= 1<<4;
	*(LedOutPut) |= 1<<12;
	*(LedOutPut) |= 1<<13;
	return 0;
}

static void __exit GpioExit(void)
{
    device_destroy(Cls1,MKDEV(Major,0));
	printk("LED exit\n");
	iounmap(LedOutPut);
	iounmap(LedMode);

	/*
	 * 注销字符设备驱动
	 */
    unregister_chrdev(Major,CNAME);
}

/*
 * 使用Linux内核提供的入口/出口API,调用自己写的入口/出口函数
 * 添加许可证
 */
module_init(GpioInit);
module_exit(GpioExit);
MODULE_LICENSE("GPL");
MODULE_INFO(intree, "Y");
  • ktimer
#include <linux/module.h>                                 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/hrtimer.h>

/* 
 * 初始化设备号,定义设备名
 */
int Major = 0;
#define CNAME "TimeGpio"

/*
 * LED基地址,以及虚拟地址
 */
#define LED_OUTPUT 0x43810040
#define LED_MODE 0x43810054
unsigned int * LedOutPut = NULL;
unsigned int * LedMode = NULL;

/*
 * 创建设备节点变量
 */
struct class * Cls;
struct device * Dev;

/*
 * 存储向应用从发送的数据
 */
char KBuf[25] = "\0";
int Freq=500;
int Numseg=500;
int Flag=0;
int Temp=500;
/*
 * 定时器结构体
 */
struct hrtimer MyHrTimer;
ktime_t Kt;

void Mymemset(char * str){
    while(*str)
		*str++ = '\0';
}

int atoi(char * str){
	int sum=0;
	while(*str){
		sum = sum*10 + *str - '0';
		str++;
	}
	return sum;
}

/*
 * 定时器中断函数,实现电平翻转功能
 */
static enum hrtimer_restart GpioLevelFlip(struct hrtimer * timer)
{
	if(Numseg>0)
	{
        *(LedOutPut) ^= 1 << 4;
		Flag ? Numseg--,Flag=0 : Flag++;
	}
	hrtimer_forward(timer,timer->base->get_time(),Kt);
	return HRTIMER_RESTART;
}

ssize_t GpioWrite(struct file *file, const char __user *ubuf, size_t size, loff_t *offs)
{
	int ret;
	/*
	 * 调用函数将灯熄灭
	 */
    printk("this is write\n");
	Mymemset(KBuf);
    ret = copy_from_user(KBuf,ubuf,size);
    if(ret){
        printk("copyfrom user error\n");
        return -EINVAL;
    }

    /*
	 * 解析传入数据
	 */
	switch(KBuf[0])
	{
	    case '1':
            Freq=atoi(&KBuf[1]);
			break;
		case '2':
			Numseg=atoi(&KBuf[1]);
			break;
	}

    /*
	 * 更改定时时间
	 */
	Kt = ktime_set(0,Freq * 500000);
	Temp=Numseg;

	printk("Kbuf:%s size:%d Freq:%dHz Numseg:%d\n",KBuf,(int)size,1000 / Freq,Numseg);
	return size;
} 

ssize_t ReadFreq(struct file *file, char __user *ubuf,size_t size, loff_t *offs)
{
	int ret;
	char send[36]="\0";
	sprintf(send,"Freq:%d Hz,Numseg:%d",1000 / Freq,Temp-Numseg);
    
	ret = copy_to_user(ubuf,send,size);
	if(ret){
		printk("copy  to user error\n");
		return -EINVAL;
	}
	return size;

}

const struct file_operations TIMER_LED = {
	.write   = GpioWrite,
	.read    = ReadFreq,
};

static int __init GpioInit(void)
{
    /*
	 * 注册自发设备驱动
	 */
	Major = register_chrdev(Major,CNAME,&TIMER_LED);
	if(Major < 0){
		printk("LED error\n");
		return Major;
	}

    Cls = class_create(THIS_MODULE,CNAME);
	if(IS_ERR(Cls)){
        printk("class_create err");
		return PTR_ERR(Cls);
	}
	Dev = device_create(Cls,NULL,MKDEV(Major,0),NULL,CNAME);
	if(IS_ERR(Dev)){
        printk("Device create error\n");
		return PTR_ERR(Dev);
	}

    /*
	 * 物理地址转换为虚拟地址
	 */
    LedOutPut = ioremap(LED_OUTPUT,64);
	if(LedOutPut == NULL){//转换失败提示
		printk("red output error\n");
		return -ENOMEM;
	}

    LedMode = ioremap(LED_MODE,64);
	if(LedMode == NULL){//转换失败提示
		printk("red mode error\n");
		return -ENOMEM;
	}

    /*
	 * 将GPIO设置为输出
	 */
	*(LedMode) |= 1<<4;
	*(LedMode) |= 1<<12;
	*(LedMode) |= 1<<13;

	/*
	 * 初始化,将端口电平设置为0
	 */
	*(LedOutPut) &= ~(1<<4);
	*(LedOutPut) &= ~(1<<12);
	*(LedOutPut) &= ~(1<<13);

	/*
	 * 定时器申请
	 */
    Kt = ktime_set(0,Freq * 500000);
	hrtimer_init(&MyHrTimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
	hrtimer_start(&MyHrTimer,Kt,HRTIMER_MODE_REL);
	MyHrTimer.function = GpioLevelFlip;

    printk("LED start\n");

	return 0;
}

static void __exit GpioExit(void)
{
    device_destroy(Cls,MKDEV(Major,0));
	class_destroy(Cls);
	printk("LED exit\n");
	iounmap(LedOutPut);
	iounmap(LedMode);
    
	/*
	 * 删除定时器
	 */
	hrtimer_cancel(&MyHrTimer);

	/*
	 * 注销字符设备驱动
	 */
    unregister_chrdev(Major,CNAME);
}

/*
 * 使用Linux内核提供的入口/出口API,调用自己写的入口/出口函数
 * 添加许可证
 */
module_init(GpioInit);
module_exit(GpioExit);
MODULE_LICENSE("GPL");
MODULE_INFO(intree, "Y");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在使用Linux Qt开发中,我们可以通过代码监听GPIO键盘输入,从而实现一些GPIO键盘控制功能。 首先,我们需要在Qt项目中引入GPIO库文件,例如wiringPi,方便控制GPIO输入输出。在程序中需要定义GPIO的输入模式,并使用wiringPi库中的函数将GPIO设置为输入模式: ```cpp pinMode(gpio_num, INPUT); ``` 接下来需要在程序中定义一个Qt定时器,用于定时读取GPIO输入电平值。我们可以使用Qt中的QTimer类来实现: ```cpp QTimer timer; timer.setInterval(50); // 设置定时器频率为50ms QObject::connect(&amp;timer, &amp;QTimer::timeout, this, &amp;MainWindow::timerSlot); timer.start(); // 启动定时器 ``` 在定时器的时间到达时,需要调用相应的槽函数来读取GPIO输入电平值。在此,我们可以使用wiringPi库中的函数来读取GPIO输入电平值: ```cpp int value = digitalRead(gpio_num); // 读取GPIO输入电平值 ``` 最后,我们可以在槽函数中根据GPIO的输入电平值来实现不同的控制逻辑。例如,我们可以根据GPIO输入电平值来控制LED亮灭等。 需要注意的是,在使用GPIO键盘输入时,需要对GPIO输入进行去抖处理,以避免出现误触的情况。在此,我们可以使用软件去抖方法,在定时器槽函数中通过检测GPIO输入电平值的连续变化来判断是否发生按键事件。 通过以上步骤,我们就可以在Linux Qt中实现GPIO键盘输入的监听与控制,为我们的项目带来更多的扩展性和灵活性。 ### 回答2: Linux是一款开源操作系统,Qt则是一个跨平台的GUI开发框架。在Linux中,可以通过监听GPIO Key来实现一些硬件相关的功能。GPIO Key是指硬件的一个键盘接口,可以用来实现一些输入和输出操作。在Linux中,我们可以使用Qt来监听GPIO Key,实现对键盘输入的响应。 在Qt中,我们可以通过QSocketNotifier类来实现对GPIO Key的监听。QSocketNotifier是一个监听器类,可以监听一个系统级别的文件描述符。我们可以创建一个QSocketNotifier对象,将GPIO Key对应的文件描述符传递给它,然后调用其activated()槽,就可以实现对GPIO Key的监听了。 具体步骤如下:首先,需要将GPIO Key对应的管脚设置为输入模式,并将它和一个中断线连接起来。然后,我们需要打开GPIO Key对应的设备文件,获取其文件描述符。接着,创建一个QSocketNotifier对象,将文件描述符通过构造函数传递给它。最后,使用connect()函数将activated()槽与自定义的槽函数进行连接,完成对GPIO Key的监听。 在槽函数中,我们可以实现对GPIO Key输入的响应。例如,可以设置一个计数器,每当GPIO Key被按下时增加1,并将其显示在程序界面上。这样,就可以实现对GPIO Key输入的简单处理了。 总之,使用Qt来监听GPIO Key非常方便,可以在Linux中实现各种硬件相关的功能。 ### 回答3: 在使用 Linux 系统中,我们可以使用 Qt 框架来监听 GPIO Key。GPIO 是通用的输入/输出端口,可用于连接不同的传感器、LCD、LED 等硬件设备。 首先,我们需要在 Linux 系统中加载 GPIO 驱动程序,并确定所需的 GPIO 号码。这可以通过编辑设备树或从系统文件中获取。 然后,我们可以使用 Qt 框架中的 QSocketNotifier 类来监视 GPIO 状态变化。我们需要在应用程序中创建一个 QSocketNotifier 对象,并指定 GPIO 号码和事件类型(例如按下或释放键)。然后,我们可以添加一个&ldquo;槽函数&rdquo;来处理 GPIO 状态变化。 最后,我们需要在应用程序中启动 Qt 事件循环,以确保 GPIO 事件的正确处理。这可以通过调用 QApplication::exec() 函数完成。 总之,Qt 框架非常适用于在 Linux 系统中监听 GPIO Key。它提供了简洁的 API,并且具有很好的可移植性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值