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

一、电路图
3个165串联组成扩展24路光耦输入检测,一个595扩展8路继电器输出
NUC980驱动595与165扩展输入输出接口_第1张图片
二、驱动源码

#include 
#include 
#include 
#include 

#include 
#include 
#include //jiffies在此头文件中定义
#include 
#include 
#include 

#include 
#include 
#include 

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);
		serial_clk_pin(0);
		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(0x00);
	}
	serial_le_pin(1);
    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);
	serial_pe_pin(0);
//	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--;
	}
	
}

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_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)); // 从用户空间拷贝数据到内核空间
    // uint16_t dig = simple_strtol(dev_buf,&dev_buf[4],10);
    // display_dig(dig);
	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"); // 模块许可

你可能感兴趣的:(NUC980,linux,NUC980,165,595,Linux,驱动)