NUC980驱动595与165扩展输入输出接口

一、电路图
3个165串联组成扩展24路光耦输入检测,一个595扩展8路继电器输出
在这里插入图片描述
二、驱动源码

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>//jiffies在此头文件中定义
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/timer.h>

#include <linux/gpio.h>
#include <mach/gpio.h>
#include <linux/delay.h>

static struct hrtimer kthread_timer;

#define DISP_BUF_LEN    2
#define DISP_DIG_LEN    4

typedef struct _disp_buf_t{
    uint8_t     output[DISP_BUF_LEN];
    uint8_t     dig[DISP_DIG_LEN]
}disp_buf_t;

disp_buf_t disp_buf;;

#define SERIAL_CLK_PIN	NUC980_PB0
#define SERIAL_PE_PIN	NUC980_PB3
#define SERIAL_LE_PIN	NUC980_PB2
#define SERIAL_IN_PIN	NUC980_PB6
#define SERIAL_OUT_PIN	NUC980_PB4

#define serial_clk_pin(sta)         gpio_set_value(SERIAL_CLK_PIN, sta)
#define serial_pe_pin(sta)          gpio_set_value(SERIAL_PE_PIN, sta)
#define serial_le_pin(sta)          gpio_set_value(SERIAL_LE_PIN, sta)
#define serial_in_pin()             gpio_get_value(SERIAL_IN_PIN)
#define serial_out_pin(sta)         gpio_set_value(SERIAL_OUT_PIN, sta)

#define LED_PIN		NUC980_PB13

#define EXTIO_IN_MAX	24
#define EXTIO_OUT_MAX	8
#define EXTIO_KEY_MAX	2
#define EXTIO_CHECK_AMX	2

#define EXTIO_SET_KEY	0
#define EXTIO_OPEN_KEY	1

#define EXTIO_KEY_RELEASE	0
#define EXTIO_KEY_PRESS		1
#define EXTIO_KEY_KEEP		2

#define EXTIO_CHECK_POWERDOWN	0
#define EXTIO_CHECK_EMERGENCY	1

typedef struct _input_t{
	uint8_t		buf[EXTIO_IN_MAX/8];
	uint8_t		save[EXTIO_IN_MAX/8];
	uint8_t		timer[EXTIO_IN_MAX];
}input_t;

typedef struct _output_t{
	uint8_t		byte[EXTIO_OUT_MAX/8];
}output_t;

typedef struct _check_t{
	uint8_t		sta[EXTIO_CHECK_AMX];
	uint8_t		time[EXTIO_CHECK_AMX];
}check_t;

typedef struct _extio_t{
	input_t		input;
	output_t	output;
	key_t		key;
	check_t		check;
}extio_t;

extio_t	extio;

void extio_write(uint8_t byte)
{
    uint8_t i;
	for( i=0; i<8; i++ ){
		
		if( byte&(0x80) )
			serial_out_pin(1);
		else
			serial_out_pin(0);
		
		serial_clk_pin(1);
		udelay(100);
		serial_clk_pin(0);
		udelay(100);
		byte<<=1;
	}
}

void extio_output(void)
{
    uint8_t i;
	for( i=0; i<EXTIO_OUT_MAX/8; i++ ){
		extio_write(extio.output.byte[i]);
        // extio_write(0x55);
		// printk("modlog: int %s, line %d.\n", __FUNCTION__, __LINE__);
	}
	serial_le_pin(1);
	udelay(100);
    serial_le_pin(0);
}

void extio_read(uint8_t *byte,uint8_t first)
{
	*byte = 0;
    uint8_t i;
	if( first ){
		
		if( serial_in_pin() )
				(*byte) |= 0x01;
		
		for( i=0; i<7; i++ ){
			
			serial_clk_pin(1);
			
			(*byte)<<=1;
			if( serial_in_pin() )
				(*byte) |= 0x01;
			
			serial_clk_pin(0);
			
		}
	}
	else{
		for( i=0; i<8; i++ ){
			
			serial_clk_pin(1);
			
			(*byte)<<=1;
			if( serial_in_pin() )
				(*byte) |= 0x01;
			
			serial_clk_pin(0);
			
		}
	}
}

void extio_input(void)
{
	serial_pe_pin(0);
	udelay(1);
	serial_pe_pin(1);
//	rt_hw_us_delay(10);
	uint8_t *in_ptr =&extio.input.buf[EXTIO_IN_MAX/8-1];
    uint8_t i;
	for( i=0; i<EXTIO_IN_MAX/8; i++ ){
		//
		if( i==0 )
			extio_read(in_ptr,1);
		else
			extio_read(in_ptr,0);
		in_ptr--;
	}

	// printk("%02x %02x %02x\n",extio.input.buf[0],extio.input.buf[1],extio.input.buf[2]);
}

void extio_input_check( void )
{
	uint8_t i,io,k,num;

	for(  num=0; num<EXTIO_IN_MAX/8; num++ )
	{
		if( extio.input.buf[num]!=extio.input.save[num] )
		{
			io = extio.input.buf[num]^extio.input.save[num];
			for( i=0; i<8; i++ )
			{
				if( io&0x01 )
				{
					if( extio.input.timer[num*8+i]<30 )
					{
						extio.input.timer[num*8+i]++;	//ÿһ¸öIO¿ڶԓ¦һ¸ö¼Ɗ±Ʒ
					}
					else
					{
						extio.input.timer[num*8+i] = 0;
						k = extio.input.buf[num];
						k >>= i;
						if( k&0x01 )
						{
							extio.input.save[num] |= (1<<i);
						}
						else
						{
							extio.input.save[num] &= (~(1<<i));
						}
					}
				}
				else
				{
					extio.input.timer[num*8+i] = 0;
				}
				io >>= 1;
			}
		}
	}
}

void extio_task(void)
{
	// extio_input();
	extio_output();
}

#define HRTIMER_TEST_CYCLE   0, (100000000 / 2)

enum hrtimer_restart hrtimer_cb_func(struct hrtimer *timer) 
{
    extio_task();
    hrtimer_forward(timer, timer->base->get_time(), ktime_set(HRTIMER_TEST_CYCLE));
    return HRTIMER_RESTART;
}

void kthread_hrtimer_init(void) {
    hrtimer_init(&kthread_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    kthread_timer.function = hrtimer_cb_func;
    hrtimer_start(&kthread_timer, ktime_set(HRTIMER_TEST_CYCLE), HRTIMER_MODE_REL);
    printk("timer init\n");
}

static int major = 0;
static const char *extio_dev_name = "extio";
static struct class *extio_dev_class;
static struct device *extio_dev_device;

static char dev_buf[4096];

#define MIN(a, b) ((a) < (b) ? (a) : (b))

static int extio_dev_open(struct inode *node, struct file *file)
{
	return 0;
}

static int extio_dev_close(struct inode *node, struct file *file)
{
	return 0;
}

static ssize_t extio_dev_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int ret;
	ret = copy_to_user(buf, dev_buf, MIN(size, 4096)); // 从内核空间拷贝数据到用户空间
	return ret;
}

static ssize_t extio_dev_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int ret;
	ret = copy_from_user(dev_buf, buf, MIN(size, 4096)); // 从用户空间拷贝数据到内核空间
    extio.output.byte[0] = simple_strtol(dev_buf,&dev_buf,3);
	printk("write %02x\n",extio.output.byte[0]);
	return ret;
}

static const struct file_operations extio_dev_fops = {
	.owner = THIS_MODULE,
	.open = extio_dev_open,
	.release = extio_dev_close,
	.read = extio_dev_read,
	.write = extio_dev_write,
};

static int __init extio_dev_init(void)
{
	int ret;
	ret = gpio_request(NUC980_PB0,"NUC980_PB0");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC980_PB0 failed!\n");
		
	}
	ret = gpio_request(NUC980_PB3,"NUC980_PB3");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC980_PB3 failed!\n");
		
	}
	ret = gpio_request(NUC980_PB2,"NUC980_PB2");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC980_PB2 failed!\n");
		
	}
    ret = gpio_request(NUC980_PB4,"NUC980_PB4");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC980_PB4 failed!\n");
		
	}
    ret = gpio_request(NUC980_PB6,"NUC980_PB6");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request NUC980_PB6 failed!\n");
		
	}
	
	gpio_direction_output(SERIAL_CLK_PIN,1);
	gpio_direction_output(SERIAL_LE_PIN,1);
	gpio_direction_output(SERIAL_PE_PIN,1);
    gpio_direction_input(SERIAL_IN_PIN);
    gpio_direction_output(SERIAL_OUT_PIN,1);
	gpio_direction_output(LED_PIN,1);
    gpio_set_value(LED_PIN, 0);
	
	// timer_init();
    kthread_hrtimer_init();
	printk("modlog: func %s, line %d.\n", __FUNCTION__, __LINE__);
	major = register_chrdev(0, extio_dev_name, &extio_dev_fops); // 注册字符设备,第一个参数0表示让内核自动分配主设备号

	extio_dev_class = class_create(THIS_MODULE, "extio_dev_class"); // 
	if (IS_ERR(extio_dev_class))
	{
		unregister_chrdev(major, extio_dev_name);
		return -1;
	}
	extio_dev_device = device_create(extio_dev_class, NULL, MKDEV(major, 0), NULL, extio_dev_name); // 创建设备节点创建设备节点,成功后就会出现/dev/char_dev_name的设备文件
	if (IS_ERR(extio_dev_device))
	{
		device_destroy(extio_dev_class, MKDEV(major, 0));
		unregister_chrdev(major, extio_dev_name);
		return -1;
	}

	return 0;
}

static void __exit extio_dev_exit(void)
{
	// timer_exit();
    hrtimer_cancel(&kthread_timer);
	printk("modlog: func %s, line %d.\n", __FUNCTION__, __LINE__);

    gpio_set_value(LED_PIN, 1);
	
	gpio_free(SERIAL_CLK_PIN);
	gpio_free(SERIAL_LE_PIN);
	gpio_free(SERIAL_PE_PIN);
    gpio_free(SERIAL_IN_PIN);
    gpio_free(SERIAL_OUT_PIN);
    gpio_free(LED_PIN);

	device_destroy(extio_dev_class, MKDEV(major, 0)); // 销毁设备节点,销毁后/dev/下设备节点文件就会删除
	class_destroy(extio_dev_class);

	unregister_chrdev(major, extio_dev_name); // 注销字符设备
}

module_init(extio_dev_init); // 模块入口
module_exit(extio_dev_exit); // 模块出口

MODULE_LICENSE("GPL"); // 模块许可


测试源码

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


int main(int argc, char **argv)
{
    int fd,value;

    if( argc !=4 ){
        printf("usage: extio_app <devpath> <value> -w\n");
        return -1;
    }

    fd = open(argv[1],O_RDWR);
    if( fd<0 ){
        printf("applog: can not open file %s\n",argv[1]);
        return -1;
    }

    if( 0 == strcmp(argv[3],"-w") ){
        write(fd,argv[2],3);
		printf("applog: write - %s\n",argv[2]);
    }
    else{
        close(fd);
        return -1;
    }
    close(fd);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵向深耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值