单片机
返回首页

IMX257虚拟网卡vnet驱动程序

2024-08-13 来源:cnblogs

一、一个简单的虚拟网卡驱动

 1 static struct net_device *vnet_dev; //定义一个网络设备结构体

 2 

 3 

 4 static const struct net_device_ops virt_netdev_ops = {

 5     .ndo_start_xmit        = NULL,

 6 };

 7 

 8 

 9 static int virt_net_init(void){

10     

11     /* 1.分配一个net_device结构体 */

12     vnet_dev = alloc_netdev(0,'vnet%d',ether_setup); //私有数据为0,

13     /* 2.设置 */

14     vnet_dev->netdev_ops = &virt_netdev_ops;

15     /* 3.注册 */

16     //register_netdevice(vnet_dev);    //会报锁的错误

17     register_netdev(vnet_dev);   //rtnl_lock();

18     return 0;

19 }

20 

21 static void virt_net_exit(void){

22     if(vnet_dev){

23         unregister_netdev(vnet_dev);

24         free_netdev(vnet_dev);

25     }

26 }

27 

28 module_init(virt_net_init);

29 module_exit(virt_net_exit);

30 MODULE_AUTHOR('Lover雪儿');

31 MODULE_LICENSE('GPL');


如上面程序所示,定义分配一个net_device结构体,注册结构体,这样就实现了一个简单的虚拟网卡驱动。


实现效果:

3e2bbcbae45fb4ad0512a6a7234b6cef_191614256986085.png

如图所示,在/sys/class/net/目录下多生成了一个vnet0的文件夹


附驱动程序virt_net1.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 #include

10 #include

11 #include

12 #include

13 #include

14 #include

15 #include

16 #include

17 

18 #include

19 #include

20 #include

21 

22 static struct net_device *vnet_dev; //定义一个网络设备结构体

23 

24 

25 static const struct net_device_ops virt_netdev_ops = {

26     .ndo_start_xmit        = NULL,

27 };

28 

29 

30 static int virt_net_init(void){

31     

32     /* 1.分配一个net_device结构体 */

33     vnet_dev = alloc_netdev(0,'vnet%d',ether_setup); //私有数据为0,

34     /* 2.设置 */

35     vnet_dev->netdev_ops = &virt_netdev_ops;

36     /* 3.注册 */

37     //register_netdevice(vnet_dev);    //会报锁的错误

38     register_netdev(vnet_dev);   //rtnl_lock();

39     return 0;

40 }

41 

42 static void virt_net_exit(void){

43     if(vnet_dev){

44         unregister_netdev(vnet_dev);

45         free_netdev(vnet_dev);

46     }

47 }

48 

49 module_init(virt_net_init);

50 module_exit(virt_net_exit);

51 MODULE_AUTHOR('Lover雪儿');

52 MODULE_LICENSE('GPL');

53 

54 

55 /*

56 

57 /////////////////////////////////////////////////////////////////////

58 网卡驱动程序框架:

59 app:  socket

60 --------------------------------------------------------------------

61         -----------------

62         ----------------- 若干层网络协议--纯软件

63         -----------------

64 hard_start_xmit() 用于发送数据包            ↑↑↑

65     ↓↓↓              sk_buff                netif_rx()用于上报数据包

66 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)

67 --------------------------------------------------------------------

68               硬件

69 //////////////////////////////////////////////////////////////////////

70               

71 网卡驱动编写:

72 1.分配一个net_device结构体

73 2.设置

74 2.1 发包函数:hard_start_xmit

75 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据

76 2.3 其他设置

77 3.注册 register_netdevice              

78     

79 

80 一、测试1th

81 insmod virt_net.ko

82 ifconfig vnet0 3.3.3.3

83 ping 3.3.3.3

84 ping 3.3.3.4  看效果 

85 

86 

87 */


二、增加ping功能


下面是我画的一个网卡驱动程序框架。

1acf69b525aad1d069cef64c38353639_191614270893328.png

所以此处我们增加一个发送数据包的函数 hard_start_xmit用于转发数据包。


1.在net_device结构体下定义hard_start_xmit。


vnet_dev->hard_start_xmit = vir_net_send_packet;


2.实现vir_net_send_packet函数


此处我们的代码只是增加一些打印语句,以便确定当我们ping的时候,是否会调用该函数。


 1 //转发发送数据包

 2 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev){

 3     static int cnt = 0;

 4     printk('vir_net_send_packet cnt = %dn',++cnt);

 5     return 0;

 6 }

 7 

 8 static const struct net_device_ops virt_netdev_ops = {

 9     .ndo_start_xmit        = virt_net_send_packet,

10 };

11 //接着在入口函数中增加net_device_ops

12 

13 vnet_dev->netdev_ops = &virt_netdev_ops;


实现效果:

485dc2ff3054900190bb1080665aeebe_191614308854466.png

ping 测试:

58d4db37122925f48af3f5f64ea0c0d2_191614319175752.png

附驱动程序virt_net2.c


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 #include

10 #include

11 #include

12 #include

13 #include

14 #include

15 #include

16 #include

17 

18 #include

19 #include

20 #include

21 

22 static struct net_device *vnet_dev; //定义一个网络设备结构体

23 

24 //转发发送数据包

25 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev){

26     static int cnt = 0;

27     printk('vir_net_send_packet cnt = %dn',++cnt);

28     return 0;

29 }

30 

31 static const struct net_device_ops virt_netdev_ops = {

32     .ndo_start_xmit        = virt_net_send_packet,

33 };

34 

35 

36 static int virt_net_init(void){

37     

38     /* 1.分配一个net_device结构体 */

39     vnet_dev = alloc_netdev(0,'vnet%d',ether_setup); //私有数据为0,

40     /* 2.设置 */

41     vnet_dev->netdev_ops = &virt_netdev_ops;

42     /* 3.注册 */

43     //register_netdevice(vnet_dev);    //会报锁的错误

44     register_netdev(vnet_dev);   //rtnl_lock();

45     return 0;

46 }

47 

48 static void virt_net_exit(void){

49     if(vnet_dev){

50         unregister_netdev(vnet_dev);

51         free_netdev(vnet_dev);

52     }

53 }

54 

55 module_init(virt_net_init);

56 module_exit(virt_net_exit);

57 MODULE_AUTHOR('Lover雪儿');

58 MODULE_LICENSE('GPL');

59 

60 

61 /*

62 

63 /////////////////////////////////////////////////////////////////////

64 网卡驱动程序框架:

65 app:  socket

66 --------------------------------------------------------------------

67         -----------------

68         ----------------- 若干层网络协议--纯软件

69         -----------------

70 hard_start_xmit() 用于发送数据包            ↑↑↑

71     ↓↓↓              sk_buff                netif_rx()用于上报数据包

72 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)

73 --------------------------------------------------------------------

74               硬件

75 //////////////////////////////////////////////////////////////////////

76               

77 网卡驱动编写:

78 1.分配一个net_device结构体

79 2.设置

80 2.1 发包函数:hard_start_xmit

81 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据

82 2.3 其他设置

83 3.注册 register_netdevice              

84     

85 

86 一、测试1th

87 insmod virt_net.ko

88 ifconfig vnet0 3.3.3.3

89 ping 3.3.3.3

90 ping 3.3.3.4  看效果 

91 

92 */


三、增加数据包的统计,设置MAC地址


有关于数据包的统计信息定义在net_device结构体的stats结构体下,主要是定义了收发数据包的个数,字节数,时间等。此处,我们就增加一个统计发送数据包的个数,以及字节数。


stats结构体如下:


发送数据包的统计

struct net_device_stats

{

    unsigned long rx_packets; / * total packets received * /

    unsigned long tx_packets; / * total packets transmitted * /

    unsigned long rx_bytes; / * total bytes received * /

    unsigned long tx_bytes; / * total bytes transmitted * /

    unsigned long rx_errors; / * bad packets received * /

    unsigned long tx_errors; / * packet transmit probls * /

    unsigned long rx_dropped; / * no space in linux buffers * /

    unsigned long tx_dropped; / * no space available in linux * /

    unsigned long multicast; / * multicast packets received * /

    unsigned long collisions;


    / * detailed rx_errors: * /

    unsigned long rx_length_errors;

    unsigned long rx_over_errors; / * receiver ring buff overflow * /

    unsigned long rx_crc_errors; / * recved pkt with crc error * /

    unsigned long rx_frame_errors; / * recv'd frame alignment error * /

    unsigned long rx_fifo_errors; / * recv'r fifo overrun * /

    unsigned long rx_missed_errors; / * receiver missed packet * /

 

    / * detailed tx_errors * /

    unsigned long tx_aborted_errors;

    unsigned long tx_carrier_errors;

    unsigned long tx_fifo_errors;

    unsigned long tx_heartbeat_errors;

    unsigned long tx_window_errors;

 

    / * for cslip etc * /

    unsigned long rx_compressed;

    unsigned long tx_compressed;

};


接下来就是在virt_net_send_packet实现数据包的自加。


 1 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)

 2 {

 3     static int cnt = 0;

 4     printk('virt_net_send_packet cnt = %dn', ++cnt);

 5 

 6     /* 更新统计信息 */

 7     dev->stats.tx_packets++;

 8     dev->stats.tx_bytes += skb->len;

 9     

10     return 0;

11 }


设置mac地址


 1 static int virt_net_init(void)

 2 {

 3     /* 1. 分配一个net_device结构体 */

 4     vnet_dev = alloc_netdev(0, 'vnet%d', ether_setup);;  /* alloc_etherdev */

 5 

 6     /* 2. 设置 */

 7     vnet_dev->netdev_ops    = &virt_netdev_ops;

 8 

 9     /* 设置MAC地址 */

10     vnet_dev->dev_addr[0] = 0x08;

11     vnet_dev->dev_addr[1] = 0x89;

12     vnet_dev->dev_addr[2] = 0x89;

13     vnet_dev->dev_addr[3] = 0x89;

14     vnet_dev->dev_addr[4] = 0x89;

15     vnet_dev->dev_addr[5] = 0x11;

16 

17     /* 设置下面两项才能ping通 */

18     //vnet_dev->flags           |= IFF_NOARP;

19     //vnet_dev->features        |= NETIF_F_NO_CSUM;    

20 

21     /* 3. 注册 */

22     //register_netdevice(vnet_dev);

23     register_netdev(vnet_dev);

24     

25     return 0;

26 }


实现效果:

5fb77e537bd6056c3fd4926f496c0ce4_191614329645566.png

附驱动程序virt_net3.c


  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include

 17 #include

 18 #include

 19 

 20 #include

 21 #include

 22 #include

 23 

 24 static struct net_device *vnet_dev;

 25 

 26 

 27 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)

 28 {

 29     static int cnt = 0;

 30     printk('virt_net_send_packet cnt = %dn', ++cnt);

 31 

 32     /* 更新统计信息 */

 33     dev->stats.tx_packets++;

 34     dev->stats.tx_bytes += skb->len;

 35     

 36     return 0;

 37 }

 38 

 39 static const struct net_device_ops virt_netdev_ops = {

 40     .ndo_start_xmit        = virt_net_send_packet,

 41 };

 42 

 43 static int virt_net_init(void)

 44 {

 45     /* 1. 分配一个net_device结构体 */

 46     vnet_dev = alloc_netdev(0, 'vnet%d', ether_setup);;  /* alloc_etherdev */

 47 

 48     /* 2. 设置 */

 49     vnet_dev->netdev_ops    = &virt_netdev_ops;

 50 

 51     /* 设置MAC地址 */

 52     vnet_dev->dev_addr[0] = 0x08;

 53     vnet_dev->dev_addr[1] = 0x89;

 54     vnet_dev->dev_addr[2] = 0x89;

 55     vnet_dev->dev_addr[3] = 0x89;

 56     vnet_dev->dev_addr[4] = 0x89;

 57     vnet_dev->dev_addr[5] = 0x11;

 58 

 59     /* 设置下面两项才能ping通 */

 60     //vnet_dev->flags           |= IFF_NOARP;

 61     //vnet_dev->features        |= NETIF_F_NO_CSUM;    

 62 

 63     /* 3. 注册 */

 64     //register_netdevice(vnet_dev);

 65     register_netdev(vnet_dev);

 66     

 67     return 0;

 68 }

 69 

 70 static void virt_net_exit(void)

 71 {

 72     unregister_netdev(vnet_dev);

 73     free_netdev(vnet_dev);

 74 }

 75 

 76 module_init(virt_net_init);

 77 module_exit(virt_net_exit);

 78 MODULE_AUTHOR('Lover雪儿');

 79 MODULE_LICENSE('GPL');

 80 

 81 

 82 /*

 83 

 84 /////////////////////////////////////////////////////////////////////

 85 网卡驱动程序框架:

 86 app:  socket

 87 --------------------------------------------------------------------

 88         -----------------

 89         ----------------- 若干层网络协议--纯软件

 90         -----------------

 91 hard_start_xmit() 用于发送数据包            ↑↑↑

 92     ↓↓↓              sk_buff                netif_rx()用于上报数据包

 93 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)

 94 --------------------------------------------------------------------

 95               硬件

 96 //////////////////////////////////////////////////////////////////////

 97               

 98 网卡驱动编写:

 99 1.分配一个net_device结构体

100 2.设置

101 2.1 发包函数:hard_start_xmit

102 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据

103 2.3 其他设置

104 3.注册 register_netdevice              

105     

106 

107 一、测试1th

108 insmod virt_net.ko

109 ifconfig vnet0 3.3.3.3

110 ping 3.3.3.3

111 ping 3.3.3.4  看效果 

112 

113 */


四、模拟回环网卡程序,实现数据包的收发过程


前面我们已经实现了转发数据包的功能,此处我们增加一个接受数据包的功能。


如程序中所示,主要就是交换数据包中的源目的MAC头信息,源目的IP信息等功能。


 1 static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)

 2 {

 3     /* 参考LDD3 */

 4     unsigned char *type;

 5     struct iphdr *ih;

 6     __be32 *saddr, *daddr, tmp;

 7     unsigned char    tmp_dev_addr[ETH_ALEN];

 8     struct ethhdr *ethhdr;

 9     

10     struct sk_buff *rx_skb;

11         

12     // 从硬件读出/保存数据

13     /* 对调'源/目的'的mac地址 */

14     ethhdr = (struct ethhdr *)skb->data;

15     memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);

16     memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);

17     memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

18 

19     /* 对调'源/目的'的ip地址 */    

20     ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));

21     saddr = &ih->saddr;

22     daddr = &ih->daddr;

23 

24     tmp = *saddr;

25     *saddr = *daddr;

26     *daddr = tmp;

27     

28     //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */

29     //((u8 *)daddr)[2] ^= 1;

30     type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);

31     //printk('tx package type = %02xn', *type);

32     // 修改类型, 原来0x8表示ping

33     *type = 0; /* 0表示reply */

34     

35     ih->check = 0;           /* and rebuild the checksum (ip needs it) */

36     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);

37     

38     // 构造一个sk_buff

39     rx_skb = dev_alloc_skb(skb->len + 2);

40     skb_reserve(rx_skb, 2); /* align IP on 16B boundary */    

41     memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

42 

43     /* Write metadata, and then pass to the receive level */

44     rx_skb->dev = dev;

45     rx_skb->protocol = eth_type_trans(rx_skb, dev);

46     rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */

47     dev->stats.rx_packets++;

48     dev->stats.rx_bytes += skb->len;

49 

50     // 提交sk_buff

51     netif_rx(rx_skb);

52 }


接着在发送数据包函数中:


 1 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)

 2 {

 3     static int cnt = 0;

 4     //printk('virt_net_send_packet cnt = %dn', ++cnt);

 5 

 6     /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */

 7     netif_stop_queue(dev); /* 停止该网卡的队列 */

 8     /* ...... */           /* 把skb的数据写入网卡 */

 9 

10     /* 构造一个假的sk_buff,上报 */

11     emulator_rx_packet(skb, dev);

12 

13     dev_kfree_skb (skb);   /* 释放skb */

14     netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */

15 

16     /* 更新统计信息 */

17     dev->stats.tx_packets++;

18     dev->stats.tx_bytes += skb->len;

19     

20     return 0;

21 }


实现效果:

0de158d22c33c8eb8f296d47fe691db2_191614341679864.png

附驱动程序virt_net4.c


  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include

 17 #include

 18 #include

 19 

 20 #include

 21 #include

 22 #include

 23 

 24 static struct net_device *vnet_dev;

 25 

 26 static void emulator_rx_packet(struct sk_buff *skb, struct net_device *dev)

 27 {

 28     /* 参考LDD3 */

 29     unsigned char *type;

 30     struct iphdr *ih;

 31     __be32 *saddr, *daddr, tmp;

 32     unsigned char    tmp_dev_addr[ETH_ALEN];

 33     struct ethhdr *ethhdr;

 34     

 35     struct sk_buff *rx_skb;

 36         

 37     // 从硬件读出/保存数据

 38     /* 对调'源/目的'的mac地址 */

 39     ethhdr = (struct ethhdr *)skb->data;

 40     memcpy(tmp_dev_addr, ethhdr->h_dest, ETH_ALEN);

 41     memcpy(ethhdr->h_dest, ethhdr->h_source, ETH_ALEN);

 42     memcpy(ethhdr->h_source, tmp_dev_addr, ETH_ALEN);

 43 

 44     /* 对调'源/目的'的ip地址 */    

 45     ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));

 46     saddr = &ih->saddr;

 47     daddr = &ih->daddr;

 48 

 49     tmp = *saddr;

 50     *saddr = *daddr;

 51     *daddr = tmp;

 52     

 53     //((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */

 54     //((u8 *)daddr)[2] ^= 1;

 55     type = skb->data + sizeof(struct ethhdr) + sizeof(struct iphdr);

 56     //printk('tx package type = %02xn', *type);

 57     // 修改类型, 原来0x8表示ping

 58     *type = 0; /* 0表示reply */

 59     

 60     ih->check = 0;           /* and rebuild the checksum (ip needs it) */

 61     ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl);

 62     

 63     // 构造一个sk_buff

 64     rx_skb = dev_alloc_skb(skb->len + 2);

 65     skb_reserve(rx_skb, 2); /* align IP on 16B boundary */    

 66     memcpy(skb_put(rx_skb, skb->len), skb->data, skb->len);

 67 

 68     /* Write metadata, and then pass to the receive level */

 69     rx_skb->dev = dev;

 70     rx_skb->protocol = eth_type_trans(rx_skb, dev);

 71     rx_skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */

 72     dev->stats.rx_packets++;

 73     dev->stats.rx_bytes += skb->len;

 74 

 75     // 提交sk_buff

 76     netif_rx(rx_skb);

 77 }

 78 

 79 static int virt_net_send_packet(struct sk_buff *skb, struct net_device *dev)

 80 {

 81     static int cnt = 0;

 82     //printk('virt_net_send_packet cnt = %dn', ++cnt);

 83 

 84     /* 对于真实的网卡, 把skb里的数据通过网卡发送出去 */

 85     netif_stop_queue(dev); /* 停止该网卡的队列 */

 86     /* ...... */           /* 把skb的数据写入网卡 */

 87 

 88     /* 构造一个假的sk_buff,上报 */

 89     emulator_rx_packet(skb, dev);

 90 

 91     dev_kfree_skb (skb);   /* 释放skb */

 92     netif_wake_queue(dev); /* 数据全部发送出去后,唤醒网卡的队列 */

 93 

 94     /* 更新统计信息 */

 95     dev->stats.tx_packets++;

 96     dev->stats.tx_bytes += skb->len;

 97     

 98     return 0;

 99 }

100 

101 static const struct net_device_ops virt_netdev_ops = {

102     .ndo_start_xmit        = virt_net_send_packet,

103 };

104 

105 static int virt_net_init(void)

106 {

107     /* 1. 分配一个net_device结构体 */

108     vnet_dev = alloc_netdev(0, 'vnet%d', ether_setup);;  /* alloc_etherdev */

109 

110     /* 2. 设置 */

111     vnet_dev->netdev_ops    = &virt_netdev_ops;

112 

113     /* 设置MAC地址 */

114     vnet_dev->dev_addr[0] = 0x08;

115     vnet_dev->dev_addr[1] = 0x89;

116     vnet_dev->dev_addr[2] = 0x89;

117     vnet_dev->dev_addr[3] = 0x89;

118     vnet_dev->dev_addr[4] = 0x89;

119     vnet_dev->dev_addr[5] = 0x11;

120 

121     /* 设置下面两项才能ping通 */

122     vnet_dev->flags           |= IFF_NOARP;

123     vnet_dev->features        |= NETIF_F_NO_CSUM;    

124 

125     /* 3. 注册 */

126     //register_netdevice(vnet_dev);

127     register_netdev(vnet_dev);

128     

129     return 0;

130 }

131 

132 static void virt_net_exit(void)

133 {

134     unregister_netdev(vnet_dev);

135     free_netdev(vnet_dev);

136 }

137 

138 module_init(virt_net_init);

139 module_exit(virt_net_exit);

140 MODULE_AUTHOR('Lover雪儿');

141 MODULE_LICENSE('GPL');

142 

143 

144 /*

145 

146 /////////////////////////////////////////////////////////////////////

147 网卡驱动程序框架:

148 app:  socket

149 --------------------------------------------------------------------

150         -----------------

151         ----------------- 若干层网络协议--纯软件

152         -----------------

153 hard_start_xmit() 用于发送数据包            ↑↑↑

154     ↓↓↓              sk_buff                netif_rx()用于上报数据包

155 调用硬件相关的驱动程序(要提供har_start_xmit,有数据时用netif_rx上报)

156 --------------------------------------------------------------------

157               硬件

158 //////////////////////////////////////////////////////////////////////

159               

160 网卡驱动编写:

161 1.分配一个net_device结构体

162 2.设置

163 2.1 发包函数:hard_start_xmit

164 2.2 收到到数据时,(在中断处理函数中)用netif_rx上报数据

165 2.3 其他设置

166 3.注册 register_netdevice              

167     

168 

169 一、测试1th

170 insmod virt_net.ko

171 ifconfig vnet0 3.3.3.3

172 ping 3.3.3.3

173 ping 3.3.3.4  看效果 

174 

175     

176 */


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章