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.查看效果