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

传感器技术 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. } 


  来源:玩转单片机


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

 
  

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

传感器技术 制造业的未来是智能化,智能化的基础就是传感器; 互联网的方向是物联网,物联网的基石也是传感器; 关注传感器技术,获得技术资讯、产品应用、市场机会,掌握最黑科技,为中国工业导航。
评论
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 123浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 153浏览
  • 在电子工程领域,高速PCB设计是一项极具挑战性和重要性的工作。随着集成电路的迅猛发展,电路系统的复杂度和运行速度不断提升,对PCB设计的要求也越来越高。在这样的背景下,我有幸阅读了田学军老师所著的《高速PCB设计经验规则应用实践》一书,深感受益匪浅。以下是我从本书中学习到的新知识和经验分享,重点涵盖特殊应用电路的PCB设计、高速PCB设计经验等方面。一、高速PCB设计的基础知识回顾与深化 在阅读本书之前,我对高速PCB设计的基础知识已有一定的了解,但通过阅读,我对这些知识的认识得到了进一步的深
    金玉其中 2024-12-05 10:01 118浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 114浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 107浏览
  • CS5466AUUSB-C  (2lanes)to HDMI2.1 8K@30HZ(4K@144) +PD3.1  CS5563DP  (4lanes) to HDMI2.1 10k@60Hz CS5565USB-C  (4lanes) to HDMI2.1 10k@60Hz CS5569USB-C (4lanes) to HDMI2.1 10k@60Hz +PD3.1CS5228ANDP++ to HDMI(4K
    QQ1540182856 2024-12-05 15:56 52浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 149浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 105浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 120浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 136浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 190浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 159浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦