您的位置:首页 > 教育 > 培训 > 购买商标_辽宁省建筑工程信息网_百度导航如何设置公司地址_什么是seo营销

购买商标_辽宁省建筑工程信息网_百度导航如何设置公司地址_什么是seo营销

2025/2/26 9:06:08 来源:https://blog.csdn.net/weixin_72755055/article/details/145852393  浏览:    关键词:购买商标_辽宁省建筑工程信息网_百度导航如何设置公司地址_什么是seo营销
购买商标_辽宁省建筑工程信息网_百度导航如何设置公司地址_什么是seo营销

SPI总线驱动整体上与I2C总线驱动类型,差别主要在设备树和数据传输上,由于SPI是由4根线实现主从机的通信,在设备树上配置时需要对SPI进行设置。

原理图可知,数码管使用的SPI4对应了单片机上的PE11-->SPI4-NSS,PE12-->SPI4-SCK,PE13-->SPI4-MISO,PE14-->SPI4-MOSI

设备树信息

需要注意在SPI4设备树信息中,一定要加spi-max-frequency属性,该属性用于设置spi的主频,如果没有,可能出现无法正常启动spi或启动spi后控制数码管时,数码管显示出现错位现象

驱动源码

#include <linux/init.h>       // 包含内核初始化相关的头文件
#include <linux/module.h>     // 包含内核模块相关的头文件
#include <linux/of.h>         // 包含设备树操作相关的头文件
#include <linux/gpio.h>       // 包含 GPIO 操作相关的头文件
#include <linux/of_gpio.h>    // 包含设备树 GPIO 相关的头文件
#include <linux/fs.h>         // 包含文件操作相关的头文件
#include <linux/uaccess.h>    // 包含用户空间访问内核空间相关的头文件
#include <linux/device.h>     // 包含设备相关的头文件
#include <linux/cdev.h>       // 包含字符设备相关的头文件
#include <linux/slab.h>       // 包含内存分配相关的头文件
#include <linux/spi/spi.h>    // 包含 SPI 相关的头文件
#include "spi_test.h"    // 包含自定义头文件//创建设备号
static int major;
//创建类
static struct class *cls;
//创建设备
static struct device *device;
//创建SPI设备
static struct spi_device *spi_dev;
//保存字符设备数据
static char spi_buf[128];static int myspi_open(struct inode *inode, struct file *file)
{unsigned int cmajor;//保存次设备号cmajor = iminor(inode);//将次设备号保存到file结构体的private_data中file->private_data = (void *)cmajor;printk("spi_open\n");return 0;
}static int myspi_close(struct inode *inode, struct file *file)
{printk("spi_close\n");return 0;
}static ssize_t myspi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//从内核空间读取数据到用户空间,如果读取数据的长度大于spi_buf的长度,按照最大长度读取if(count > sizeof(spi_buf)){count = sizeof(spi_buf);}ret = copy_to_user(buf, spi_buf, count);if(ret < 0){printk("copy_to_user failed\n");return -1;}printk("spi_read\n");return 0;
}static ssize_t myspi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//将用户空间的数据拷贝到内核空间,如果传输数据的长度大于spi_buf的长度,按照最大长度传输if (count > sizeof(spi_buf)){count = sizeof(spi_buf);}ret = copy_from_user(spi_buf, buf, count);if (ret < 0){printk("copy_from_user failed\n");return -1;}printk("spi_write\n");return 0;
}static int myspi_write_data(const uint8_t cmd, const uint8_t data)
{uint8_t spi_buf1[2] = {cmd, data};int ret = 0;printk("cmd = %x\n", spi_buf1[0]);ret = spi_write(spi_dev, spi_buf1, 2);return ret;
}static long myspi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{uint8_t data;unsigned long ret ;//从用户空间读取数据ret = copy_from_user(&data, (void *)arg, sizeof(data));if (ret < 0){printk("copy_from_user failed\n");return -1;}//根据cmd的值进行不同的操作    switch (cmd){case SET_DAT0:ret = myspi_write_data(0x01, data);break;case SET_DAT1:ret = myspi_write_data(0x02, data);break;case SET_DAT2:ret = myspi_write_data(0x04, data);break;case SET_DAT3:ret = myspi_write_data(0x08, data);break; case SET_DAT4:ret = myspi_write_data(0x0f, data);break;default:break;}if (ret != 0){printk("spi_write failed\n");return -1;}printk("spi_ioctl, data = %x\n", data);return 0;
}//定义file_operations结构体
struct file_operations fops = {.owner = THIS_MODULE,.open = myspi_open,.release = myspi_close,.read = myspi_read,.write = myspi_write,.unlocked_ioctl = myspi_ioctl,
};//编写spi设备驱动
int	myspi_probe(struct spi_device *spi)
{//unsigned char buf[]={0X01,0X6D};//0X01表示写数据,0X6D表示写入的数据//spi_write(spi,buf,sizeof(buf));//给从机发送一个数据,让最左边数码管显示数字5printk("myspi_probe\n");spi_dev = spi;//1.创建设备号major = register_chrdev(0, "myspi", &fops);if (major < 0){printk("register_chrdev failed\n");return -1;}//2.创建类cls = class_create(THIS_MODULE, "myspi");if (IS_ERR(cls)){printk("class_create failed\n");unregister_chrdev(major, "myspi");return -1;}//3.创建设备device = device_create(cls, NULL, MKDEV(major, 0), NULL, "myspi");if (IS_ERR(device)){printk("device_create failed\n");class_destroy(cls);unregister_chrdev(major, "myspi");return -1;}return 0;
}int	myspi_remove(struct spi_device *spi)
{printk("myspi_remove\n");    device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, "myspi");return 0;
}static const struct of_device_id spi_table[] = {{ .compatible = "johnson,m74hc595", },{ /* sentinel */ },
};struct spi_driver myspi_driver = {.probe = myspi_probe,.remove = myspi_remove,.driver = {.name = "m74hc595",.of_match_table = spi_table,},
};//一键注册宏定义
module_spi_driver(myspi_driver);
MODULE_LICENSE("GPL");  //声明开源许可

头文件

#ifndef __SPITEST_H__
#define __SPITEST_H__#define SET_DAT0 _IOW('s', 0, int)
#define SET_DAT1 _IOW('s', 1, int)
#define SET_DAT2 _IOW('s', 2, int)
#define SET_DAT3 _IOW('s', 3, int)
#define SET_DAT4 _IOW('s', 4, int)#endif

应用程序 --> 实现在数码管上依次显示数字

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "spi_test.h"const uint8_t num[10] = {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};int main()
{int fd = 0;int date = 0;//打开设备文件fd = open("/dev/myspi", O_RDWR);if (fd < 0){printf("open myspi failed\n");return -1;}while(1){ioctl(fd, SET_DAT0, &num[date]);sleep(1);ioctl(fd, SET_DAT1, &num[date]);sleep(1);ioctl(fd, SET_DAT2, &num[date]);sleep(1);ioctl(fd, SET_DAT3, &num[date]);sleep(1);ioctl(fd, SET_DAT4, &num[date]);if (++date > 9){date = 0;}sleep(1);}   //关闭设备文件close(fd);return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com