从瑞萨单片机移植到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模拟时序驱动数码管