CAT | DIY
在调试新装的Arduino Diecimila贴片版本时,遇到一个非常诡异的现象:在将Bootloader通过编程器写入到ATmega168里之后,再通过Arduino的集成开发环境下载程序时,第一次下载完全正常,可第二次就无法完成下载了!
一开始怀疑是熔丝位设置的问题,可奇怪的是相同的设置在直插版本上就没有问题,试了一个晚上,无果。第二天Google了一下,Arduino论坛上有人遇到了现象跟我类似的问题,别人提供的解释是说没有对加锁位(Lock Bit)进行设置。以为找到了问题的症结所在,晚上回到家继续用我的编程器狂写ATmega168,但现象依然如旧:第一次下载没有问题,第二次无法下载。几乎崩溃!
同一个问题纠缠了两天,虽然没有解决,但是了解到了不少ATmega168有关熔丝位和Lock Bit的设置知识。根据Wolf Paulus对熔丝位的描述和Aduino Playground里对锁定位的描述,在我的编程器里分别做了如下的设置:
其中BLB1的设置比较重要,它是用来对Bootloader进行保护的。其中SPIEN经实验,在不选中时用下载线能够正常下载Bootloader。
仔细分析了各种可能性,最后还是在对照PCB检查电路时发现了问题,焊接时没有焊C11,焊上去之后就一切正常了,郁闷了我三个晚上的尽然就是一个小小的电容!
查了查 Arduino Diecimila有关自动重启的说明,总算搞清这个电容是用来连接FT232RL的DTR和ATmega168的RESET,如果不接这个电容,或者数值不对(比如今天我就错接了22pF的),都有可能导致Arduino程序无法正确下载。
同样的问题也会发生在Arduino Mini上,得到的启示是在连接USB Adapter和Arduino Mini时,除了电源之外,还要将DTR和RST通过一个100nF的电容连接起来! 真是到处都是陷阱啊,不过这么一折腾,倒是弄清楚了不少东西,虽然时间是花了不少:)
Arduino Mini在设计上力求很小的体积,因此并不具有完整版的Arduino的全部功能,其中的USB下载部分就是通过USB适配器(Adapter)来实现的。USB Adapter其实就是一个USB转串口的电路,采用的是FT232RL芯片,因此原理上除了可以做为Arduino Mini的适配器外,还能够用于其它需要USB转串口(TTL电平)的场合:
在配合Arduino Mini使用时,要只需要将USB Adapter上的5V,GND,TX,RX四个端口,与Arduino Mini上相应的5V,GND,TX,RX四个端口相连接就可以了。
为了配合之后的验证,上面的电路中还加了一个LED灯,其目的是用下面的Arduino程序来验证Arduino Mini上的数字输出功能:
int BASE = 2;
int NUM = 12;
int index = 0;
void setup()
{
for (int i = BASE; i < BASE + NUM; i ++) {
pinMode(i, OUTPUT);
}
}
void loop()
{
for (int i = BASE; i < BASE + NUM; i ++) {
digitalWrite(i, LOW);
}
digitalWrite(BASE + index, HIGH);
index = (index + 1) % NUM;
delay(100);
}
这次还算顺利,上面的程序通过USB适配器很轻松地就下载到了Arduino Mini中,并且将LED接在相应的数字管脚上,都可以看到LED一闪一闪的效果。
现在基本能够确定USB Adapter的工作是正常的,Arduino Mini也部分正常工作了,接下来还需要验证的功能包括Arduino Mini的模拟输入部分,以及9V电源部分。此时上次买的直流电源就派上用场了,直接把输出调整到9V,接到Arduino Mini的9V和GND端口,发现刚才写入的程序完全正常,并且用万用表量了Arduino Mini上的5V管脚,电压也是5V

今天先到这里,明天想想如何验证模拟输入部分,休息,休息,好好休息!
制作Arduino Mini的念头由来已久,但直到差不多四周之前才花了一周左右的时间来画Arduimo Mini的原理图和PCB,然后送去工厂做板又一直拖了两周才拿到电路板。这周末总算可以动手焊接了,难度不算太大,唯一能算上的麻烦的就是板子实在太小(长3.1厘米宽1.9厘米)了,要在上面定位表贴元件可不是件轻松的事情。
Arduino Mini采用的是贴片版本的ATmega168,本来打算买一个编程器转换座,直接在编程器上将Bootloader写进去,但一打听价格居然要300多块,最终决定还是决定用自己做的USB编程器。于是在实验板上搭了一个简单的Arduino Mini下载电路,并连接上USB编程器:
之后整整一个下午加一个晚上就浪费在如何将Bootloader下载到Arduino Mini里了。先是USB编程器组装好之后,在Windows上怎么也找不到这一USB设备,好在上次有成功的经验,知道电路肯定没有问题,来来回回研究了好几轮熔丝位的设置,USB编程器总算是可以被Windows识别出来了。期间一直纳闷为啥当初没有把送Whale的那个编程器的熔丝位读出来:(
接下去的过程更加令人郁闷,用avrdude怎么也无法与Arduino Mini正确地通信上,期间一度怀疑是不是Arduino Mini的板子画得有问题,但一根一根线用万用表查看似乎又是正确的,至少是ISP这一部分。于是乎不断地检查复位电路、晶振电路、ISP接口,时间就这样一点一点地流去,一点进展也没有。上网查了不少资料,唯一得到的经验就是用一个LED来检查MISO、MOSI、SCK和RST几个管脚,来看这几个信号是不是正确的,在我的Arduio Mini上,MOSI是没有任何反应的。
现象只能说明一点,ATmega168没有给出任何反馈,但一个最简单的单片机系统就只是依赖一个晶振电路和RST电路,这两部分在我看来都没有什么问题,倒底是怎么回事呢?
最后连我自己都没有想清楚为什么会去检查USB编程器,并在JP2上加了一个跳线,问题得到解决。原因是这样的,默认出厂的ATmega168使用的是内部晶振,频率非常低,而我做的这个USB编程器在芯片频率很低的情况下必须使用JP2这个跳线。这一情况在上次烧写ATtiny的时候也遇到过,并且也是费了好大的劲才解决,看来上次得到的教训还是不够深刻啊。
再后来的过程就算比较正常了,使用avrdude设置Arduino Mini的熔丝位,并下载Bootloader:
avrdude -c usbasp -p m168 -V -e -U lock:w:0×3F:m -U hfuse:w:0xDF:m -U lfuse:w:0xFF:m -U efuse:w:0xf8:m
avrdude -c usbasp -p m168 -V -D -U flash:w:ATmegaBOOT_168_diecimila.hex:i
avrdude -c usbasp -p m168 -V -U lock:w:0xCF:m
第一步老提示我扩展熔丝位要从0xf8变成0,我选了N,没有发现什么问题,再用智峰的ProgISP读出来也是0xf8。Bootloader下载完后,在数字I/O的13号管脚上接了一个小LED,发现是一闪一闪的,总算第一步算是完成了。兴许后面还会有别的问题,留到以后再慢慢解决吧,今天的确没有时间和精力再去纠缠了。
最近的问题是想做的事情和东西很多,自己得保持一个合适的速度和计划,还是觉得时间不够花,效率又不是那么高,不过只是玩玩,无所谓了:)
整个Wiring最后两部分电路是外部电源和EEPROM。外部电源电路与Arduino上的基本没有什么区别,采用的也是78M05这样的电源芯片,相应的元件清单如下:
| 类型 | 标记 | 数量 | 规格 |
|---|---|---|---|
| 电源芯片 | IC4 | 1 | LM78M05 |
| 电容 | C10, C11 | 2 | 100nF |
| 电容 | C12, C13 | 2 | 100uF |
| 整流二极管 | D1 | 1 | 1N4004 |
| 类型 | 标记 | 数量 | 规格 |
|---|---|---|---|
| EEPROM芯片 | IC3 | 1 | 93C46 |
| 电阻 | R5 | 1 | 10K, 1/4W |
| 电阻 | R6 | 1 | 2.2K, 1/4W |
为了对其中的EEPROM功能进行验证,我试验了另外一个Wiring工程:
#include
char val;
void setup() {
if(EEPROM.read(16) != 'F') {
EEPROM.write(16, 'F');
}
val = EEPROM.read(16);
pinMode(48, OUTPUT);
}
void loop() {
if( 'F' == val) {
digitalWrite(48, HIGH);
}
delay(100);
}
上述Wiring工程在初始化过程中先读取EEPROM中地址为16的字节单元中的值,并在其不是字符F的情况下,往该地址单元中写入字符F,然后再从中读取这来。这样如果EEPROM正常工作的话,就能够保证变量val在setup()函数执行完后,其值一定是字符F。在loop()函数中,如果检查出val的值确实是字符F,就点亮Wiring板子上自带的LED(接在数字I/O的48管脚上)。
习惯了Arduino程序下载时不需要按复位键,并且在下载完成后也不需要按复位键,刚接触到Wiring时对其在这两个位置上还需要按复位键的做法的确有些不适应:-) 真希望Wiring在接下去的版本中能对这一地方进行改进。昨天发邮件问Wiring的作者为什么不把bootloader的源码公布出来,得到的答案居然是他把源码弄丢了,现在只有二进建的版本,我晕…
最后贴一张我制作的Wiring在运行上述EEPROM工程时的效果图,用的是外接电源,右侧的红灯是电源灯,左侧的绿灯是Wiring自带的LED。

Wiring的核心是一个ATmega128单片机,也是整个电路中最复杂和最容易出错的部分。焊接上因为有了之前FT232BL的相关经验,并没有遇上太大的麻烦,而剩下的一些贴片元件基本上也不算太难。唯一遇到的问题可能就是这些元件实在太小,本人的眼神又不算太好,经常弄飞一两个,掉在地上找不着了:)
| 类型 | 标记 | 数量 | 规格 |
|---|---|---|---|
| AVR单片机 | IC1 | 1 | ATmega128-16AU |
| 电容 | C6, C7 | 2 | 22pF |
| 电容 | C8, C9 | 1 | 100nF |
| 电阻 | R7 | 1 | 10K |
| 电阻 | R8, R9 | 2 | 1.8k |
| 电阻 | R11 | 1 | 270 |
| 电阻 | R14, R15 | 2 | 1K |
| 晶振 | Q2 | 1 | 16M, 二脚直插式 |
| 晶振 | Q3 | 1 | 32.768K, 32C31, 四脚表贴式 |
| 按钮 | RESET | 1 | 四脚直插式 |
| 发光二极管 | PWR | 1 | 红色 |
| 发光二极管 | LED | 1 | 绿色 |
| 10P引脚座 | ISP | 1 | 黑色 |
Wiring的bootloader是事先驻留在ATmega128里的一小段程序,它的作用接收来自于Wiring IDE的命令,实现Wiring工程的下载。往AVR芯片里烧bootloader是非常关键的一步,同时也是对芯片能否正常工作做初步的检测,AVR系列芯片都提供ISP接口,借助这一接口和PonyProg这样的软件,就能够实现对bootloader的烧写。
早先就听网友说过Wiring的bootloader在Wiring的网站上找不到,试了一下果然如些,难怪Wiring不如Arduino那么流行;-) 没有办法,按照论坛里的提示,给作者发了一个邮件要bootloader,等了一天拿到bootloader的HEX文件。
有了之前DIY Arduino的经验,AVR熔丝位的设置这回一开始就考虑到了,按照网上搜索到的文章里的说明,下图在PonyProg中为ATmega128设置的熔丝位:
接下去的过程比较顺利,用PongProg和自制的并口下载线成功地将bootloader烧写到Wiring上的ATmega128中,由于ATmega128的Flash有128K,所以相应的烧写时间比较长。
最后一步就是如何将Wiring程序下载到Wiring板上了,这与在Arduino上是一样的。下面是我试验的第一个Wiring程序:
int ledPin = 0;
void setup()
{
pinMode(ledPin, OUTPUT);
}
void loop()
{
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
该程序比较简单,只是不断地点亮接在数字I/O管脚0上的LED,实验成功!之前我担心最有可能出现问题的电路部分基本算是调试成功。当然,之后要一个一个验证每个管脚的功能,一共50个,哈哈:)










