通过wifi给Arduino板烧写程序

在《TP-Link TL-WR703n路由USB口用途1——串口》中介绍了通过USB口与Arduino串口通讯,更进一步也可以通过USB串口将程序烧写到Arduino,再配一个web服务实现上传程序到wr703n,就实现了通过wifi给arduino烧写程序。

参考:http://www.elcojacobs.com/programming-my-arduino-over-wifi/

 

第一步:编译烧写工具avrdude


烧写程序需要用到avrdude这个工具, 由于openwrt没有现成可用包,我们需要自己编译

(不想麻烦的同学可以直接下载已经编译好的avrdude包

前面参考文章的做法是直接在路由器的linux系统中下载编译工具进行编译,但是编译工具一般体积庞大(30M+),在wr703n可怜的4M Flash + 32M RAM配置下,除非外挂USB存储卡,否则肯定行不通。

这里我们用另外一种方法:交叉编译。首先在一台普通的Linux系统(Ubuntu、Debian、Fedora都可以,我用的是Arch,比较小众,但是够简洁速度快),下载openwrt编译工具链OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2,解压

$ tar xvf OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2
$ ls
OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2
OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2
$ ls OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2
LICENSE toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2
README.TOOLCHAIN version.mk
$ ls OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/
bin info.mk lib libexec mips-openwrt-linux-uclibc share
include initial lib64 mips-openwrt-linux sbin usr
$ ls OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/
g++-uc mips-openwrt-linux-uclibc-as.bin
g++-uc+std mips-openwrt-linux-uclibc-c++
ldd mips-openwrt-linux-uclibc-c++.bin
mips-openwrt-linux-addr2line mips-openwrt-linux-uclibc-c++filt
mips-openwrt-linux-ar mips-openwrt-linux-uclibc-cc
mips-openwrt-linux-as mips-openwrt-linux-uclibc-cpp
mips-openwrt-linux-c++ mips-openwrt-linux-uclibc-cpp.bin
mips-openwrt-linux-c++filt mips-openwrt-linux-uclibc-elfedit
mips-openwrt-linux-cpp mips-openwrt-linux-uclibc-g++
mips-openwrt-linux-elfedit mips-openwrt-linux-uclibc-g++.bin
mips-openwrt-linux-g++ mips-openwrt-linux-uclibc-gcc
mips-openwrt-linux-gcc mips-openwrt-linux-uclibc-gcc-4.6.3
mips-openwrt-linux-gcc-4.6.3 mips-openwrt-linux-uclibc-gcc.bin
mips-openwrt-linux-gcov mips-openwrt-linux-uclibc-gcov
mips-openwrt-linux-gdb mips-openwrt-linux-uclibc-gdb
mips-openwrt-linux-gprof mips-openwrt-linux-uclibc-gprof
mips-openwrt-linux-ld mips-openwrt-linux-uclibc-ld
mips-openwrt-linux-ld.bfd mips-openwrt-linux-uclibc-ld.bfd
mips-openwrt-linux-nm mips-openwrt-linux-uclibc-ld.bin
mips-openwrt-linux-objcopy mips-openwrt-linux-uclibc-nm
mips-openwrt-linux-objdump mips-openwrt-linux-uclibc-objcopy
mips-openwrt-linux-ranlib mips-openwrt-linux-uclibc-objdump
mips-openwrt-linux-readelf mips-openwrt-linux-uclibc-ranlib
mips-openwrt-linux-size mips-openwrt-linux-uclibc-readelf
mips-openwrt-linux-strings mips-openwrt-linux-uclibc-size
mips-openwrt-linux-strip mips-openwrt-linux-uclibc-strings
mips-openwrt-linux-uclibc-addr2line mips-openwrt-linux-uclibc-strip
mips-openwrt-linux-uclibc-ar mips-openwrt-linux-uclibc-wrapper.sh
mips-openwrt-linux-uclibc-as

在bin目录下看到了mips-openwrt-linux-gcc

接下来下载avrdude源代码, 我们选择最新版本avrdude-6.0rc1.tar.gz,解压

$ tar xvf avrdude-6.0rc1.tar.gz
$ cd avrdude-6.0rc1
/ 创建一个软链接指向前面的toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2目录 /
$ ln -sv ../OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2 toolchain
$ ll -l toolchain
lrwxrwxrwx 1 jfo users 123 Aug 25 13:03 toolchain -> ../OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.6-linaro_uClibc-0.9.33.2/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2//

下面开始编译,编译之前参考Openwrt官网介绍的如何交叉编译,稍作修改

$ export PATH=pwd/toolchain/bin:$PATH
$ export STAGING_DIR=pwd/toolchain
$ ./configure –prefix=/opt –host=mips-openwrt-linux
$ make
$ make install
$ find /opt
/opt
/opt/etc
/opt/etc/avrdude.conf
/opt/share
/opt/share/man
/opt/share/man/man1
/opt/share/man/man1/avrdude.1
/opt/bin
/opt/bin/avrdude

运行./configure时–host=mips-openwrt-linux-uclibc出错,改为mips-openwrt-linux,–host指定编译出的程序将要在什么系统中运行,编译安装之后在/opt/bin下可以看到avrdude,以及它的配置文件/opt/etc/avrdude.conf

 

第二步:通过USB串口烧写程序


在Arduino IDE中写好程序之后,编译生成二进制程序(File > Preferences 中勾上compilation可以在log中看到编译成功的hex文件位置)

这里我们用的还是在《tp-link-tl-wr703n路由usb口用途1-串口》中的程序,每秒钟打印一次接在pin 2上的pushbutton的状态,编译生成的二进制文件为sketch_aug25b.cpp.hex

将sketch_aug25b.cpp.hex和前面编译出的avrdude、avrdude.conf传到wr703n的Openwrt上(怎么传方法多种多样,我用的scp),avrdude保存至/opt/bin/avrdude,avrdude.conf保存至/opt/etc/avrdue.conf,运行下面命令:

$ /opt/bin/avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -C /opt/etc/avrdude.conf -U flash:w:sketch_aug25b.cpp.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: “flash” memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file “sketch_aug25b.cpp.hex”
avrdude: input file sketch_aug25b.cpp.hex auto detected as Intel Hex
avrdude: writing flash (3044 bytes):

Writing | ################################################## | 100% 0.47s

avrdude: 3044 bytes of flash written
avrdude: verifying flash memory against sketch_aug25b.cpp.hex:
avrdude: load data flash data from input file sketch_aug25b.cpp.hex:
avrdude: input file sketch_aug25b.cpp.hex auto detected as Intel Hex
avrdude: input file sketch_aug25b.cpp.hex contains 3044 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.39s

avrdude: verifying …
avrdude: 3044 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done. Thank you.
可以看到烧写成功!到这里我们已经成功一半了,剩下就是搭建一个web服务,上传需要烧写的程序了

 

第三步:通过Web界面烧写程序


关键部分代码包含一个上传文件的form、上传文件成功后服务器在后台调用shell_exec avrdude烧写程序两部分

<div class=”tool-programer”>
<span class=”label label-warning”>Choose file to upload:</span>
<div style=”margin-top: 10px;”>
<form action=”” method=”post” enctype=”multipart/form-data”>
<input type=”file” name=”file”>
<input type=”submit” name=”upload” value=”Go!”>
</form>
</div>
<div>
<?php
if (isset($_POST[‘upload’])) {
$file = $_FILES[“file”];
if ($file[“error”] > 0) {
$upload_error_strings = array( false,
“The uploaded file exceeds the upload_max_filesize directive in php.ini.”,
“The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.”,
“The uploaded file was only partially uploaded.”,
“No file was uploaded.”,
‘’,
“Missing a temporary folder.”,
“Failed to write file to disk.”,
“File upload stopped by extension.”
);
echo “Error: “ . $upload_error_strings[$file[“error”]];
} else {
$name = $file[“name”];
$tmp_name = $file[“tmp_name”];
$tmp_name = escapeshellcmd($tmp_name);
$size = $file[“size”];
$output = shell_exec(“/opt/bin/avrdude -p m328p -c arduino -b 115200 -P /dev/ttyUSB0 -C /opt/etc/avrdude.conf -U flash:w:”.trim($tmp_name) . “ 2>&1”);
$output = htmlspecialchars($output);
?>
<div class=’alert’>
<span>Successfully uploaded <b><?php echo $name; ?></b> to the Arduino with avrdude </span>
<span>(size: <?php echo round($size/1024, 2); ?>Kb)</span>
</div>
<hr>
<span class=”label label-warning”>avrdude output:</span>
<div class=”pre-container” style=”margin-top: 10px; min-height: 100px;”>
<pre class=”clear-pre”><?php echo $output; ?></pre>
</div>
<?php
}
}
?>
</div>
</div>

完整的服务器端程序在这里下载https://github.com/jfojfo/arduino-web-control-panel,找到shell_exec这一行,将参数改成自己的开发板型号即可

如果Openwrt所剩存储空间不够,可以删除js/bootstrap-2.3.2.min.js、js/jquery-1.7.1.min.js、css/bootstrap.min.css、css/bootstrap-responsive.min.css这几个文件,浏览器打开页面时会从baidu服务器拉取这几个文件

下面在Openwrt上配置uhttpd,可以参考http://wiki.openwrt.org/doc/uci/uhttpd,首先安装php模块

root@OpenWrt:~# opkg install php5 php5-cgi

安装这两个模块需要1M+存储空间,4M Flash空间不够用,没有升级8M Flash的,建议制作U盘启动系统,参考《TP-Link TL-WR703n路由USB口用途2——挂载U盘,从U盘启动

安装成功后配置/etc/config/uhttpd,添加以下内容,home修改为自己的web应用根目录

config uhttpd web
list listen_http 0.0.0.0:8080
option home /root/arduino-web-control-panel
option cgi_prefix /cgi-bin
option index_page index.php
list interpreter “.php=/usr/bin/php-cgi”

重启uhttpd服务,浏览器登陆http://192.168.1.1:8080,就可以看到上传程序的web界面了

root@OpenWrt:/etc/config# /etc/init.d/uhttpd restart

 

贴一张上传成功界面

program_success

Ok,已经成功通过wifi给Arduino板烧写程序。

除了烧写程序,通过wifi还可干很多事情,比如读/写Arduino的Pin引脚、串口读写、usb camera监控等等,以后在arduino-web-control-panel项目中可以添加更多的web控制模块。