【正点原子MP157连载】第三十七章 Linux MISC驱动实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7_misc原理图-程序员宅基地

技术标签: stm32  LINUX  linux  驱动开发  

1)实验平台:正点原子STM32MP157开发板
2)购买链接:https://item.taobao.com/item.htm?&id=629270721801
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-318813-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子STM32MP157技术交流群:691905614
在这里插入图片描述

第三十七章 Linux MISC驱动实验

misc的意思是混合、杂项的,因此MISC驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用MISC驱动。MISC驱动其实就是最简单的字符设备驱动,通常嵌套在platform总线驱动中,实现复杂的驱动,本章我们就来学习一下MISC驱动的编写。

37.1 MISC设备驱动简介
所有的MISC设备驱动的主设备号都为10,不同的设备使用不同的从设备号。随着Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号,MISC设备驱动就用于解决此问题。MISC设备会自动创建cdev,不需要像我们以前那样手动创建,因此采用MISC设备驱动可以简化字符设备驱动的编写。我们需要向Linux注册一个miscdevice设备,miscdevice是一个结构体,定义在文件include/linux/miscdevice.h中,内容如下:

示例代码37.1.1 miscdevice结构体代码
66 struct miscdevice  {
    
67  	int minor;                          		/* 子设备号 		*/
68  	const char *name;                   		/* 设备名字 		*/          
69  	const struct file_operations *fops; 	/* 设备操作集 	*/
70  	struct list_head list;
71  	struct device *parent;
72  	struct device *this_device;
73  	const struct attribute_group **groups;
74  	const char *nodename;
75  	umode_t mode;
76 };
定义一个MISC设备(miscdevice类型)以后我们需要设置minor、name和fops这三个成员变量。minor表示子设备号,MISC设备的主设备号为10,这个是固定的,需要用户指定子设备号,Linux系统已经预定义了一些MISC设备的子设备号,这些预定义的子设备号定义在include/linux/miscdevice.h文件中,如下所示:
示例代码37.1.2 预定义的MISC设备子设备号
15 #define PSMOUSE_MINOR        		1
16 #define MS_BUSMOUSE_MINOR    		2   /* unused */
17 #define ATIXL_BUSMOUSE_MINOR 	3   /* unused */
18 /*#define AMIGAMOUSE_MINOR   	4   FIXME OBSOLETE */
19 #define ATARIMOUSE_MINOR 			5  	/* unused */
20 #define SUN_MOUSE_MINOR      		6   /* unused */
......
61 #define MISC_DYNAMIC_MINOR   	255
我们在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口。

name就是此MISC设备名字,当此设备注册成功以后就会在/dev目录下生成一个名为name的设备文件。fops就是字符设备的操作集合,MISC设备驱动最终是需要使用用户提供的fops操作集合。
当设置好miscdevice以后就需要使用misc_register函数向系统中注册一个MISC设备,此函数原型如下:
int misc_register(struct miscdevice * misc)
函数参数和返回值含义如下:
misc:要注册的MISC设备。
返回值:负数,失败;0,成功。
以前我们需要自己调用一堆的函数去创建设备,比如在以前的字符设备驱动中我们会使用如下几个函数完成设备创建过程:

示例代码37.1.3 传统的创建设备过程
1 alloc_chrdev_region();    	/* 申请设备号 	*/
2 cdev_init();          		/* 初始化cdev  */
3 cdev_add();               	/* 添加cdev  	*/
4 class_create();           	/* 创建类 		*/
5 device_create();      		/* 创建设备 		*/
现在我们可以直接使用misc_register一个函数来完成示例代码37.1.3中的这些步骤。当我们卸载设备驱动模块的时候需要调用misc_deregister函数来注销掉MISC设备,函数原型如下:

int misc_deregister(struct miscdevice *misc)
函数参数和返回值含义如下:
misc:要注销的MISC设备。
返回值:负数,失败;0,成功。
以前注销设备驱动的时候,我们需要调用一堆的函数去删除此前创建的cdev、设备等等内容,如下所示:

示例代码37.1.4 传统的删除设备的过程
1 cdev_del();						/*  删除cdev 	*/
2 unregister_chrdev_region(); 	/* 注销设备号 	*/
3 device_destroy();     			/* 删除设备 		*/
4 class_destroy();      			/* 删除类 		*/
现在我们只需要一个misc_deregister函数即可完成示例代码37.1.4中的这些工作。关于MISC设备驱动就讲解到这里,接下来我们就使用platform加MISC驱动框架来编写beep蜂鸣器驱动。

37.2 硬件原理图分析
本章实验我们只使用到正点原子的STM32MP1开发板上的BEEP蜂鸣器,因此实验硬件原理图参考26.2小节即可。
37.3 实验程序编写
本实验对应的例程路径为:开发板光盘1、程序源码2、Linux驱动例程19_miscbeep。
本章实验我们采用platform加misc的方式编写beep驱动,这也是实际的Linux驱动中很常用的方法。采用platform来实现总线、设备和驱动,misc主要负责完成字符设备的创建。
37.3.1 修改设备树
本章实验我们需要用到蜂鸣器,因此需要在stm32mp157d-atk.dts文件中创建蜂鸣器设备节点。
1、添加pinctrl节点
在STM32MP157开发板上的蜂鸣器使用了PC7这个引脚,打开stm32mp15-pinctrl.dtsi文件,在pinctrl节点下添加一个‘beep_pins_a’子节点,这个节点就是蜂鸣器的pinctrl配置。

示例代码37.3.1.1 蜂鸣器的pinctrl节点
1 beep_pins_a: beep_pins {
    
2 		pins {
    
3        	pinmux = <STM32_PINMUX('C', 7, GPIO)>; /* BEEP */
4        	drive-push-pull;
5        	bias-pull-up;
6      		output-high;
7        	slew-rate = <0>;
8 		};
9 };
2、添加beep设备节点
在26.3.1小节我们创建了一个名为“beep”的子节点,本章我们就在这个子节点里面稍微修改即可,修改完成以后的beep子节点内容如下:
示例代码37.3.1.2 蜂鸣器节点
1 beep {
    
2 		compatible = "alientek,beep";
3      	status = "okay";
4   	pinctrl-names = "default";
5     	pinctrl-0 = <&beep_pins_a>;
6      	beep-gpio = <&gpioc 7 GPIO_ACTIVE_HIGH>;
7 };
相比26.3.1小节里面的beep节点,这里仅仅添加了第4~5行,这两行指定BEEP所使用的引脚pinctrl子节点。

37.3.2 beep驱动程序编写
新建名为“19_miscbeep”的文件夹,然后在19_miscbeep文件夹里面创建vscode工程,工作区命名为“miscbeep。新建名为miscbeep.c的驱动文件,在miscbeep.c中输入如下所示内容:

示例代码37.3.2.1 miscbeep.c文件代码段
1   #include <linux/types.h>
2   #include <linux/kernel.h>
3   #include <linux/delay.h>
4   #include <linux/ide.h>
5   #include <linux/init.h>
6   #include <linux/module.h>
7   #include <linux/errno.h>
8   #include <linux/gpio.h>
9   #include <linux/cdev.h>
10  #include <linux/device.h>
11  #include <linux/of.h>
12  #include <linux/of_address.h>
13  #include <linux/of_gpio.h>
14  #include <linux/platform_device.h>
15  #include <linux/miscdevice.h>
16  #include <asm/mach/map.h>
17  #include <asm/uaccess.h>
18  #include <asm/io.h>
19  
20  #define MISCBEEP_NAME   	"miscbeep"  	/* 名字   	*/
21  #define MISCBEEP_MINOR  	144         	/* 子设备号 */
22  #define BEEPOFF          	0           		/* 关蜂鸣器	*/
23  #define BEEPON          	1           		/* 开蜂鸣器 	*/
24  
25  /* miscbeep设备结构体 */
26  struct miscbeep_dev{
    
27      dev_t devid;           	/* 设备号  	*/
28      struct cdev cdev;      	/* cdev   	*/
29      struct class *class;    	/* 类      	*/
30      struct device *device;  	/* 设备    	*/
31      int beep_gpio;          	/* beep所使用的GPIO编号       */
32  };
33  
34  struct miscbeep_dev miscbeep;   	/* beep设备 */
35  
36  /*
37   * @description  	: beep相关初始化操作
38   * @param – pdev	: struct platform_device指针,也就是platform设备指针
39   * @return       	: 成功返回0,失败返回负数
40   */
41  static int beep_gpio_init(struct device_node *nd)
42  {
    
43      int ret;
44      
45      /* 从设备树中获取GPIO */
46      miscbeep.beep_gpio = of_get_named_gpio(nd, "beep-gpio", 0);
47      if(!gpio_is_valid(miscbeep.beep_gpio)) {
    
48          printk("miscbeep:Failed to get beep-gpio\n");
49          return -EINVAL;
50      }
51      
52      /* 申请使用GPIO */
53      ret = gpio_request(miscbeep.beep_gpio, "beep");
54      if(ret) {
    
55          printk("beep: Failed to request beep-gpio\n");
56          return ret;
57      }
58      
59      /* 将GPIO设置为输出模式并设置GPIO初始化电平状态 */
60      gpio_direction_output(miscbeep.beep_gpio, 1);
61      
62      return 0;
63  }
64  
65  /*
66   * @description 	: 打开设备
67   * @param – inode	: 传递给驱动的inode
68   * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
69   *                    一般在open的时候将private_data指向设备结构体。
70   * @return        	: 0 成功;其他 失败
71   */
72  static int miscbeep_open(struct inode *inode, struct file *filp)
73  {
    
74      return 0;
75  }
76  
77  /*
78   * @description  	: 向设备写数据 
79   * @param – filp	: 设备文件,表示打开的文件描述符
80   * @param - buf 	: 要写给设备写入的数据
81   * @param - cnt  	: 要写入的数据长度
82   * @param - offt 	: 相对于文件首地址的偏移
83   * @return        	: 写入的字节数,如果为负值,表示写入失败
84   */
85  static ssize_t miscbeep_write(struct file *filp,
 const char __user *buf, size_t cnt, loff_t *offt)
86  {
    
87      int retvalue;
88      unsigned char databuf[1];
89      unsigned char beepstat;
90  
91      retvalue = copy_from_user(databuf, buf, cnt);
92      if(retvalue < 0) {
    
93          printk("kernel write failed!\r\n");
94          return -EFAULT;
95      }
96  
97      beepstat = databuf[0];      						/* 获取状态值 */
98      if(beepstat == BEEPON) {
        
99          gpio_set_value(miscbeep.beep_gpio, 0);  	/* 打开蜂鸣器 */
100     } else if(beepstat == BEEPOFF) {
    
101         gpio_set_value(miscbeep.beep_gpio, 1);  	/* 关闭蜂鸣器 */
102     }
103     return 0;
104 }
105 
106 /* 设备操作函数 */
107 static struct file_operations miscbeep_fops = {
    
108     .owner = THIS_MODULE,
109     .open = miscbeep_open,
110     .write = miscbeep_write,
111 };
112 
113 /* MISC设备结构体 */
114 static struct miscdevice beep_miscdev = {
    
115     .minor = MISCBEEP_MINOR,
116     .name = MISCBEEP_NAME,
117     .fops = &miscbeep_fops,
118 };
119 
120  /*
121   * @description 	: flatform驱动的probe函数,当驱动与
122   *                    设备匹配以后此函数就会执行
123   * @param – dev	: platform设备
124   * @return       	: 0,成功;其他负值,失败
125   */
126 static int miscbeep_probe(struct platform_device *pdev)
127 {
    
128     int ret = 0;
129 
130     printk("beep driver and device was matched!\r\n");
131 
132     /* 初始化BEEP */
133     ret = beep_gpio_init(pdev->dev.of_node);
134     if(ret < 0)
135         return ret;
136         
137     /* 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备
138      * 所以我们不需要自己注册字符设备驱动,只需要注册misc设备驱动即可
139      */
140     ret = misc_register(&beep_miscdev);
141     if(ret < 0){
    
142         printk("misc device register failed!\r\n");
143         goto free_gpio;
144     }
145 
146     return 0;
147     
148 free_gpio:
149     gpio_free(miscbeep.beep_gpio);
150     return -EINVAL;
151 }
152 
153 /*
154  * @description 	: platform驱动的remove函数
155  * @param - dev 	: platform设备
156  * @return       	: 0,成功;其他负值,失败
157  */
158 static int miscbeep_remove(struct platform_device *dev)
159 {
    
160     /* 注销设备的时候关闭LED灯 */
161     gpio_set_value(miscbeep.beep_gpio, 1);
162     
163     /* 释放BEEP */
164     gpio_free(miscbeep.beep_gpio);
165 
166     /* 注销misc设备 */
167     misc_deregister(&beep_miscdev);
168     return 0;
169 }
170 
171  /* 匹配列表 */
172  static const struct of_device_id beep_of_match[] = {
    
173      {
     .compatible = "alientek,beep" },
174      {
     /* Sentinel */ }
175  };
176  
177  /* platform驱动结构体 */
178 static struct platform_driver beep_driver = {
    
179      .driver     = {
    
180          .name   = "stm32mp1-beep",         /* 驱动名字,用于和设备匹配 */
181          .of_match_table = beep_of_match, /* 设备树匹配表          */
182      },
183      .probe      = miscbeep_probe,
184      .remove     = miscbeep_remove,
185 };
186 
187 /*
188  * @description 	: 驱动出口函数
189  * @param       	: 无
190  * @return      	: 无
191  */
192 static int __init miscbeep_init(void)
193 {
    
194     return platform_driver_register(&beep_driver);
195 }
196 
197 /*
198  * @description 	: 驱动出口函数
199  * @param       	: 无
200  * @return      	: 无
201  */
202 static void __exit miscbeep_exit(void)
203 {
    
204     platform_driver_unregister(&beep_driver);
205 }
206 
207 module_init(miscbeep_init);
208 module_exit(miscbeep_exit);
209 MODULE_LICENSE("GPL");
210 MODULE_AUTHOR("ALIENTEK");
211 MODULE_INFO(intree, "Y");

第72~111行,标准的字符设备驱动。
第114~118行,MISC设备beep_miscdev,第115行设置子设备号为144,第116行设置设备名字为“miscbeep”,这样当系统启动以后就会在/dev/目录下存在一个名为“miscbeep”的设备文件。第117行,设置MISC设备的操作函数集合,为file_operations类型。
第126~151行,platform框架的probe函数,当驱动与设备匹配以后此函数就会执行,首先在此函数中初始化BEEP所使用的IO。最后在140行通过misc_register函数向Linux内核注册MISC设备,也就是前面定义的beep_miscdev。
第158~168行,platform框架的remove函数,在此函数中调用misc_deregister函数来注销MISC设备。
第192~205,标准的platform驱动。
37.3.3 编写测试APP
新建miscbeepApp.c文件,然后在里面输入如下所示内容:

示例代码37.3.2.2 miscbeepApp.c文件代码段
1  #include <stdio.h>
2  #include <unistd.h>
3  #include <sys/types.h>
4  #include <sys/stat.h>
5  #include <fcntl.h>
6  #include <stdlib.h>
7  #include <string.h>
8  
9  #define BEEPOFF 	0
10 #define BEEPON   	1
11 
12 /*
13  * @description  	: main主程序
14  * @param - argc 	: argv数组元素个数
15  * @param - argv 	: 具体参数
16  * @return        	: 0 成功;其他 失败
17  */
18 int main(int argc, char *argv[])
19 {
    
20  	int fd, retvalue;
21 	 	char *filename;
22  	unsigned char databuf[1];
23  
24  	if(argc != 3){
    
25      	printf("Error Usage!\r\n");
26      	return -1;
27  	}
28 
29  	filename = argv[1];
30  	fd = open(filename, O_RDWR); 	/* 打开beep驱动 */
31  	if(fd < 0){
    
32      	printf("file %s open failed!\r\n", argv[1]);
33      	return -1;
34  	}
35 
36  	databuf[0] = atoi(argv[2]); 		/* 要执行的操作:打开或关闭 */
37  	retvalue = write(fd, databuf, sizeof(databuf));
38  	if(retvalue < 0){
    
39      	printf("BEEP Control Failed!\r\n");
40      	close(fd);
41      	return -1;
42  	}
43 
44  	retvalue = close(fd); 			/* 关闭文件 */
45  	if(retvalue < 0){
    
46      	printf("file %s close failed!\r\n", argv[1]);
47      	return -1;
48  	}
49  	return 0;
50 }
miscbeepApp.c文件内容和其他例程的测试APP基本一致,很简单,这里就不讲解了。

37.4 运行测试
37.4.1 编译驱动程序和测试APP
1、编译驱动程序
编写Makefile文件,本章实验的Makefile文件和第四十章实验基本一样,只是将obj-m变量的值改为“miscbeep.o”,Makefile内容如下所示:

示例代码37.4.1.1 Makefile文件
1  KERNELDIR := /home/zuozhongkai/linux/my_linux/linux-5.4.31
...... 
4  obj-m := miscbeep.o
......
11 clean:
12  $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
第4行,设置obj-m变量的值为“miscbeep.o”。
输入如下命令编译出驱动模块文件:

make -j32
编译成功以后就会生成一个名为“miscbeep.ko”的驱动模块文件。
2、编译测试APP
输入如下命令编译测试miscbeepApp.c这个测试程序:
arm-none-linux-gnueabihf-gcc miscbeepApp.c -o miscbeepApp
编译成功以后就会生成miscbeepApp这个应用程序。
37.4.2 运行测试
将上一小节编译出来miscbeep.ko和miscbeepApp这两个文件拷贝到rootfs/lib/modules/5.4.31目录中,重启开发板,进入到目录lib/modules/5.4.31中,输入如下命令加载miscbeep.ko这个驱动模块。
depmod //第一次加载驱动的时候需要运行此命令
modprobe miscbeep.ko //加载设备模块
当驱动模块加载成功以后我们可以在/sys/class/misc这个目录下看到一个名为“miscbeep”的子目录,如图37.4.2.1所示:
在这里插入图片描述

图37.4.2.1 misbeep子目录
所有的misc设备都属于同一个类,/sys/class/misc目录下就是misc这个类的所有设备,每个设备对应一个子目录。
驱动与设备匹配成功以后就会生成/dev/miscbeep这个设备驱动文件,输入如下命令查看这个文件的主次设备号:
ls /dev/miscbeep -l
结果如图37.4.2.2所示:
在这里插入图片描述

图37.4.2.2 /dev/miscbeep设备文件
从图37.4.2.2可以看出,/dev/miscbeep这个设备的主设备号为10,次设备号为144,和我们驱动程序里面设置的一致。
输入如下命令打开BEEP:
./miscbeepApp /dev/miscbeep 1 //打开BEEP
在输入如下命令关闭LED灯:
./miscbeepApp /dev/miscbeep 0 //关闭BEEP
观察一下BEEP能否打开和关闭,如果可以的话就说明驱动工作正常,如果要卸载驱动的话输入如下命令即可:
rmmod miscbeep.ko

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_55796564/article/details/122944237

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签