NUC980模拟时序驱动595输出动态扫描数码管驱动程序

从瑞萨单片机移植到NUC980数码管动态扫描驱动,硬件定时器定时刷新

驱动源码

#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_RCLK_PIN	NUC980_PB0
#define SERIAL_SCLK_PIN	NUC980_PB3
#define SERIAL_DIO_PIN	NUC980_PB2

#define LED_PIN		NUC980_PB13

#define serial_rclk_pin(sta)       gpio_set_value(SERIAL_RCLK_PIN, sta)
#define serial_sclk_pin(sta)       gpio_set_value(SERIAL_SCLK_PIN, sta)
#define serial_dio_pin(sta)        gpio_set_value(SERIAL_DIO_PIN, sta)

const uint8_t dig_code[]={
        /********生成 0-f 的编码********/
        0xC0,0
        0xF9,1
        0xA4,2
        0xB0,3
        0x99,4
        0x92,5
        0x82,6
        0xF8,7
        0x80,8
        0x90,9
        0x88,A
        0x80,B
        0xC6,C
        0xC0,D
        0x86,E
        0x8E,F
};

void display_dig(uint16_t dig)
{
    uint8_t zero=0;
    dig %= 9999;
    if( dig/1000 ){
        disp_buf.dig[0] = dig_code[dig/1000];
        dig %= 1000;
        zero = 1;
    }
    else{
        disp_buf.dig[0] = 0xff;
    }

    if( dig/100 ){
        disp_buf.dig[1] = dig_code[dig/100];
        dig %= 100;
        zero = 1;
    }
    else if(zero){
        disp_buf.dig[1] = dig_code[0];
    }
    else{
        disp_buf.dig[1] = 0xff;
    }

    if( dig/10 ){
        disp_buf.dig[2] = dig_code[dig/10];
        dig %= 10;
        zero = 1;
    }
    else if(zero){
        disp_buf.dig[2] = dig_code[0];
    }
    else{
        disp_buf.dig[2] = 0xff;
    }

    if( dig ){
        disp_buf.dig[3] = dig_code[dig];
    }
    else if(zero){
        disp_buf.dig[3] = dig_code[0];
    }
    else{
        disp_buf.dig[3] = 0xff;
    }
}

void display_led(void)
{
	static uint16_t cnt=0;
	static uint16_t time=0;
    const uint8_t pos_v[] = {0x08,0x04,0x02,0x01};
    static uint8_t pos = 0;
    disp_buf.output[0] = pos_v[pos];
    disp_buf.output[1] = disp_buf.dig[pos];
    pos++;
    if( pos>=4 )
        pos = 0;
}

static void display_wr_byte(uint8_t data)
{
	uint8_t i;
    for( i=0; i<8; i++ ){
        serial_dio_pin(data&0x80?1:0);
        udelay(1);
        serial_sclk_pin(1);
        udelay(1);
        serial_sclk_pin(0);

        data <<= 1;
    }
}

static void display_refresh(void)
{
	uint8_t i;
    for( i=DISP_BUF_LEN; i>0; i-- ){
        display_wr_byte(disp_buf.output[i-1]);
    }
    serial_rclk_pin(1);
    udelay(1);
    serial_rclk_pin(0);
}

#define HRTIMER_TEST_CYCLE   0, (5000000 / 2)

enum hrtimer_restart hrtimer_cb_func(struct hrtimer *timer) 
{
    display_led();
	display_refresh();
    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);
}

// struct timer_list mytimer;//定义一个定时器
// // static uint8_t stop_timer=0;
// void  mytimer_ok(unsigned long arg)
// {
// 	display_led();
// 	display_refresh();
//     // if( stop_timer==1 )
//     mod_timer(&mytimer, jiffies + 5);
// } 

// int timer_init (void)
// {
//     // stop_timer=1;
//     printk("timer init\n");
//     init_timer(&mytimer);     //初始化定时器
//     // init_timer_deferrable(&mytimer);
//     mytimer.expires = jiffies+1;//设定超时时间,100代表1秒
//     mytimer.data = 250;    //传递给定时器超时函数的值
//     mytimer.function = mytimer_ok;//设置定时器超时函数
//     add_timer(&mytimer); //添加定时器,定时器开始生效
//     return 0;
// }   

// void timer_exit (void)
// {
//     // stop_timer=0;
//     del_timer(&mytimer);//卸载模块时,删除定时器
//     printk("timer exit\n");
// }

static int major = 0;
static const char *led595_dev_name = "led595";
static struct class *led595_dev_class;
static struct device *led595_dev_device;

static char dev_buf[4096];

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

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

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

static ssize_t led595_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 led595_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 led595_dev_fops = {
	.owner = THIS_MODULE,
	.open = led595_dev_open,
	.release = led595_dev_close,
	.read = led595_dev_read,
	.write = led595_dev_write,
};

static int __init led595_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");
		
	}
	
	gpio_direction_output(SERIAL_RCLK_PIN,1);
	gpio_direction_output(SERIAL_SCLK_PIN,1);
	gpio_direction_output(SERIAL_DIO_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, led595_dev_name, &led595_dev_fops); // 注册字符设备,第一个参数0表示让内核自动分配主设备号

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

	return 0;
}

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

    gpio_set_value(LED_PIN, 1);
    display_wr_byte(0xff);
    display_wr_byte(0xff);
	
	gpio_free(SERIAL_RCLK_PIN);
	gpio_free(SERIAL_SCLK_PIN);
	gpio_free(SERIAL_DIO_PIN);
    gpio_free(LED_PIN);

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

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

module_init(led595_dev_init); // 模块入口
module_exit(led595_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: led595_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],4);
		printf("applog: write - %d\n",value);
    }
    else{
        close(fd);
        return -1;
    }
    close(fd);
    return 0;
}

在这里插入图片描述
数码管从淘宝买,2个595驱动4位数码管
在这里插入图片描述

NUC980模拟时序驱动数码管

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

纵向深耕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值