linux树莓派3b智能家居(一) 继电器驱动编写以及测试

本文详细介绍了一种基于Linux的嵌入式系统驱动开发过程,包括驱动文件的基本框架搭建、自定义指令格式的设计以及核心思想的阐述。通过具体的代码示例,展示了如何使用switch-case结构实现对继电器的不同操作,并提供了驱动测试程序的编写指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

驱动文件编写(基于框架)

基本框架

#include <linux/fs.h>		 //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>	 //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件


static struct class *relay_class;  
static struct device *relay_class_dev;

static dev_t devno;                //设备号
static int major =235;  		   //主设备号
static int minor =0;			   //次设备号
static char *module_name="relay";   //模块名


static int relay_open(struct inode *inode,struct file *file)
{
    printk("relay_open\n");  //内核的打印函数和printf类似
  
    return 0;
}

static ssize_t relay_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
 
    copy_from_user(&usercmd,buf,count);
    
    return 0;
}

static struct file_operations relay_fops = {

    .owner = THIS_MODULE,
    .open  = relay_open,
    .write = relay_write,
};

int __init relay_drv_init(void)   
{

    int ret;
    devno = MKDEV(major,minor);  //创建设备号
    ret   = register_chrdev(major, module_name,&relay_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中

    relay_class=class_create(THIS_MODULE,"myfirstdemo");
    relay_class_dev =device_create(relay_class,NULL,devno,NULL,module_name);  //创建设备文件
 
    return 0;
}

void __exit relay_drv_exit(void)
{

    device_destroy(relay_class,devno);
    class_destroy(relay_class);
    unregister_chrdev(major, module_name);  //卸载驱动

}

module_init(relay_drv_init);  //入口
module_exit(relay_drv_exit);
MODULE_LICENSE("GPL v2");

核心部分(自定义指令格式)

核心思想:继电器有4路,开关各一条指令,全开全关各一条指令,总共10条指令,根据不同指令实现不同操作,推荐使用switich case来选择,指令格式推荐:char型,ascll码形式或者16进制形式,int型10进制或者16进制。

将switch case写入以下函数。这里采用int型16进制(只用到2位16进制数),赋予一些简单的可以理解的含义(也可以直接粗暴的选0-9),第一位表示继电器通道,0表示所有通道,1表示通道1,以此类推,第二位表示高地电平,1表示高电平,0表示低电平。只是人为赋予的含义!!!!

执行内容:根据选择的树莓派IO口,以及人为规定的指令,来让对应寄存器的对应位 置1(SET寄存器和CLR寄存器)

例如:树莓派IO口选择的是5 6 13 19,指令0x01

	    case 0x01:
		    *GPSET0 = 0x1<<5;
		    *GPSET0 = 0x1<<6;
		    *GPSET0 = 0x1<<13;
		    *GPSET0 = 0x1<<19;
static ssize_t relay_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
	int usercmd = 0x01;    
    copy_from_user(&usercmd,buf,count);
    switch(usercmd){
	    case 0x01:

		    break;
	    case 0x11:

		    break;
	    case 0x21:

		    break;
	    case 0x31:

		    break;
	    case 0x41:

		    break;
	    case 0x00:

	    case 0x10:

		    break;
	    case 0x20:

		    break;
	    case 0x30:

		    break;
	    case 0x40:

		    break;  
    }
	return 0;
}

驱动加载省略1万字

驱动测试

编写测试程序

注意:内核switch case使用的是16进制选择,测试程序输入也要16进制输入(scanf 格式控制符%x)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>



int main()
{
	int cmd = 0x01;
	int size = 0;
	int fd = open("/dev/relay",O_RDWR);
		
	if(fd == -1){
		perror("open");
		exit(-1);
	}

	while(1){
		printf("input cmd : ");
		scanf("%x",&cmd);
		printf("your cmd : %x\n",cmd);

		switch(cmd){
			case 0x00:
			case 0x10:
			case 0x20:
			case 0x30:
			case 0x40:	
			case 0x01:
			case 0x11:
			case 0x21:
			case 0x31:
			case 0x41:
				write(fd,&cmd,4);
				break;
			default:
				printf("cmd not exist\n");
				break;	
	
		}
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值