linux驱动数码管-基于74HC164D

本文介绍了如何通过查看电路原理图和GPIO口配置,使用74HC164D移位寄存器驱动共阳极数码管,利用UART2的GPIO复用功能,并给出了详细的驱动代码示例。重点展示了设置单数和双数数码显示的方法,以及使用Linux设备驱动实现过程。

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

1、查看电路原理图,确定驱动数码管对应的元件,及GPIO口

2、这里我们用的uart2的引脚,复用为GPIO口

3、上面确定了驱动数码管涉及的元器件为CS4021B(数码管)、74HC164D(移位寄存器)以及SOC的GPIO口,所以需要先找到74HC164D的芯片资料,查看该芯片是如何驱动A-G、A1-G1并输出特定的电平控制数码管

4、当时钟信号(CP 对应 SCK)从低电平变为高电平时,芯片将读取DSA(B)输入的电平信号,并将电平信号保存到Q0上(同时Q0会输出该电平),当时钟CP第二次由低电平变为高电平的时候将 Q0 的数据移动到 Q1,新的电平信号将被保存在 Q0。依此类推,每一个时钟周期中都有一个串行数据输入到 Q0,而其他的数据则不断往高位移动直到有数据传输结束。如果不再有时钟周期输入,则这些数据将暂存在输出端。

5、确定数码管的真值表,电路采用的共阳极,因此数码管Qn输出低电平时,对应的LED会亮,对应的真值表如下

6、驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/delay.h>




#define DIGITAL_TUBE_SCK 64
#define DIGITAL_TUBE_SDA 65

#define LOW				 0
#define HIGH			 1

struct digital_tube{
	int major;
	struct class *class;
	struct device *dev;
	
};

struct digital_tube *lpf_digital_tube;

int digital_tube_open(struct inode *inode,struct file *filp)
{

	printk("---------LPF:%s----------\n",__func__);
	
	return 0;
}

int digital_tube_release(struct inode *inode,struct file *filp)
{

	printk("---------LPF:%s----------\n",__func__);

	return 0;
}

static const struct file_operations digital_tube_fops={
	.owner = THIS_MODULE,
	.open = digital_tube_open,
	.release = digital_tube_release,
};

//echo X(0<= X <10) > digital_tube_value,执行此函数
static void set_single_number(int number)
{
	u8 true_table[] = {0x02,0x9E,0x24,0x0C,0x98,0x48,0x40,0x1E,0x00,0x08};
	u8 data;
	u8 value;
	int count;
	
	data = true_table[number];

	for(count=0;count < 8;count ++){

		value = data&0x01;
		printk("-------LPF:%o---------\n",value);
		gpio_direction_output(DIGITAL_TUBE_SDA,value);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SCK,HIGH);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SDA,LOW);
		
		data = data>>1;

	}

	data=0xFE;
	
	for(count=0;count<8;count++){

		value = data&0x01;
		printk("-------LPF:%o---------\n",value);
		gpio_direction_output(DIGITAL_TUBE_SDA,value);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SCK,HIGH);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SDA,LOW);
		
		data = data>>1;

	}
	

}

//echo X(X >= 10) > digital_tube_value,执行此函数

static void set_double_number(int number)
{

	u8 true_table[] = {0x02,0x9E,0x24,0x0C,0x98,0x48,0x40,0x1E,0x00,0x08};
	u8 data;
	u8 value;
	int count;
	
	data = true_table[number];

	for(count=0;count < 8;count ++){

		value = data&0x01;
		printk("-------LPF:%o---------\n",value);
		gpio_direction_output(DIGITAL_TUBE_SDA,value);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SCK,HIGH);
		gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
		gpio_direction_output(DIGITAL_TUBE_SDA,LOW);
		
		data = data>>1;

	}
	
}



/*返回写入的字符串长度,否则会无限回调 */
static ssize_t echo_digital_tube_value(struct device *dev,struct device_attribute *attr, const char *buf, size_t len)        
{
	int value = 0 ;
	//int i;
	int single_value,double_value;
	
	/*将应用空间传递的(char *)类型数据转换为内核空间10进制整形 */
	value = simple_strtoul(buf, NULL, 10);
	
	if(value<0 && value >99 )
		return len;
	
	single_value = value % 10;
	double_value = value / 10;

	printk("---------LPF:%s----------\n",__func__);
	printk("---------LPF:value %d single_value %d double_value %d----------\n",value,single_value,double_value);

	if(double_value == 0){
		
		set_single_number(single_value);
		
	}else{
	
		set_double_number(single_value);
		set_double_number(double_value);
		
	}
		

	return len;
}

static ssize_t cat_digital_tube_value(struct device *dev,struct device_attribute *attr, char *buf)
{

	printk("---------LPF:%s----------\n",__func__);
	
	return 0;

}


/*
	#define DEVICE_ATTR(_name, _mode, _show, _store)  /
	
		struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

	类似:static struct kobj_attribute hello_value_attribute = __ATTR(hello_value, 0666, hello_show, hello_store);

	S_IWUSR|S_IRUSR 读写权限
*/

static DEVICE_ATTR(digital_tube_value, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP  ,cat_digital_tube_value, echo_digital_tube_value);

/* 驱动模块入口 */
static int __init digital_tube_init_module(void)
{
	int ret;

	/*空间申请*/
	lpf_digital_tube = kzalloc(sizeof(struct digital_tube),GFP_KERNEL);
	if(IS_ERR(lpf_digital_tube)){
		printk("-------LPF-%s:kzalloc lpf_digital_tube failed!--------\n",__func__);
		ret = PTR_ERR(lpf_digital_tube);
		return ret;
	}

	/* 设备号申请*/
	lpf_digital_tube->major = register_chrdev(0, "digital_tube_major", &digital_tube_fops);
	if(lpf_digital_tube->major < 0){
		printk("-------LPF-%s:failed to creat lpf_digital_tube->major-------\n",__func__);
		ret = -EINVAL;
		goto err_kzalloc;
	}

	/*创建设备类*/
	lpf_digital_tube->class = class_create(THIS_MODULE, "digital_tube_class");
	if(IS_ERR(lpf_digital_tube->class)){
		printk("-------LPF-%s:failed to creat lpf_digital_tube->class--------\n",__func__);
		ret = PTR_ERR(lpf_digital_tube->class);
		goto err_register;
	}

	/*创建digital_tube_device设备节点文件*/
	lpf_digital_tube->dev = device_create(lpf_digital_tube->class,NULL,MKDEV(lpf_digital_tube->major, 0),NULL,"digital_tube_device");
	if(IS_ERR(lpf_digital_tube->dev)){
		printk("-------LPF-%s:failed to creat lpf_digital_tube->dev--------\n",__func__);
		ret = PTR_ERR(lpf_digital_tube->dev);
		goto err_device_create;
	}

	/* 在 设备目录下创建一个digital_tube_value属性文件 /sys/class/digital_tube_class/digital_tube_device/digital_tube_value */
	ret=sysfs_create_file(&(lpf_digital_tube->dev->kobj), &dev_attr_digital_tube_value.attr);
	if(ret != 0){
		printk("-------LPF-%s:failed to creat sysfs_create_file ret:%d--------\n",__func__,ret);
		goto err_sysfs_create_file;
	}

	/* gpio_request */
	ret = gpio_request(DIGITAL_TUBE_SDA, "digital_tube_sda");
	if(ret!=0){
		printk("-------LPF-%s:SDA_GPIO: %d request failed!--------\n",__func__,DIGITAL_TUBE_SDA);
		goto err_sda_request;
		
	}else{
		printk("-------LPF-%s:SDA_GPIO: %d request success!-------\n",__func__,DIGITAL_TUBE_SDA);
	}

	ret = gpio_request(DIGITAL_TUBE_SCK, "digital_tube_sck");
	if(ret!=0){
		printk("-------LPF-%s:SCK_GPIO: %d request failed!--------\n",__func__,DIGITAL_TUBE_SCK);
		goto err_sck_request;

	}else{
		printk("-------LPF-%s:SCK_GPIO: %d request success!-------\n",__func__,DIGITAL_TUBE_SCK);
	}

	gpio_direction_output(DIGITAL_TUBE_SDA,LOW);
	gpio_direction_output(DIGITAL_TUBE_SCK,LOW);
	
	
	return ret;
	
/*错误处理*/
err_sck_request:	
	gpio_free(DIGITAL_TUBE_SDA);
err_sda_request:
	sysfs_remove_file(&(lpf_digital_tube->dev->kobj), &dev_attr_digital_tube_value.attr); //删除创建的属性文件
err_sysfs_create_file:
	device_destroy(lpf_digital_tube->class,MKDEV(lpf_digital_tube->major, 0));
err_device_create:
	class_destroy(lpf_digital_tube->class);
err_register:
	unregister_chrdev(lpf_digital_tube->major,"digital_tube_major"); 
err_kzalloc:
	kfree(lpf_digital_tube);
	
	return ret;	
}

/* 驱动模块出口 */
static void __exit digital_tube_exit_module(void)
{

	gpio_free(DIGITAL_TUBE_SCK);
	gpio_free(DIGITAL_TUBE_SDA);
	sysfs_remove_file(&(lpf_digital_tube->dev->kobj), &dev_attr_digital_tube_value.attr);
	device_destroy(lpf_digital_tube->class,MKDEV(lpf_digital_tube->major, 0));
	class_destroy(lpf_digital_tube->class);
	unregister_chrdev(lpf_digital_tube->major,"digital_tube_major"); 
	kfree(lpf_digital_tube);

}

module_init(digital_tube_init_module);
module_exit(digital_tube_exit_module); 
MODULE_LICENSE("Dual BSD/GPL");

6.查看效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值