驱动编程——实现数码管的数字显示

驱动编程——实现数码管的数字显示 实验现象1管显示02管显示13管显示24管显示31管显示4……2管亮93管亮04管亮1……数码管的显示原理不再赘述编写设备树节点spi4{ pinctrl-names default, sleep; pinctrl-0 spi4_pins_b; pinctrl-1 spi4_sleep_pins_b; cs-gpios gpioe 11 0;//代表片选线 status okay; m74hc5950 {//0表示是SPI总线上的第0个设备 compatible hqyj,m74hc595; reg 0; spi-max-frequency 10000000;//SPI总线速率 //59MHZ }; };因为大小端的关系arm架构的stm32开发板的数码管指令为/*数码管编码,从DP到A发送 * A B C D E F G DP * 1 1 1 1 1 1 0 0 0x3F 0 * 0 1 1 0 0 0 0 0 0x06 1 * 1 1 0 1 1 0 1 0 0x5B 2 * 1 1 1 1 0 0 1 0 0x4F 3 * 0 1 1 0 0 1 1 0 0x66 4 * 1 0 1 1 0 1 1 0 0x6D 5 * 1 0 1 1 1 1 1 0 0x7D 6 * 1 1 1 0 0 0 0 0 0x07 7 * 1 1 1 1 1 1 1 0 0x7F 8 * 1 1 1 1 0 1 1 0 0x6F 9 * */ //char buf[] {0x2, 0x6d};四个灯分别为0x1、0x2、0x4、0x8由于未知原因我还不知道为什么0x2无法通过ioctl传递给驱动文件故我发送0x5当驱动的ioctl函数检测到0x5后自动转化为0x2.#include stdio.h #include string.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdlib.h #include string.h #include sys/wait.h #include sys/ioctl.h //头文件很多对吧其实有些可能没用到但是我懒得分辨是哪些了 int main(int argc, char const *argv[]) { unsigned int buf[] {0x1, 0x5, 0x4, 0x8}; //存放LED灯信息 unsigned long kbuf[] {0x3F, 0x06, 0x5B, 0x4F, 0x66, \ 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; //10个数字 int fd0 open(/dev/myled, O_RDWR); if(fd0 0) { printf(文件打开失败\n); exit(-1); } int i0, j0; while (1) { if(i 4) i 0; if(j 10) j 0; ioctl(fd0, buf[i], kbuf[j]); i; j; sleep(1); } return 0; }test.c文件内buf数组和kbuf数组选择的数据类型分别为 ”无符号整型“ 和 “无符号长整形” 采用它们的原因是驱动文件内的ioctl函数的参数是这样的不然我会选择直接发送char类型。驱动文件内m74hc595.c#include linux/init.h #include linux/module.h #include linux/fs.h #include linux/io.h #include linux/cdev.h #include linux/ioctl.h #include linux/device.h #include linux/uaccess.h #include linux/slab.h #include linux/poll.h #include linux/spi/spi.h #define CNAME myled int major; //定义变量接受主设备号 struct class *cls;//句柄 struct device *dev; //定义一个指向设备节点的指针 struct device_node *node; struct property *pr; //属性结构体指针 struct gpio_desc *desc; //给定时器分配对象 struct timer_list mytimer; int condition 0; //long kbuf[2]; //定义队列头 wait_queue_head_t wq_head; //接受*spi struct spi_device *spi_1 NULL; //ioctl函数接收应用层发送来的数据 long ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char kbuf[2]; if (cmd 0x5) cmd 0x2; kbuf[0] (char)cmd; kbuf[1] (char)arg; printk(%#x\n, cmd); //读取数据后填入 spi_write(spi_1, kbuf, sizeof(kbuf)); return 0; } //设备操作方法结构体指针 struct file_operations fops { .unlocked_ioctl ioctl, //因为unlocked_ioctl函数重写了。 }; //设备树匹配表 struct of_device_id of_table[] { {.compatible hqyj, m74hc595}, {}, }; MODULE_DEVICE_TABLE(of, of_table); //因为本驱动采用了module_spi_driver(m74hc595) //所以没有了static int __init函数驱动运行后直接从这里进入 //所以其中要用到的变量或者函数要写在这个函数之前 int m74hc595_probe(struct spi_device *spi) { spi_1 spi; //把spi指针接出去ioctl中的spi_write函数要用 //动态注册字符设备驱动 major register_chrdev(0, CNAME, fops); if (major 0) { printk(字符设备驱动注册失败\n); return major; } printk(字符设备驱动注册成功major%d\n, major); //向上提交节点目录 cls class_create(THIS_MODULE, LED); if (IS_ERR(cls)) { printk(向上提交目录失败\n); return PTR_ERR(cls); } printk(向上提交目录成功\n); //创建设备节点 dev device_create(cls, NULL, MKDEV(major, 0), NULL, myled); if (IS_ERR(dev)) { printk(创建节点失败\n); return PTR_ERR(dev); } printk(创建节点成功\n); return 0; } //驱动函数出口 int m74hc595_remove(struct spi_device *spi) { printk(%s:%d,__FILE__, __LINE__); //销毁节点 device_destroy(cls, MKDEV(major,0)); //销毁目录 class_destroy(cls); //注销字符设备驱动 unregister_chrdev(major,CNAME); return 0; } //下面这个函数要放在重写的probe和remove函数后 //定义SPI对象并初始化 struct spi_driver m74hc595 { .probe m74hc595_probe, .remove m74hc595_remove, .driver { .name m74hc595, .of_match_table of_table, }, }; module_spi_driver(m74hc595); MODULE_LICENSE(GPL);