把嵌入式设备驱动比相亲,那总线就是红娘,设备是男方,驱动是女方.....

传感器技术 2020-03-02 00:00


一、platform 驱动的工作过程


platform模型驱动编程,需要实现platform_device(设备)与platform_driver(驱动)在platform(虚拟总线)上的注册、匹配,相互绑定,然后再做为一个普通的字符设备进行相应的应用,总之如果编写的是基于字符设备的platform驱动,在遵循并实现platform总线上驱动与设备的特定接口的情况下,最核心的还是字符设备的核心结构:cdev、 file_operations(他包含的操作函数接口)、dev_t(设备号)、设备文件(/dev)等,因为用platform机制编写的字符驱动,它的本质是字符驱动。


我们要记住,platform 驱动只是在字符设备驱动外套一层platform_driver 的外壳。


在一般情况下,2.6内核中已经初始化并挂载了一条platform总线在sysfs文件系统中。那么我们编写platform模型驱动时,需要完成两个工作:


a -- 实现platform驱动 

b -- 实现platform设备


然而在实现这两个工作的过程中还需要实现其他的很多小工作,在后面介绍。platform模型驱动的实现过程核心架构就很简单,如下所示:

 

platform驱动模型三个对象:platform总线、platform设备、platform驱动。

platform总线对应的内核结构:struct bus_type-->它包含的最关键的函数:match() (要注意的是,这块由内核完成,我们不参与)

platform设备对应的内核结构:struct platform_device-->注册:platform_device_register(unregister)

platform驱动对应的内核结构:struct platform_driver-->注册:platform_driver_register(unregister)

       

那具体platform驱动的工作过程是什么呢:


设备(或驱动)注册的时候,都会引发总线调用自己的match函数来寻找目前platform总线是否挂载有与该设备(或驱动)名字匹配的驱动(或设备),如果存在则将双方绑定;


如果先注册设备,驱动还没有注册,那么设备在被注册到总线上时,将不会匹配到与自己同名的驱动,然后在驱动注册到总线上时,因为设备已注册,那么总线会立即匹配与绑定这时的同名的设备与驱动,再调用驱动中的probe函数等;


如果是驱动先注册,同设备驱动一样先会匹配失败,匹配失败将导致它的probe函数暂不调用,而是要等到设备注册成功并与自己匹配绑定后才会调用。

 


二、实现platform 驱动与设备的详细过程




1、思考问题?

在分析platform 之前,可以先思考一下下面的问题:

a -- 为什么要用 platform 驱动?不用platform驱动可以吗?

b -- 设备驱动中引入platform 概念有什么好处?


现在先不回答,看完下面的分析就明白了,后面会附上总结。

 


2、platform_device 结构体 VS   platform_driver 结构体

这两个结构体分别描述了设备和驱动,二者有什么关系呢?先看一下具体结构体对比



前面提到,实现platform模型的过程就是总线对设备和驱动的匹配过程 。打个比方,就好比相亲,总线是红娘,设备是男方,驱动是女方:


a -- 红娘(总线)负责男方(设备)和女方(驱动)的撮合;    

b -- 男方(女方)找到红娘,说我来登记一下,看有没有合适的姑娘(汉子)—— 设备或驱动的注册

c -- 红娘这时候就需要看看有没有八字(二者的name 字段)匹配的姑娘(汉子)——match 函数进行匹配,看name是否相同;

d -- 如果八字不合,就告诉男方(女方)没有合适的对象,先等着,别急着乱做事 —— 设备和驱动会等待,直到匹配成功;

e -- 终于遇到八字匹配的了,那就结婚呗!接完婚,男方就向女方交代,我有多少存款,我的房子在哪,钱放在哪等等( struct resource    *resource),女方说好啊,于是去房子里拿钱,去给男方买菜啦,给自己买衣服、化妆品、首饰啊等等(int (*probe)(struct platform_device *) 匹配成功后驱动执行的第一个函数),当然如果男的跟小三跑了(设备卸载),女方也不会继续待下去的(  int (*remove)(struct platform_device *))。

 


3、设备资源结构体

在struct platform_device 结构体中有一重要成员 struct resource *resource


[cpp] view plain copy

1. struct resource {  

2.     resource_size_t start;  资源起始地址     

3.     resource_size_t end;   资源结束地址  

4.     const char *name;        

5.     unsigned long flags;   区分是资源什么类型的  

6.     struct resource *parent, *sibling, *child;  

7. };  

8.   

9. #define IORESOURCE_MEM        0x00000200  

10. #define IORESOURCE_IRQ        0x00000400     


flags 指资源类型,我们常用的是 IORESOURCE_MEM、IORESOURCE_IRQ  这两种。start 和 end 的含义会随着 flags而变更,如


a -- flags为IORESOURCE_MEM 时,start 、end 分别表示该platform_device占据的内存的开始地址和结束值; 

b -- flags为 IORESOURCE_IRQ   时,start 、end 分别表示该platform_device使用的中断号的开始地址和结束值; 


下面看一个实例:


[cpp] view plain copy

1. static struct  resource beep_resource[] =  

2. {  

3.     [0] = {  

4.             .start = 0x114000a0,  

5.         .end = 0x114000a0+0x4,  

6.             .flags = IORESOURCE_MEM,  

7.     },  

8.   

9.     [1] = {  

10.             .start = 0x139D0000,  

11.             .end = 0x139D0000+0x14,  

12.             .flags = IORESOURCE_MEM,  

13.     },  

14. };   


好酒好礼,五粮液十五酱!(点击进入)




4、将字符设备添加到platform的driver中


前面我们提到platform 驱动只是在字符设备驱动外套一层platform_driver 的外壳,下面我们看一下添加的过程:


[cpp] view plain copy

1. static struct file_operations hello_ops=  

2. {  

3.     .open = hello_open,  

4.     .release = hello_release,  

5.     .unlocked_ioctl = hello_ioctl,  

6. };  

7.   

8. static int hello_remove(struct platform_device *pdev)  

9. {  

10.     注销分配的各种资源  

11. }  

12.   

13. static int hello_probe(struct platform_device *pdev)  

14. {  

15.     1.申请设备号  

16.     2.cdev初始化注册,&hello_ops  

17.     3.从pdev读出硬件资源  

18.     4.对硬件资源初始化,ioremap,request_irq( )  

19. }  

20.   

21. static int hello_init(void)  

22. {  

23.     只注册 platform_driver  

24. }  

25.   

26. static void hello_exit(void)  

27. {  

28.     只注销 platform_driver  

29. }  


可以看到,模块加载和卸载函数仅仅通过paltform_driver_register()、paltform_driver_unregister() 函数进行 platform_driver 的注册和注销,而原先注册和注销字符设备的工作已经被移交到 platform_driver 的 probe() 和 remove() 成员函数中。



5、platform是如何匹配device和driver


这时就该总线出场了,系统为platform总线定义了一个bus_type 的实例platform_bus_type,其定义如下:


[cpp] view plain copy

1. struct bus_type platform_bus_type = {  

2.     .name        = "platform",  

3.     .dev_groups    = platform_dev_groups,  

4.     .match        = platform_match,  

5.     .uevent        = platform_uevent,  

6.     .pm        = &platform_dev_pm_ops,  

7. };  


其又是怎样工作的呢?在platform.c (e:\linux-3.14-fs4412\drivers\base)    31577    2014/3/31 中可以看到



[cpp] view plain copy

1. __platform_driver_register()  

2. {  

3.     drv->driver.bus = &platform_bus_type;     536行  

4. }  



在platform_bus_type 中调用 了platform_match:


[cpp] view plain copy

1. static int platform_match(struct device *dev, struct device_driver *drv)  

2. {  

3.     struct platform_device *pdev = to_platform_device(dev);  

4.     struct platform_driver *pdrv = to_platform_driver(drv);  

5.   

6.     匹配设备树信息,如果有设备树,就调用 of_driver_match_device() 函数进行匹配  

7.     if (of_driver_match_device(dev, drv))  

8.         return 1;  

9.   

10.   

11.     匹配id_table  

12.     if (pdrv->id_table)  

13.         return platform_match_id(pdrv->id_table, pdev) != NULL;  

14.   

15.     最基本匹配规则  

16.     return (strcmp(pdev->name, drv->name) == 0);  

17. }  



 6、解决问题

现在可以回答这两个问题了

a -- 为什么要用 platform 驱动?不用platform驱动可以吗?

b -- 设备驱动中引入platform 概念有什么好处?


引入platform模型符合Linux 设备模型 —— 总线、设备、驱动,设备模型中配套的sysfs节点都可以用,方便我们的开发;当然你也可以选择不用,不过就失去了一些platform带来的便利;


设备驱动中引入platform 概念,隔离BSP和驱动。在BSP中定义platform设备和设备使用的资源、设备的具体匹配信息,而在驱动中,只需要通过API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。

 


三、实例



这是一个蜂鸣器的驱动,其实前面已经有解析 Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动, 下面来看一下,套上platform 外壳后的程序:



1、device.c



[cpp] view plain copy

1. #include <linux/module.h>  

2. #include <linux/device.h>  

3. #include <linux/platform_device.h>  

4. #include <linux/ioport.h>  

5.   

6. static struct resource beep_resource[] =  

7. {  

8.     [0] ={  

9.         .start = 0x114000a0,  

10.         .end =  0x114000a0 + 0x4,  

11.         .flags = IORESOURCE_MEM,  

12.     },  

13.   

14.     [1] ={  

15.         .start = 0x139D0000,  

16.         .end =  0x139D0000 + 0x14,  

17.         .flags = IORESOURCE_MEM,  

18.     }  

19. };  

20.   

21. static void hello_release(struct device *dev)  

22. {  

23.     printk("hello_release\n");  

24.     return ;  

25. }  

26.   

27.   

28.   

29. static struct platform_device hello_device=  

30. {  

31.     .name = "bigbang",  

32.     .id = -1,  

33.     .dev.release = hello_release,  

34.     .num_resources = ARRAY_SIZE(beep_resource),  

35.     .resource = beep_resource,  

36. };  

37.   

38. static int hello_init(void)  

39. {  

40.     printk("hello_init");  

41.     return platform_device_register(&hello_device);  

42. }  

43.   

44. static void hello_exit(void)  

45. {  

46.     printk("hello_exit");  

47.     platform_device_unregister(&hello_device);  

48.     return;  

49. }  

50.   

51. MODULE_LICENSE("GPL");  

52. module_init(hello_init);  

53. module_exit(hello_exit);  


 


2、driver.c



[cpp] view plain copy

1. #include <linux/module.h>  

2. #include <linux/fs.h>  

3. #include <linux/cdev.h>  

4. #include <linux/device.h>  

5. #include <linux/platform_device.h>  

6. #include <asm/io.h>  

7.   

8. static int major = 250;  

9. static int minor=0;  

10. static dev_t devno;  

11. static struct class *cls;  

12. static struct device *test_device;  

13.            

14. #define TCFG0         0x0000                 

15. #define TCFG1         0x0004                              

16. #define TCON          0x0008               

17. #define TCNTB0        0x000C            

18. #define TCMPB0        0x0010             

19.   

20. static unsigned int *gpd0con;  

21. static void *timer_base;  

22.   

23. #define  MAGIC_NUMBER    'k'  

24. #define  BEEP_ON    _IO(MAGIC_NUMBER    ,0)  

25. #define  BEEP_OFF   _IO(MAGIC_NUMBER    ,1)  

26. #define  BEEP_FREQ   _IO(MAGIC_NUMBER   ,2)  

27.   

28. static void fs4412_beep_init(void)  

29. {     

30.     writel ((readl(gpd0con)&~(0xf<<0)) | (0x2<<0),gpd0con);  

31.     writel ((readl(timer_base +TCFG0  )&~(0xff<<0)) | (0xff <<0),timer_base +TCFG0);   

32.     writel ((readl(timer_base +TCFG1 )&~(0xf<<0)) | (0x2 <<0),timer_base +TCFG1 );   

33.   

34.     writel (500, timer_base +TCNTB0  );  

35.     writel (250, timer_base +TCMPB0 );  

36.     writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x2 <<0),timer_base +TCON );   

37. }  

38.   

39. void fs4412_beep_on(void)  

40. {  

41.     writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x9 <<0),timer_base +TCON );  

42. }  

43.   

44. void fs4412_beep_off(void)  

45. {  

46.     writel ((readl(timer_base +TCON )&~(0xf<<0)) | (0x0 <<0),timer_base +TCON );  

47. }  

48.   

49. static void beep_unmap(void)  

50. {  

51.         iounmap(gpd0con);  

52.         iounmap(timer_base);  

53. }  

54.   

55. static int beep_open (struct inode *inode, struct file *filep)  

56. {  

57.     fs4412_beep_on();  

58.     return 0;  

59. }  

60.   

61. static int beep_release(struct inode *inode, struct file *filep)  

62. {  

63.      fs4412_beep_off();  

64.      return 0;  

65. }  

66.   

67. #define BEPP_IN_FREQ 100000  

68. static void beep_freq(unsigned long arg)  

69. {  

70.     writel(BEPP_IN_FREQ/arg, timer_base +TCNTB0  );  

71.     writel(BEPP_IN_FREQ/(2*arg), timer_base +TCMPB0 );  

72.   

73. }  

74.   

75. static long beep_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)  

76. {  

77.     switch(cmd)  

78.     {  

79.         case BEEP_ON:  

80.             fs4412_beep_on();  

81.             break;  

82.         case BEEP_OFF:  

83.             fs4412_beep_off();  

84.             break;  

85.         case BEEP_FREQ:  

86.             beep_freq( arg );  

87.             break;  

88.         default :  

89.             return -EINVAL;  

90.     }  

91.     return 0;  

92. }  

93.   

94. static struct file_operations beep_ops=  

95. {  

96.     .open     = beep_open,  

97.     .release = beep_release,  

98.     .unlocked_ioctl      = beep_ioctl,  

99. };  

100.   

101. static int beep_probe(struct platform_device *pdev)  

102. {  

103.     int ret;      

104.     printk("match ok!");  

105.       

106.     gpd0con = ioremap(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start);  

107.     timer_base = ioremap(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start);  

108.   

109.     devno = MKDEV(major,minor);  

110.     ret = register_chrdev(major,"beep",&beep_ops);  

111.   

112.     cls = class_create(THIS_MODULE, "myclass");  

113.     if(IS_ERR(cls))  

114.     {  

115.         unregister_chrdev(major,"beep");  

116.         return -EBUSY;  

117.     }  

118.   

119.     test_device = device_create(cls,NULL,devno,NULL,"beep");//mknod /dev/hello  

120.     if(IS_ERR(test_device))  

121.     {  

122.         class_destroy(cls);  

123.         unregister_chrdev(major,"beep");  

124.         return -EBUSY;  

125.     }  

126.       

127.     fs4412_beep_init();  

128.       

129.     return 0;  

130. }  

131.   

132. static int beep_remove(struct platform_device *pdev)  

133. {  

134.     beep_unmap();  

135.     device_destroy(cls,devno);  

136.     class_destroy(cls);   

137.     unregister_chrdev(major,"beep");  

138.   

139.     return 0;  

140. }  

141.   

142.   

143. static struct platform_driver beep_driver=  

144. {  

145.     .driver.name = "bigbang",  

146.     .probe = beep_probe,  

147.     .remove = beep_remove,  

148. };  

149.    

150.   

151. static int beep_init(void)  

152. {  

153.     printk("beep_init");  

154.       

155.     return platform_driver_register(&beep_driver);  

156. }  

157.   

158. static void beep_exit(void)  

159. {  

160.     printk("beep_exit");  

161.     platform_driver_unregister(&beep_driver);  

162.       

163.     return;  

164. }  

165.   

166.   

167. MODULE_LICENSE("GPL");  

168. module_init(beep_init);  

169. module_exit(beep_exit); 




3、makefile   



[cpp] view plain copy

1. ifneq  ($(KERNELRELEASE),)  

2. obj-m:=device.o driver.o  

3. $(info "2nd")  

4. else  

5. #KDIR := /lib/modules/$(shell uname -r)/build  

6. KDIR := /home/fs/linux/linux-3.14-fs4412  

7. PWD:=$(shell pwd)  

8. all:  

9.     $(info "1st")  

10.     make -C $(KDIR) M=$(PWD) modules  

11. clean:  

12.     rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order  

13. endif  


 


4、test.c




[cpp] view plain copy

1. #include <sys/types.h>  

2. #include <sys/stat.h>  

3. #include <fcntl.h>  

4. #include <stdio.h>  

5.   

6. main()  

7. {  

8.     int fd,i,lednum;  

9.   

10.     fd = open("/dev/beep",O_RDWR);  

11.     if(fd<0)  

12.     {  

13.         perror("open fail \n");  

14.         return ;  

15.     }  

16.       

17.     sleep(10);  

18.     close(fd);  

19. } 


  来源:玩转单片机


免责声明:本文系网络转载,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请第一时间告知,我们将根据您提供的证明材料确认版权并按国家标准支付稿酬或立即删除内容!本文内容为原作者观点,并不代表本公众号赞同其观点和对其真实性负责。

 
  

为您发布产品,请点击“阅读原文”

传感器技术 制造业的未来是智能化,智能化的基础就是传感器; 互联网的方向是物联网,物联网的基石也是传感器; 关注传感器技术,获得技术资讯、产品应用、市场机会,掌握最黑科技,为中国工业导航。
评论
  • 在驾驶培训与考试的严谨流程中,EST580驾培驾考系统扮演着至关重要的数据角色。它不仅集成了转速监控、车速管理、转向角度测量、转向灯光控制以及手刹与安全带状态检测等多项功能,还通过高精度的OBD数据采集器实时捕捉车辆运行状态,确保学员在模拟及实际驾驶中的每一步操作都精准无误。EST580驾培驾考转速车速转向角转向灯光手刹安全带OBD数据采集器系统的重要性及其功能:1、提高评判效率:通过原车CAN协议兼容,不同车型通过刷写固件覆盖,不仅提高了考试的数字化、自动化程度,还减少了人为干预的安装需要,从
    lauguo2013 2024-12-09 16:51 57浏览
  • 随着各行各业对可靠、高效电子元件的需求不断增长,国产光耦合器正成为全球半导体市场的重要参与者。这些元件利用先进的制造工艺和研究驱动的创新,弥补了高性能和可负担性之间的差距。本文探讨了国产光耦合器日益突出的地位,重点介绍了其应用和技术进步。 关键技术进步国产光耦合器制造商在提高性能和多功能性方面取得了重大进展。高速光耦合器现在能够处理快速数据传输,使其成为电信和工业自动化中不可或缺的一部分。专为电力电子设计的栅极驱动器光耦合器可确保电动汽车和可再生能源逆变器等高压系统的精确控制。采用碳化
    克里雅半导体科技 2024-12-06 16:34 160浏览
  • 2024年12月09日 环洋市场咨询机构出版了一份详细的、综合性的调研分析报告【全球电机控制系统芯片 (SoC)行业总体规模、主要厂商及IPO上市调研报告,2024-2030】。本报告研究全球电机控制系统芯片 (SoC)总体规模,包括产量、产值、消费量、主要生产地区、主要生产商及市场份额,同时分析电机控制系统芯片 (SoC)市场主要驱动因素、阻碍因素、市场机遇、挑战、新产品发布等。报告从电机控制系统芯片 (SoC)产品类型细分、应用细分、企业、地区等角度,进行定量和定性分析,包括产量、产值、均价
    GIRtina 2024-12-09 11:32 97浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-09 08:53 81浏览
  • 在Python中,线程的启动和管理是一个复杂而关键的过程。通过上述代码截图,我们可以深入了解Python中线程启动和处理的具体实现。以下是对图1中内容的详细解析: 4.3.3、启动线程 当调用`rt_thread_startup`函数时,该函数负责将指定线程的状态更改为就绪状态,并将其放入相应优先级的队列中等待调度。这一步骤确保了线程能够被操作系统识别并准备执行。如果新启动的线程的优先级高于当前正在运行的线程,系统将立即切换到这个高优先级线程,以保证重要任务的及时执行。 //```c /*
    丙丁先生 2024-12-06 12:30 111浏览
  •   在外地五年,回家就是大清洁、大清理,忙活了一个多月,废旧物品实在太多太多!除了老旧或出故障了的家具家电外,就是以前职业生涯养成的研究分析习惯而收留和拆解下的电子电器电脑整机、部件、零件、材料、辅料等等。  家具家电不说了,说说保留的各种各样机械、电器、电气、电子类的吧!有好有坏,扔又舍不得,满满的回忆,历史的烙印。留又没有用,拆解做分析和学习是忙不过来的了,加之,到如今个人做拆解的学习目的已经淡化了,也是因为用不着了。以前是研究学习和促进废物利用,理想也梦想能唤起循环使用产业链,结论是根本不
    自做自受 2024-12-08 22:59 158浏览
  • 学习如何在 MYIR 的 ZU3EG FPGA 开发板上部署 Tiny YOLO v4,对比 FPGA、GPU、CPU 的性能,助力 AIoT 边缘计算应用。(文末有彩蛋)一、 为什么选择 FPGA:应对 7nm 制程与 AI 限制在全球半导体制程限制和高端 GPU 受限的大环境下,FPGA 成为了中国企业发展的重要路径之一。它可支持灵活的 AIoT 应用,其灵活性与可编程性使其可以在国内成熟的 28nm 工艺甚至更低节点的制程下实现高效的硬件加速。米尔的 ZU3EG 开发板凭借其可重
    米尔电子嵌入式 2024-12-06 15:53 172浏览
  • 开发板在默认情况下,OpenHarmony系统开机后 30 秒会自动息屏,自动息屏会让不少用户感到麻烦,触觉智能教大家两招轻松取消自动息屏。使用触觉智能Purple Pi OH鸿蒙开发板演示,搭载了瑞芯微RK3566四核处理器,Laval鸿蒙社区推荐开发板,已适配全新OpenHarmony5.0 Release系统,SDK源码全开放!SDK源码中修改修改以下文件参数:base/powermgr/power_manager/services/native/profile/power_mode_co
    Industio_触觉智能 2024-12-09 11:39 76浏览
  • 进入11月中下旬,智能手机圈再度热闹起来。包括华为、小米、OPPO、vivo等诸多手机厂商,都在陆续预热发布新机,其中就包括华为Mate 70、小米Redmi K80、vivo的S20,IQOO Neo10等热门新机,这些热门新机的集中上市迅速吸引了全行业的目光。而在诸多手机厂商集体发布新机的背后,是智能手机行业的“触底反弹”。据机构数据显示,2024年第三季度,中国智能手机市场出货量约为6878万台,同比增长3.2%,连续四个季度保持同比增长,显然新一轮手机换机潮已在加速到来。憋了三年,国内智
    刘旷 2024-12-09 10:43 80浏览
  • 自20世纪60年代问世以来,光耦合器彻底改变了电子系统实现电气隔离和信号传输的方式。通过使用光作为传输信号的媒介,光耦合器消除了直接电气连接的需求,确保了安全性和可靠性。本文记录了光耦合器技术的发展,重点介绍了关键创新、挑战以及这一不可或缺组件的未来发展。 过去:起源和早期应用光耦合器的发明源于处理高压或嘈杂环境的系统对安全电气隔离的需求。早期的光耦合器由LED和光电晶体管的简单组合组成,可提供可靠的隔离,但具有明显的局限性:低速:早期的光耦合器速度慢,频率响应有限,不适合高速数字通信
    腾恩科技-彭工 2024-12-06 16:28 144浏览
  • 光耦合器以其提供电气隔离的能力而闻名,广泛应用于从电源到通信系统的各种应用。尽管光耦合器非常普遍,但人们对其特性和用途存在一些常见的误解。本文将揭穿一些最常见的误解,以帮助工程师和爱好者做出更明智的决策。 误解1:光耦合器的使用寿命较短事实:虽然光耦合器内部的LED会随着时间的推移而退化,但LED材料和制造工艺的进步已显著提高了其使用寿命。现代光耦合器的设计使用寿命为正常工作条件下的数十年。适当的热管理和在推荐的电流水平内工作可以进一步延长其使用寿命。误解2:光耦合器对于现代应用来说太
    腾恩科技-彭工 2024-12-06 16:29 186浏览
  • “SPI转CAN-FD”是嵌入式开发领域的常用方法,它极大地促进了不同通信接口之间的无缝连接,并显著降低了系统设计的复杂性。飞凌嵌入式依托瑞芯微RK3562J处理器打造的OK3562J-C开发板因为内置了SPI转CAN-FD驱动,从而原生支持这一功能。该开发板特别设计了一组SPI引脚【P8】,专为SPI转CAN-FD应用而引出,为用户提供了极大的便利。MCP2518FD是一款在各行业中都有着广泛应用的CAN-FD控制器芯片,本文就将为大家介绍如何在飞凌嵌入式RK3562J开发板上适配MCP251
    飞凌嵌入式 2024-12-07 14:30 93浏览
  • 光耦合器对于确保不同电路部分之间的电气隔离和信号传输至关重要。通过防止高压干扰敏感元件,它们可以提高安全性和可靠性。本指南将指导您使用光耦合器创建一个简单的电路,介绍其操作的基本原理和实际实施。光耦合器的工作原理光耦合器包含一个LED和一个光电晶体管。当LED接收到信号时,它会发光,激活光电晶体管,在保持隔离的同时传输信号。这使其成为保护低功耗控制电路免受高压波动影响的理想选择。组件和电路设置对于这个项目,我们将使用晶体管输出光耦合器(例如KLV2002)。收集以下组件:光耦合器、1kΩ电阻(输
    克里雅半导体科技 2024-12-06 16:34 235浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦