声明: 本次调试使用的方法都是来自于韦东山老师第二期驱动视频中的驱动调试,若有侵权,联系作者,我会删除。
之前已经说过了,之所以提前学习驱动调试,是因为之前学习dm9000的时候出现了bug,不想去浪费大量的时间瞪着大眼去看,所以就提前学习了调试的方法,正好可以拿这个bug来检验最近的学习成果,发现调bug是很有趣的事。这次调bug用到了老师的三种方法: 1.根据内核打印的错误信息进行分析 2, pirntk打印语句 3.寄存器工具。个人感觉这些工具都是非常有用的,其中,根据内核打印信息快速定位错误的地方,printk分析,寄存器工具用来查看寄存器的数据。下面是实际的调试过程,因为调试的时候并没有完全保存所有数据,所以数据不完整,只能提供一个大致的思路,供以后阅读。

下面是实际测试的过程中错误的输出信息:
Unable to handle kernel paging request at virtual address c486b000
pgd = c0004000
[c486b000] *pgd=30475011, *pte=00000000, *ppte=00000000
Internal error: Oops: 807 [#1]
Modules linked in:
CPU: 0 Not tainted (2.6.22.6 #39)
PC is at dmfe_probe1+0xa8/0x440
LR is at 0xc035fd70
pc : [] lr : [] psr: a0000013
sp : c0479f08 ip : c035fd70 fp : c0479f44
r10: 00000000 r9 : 00000000 r8 : c0022fd8
r7 : c06b8800 r6 : c038a1dc r5 : c02c05a8 r4 : c038a1dc
r3 : 00000028 r2 : 00000001 r1 : c486b000 r0 : c486b000
Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: c000717f Table: 30004000 DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc0478258)
Stack: (0xc0479f08 to 0xc047a000)
9f00: c02c05a8 00000197 00000000 336e6000 c0475544 c06b8800
9f20: c038a1dc c486e014 c0478000 c0022fd8 c0024864 00000000 c0479f60 c0479f48
9f40: c001d6a4 c001d1f0 00000174 c038a1dc c486c000 c0479f80 c0479f64 c001d820
9f60: c001d630 000006a6 00000000 00000000 00000000 c0479ff4 c0479f84 c0008a94
9f80: c001d70c e5923018 e5924008 00000000 00000001 e5823018 00000000 00000000
9fa0: 00000000 c0479fb0 c002bfa4 c0041330 00000000 00000000 c00089c0 c00476f0
9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
9fe0: 00000000 00000000 00000000 c0479ff8 c00476f0 c00089d0 e5873040 e59f3260
Backtrace:
[] (dmfe_probe1+0x0/0x440) from [] (dmfe_probe+0x84/0xdc)
[] (dmfe_probe+0x0/0xdc) from [] (dm9000c_init+0x124/0x1b8)
r5:c486c000 r4:c038a1dc
[] (dm9000c_init+0x0/0x1b8) from [] (kernel_init+0xd4/0x28c)
r6:00000000 r5:00000000 r4:00000000
[] (kernel_init+0x0/0x28c) from [] (do_exit+0x0/0x760)
Code: e3a03028 e3500201 e1a01000 328114f3 (e5c13000)
Kernel panic - not syncing: Attempted to kill init!

很明显: pc = c001d288这个是内核出现的错误,其实都可以猜出来是内核出现的错误,因为挂载跟文件系统就卡住了,而我修改了内核
移植了新的dm9000进去编译内核的。但是为了谨慎起见,还是看一下内核的地址范围:

vi System.map1 c0004000 A swapper_pg_dir  //gg移至开头
.....
22959 c03c63f4 B _end            //G移至结尾

可以看的出来pc = c001d288是在内核的范围内,对内核进行反汇编:
arm-linux-objdump -D vmlinux > vmlinux.dis
vi vmlinux.dis
/c001d288
下面是搜索的结果,可以看出程序错误的地方就是dmfe_probe1函数中的
22539 c001d1e0 <dmfe_probe1>:
22540 c001d1e0: e1a0c00d mov ip, sp
22541 c001d1e4: e92ddff0 stmdb sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
22542 c001d1e8: e24cb004 sub fp, ip, #4 ; 0x4
22543 c001d1ec: e24dd014 sub sp, sp, #20 ; 0x14
22544 c001d1f0: e59f43c4 ldr r4, [pc, #964] ; c001d5bc <.init+0x1539c>
22545 c001d1f4: e59f53c4 ldr r5, [pc, #964] ; c001d5c0 <.init+0x153a0>
22546 c001d1f8: e5942000 ldr r2, [r4]
22547 c001d1fc: e3a0cf63 mov ip, #396 ; 0x18c
22548 c001d200: e59f33bc ldr r3, [pc, #956] ; c001d5c4 <.init+0x153a4>
22549 c001d204: e3a01e37 mov r1, #880 ; 0x370
22550 c001d208: e1a07000 mov r7, r0
22551 c001d20c: e59f03b4 ldr r0, [pc, #948] ; c001d5c8 <.init+0x153a8>
22552 c001d210: e88d1020 stmia sp, {r5, ip}
22553 c001d214: eb00a32c bl c0045ecc
22554 c001d218: e59f13ac ldr r1, [pc, #940] ; c001d5cc <.init+0x153ac>
22555 c001d21c: e3a02006 mov r2, #6 ; 0x6
22556 c001d220: e24b0030 sub r0, fp, #48 ; 0x30
22557 c001d224: eb05629d bl c0175ca0
22558 c001d228: e59fc3a0 ldr ip, [pc, #928] ; c001d5d0 <.init+0x153b0>
22559 c001d22c: e5942000 ldr r2, [r4]
22560 c001d230: e3a09000 mov r9, #0 ; 0x0
22561 c001d234: e59f038c ldr r0, [pc, #908] ; c001d5c8 <.init+0x153a8>
22562 c001d238: e3a01e37 mov r1, #880 ; 0x370
22563 c001d23c: e59f3380 ldr r3, [pc, #896] ; c001d5c4 <.init+0x153a4>
22564 c001d240: e88d1020 stmia sp, {r5, ip}
22565 c001d244: e50b9034 str r9, [fp, #-52]
22566 c001d248: eb00a31f bl c0045ecc
22567 c001d24c: e59f6368 ldr r6, [pc, #872] ; c001d5bc <.init+0x1539c>
22568 c001d250: e59fc37c ldr ip, [pc, #892] ; c001d5d4 <.init+0x153b4>
22569 c001d254: e5962000 ldr r2, [r6]
22570 c001d258: e58dc004 str ip, [sp, #4]
22571 c001d25c: e59fc35c ldr ip, [pc, #860] ; c001d5c0 <.init+0x153a0>
22572 c001d260: e3a01e37 mov r1, #880 ; 0x370
22573 c001d264: e59f3358 ldr r3, [pc, #856] ; c001d5c4 <.init+0x153a4>
22574 c001d268: e59f0358 ldr r0, [pc, #856] ; c001d5c8 <.init+0x153a8>
22575 c001d26c: e58dc000 str ip, [sp]
22576 c001d270: eb00a315 bl c0045ecc
22577 c001d274: e5960000 ldr r0, [r6]
22578 c001d278: e3a03028 mov r3, #40 ; 0x28
22579 c001d27c: e3500201 cmp r0, #268435456 ; 0x10000000
22580 c001d280: e1a01000 mov r1, r0
22581 c001d284: 328114f3 addcc r1, r1, #-218103808 ; 0xf3000000
22582 c001d288: e5c13000 strb r3, [r1] //这里就是错误的地方,因为PC = c001d288
22583 c001d28c: e2803004 add r3, r0, #4 ; 0x4
22584 c001d290: e3530201 cmp r3, #268435456 ; 0x10000000

阅读汇编语言,可以看出在C语言中出错的是这一句话: id_val = inb(iobase + 4);下面是dmfe_probe1的代码
int __init dmfe_probe1(struct net_device *dev)
{
DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, FILE, FUNCTION, LINE);
struct board_info db; / Point a board information structure /
u32 id_val;
u16 i, dm9000_found = FALSE;
u8 MAC_addr[6]={0x00,0x60,0x6E,0x33,0x44,0x55};
u8 HasEEPROM=0,chip_info;
DMFE_DBUG(0, “dmfe_probe1()”,0);
DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, FILE, FUNCTION, LINE);
/
Search All DM9000 serial NIC */
do {

DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__); outb(DM9KS_VID_L, iobase);id_val = inb(iobase + 4);outb(DM9KS_VID_H, iobase);id_val |= inb(iobase + 4) << 8;outb(DM9KS_PID_L, iobase);id_val |= inb(iobase + 4) << 16;outb(DM9KS_PID_H, iobase);id_val |= inb(iobase + 4) << 24;if (id_val == DM9KS_ID || id_val == DM9010_ID) {/* Request IO from system */if(!request_region(iobase, 2, dev->name))return -ENODEV;printk(KERN_ERR"<DM9KS> I/O: %x, VID: %x \n",iobase, id_val);dm9000_found = TRUE;/* Allocated board information structure */memset(dev->priv, 0, sizeof(struct board_info));db = (board_info_t *)dev->priv;dmfe_dev    = dev;db->io_addr  = iobase;db->io_data = iobase + 4;   db->chip_revision = ior(db, DM9KS_CHIPR);chip_info = ior(db,0x43);/* guangchang@2650253773 *//* 这个不用,因为所选的网卡的确不符合,但是也可以使用这个驱动程序 *///if((db->chip_revision!=0x1A) || ((chip_info&(1<<5))!=0) || ((chip_info&(1<<2))!=1)) return -ENODEV;/* driver system function */                dev->base_addr       = iobase;dev->irq       = irq;dev->open         = &dmfe_open;dev->hard_start_xmit   = &dmfe_start_xmit;dev->watchdog_timeo  = 5*HZ;    dev->tx_timeout      = dmfe_timeout;dev->stop        = &dmfe_stop;dev->get_stats         = &dmfe_get_stats;dev->set_multicast_list = &dm9000_hash_table;dev->do_ioctl        = &dmfe_do_ioctl;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,28)
dev->ethtool_ops = &dmfe_ethtool_ops;
#endif
#ifdef CHECKSUM
//dev->features |= NETIF_F_IP_CSUM;
dev->features |= NETIF_F_IP_CSUM|NETIF_F_SG;
#endif
db->mii.dev = dev;
db->mii.mdio_read = mdio_read;
db->mii.mdio_write = mdio_write;
db->mii.phy_id = 1;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
db->mii.phy_id_mask = 0x1F;
db->mii.reg_num_mask = 0x1F;
#endif
//db->msg_enable =(debug == 0 ? DMFE_DEF_MSG_ENABLE : ((1 << debug) - 1));

     /* Read SROM content */for (i=0; i<64; i++)((u16 *)db->srom)[i] = read_srom_word(db, i);/* Get the PID and VID from EEPROM to check */id_val = (((u16 *)db->srom)[4])|(((u16 *)db->srom)[5]<<16); printk("id_val=%x\n", id_val);if (id_val == DM9KS_ID || id_val == DM9010_ID) HasEEPROM =1;/* Set Node Address */for (i=0; i<6; i++){if (HasEEPROM) /* use EEPROM */dev->dev_addr[i] = db->srom[i];else    /* No EEPROM */dev->dev_addr[i] = MAC_addr[i];  }}//end of if()iobase += 0x10;DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__);
}while(!dm9000_found && iobase <= DM9KS_MAX_IO);
DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__);
return dm9000_found ? 0:-ENODEV;

}

阅读汇编语言,怎么阅读汇编语言不要问我,自己去看书。阅读汇编语言可以看到是寄存器r1出现了问题,r1也就是
iobase ,iobase是一个地址值。从下面这句话,可以看出iobase很有可能越界了,只是调试的过程中,刚刚学习调试,我并没有想到那么多,没有考虑到这点。
Unable to handle kernel paging request at virtual address c486b000
然后去看看iobase的初始化:
iobase = (int)ioremap(0x20000000, 1024); //后面的1024很有作用
发现这句话也没有什么问题,这个时候就要加上打印语句,跟踪iobase,看看iobase究竟出现了什么问题
下面是打印语句

注意一点,打印的时候一定要分清是十六进制还是十进制,我刚开始打印的时候就是弄错了,所以出了很大的问题,这个就不详述 了。

我在int __init dm9000c_init(void)中的多处加入打印语句,打印出了下面的信息:
iobase = c486a000
iobase = c486a000
iobase = c486a000
并且dmfe_probe后面的打印语句没有打印,再次证明是dmfe_probe函数出现了问题,这个时候我发现了一件事,那就是寄存器r1也就是iobase的数值和打印的数值不一致, r1 = c486b000 , 而打印的数值是c486a000,恰好相差了0x1000,这个数也就是4096,可惜我当时没有看出来,4096 = 4 *1024,这个数值很重要,因为在映射的时候:
iobase = (int)ioremap(0x20000000, 1024)
我只给iobase映射了1024字节的数据,很明显指针超出了映射的空间,为什么超出了映射空间。因为iobase是在一个循环语句里:
do {

DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__); outb(DM9KS_VID_L, iobase);id_val = inb(iobase + 4);outb(DM9KS_VID_H, iobase);id_val |= inb(iobase + 4) << 8;outb(DM9KS_PID_L, iobase);id_val |= inb(iobase + 4) << 16;outb(DM9KS_PID_H, iobase);id_val |= inb(iobase + 4) << 24;DBG_PRINTK("%0x, %s %s %d\n", iobase, __FILE__, __FUNCTION__, __LINE__);
dmfe_dev = dmfe_probe();DBG_PRINTK("%0x, %s %s %d\n", iobase, __FILE__, __FUNCTION__, __LINE__); ..........else  /* No EEPROM */dev->dev_addr[i] = MAC_addr[i];  }}//end of if()iobase += 0x10;   每次循环都会是iobase的数值增加,所以最终会超出映射空间DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__);
}while(!dm9000_found && iobase <= DM9KS_MAX_IO);
DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, __FILE__, __FUNCTION__, __LINE__);
return dm9000_found ? 0:-ENODEV;

}
while(!dm9000_found && iobase <= DM9KS_MAX_IO);
一直循环意味着什么,意味着while(!dm9000_found && iobase <= DM9KS_MAX_IO); 这句话一直成立,说明里面的条件为真
注意一下, iobase <= DM9KS_MAX_IO这句话是x86使用的,jz2440不必看这句话,我之前一直困惑为什么会循环,iobase >= c486a000 ,而DM9KS_MAX_IO = 390,这句话一直是不成立的,不可能循环,至于这两个数值是怎么来的,后面会有打印语句给你们看。然后我请教了韦东山老师,才明白,感谢韦东山老师。这样while里面的语句只需要看!dm9000_found 这句话就行了,居然一直循环,循环到iobase超出了映射空间,说明!dm9000_found ,说明这句话一直成立,也就是找不到dm9000设备,说明很有可能就是硬件相关的代码设置错误,我使用(实际上我没有使用,我只是瞥了一眼硬件设置,发现某个寄存器好像不对,仔细看了一下果然不对,要是对硬件熟悉 的话,使用自制的寄存器工具可以看出来硬件的设置的确是有问题的),于是我修改了硬件 代码,如下:
*bankcon4 = (1 << 8) | (1 << 6);
之前的代码是这样的: bankcon4 = (1 << 6);
所以说一定要细心。
这个是我后来调完bug才想到的,实际上我当时调试bug的时候思路并不是这样的,我当时发现的iobase的数值发现了变化,但是我不知道怎么变化的,于是在dmfe_probe1中加入了打印语句
/
打印 */
#define DBG_PRINTK printk
//#define DBG_PRINTK(x…)
DBG_PRINTK("%0x, %0x, %s %s %d\n", DM9KS_MAX_IO, iobase, FILE, FUNCTION, LINE);
然后发现在循环语句中iobase一直变化;
my name is guangchang/nc486a000, drivers/net/dm9000_modify.c dm9000c_init 1689
c486a000, drivers/net/dm9000_modify.c dm9000c_init 1702
c486a000, drivers/net/dm9000_modify.c dmfe_probe 356
c486a000, drivers/net/dm9000_modify.c dmfe_probe 361
c486a000, drivers/net/dm9000_modify.c dmfe_probe 372
370, c486a000, drivers/net/dm9000_modify.c dmfe_probe1 396
370, c486a000, drivers/net/dm9000_modify.c dmfe_probe1 403
370, c486a000, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486a010, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486a010, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486a020, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486a020, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486a030, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486a030, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486a040, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486a040, drivers/net/dm9000_modify.c dmfe_probe1 407

370, c486afd0, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486afd0, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486afe0, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486afe0, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486aff0, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486aff0, drivers/net/dm9000_modify.c dmfe_probe1 407
370, c486b000, drivers/net/dm9000_modify.c dmfe_probe1 488
370, c486b000, drivers/net/dm9000_modify.c dmfe_probe1 407
Unable to handle kernel paging request at virtual address c486b000
pgd = c0004000
[c486b000] *pgd=30475011, *pte=00000000, *ppte=00000000
Internal error: Oops: 807 [#1]
Modules linked in:
CPU: 0 Not tainted (2.6.22.6 #39)
PC is at dmfe_probe1+0xa8/0x440
LR is at 0xc035fd70
pc : [] lr : [] psr: a0000013
sp : c0479f08 ip : c035fd70 fp : c0479f44
r10: 00000000 r9 : 00000000 r8 : c0022fd8
r7 : c06b8800 r6 : c038a1dc r5 : c02c05a8 r4 : c038a1dc
r3 : 00000028 r2 : 00000001 r1 : c486b000 r0 : c486b000
Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment kernel
Control: c000717f Table: 30004000 DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc0478258)

从这个信息中,可以看到iobase一直变化:
370, c486b000, drivers/net/dm9000_modify.c dmfe_probe1 407
这个打印语句中,分别代表着 DM9KS_MAX_IO iobase, 所在文件 所在函数 所在行数
然后我分析了循环的条件,刚开始由于DM9KS_MAX_IO 的误导,一直不明白,后来干脆放弃这句话,不看这句话,发现是找不到dm9000 的设备,我猜测是因为dm9000的硬件设置发生了错误,后来用自制寄存器工具发现了是因为bankcon4 寄存器设置错了,修改后终于解决了这个bug。

这次调试bug感觉非常有意思,因为这次的调试bug是有着一定的思路去调试,而不是像以前那样一步步检查代码,经常看了半天也不知道所以然,解决了这个bug感觉非常有成就感,因为是第一次自己去调试bug,所以手段还是很稚嫩,我相信我会越来越会调bug,这是一件非常有意思的事情,非常感谢卫东山老师的辛苦付出录制视频供我们学习。个人感觉,韦东山老师的几个方法都非常有效,但是如果单独使用一个方法,可能效果不太好,最好的方法是各个方法兼顾使用,让调试的更加顺利。
今天就到此为止。文章写得很乱,如果你有所收获,我也很开心。

牛刀小试:移植dm9000的bug调试相关推荐

  1. ML之回归预测:利用十(xgboost,10-1)种机器学习算法对无人驾驶汽车系统参数(2017年的data,18+2)进行回归预测值VS真实值——bug调试记录

    ML之回归预测:利用十(xgboost,10-1)种机器学习算法对无人驾驶汽车系统参数(2017年的data,18+2)进行回归预测值VS真实值--bug调试记录 目录 输出结果 1.增加XGBR算法 ...

  2. 谷歌浏览器bug调试快捷键_Bug压榨初学者指南:如何使用调试器和其他工具查找和修复Bug

    谷歌浏览器bug调试快捷键 As web developers, it often feels like we spend more time fixing bugs and trying to so ...

  3. Bug调试(lldb)

    原文网址:http://www.cnblogs.com/Twisted-Fate/p/4760156.html 今天博主有一些Bug调试的需求,遇到了一些困难点,在此和大家分享,希望能够共同进步. X ...

  4. 论 BUG调试与(程序猿)初学者

    作为一枚程序猿,BUG调试是最基本的技能,对于初学者更是重中之重.个人而言,要想为自己的程序猿生涯更上一层楼,就得知道什么是BUG调试,而且还必须知道怎么调好BUG.那么BUG究竟是什么呢?在我之前的 ...

  5. 【Bug 调试】修复注册验证问题 第十三届蓝桥杯(Web 应用开发)线上模拟赛

    [Bug 调试]修复注册验证问题 考试需求: 解答: index.js: // " abc " ----> "abc " ----> "a ...

  6. 海思平台上USB WIFI的移植与局域网无线调试和视频流预览-第5/11季视频课程-朱有鹏-专题视频课程...

    海思平台上USB WIFI的移植与局域网无线调试和视频流预览-第5/11季视频课程-143人已学习 课程介绍         本季课程在开发板上移植USB WIFI模块(套装附带的MT7601模块), ...

  7. openssh移植 for pycharm 远程调试 sftp

    openssh移植 for pycharm 远程调试 sftp imx8mq根文件系统制作--openssh移植 https://blog.csdn.net/ggxyx123/article/deta ...

  8. 飞桨paddle遇到bug调试修正【迁移工具、版本兼容性】

    PaddlePaddlle强化学习及PARL框架{飞桨} [一]-环境配置+python入门教学 [二]-Parl基础命令 [三]-Notebook.&pdb.ipdb 调试 [四]-强化学习 ...

  9. 基于FPGA的FOC电流采样Bug调试记录

    #基于FPGA的FOC电流采样Bug调试记录 博主在调试FOC闭环控制中遇到了一个bug,冥思苦想两三天,最终一步步地调试时序,最终找到了bug,在调试过程中学会了debug的思想,也明白了调试过程中 ...

最新文章

  1. 2022-2028年中国网络出版产业投资分析及前景预测报告
  2. Python基础——PyCharm版本——第九章、MySQL操作(核心4)
  3. python单位根检验看结果_Python ADF 单位根检验 如何查看结果的实现
  4. JDK源码(19)-Void
  5. Effects on PV3D
  6. 受力分析软件_大赛作品 | 关于Z型路灯受力情况分析
  7. Arduino无法下载,重刷Bootloader后解决问题
  8. Java集成第三方推送(极光推送)——文档篇
  9. Unity-VScode-Emmylua配置报错解决
  10. 自定义radio图标
  11. Python3.7安装教程
  12. 扩展卡尔曼滤波EKF—目标跟踪中的应用(算法部分)
  13. 10款实用苹果Siri快捷指令分享
  14. fai 安装debian
  15. Wox主题样式基础的自定义
  16. 基于Profibus-DP协议的PLC智能从站设计
  17. 推土机距离_推土机工程师指南
  18. ASIC设计中的分频时钟
  19. kazam使用_尝试使用2种免费的桌面录制工具:SimpleScreenRecorder和Kazam
  20. 计算机程序必须在有限的步骤内完成,苏教版必修三 §1.1 算法的含义 学案.docx...

热门文章

  1. SM5308原厂2.1A 充电 2.4 A 放电高集成度移动电源IC芯片SOC
  2. Linux创建用户并授予SSH权限
  3. Semtech SM712.TCT 瞬态电压抑制器(TVS)二极管
  4. EIP712 web3.py签名问题注意事项
  5. solid works方程式笔记
  6. 机械师创物者14 评测怎么样
  7. JVM工具之jstat
  8. 32.如何把一个公共的类给抽离出来?让所有的项目都可以用?嘻哈的简写笔记——SpringBoot
  9. GitHub加速网址及使用教程
  10. Android 全局大喇叭——详解广播机制