<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Arduino中国 &#187; 电子积木</title>
	<atom:link href="http://blog.flamingoeda.com/tag/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.flamingoeda.com</link>
	<description>Flamingo EDA</description>
	<lastBuildDate>Sat, 13 Aug 2011 11:41:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Arduino 电子积木 霍尔开关</title>
		<link>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e9%9c%8d%e5%b0%94%e5%bc%80%e5%85%b3/</link>
		<comments>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e9%9c%8d%e5%b0%94%e5%bc%80%e5%85%b3/#comments</comments>
		<pubDate>Sat, 13 Aug 2011 11:38:27 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[接近开关]]></category>
		<category><![CDATA[霍尔元件]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=729</guid>
		<description><![CDATA[首先科普一下，当一块通有电流的金属或半导体薄片垂直地放在磁场中时，薄片的两端就会产生电位差，这种现象就称为霍尔效应。霍尔开关则是利用霍尔效应的一种传感器，它可以很方便的把磁信号转换成电信号，具有很高的可靠性和灵敏度。 在Arduino上使用霍尔开关比较简单，电路连接上只需要用专用的传感器连接线，将霍尔开关与传感器扩展板上的相应端口连接起来就可以了： 编程的话使用最简单的数字输入函数digitalRead()进行读取就可以了： int ledPin = 13; int switchPin = 19; int value = 0; void setup() { &#160;&#160;pinMode(switchPin, INPUT); &#160;&#160;pinMode(ledPin, OUTPUT); &#160;&#160;Serial.begin(9600); } void loop() { &#160;&#160;value&#160;=&#160;digitalRead(switchPin); &#160;&#160;if (HIGH == value) { &#160;&#160;&#160;&#160;digitalWrite(ledPin, HIGH); &#160;&#160;}&#160;else { &#160;&#160;&#160;&#160;digitalWrite(ledPin, LOW); &#160;&#160;} } 使用的时候当霍尔开关靠近磁铁的时候，从Arduino相应引脚读出来的值为高，而当霍尔开关远离磁铁的时候，从Arduino相应引脚读出来的值为低。另外这里介绍的霍尔开关模块属于单极性霍尔元件，所以只对磁铁的南极或者北极有响应，实验的时候如果发现不响应的话可以试着换磁铁的另一极使用噢;-) &#160; &#160;]]></description>
			<content:encoded><![CDATA[<p>首先科普一下，当一块通有电流的金属或半导体薄片垂直地放在磁场中时，薄片的两端就会产生电位差，这种现象就称为霍尔效应。霍尔开关则是利用霍尔效应的一种传感器，它可以很方便的把磁信号转换成电信号，具有很高的可靠性和灵敏度。</p>
<p><img class="aligncenter" title="hall" src="http://image.flamingoeda.com/albums/userpics/10002/febb_hall_1.JPG" alt="" width="460" height="345" />在Arduino上使用霍尔开关比较简单，电路连接上只需要用专用的传感器连接线，将霍尔开关与传感器扩展板上的相应端口连接起来就可以了：</p>
<p><img class="aligncenter" title="hall" src="http://image.flamingoeda.com/albums/userpics/10002/febb_hall_3.JPG" alt="" width="460" height="345" /></p>
<p>编程的话使用最简单的数字输入函数digitalRead()进行读取就可以了：</p>
<pre>
<span style="color: #CC6600;">int</span> ledPin = 13;
<span style="color: #CC6600;">int</span> switchPin = 19;
<span style="color: #CC6600;">int</span> value = 0; 

<span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>setup</b></span>() {
&nbsp;&nbsp;<span style="color: #CC6600;">pinMode</span>(switchPin, <span style="color: #006699;">INPUT</span>);
&nbsp;&nbsp;<span style="color: #CC6600;">pinMode</span>(ledPin, <span style="color: #006699;">OUTPUT</span>);
&nbsp;&nbsp;<span style="color: #CC6600;"><b>Serial</b></span>.<span style="color: #CC6600;">begin</span>(9600);
}

<span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>loop</b></span>() {
&nbsp;&nbsp;value&nbsp;=&nbsp;<span style="color: #CC6600;">digitalRead</span>(switchPin);
&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (<span style="color: #006699;">HIGH</span> == value) {
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">HIGH</span>);
&nbsp;&nbsp;}&nbsp;<span style="color: #CC6600;">else</span> {
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">LOW</span>);
&nbsp;&nbsp;}
}
</pre>
<p>使用的时候当霍尔开关靠近磁铁的时候，从Arduino相应引脚读出来的值为高，而当霍尔开关远离磁铁的时候，从Arduino相应引脚读出来的值为低。另外这里介绍的霍尔开关模块属于单极性霍尔元件，所以只对磁铁的南极或者北极有响应，实验的时候如果发现不响应的话可以试着换磁铁的另一极使用噢;-)</p>
<p><img class="aligncenter" title="hall" src="http://image.flamingoeda.com/albums/userpics/10002/febb_hall_4.JPG" alt="" width="460" height="345" /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e9%9c%8d%e5%b0%94%e5%bc%80%e5%85%b3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino 电子积木 4位7段数码管</title>
		<link>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-4%e4%bd%8d7%e6%ae%b5%e6%95%b0%e7%a0%81%e7%ae%a1/</link>
		<comments>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-4%e4%bd%8d7%e6%ae%b5%e6%95%b0%e7%a0%81%e7%ae%a1/#comments</comments>
		<pubDate>Fri, 12 Aug 2011 16:22:11 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[数码管]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=726</guid>
		<description><![CDATA[7段数码管可以用来很方便地显示0-9的数字以及，因此在一些电子制作中经常被使用到。7段数码管顾名思义其实就是由7个LED组成，它们一般按照共阴或者共阳的方式连接在一起，既然原理上这么简单，那么用Arduino来驱动7段数码管的方式自然就不言而喻了：分别将7个LED的引脚连接到Arduino的7个引脚上，然后通过给相应引脚置高或者置低的方式来控制7段数码管上显示出不同的数字来。可是仔细想想你会发现，通常Arduino上只有12个可以使用的数字引脚，如果驱动一个7段数码管就需要占用7个引脚，那驱动两个更者更多7段数码管的话，Arduino的引脚数目马上就告急了！这个时候你就可以考虑我们这里介绍的这个4路7段数码管的电子积木模块了:-) 这个4位7段数码管的模块采用专用的驱动芯片来控制数码管的各个引脚，并且使用I2C总线与Arduino进行连接，也就是说我们只需要用两根数据线就可以用Arduino来控制这一数码管模块了： 连接的方法很简单，只需要用专用的I2C连接线，将这一4位7段数码管与Arduino专用扩展板上的I2C端口连接起来就可以了： 同时注意将模块背面的RS开关设置到ON的位置，使能I2C引脚上的上拉电阻： 测试的时候可以使用如下的代码，该代码可以在数码管上循环显示0-9和a-f，同时还可以控制数码管上的小数点： #include&#160;"Wire.h" // enable I2C bus //byte&#160;saa1064&#160;=&#160;0x70&#160;&#62;&#62;&#160;1;&#160;//&#160;define&#160;the&#160;I2C&#160;bus&#160;address&#160;for&#160;our&#160;SAA1064&#160;(pin&#160;1&#160;to&#160;GND) byte saa1064 = 0x76 &#62;&#62; 1; // define the I2C bus address for our SAA1064 (pin 1 to VCC) int digits[16]={63, 6, 91, 79, 102, 109, 125,7, 127, 111, 119, 124, 57, 94, 121, 113}; //&#160;these&#160;are&#160;the&#160;byte&#160;representations&#160;of&#160;pins&#160;required&#160;to&#160;display&#160;each&#160;digit&#160;0~9&#160;then&#160;A~F void setup() { &#160;&#160;Wire.begin(); // start up I2C [...]]]></description>
			<content:encoded><![CDATA[<p>7段数码管可以用来很方便地显示0-9的数字以及，因此在一些电子制作中经常被使用到。7段数码管顾名思义其实就是由7个LED组成，它们一般按照共阴或者共阳的方式连接在一起，既然原理上这么简单，那么用Arduino来驱动7段数码管的方式自然就不言而喻了：分别将7个LED的引脚连接到Arduino的7个引脚上，然后通过给相应引脚置高或者置低的方式来控制7段数码管上显示出不同的数字来。可是仔细想想你会发现，通常Arduino上只有12个可以使用的数字引脚，如果驱动一个7段数码管就需要占用7个引脚，那驱动两个更者更多7段数码管的话，Arduino的引脚数目马上就告急了！这个时候你就可以考虑我们这里介绍的这个4路7段数码管的电子积木模块了:-)</p>
<p><img class="aligncenter" title="7seg" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_3.JPG" alt="" width="460" height="345" /></p>
<p>这个4位7段数码管的模块采用专用的驱动芯片来控制数码管的各个引脚，并且使用I2C总线与Arduino进行连接，也就是说我们只需要用两根数据线就可以用Arduino来控制这一数码管模块了：</p>
<p><img class="aligncenter" title="7seg" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_2.JPG" alt="" width="460" height="345" /></p>
<p>连接的方法很简单，只需要用专用的I2C连接线，将这一4位7段数码管与Arduino专用扩展板上的I2C端口连接起来就可以了：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_8.JPG" alt="" width="460" height="345" /></p>
<p>同时注意将模块背面的RS开关设置到ON的位置，使能I2C引脚上的上拉电阻：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_7.JPG" alt="" width="230" height="173" /></p>
<p>测试的时候可以使用如下的代码，该代码可以在数码管上循环显示0-9和a-f，同时还可以控制数码管上的小数点：</p>
<pre>
#include&nbsp;<span style="color: #006699;">"Wire.h"</span>  <span style="color: #7E7E7E;">// enable I2C bus</span>

<span style="color: #7E7E7E;">//byte&nbsp;saa1064&nbsp;=&nbsp;0x70&nbsp;&gt;&gt;&nbsp;1;&nbsp;//&nbsp;define&nbsp;the&nbsp;I2C&nbsp;bus&nbsp;address&nbsp;for&nbsp;our&nbsp;SAA1064&nbsp;(pin&nbsp;1&nbsp;to&nbsp;GND)</span>
<span style="color: #CC6600;">byte</span> saa1064 = 0x76 &gt;&gt; 1; <span style="color: #7E7E7E;">// define the I2C bus address for our SAA1064 (pin 1 to VCC)</span>

<span style="color: #CC6600;">int</span> digits[16]={63, 6, 91, 79, 102, 109, 125,7, 127, 111, 119, 124, 57, 94, 121, 113};
<span style="color: #7E7E7E;">//&nbsp;these&nbsp;are&nbsp;the&nbsp;byte&nbsp;representations&nbsp;of&nbsp;pins&nbsp;required&nbsp;to&nbsp;display&nbsp;each&nbsp;digit&nbsp;0~9&nbsp;then&nbsp;A~F</span>

<span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>setup</b></span>()
{
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">begin</span>(); <span style="color: #7E7E7E;">// start up I2C bus</span>
&nbsp;&nbsp;<span style="color: #CC6600;">delay</span>(500);
&nbsp;&nbsp;initDisplay();
}

<span style="color: #CC6600;">void</span> initDisplay()
<span style="color: #7E7E7E;">//&nbsp;turns&nbsp;on&nbsp;dynamic&nbsp;mode&nbsp;and&nbsp;adjusts&nbsp;segment&nbsp;current&nbsp;to&nbsp;12mA</span>
{
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">beginTransmission</span>(saa1064);
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(<span style="color: #006699;">B00000000</span>); <span style="color: #7E7E7E;">// this is the instruction byte. Zero means the next byte is the control byte</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(<span style="color: #006699;">B01000111</span>); <span style="color: #7E7E7E;">// control byte (dynamic mode on, digits 1+3 on, digits 2+4 on, 12mA segment current</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">endTransmission</span>();
}

<span style="color: #CC6600;">void</span> displayDigits()
<span style="color: #7E7E7E;">//&nbsp;show&nbsp;all&nbsp;digits&nbsp;0~9,&nbsp;A~F&nbsp;on&nbsp;all&nbsp;digits&nbsp;of&nbsp;display</span>
{
&nbsp;&nbsp;<span style="color: #CC6600;">for</span> (<span style="color: #CC6600;">int</span> z=0; z&lt;16; z++)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">beginTransmission</span>(saa1064);
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(1); <span style="color: #7E7E7E;">// instruction byte - first digit to control is 1 (right hand side)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]); <span style="color: #7E7E7E;">// digit 1 (RHS)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]); <span style="color: #7E7E7E;">// digit 2</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]); <span style="color: #7E7E7E;">// digit 3</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]); <span style="color: #7E7E7E;">// digit 4 (LHS)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">endTransmission</span>();
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">delay</span>(500);
&nbsp;&nbsp;}

<span style="color: #7E7E7E;">//&nbsp;now&nbsp;repeat&nbsp;but&nbsp;with&nbsp;decimal&nbsp;point</span>

&nbsp;<span style="color: #CC6600;">for</span> (<span style="color: #CC6600;">int</span> z=0; z&lt;16; z++)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">beginTransmission</span>(saa1064);
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(1); <span style="color: #7E7E7E;">// instruction byte - first digit to control is 1 (right hand side)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]+128); <span style="color: #7E7E7E;">// digit 1 (RHS)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]+128); <span style="color: #7E7E7E;">// digit 2</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]+128); <span style="color: #7E7E7E;">// digit 3</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(digits[z]+128); <span style="color: #7E7E7E;">// digit 4 (LHS)</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">endTransmission</span>();
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">delay</span>(500);
&nbsp;&nbsp;}
}

<span style="color: #CC6600;">void</span> clearDisplay()
<span style="color: #7E7E7E;">//&nbsp;clears&nbsp;all&nbsp;digits</span>
{
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">beginTransmission</span>(saa1064);
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(1); <span style="color: #7E7E7E;">// instruction byte - first digit to control is 1 (right hand side)</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(0); <span style="color: #7E7E7E;">// digit 1 (RHS)</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(0); <span style="color: #7E7E7E;">// digit 2</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(0); <span style="color: #7E7E7E;">// digit 3</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">send</span>(0); <span style="color: #7E7E7E;">// digit 4 (LHS)</span>
&nbsp;&nbsp;<span style="color: #CC6600;">Wire</span>.<span style="color: #CC6600;">endTransmission</span>();
}

<span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>loop</b></span>()
{
&nbsp;&nbsp;displayDigits();
&nbsp;&nbsp;clearDisplay();
&nbsp;&nbsp;<span style="color: #CC6600;">delay</span>(1000);
}
</pre>
<p>运行结果如下图所示：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_9.JPG" alt="" width="460" height="345" /></p>
<p>由于该模块使用的是I2C接口，因此实际上也允许同时接入多个数码管模块，但必须对模块的地址进行设置。在数码管模块的背面有一个ADDR跳线，正是进行这一地址位设置的：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_4.JPG" alt="" width="230" height="173" /></p>
<p>设置的办法是用铬铁将中间的引脚分别与VCC或者GND端连接起来，如果中间引脚与VCC连接时，相应的地址为0&#215;76：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_5.JPG" alt="" width="230" height="173" /></p>
<p>如果中间引脚与GND连接时，相应的地址为0&#215;70：</p>
<p><img class="aligncenter" title="7seg4" src="http://image.flamingoeda.com/albums/userpics/10002/febb_7seg4_6.JPG" alt="" width="230" height="173" /></p>
<p>这一模块在出厂时中间的引脚即不与VCC连接，也不与GND连接，此时的地址也是0&#215;76。</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2011/08/13/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-4%e4%bd%8d7%e6%ae%b5%e6%95%b0%e7%a0%81%e7%ae%a1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino 电子积木 FlexiForce压力传感器</title>
		<link>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-flexiforce%e5%8e%8b%e5%8a%9b%e4%bc%a0%e6%84%9f%e5%99%a8/</link>
		<comments>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-flexiforce%e5%8e%8b%e5%8a%9b%e4%bc%a0%e6%84%9f%e5%99%a8/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 14:30:40 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[FlexiForce]]></category>
		<category><![CDATA[压力传感器]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=670</guid>
		<description><![CDATA[FlexiForce传感器由由美国Tekscan公司生产的一种电阻元件，其特点是电导率与负载之间能够呈现高度的线性关系。在完全没有压力的状况下，该传感器所表现出来的电阻值非常大，可 以说基本上是一个开放式电路；但随着压力增加，电阻值开始下降，最后可以达到10千欧或者更低的水平。 FlexiForce压力传感器在实际使用的时候需要搭配相应的放大电路，因此我们设计了这一电子积木，以便在实际工程中能够很方便地运用这一传感器： 同其他电子积木一样，在使用的时候只需要用传感器连接线，将该模块与传感器扩展板连接起来就可以了： 对Arduino来讲，读取该传感器输出的值与其它模拟传感器的做法是一样的，下面是相应的测试代码： int sensorPin = 5; int value = 0; void setup() { Serial.begin(9600); } void loop() { value = analogRead(sensorPin); Serial.println(value, DEC); delay(10); }]]></description>
			<content:encoded><![CDATA[<p>FlexiForce传感器由由美国Tekscan公司生产的一种电阻元件，其特点是电导率与负载之间能够呈现高度的线性关系。在完全没有压力的状况下，该传感器所表现出来的电阻值非常大，可 以说基本上是一个开放式电路；但随着压力增加，电阻值开始下降，最后可以达到10千欧或者更低的水平。</p>
<p>FlexiForce压力传感器在实际使用的时候需要搭配相应的放大电路，因此我们设计了这一电子积木，以便在实际工程中能够很方便地运用这一传感器：</p>
<p><img class="aligncenter" title="flexiforce" src="http://image.flamingoeda.com/albums/userpics/febb_flexiforce.JPG" alt="" width="460" height="345" /></p>
<p>同其他电子积木一样，在使用的时候只需要用传感器连接线，将该模块与传感器扩展板连接起来就可以了：</p>
<p><img class="aligncenter" title="flexiforce" src="http://image.flamingoeda.com/albums/userpics/febb_flexiforce_2.JPG" alt="" width="460" height="345" /></p>
<p>对Arduino来讲，读取该传感器输出的值与其它模拟传感器的做法是一样的，下面是相应的测试代码：</p>
<pre><span style="color: #cc6600;">int</span> sensorPin = 5;
<span style="color: #cc6600;">int</span> value = 0;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>() {
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>() {
  value = <span style="color: #cc6600;">analogRead</span>(sensorPin);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(value, <span style="color: #006699;">DEC</span>);
  <span style="color: #cc6600;">delay</span>(10);
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-flexiforce%e5%8e%8b%e5%8a%9b%e4%bc%a0%e6%84%9f%e5%99%a8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino 电子积木 RS485串口模块</title>
		<link>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-rs485%e4%b8%b2%e5%8f%a3%e6%a8%a1%e5%9d%97/</link>
		<comments>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-rs485%e4%b8%b2%e5%8f%a3%e6%a8%a1%e5%9d%97/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 16:16:14 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[RS485]]></category>
		<category><![CDATA[网络]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=675</guid>
		<description><![CDATA[RS232串口是我们非常熟悉的一种Arduino与计算机之间进行数据交换的手段，虽然最新的Arduino在设计时都采用了USB转串口的方式，但最初一版的Arduino的确是基于RS232串口的。直到现在，RS232仍然在实际的工程项目中大量用到，不过这种方式有两个致命的弱点：一是传输距离不能太长，二是只能实现两个设备之间的点对点通信。我们这里要介绍的RS485模块正好解决了这两个问题： RS485串行总线接口标准以差分平衡方式传输信号，具有很强的抗共模干扰的能力，允许一对双绞线上一个发送器驱动多个 负载设备，其理论的通讯距离是1200米，速率高达20Mbps，并可以用在强噪声的环境中正常工作，因此在工业通讯领域中被广泛应用。 当我们在Arduino上使用RS485时，更多的可能是借助其互连功能，将多个Arduino连接成一个RS485网络，来实现各个Arduino之间的通信。 在由RS485构成的多机串行通信系统中，一般采用的都是主从式结构：也就是说主机负责所有的通信协调过程，从机一般被动地接收主机发送过来的数据，或者根据主机的命令向主机反馈相应的数据，各个从机之间一般不进行数据交换，而是通过主机进行中转。之所以采用这种方式是因为于RS485是一种半双工通讯，发送和接收共用同一物理信道，在任一时刻都只允许一台设备处于发送状态。如果在时序上配合不好，就会发生总线冲突，使整个系统的通讯瘫痪，从而无法正常工作。 我们以一个三个结点的网络为例，介绍如何利用RS485串口模块来构建一个RS485网络，该网络中包括一台作为主机使用的Arduino（S）和两台作为从机使用的Arduino（CA, CB）。对于网络中的每一台Arduino来讲，硬件连接上我们都需要一块Arduino专用传感器扩展板、一条COM连接线和一条通用传感器连接线，其中COM连接线用来将RS485串口模块与传感器扩展板上的COM口连接起来，而通用传感器连接线则用来将RS485串口模块上的RE/DE引脚和标号为2的数字I/O口连接起来： 我们之前已经介绍过，RS485网络上的任何时候都只有一台设备处于发送状态，而其它设备则应该全部都处于接收状态。Arduino正是通过对RE/DE引脚的控制，来指定该设备是向RS485网络中发送数据，还是从RS485网络中接收数据。为了说明上的方便，在我们的例子中主设备S一直都处于发送状态，相应的RE/DE引脚一直处于高电平状态；两台从设备CA和CB一直处于接收状态，相应的RE/DE引脚则一直处于低电平状态。 在RS485串口模块上另一个需要引起我们注意的就是标记为“TERM?”的开关，它是用来控制终端电阻的，目的是为了吸收RS485网络中的反射信号，以保证正常传输的信号不受到干扰。不过该电阻只能在RS485总线上的最后一台设备上出现，这也是为什么叫做终端电阻的原因。在我们上面给出的网络拓朴图中不难看出，从机CB是总线上的最后一台设置，因此我们需要在该设备所对应的RS485串口模块上将“TERM?”开关拨到“Y”的位置： 而在主机S和从机CA上该开关都需要设置到与之相反的位置上： 由于是要将三个Arduino连接成一个RS485网络，因此我们还需要将RS485 串口模块两两连接起来，这是通过RS485串口模块上的“485 IN”和“485 THU”两个插座来实现的。具体说来，就是我们需要将前一个RS485串口模块的“485 THU”接口，与下一个RS485串口模块的“485 IN”接口连接起来，连接的时候我们可以使用模拟传感器连接线，或者是普通的杜邦线。对于我们正在构建的三个结点的RS485网络来讲，则是要求主机S的“485 THU”与从机CA的“485 IN”连接起来，然后再将从机CA的“485 THU”与从机CB的“485 IN”连接起来，实验中我们使用的是长度为2米的模拟传感器连接线。下图中从左至右依次为主机S，从机CA和从机CB： 硬件都连接好之后，下面我们就可以为各个Arduino来编写相应的程序了。下面是主机S的代码： int EN = 2; void setup() { pinMode(EN, OUTPUT); Serial.begin(19200); } void loop() { // send data digitalWrite(EN, HIGH);//使能发送 Serial.print('A'); Serial.print('B'); delay(1000); } 从主机S的代码不难看出，虽然采用的是RS485串口协议，但编程时使用的还是普通的串口操作语句。 下面是从机CA所使用的代码： int ledPin = 13; int EN = 2; int [...]]]></description>
			<content:encoded><![CDATA[<p>RS232串口是我们非常熟悉的一种Arduino与计算机之间进行数据交换的手段，虽然最新的Arduino在设计时都采用了USB转串口的方式，但最初一版的Arduino的确是基于RS232串口的。直到现在，RS232仍然在实际的工程项目中大量用到，不过这种方式有两个致命的弱点：一是传输距离不能太长，二是只能实现两个设备之间的点对点通信。我们这里要介绍的RS485模块正好解决了这两个问题：</p>
<p><img class="aligncenter" title="rs485" src="http://image.flamingoeda.com/albums/userpics/febb_rs485_1.JPG" alt="" width="460" height="345" /></p>
<p>RS485串行总线接口标准以差分平衡方式传输信号，具有很强的抗共模干扰的能力，允许一对双绞线上一个发送器驱动多个 负载设备，其理论的通讯距离是1200米，速率高达20Mbps，并可以用在强噪声的环境中正常工作，因此在工业通讯领域中被广泛应用。 当我们在Arduino上使用RS485时，更多的可能是借助其互连功能，将多个Arduino连接成一个RS485网络，来实现各个Arduino之间的通信。</p>
<p>在由RS485构成的多机串行通信系统中，一般采用的都是主从式结构：也就是说主机负责所有的通信协调过程，从机一般被动地接收主机发送过来的数据，或者根据主机的命令向主机反馈相应的数据，各个从机之间一般不进行数据交换，而是通过主机进行中转。之所以采用这种方式是因为于RS485是一种半双工通讯，发送和接收共用同一物理信道，在任一时刻都只允许一台设备处于发送状态。如果在时序上配合不好，就会发生总线冲突，使整个系统的通讯瘫痪，从而无法正常工作。</p>
<p>我们以一个三个结点的网络为例，介绍如何利用RS485串口模块来构建一个RS485网络，该网络中包括一台作为主机使用的Arduino（S）和两台作为从机使用的Arduino（CA, CB）。对于网络中的每一台Arduino来讲，硬件连接上我们都需要一块Arduino专用传感器扩展板、一条COM连接线和一条通用传感器连接线，其中COM连接线用来将RS485串口模块与传感器扩展板上的COM口连接起来，而通用传感器连接线则用来将RS485串口模块上的RE/DE引脚和标号为2的数字I/O口连接起来：</p>
<p><img class="aligncenter" title="rs485" src="http://image.flamingoeda.com/albums/userpics/febb_rs485_2.JPG" alt="" width="460" height="345" /></p>
<p>我们之前已经介绍过，RS485网络上的任何时候都只有一台设备处于发送状态，而其它设备则应该全部都处于接收状态。Arduino正是通过对RE/DE引脚的控制，来指定该设备是向RS485网络中发送数据，还是从RS485网络中接收数据。为了说明上的方便，在我们的例子中主设备S一直都处于发送状态，相应的RE/DE引脚一直处于高电平状态；两台从设备CA和CB一直处于接收状态，相应的RE/DE引脚则一直处于低电平状态。</p>
<p>在RS485串口模块上另一个需要引起我们注意的就是标记为“TERM?”的开关，它是用来控制终端电阻的，目的是为了吸收RS485网络中的反射信号，以保证正常传输的信号不受到干扰。不过该电阻只能在RS485总线上的最后一台设备上出现，这也是为什么叫做终端电阻的原因。在我们上面给出的网络拓朴图中不难看出，从机CB是总线上的最后一台设置，因此我们需要在该设备所对应的RS485串口模块上将“TERM?”开关拨到“Y”的位置：</p>
<p><img class="aligncenter" title="rs485" src="http://image.flamingoeda.com/albums/userpics/febb_rs485_3.JPG" alt="" width="460" height="345" /></p>
<p>而在主机S和从机CA上该开关都需要设置到与之相反的位置上：</p>
<p><img class="aligncenter" title="rs485" src="http://image.flamingoeda.com/albums/userpics/febb_rs485_4.JPG" alt="" width="460" height="345" /></p>
<p>由于是要将三个Arduino连接成一个RS485网络，因此我们还需要将RS485 串口模块两两连接起来，这是通过RS485串口模块上的“485 IN”和“485 THU”两个插座来实现的。具体说来，就是我们需要将前一个RS485串口模块的“485 THU”接口，与下一个RS485串口模块的“485 IN”接口连接起来，连接的时候我们可以使用模拟传感器连接线，或者是普通的杜邦线。对于我们正在构建的三个结点的RS485网络来讲，则是要求主机S的“485 THU”与从机CA的“485 IN”连接起来，然后再将从机CA的“485 THU”与从机CB的“485 IN”连接起来，实验中我们使用的是长度为2米的模拟传感器连接线。下图中从左至右依次为主机S，从机CA和从机CB：</p>
<p><img class="aligncenter" title="rs485" src="http://image.flamingoeda.com/albums/userpics/febb_rs485_5.JPG" alt="" width="460" height="345" /></p>
<p>硬件都连接好之后，下面我们就可以为各个Arduino来编写相应的程序了。下面是主机S的代码：</p>
<pre><span style="color: #cc6600;">int</span> EN = 2;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">pinMode</span>(EN, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(19200);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
<span style="color: #7e7e7e;">// send data </span>
  <span style="color: #cc6600;">digitalWrite</span>(EN, <span style="color: #006699;">HIGH</span>);<span style="color: #7e7e7e;">//使能发送</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">'A'</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">'B'</span>);
  <span style="color: #cc6600;">delay</span>(1000);
}
</pre>
<p>从主机S的代码不难看出，虽然采用的是RS485串口协议，但编程时使用的还是普通的串口操作语句。</p>
<p>下面是从机CA所使用的代码：</p>
<pre><span style="color: #cc6600;">int</span> ledPin = 13;
<span style="color: #cc6600;">int</span> EN = 2;
<span style="color: #cc6600;">int</span> val;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">pinMode</span>(ledPin, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #cc6600;">pinMode</span>(EN, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(19200);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #7e7e7e;">// receive data</span>
 <span style="color: #cc6600;">digitalWrite</span>(EN, <span style="color: #006699;">LOW</span>);<span style="color: #7e7e7e;">//使能接收</span>
 val = <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">read</span>();
  <span style="color: #cc6600;">if</span> (-1 != val) {
    <span style="color: #cc6600;">if</span> (<span style="color: #006699;">'A'</span> == val) {
      <span style="color: #cc6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">HIGH</span>);
      <span style="color: #cc6600;">delay</span>(500);
      <span style="color: #cc6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">LOW</span>);
      <span style="color: #cc6600;">delay</span>(500);
    }
 }
}
</pre>
<p>下面是从机CB所使用的代码：</p>
<pre><span style="color: #cc6600;">int</span> ledPin = 13;
<span style="color: #cc6600;">int</span> EN = 2;
<span style="color: #cc6600;">int</span> val;

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">pinMode</span>(ledPin, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #cc6600;">pinMode</span>(EN, <span style="color: #006699;">OUTPUT</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(19200);
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  <span style="color: #7e7e7e;">// receive data</span>
 <span style="color: #cc6600;">digitalWrite</span>(EN, <span style="color: #006699;">LOW</span>);<span style="color: #7e7e7e;">//使能接收</span>
 val = <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">read</span>();
  <span style="color: #cc6600;">if</span> (-1 != val) {
    <span style="color: #cc6600;">if</span> (<span style="color: #006699;">'B'</span> == val) {
      <span style="color: #cc6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">HIGH</span>);
      <span style="color: #cc6600;">delay</span>(500);
      <span style="color: #cc6600;">digitalWrite</span>(ledPin, <span style="color: #006699;">LOW</span>);
      <span style="color: #cc6600;">delay</span>(500);
    }
 }
}
</pre>
<p>从代码中不难看出，CA和CB分别响应主机S发送过来的字母A或者B，然后做相应的反应：点亮一个LED灯。在将三台Arduino都分别通电之后，你就可以看到作为主机的CA和CB在接到主机S发过来的命令之后，分别做相应的点灯动作。</p>
<p>最后需要说明的一点是，虽然在我们的例子中演示的是主机S不断向从机CA和CB发送数据的单向通信过程，但其实在RS485网络中也是可以实现双向通信的，只但需要在代码上做更多的工作，并且需要在主机和从面之间根据应用的需要定义一个相应的数据通信协议。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/11/30/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-rs485%e4%b8%b2%e5%8f%a3%e6%a8%a1%e5%9d%97/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arduino 电子积木 WAV声音插放模块</title>
		<link>http://blog.flamingoeda.com/2010/11/21/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-wav%e5%a3%b0%e9%9f%b3%e6%8f%92%e6%94%be%e6%a8%a1%e5%9d%97/</link>
		<comments>http://blog.flamingoeda.com/2010/11/21/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-wav%e5%a3%b0%e9%9f%b3%e6%8f%92%e6%94%be%e6%a8%a1%e5%9d%97/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 14:12:52 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[WAV]]></category>
		<category><![CDATA[声音]]></category>
		<category><![CDATA[播放器]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=663</guid>
		<description><![CDATA[在Arduino上进行声音的播放可以有几种方案，一种是利用语音芯片对事先存储好的声音数据进行播放，这种方案一般只能进行语音数据的播放，音质比较差，面且播放的时长比较受限；第二种办法是播放MP3文件，但这种方式需要专门的MP3解压芯片；第三种可以借助的办法就是下面要介绍的WAV声音播放模块 ，其做法是将事先录制好的WAV文件存储到SD卡中，Arduino负责从SD卡中读出未经压缩的声音文件，再送到WAV模块中进行播放： 目前这一方案受限于所采用的DAC芯片精度的影响，最高只能做到16bit，22KHz，Mono格式的WAV文件，不过这对于大部分应用场合来讲已经足够了。 使用该模块时需要事先准备好符合我们要求WAV文件，有不少音频转换软件可以完成该任务。下面我们以Audacity（http://audacity.sourceforge.net/）为例，讲述如何讲MP3文件转换成我们所需要的格式。 运行Audacity之后，选择“File”菜单下的“Open”命令，打开需要进行转换的MP3文件： 通常MP3文件都是立体声（Stereo）格式的，我们需要将其分离成两个单独的音轨，这可以通过选择左侧声音文件标题下拉框中的“Split Stereo Track”命令来完成： 为了避免这两个音轨在混音之后音量过大，我们可以分在每个音轨上将增益（Gain）设置成-6dB，修改的方法是拖动相应音轨左侧标有正负号的滑动条： 将下来我们需要从每条音频的标题下拉菜单下选择“Mono”命令，将其转换成单声道格式，注意每一路都需要做这个转换： 现在我们可以选择“Project”菜单下的“Quick Mix”命令来完成单声道文件的混音： 通过上述的步骤，我们已经将立体声（Stereo）格式的声音数据转化成单声道（Mono）格式的声音数据，此外我们还需要设置相应的采样位数和采样频率。对于采样位数的设置，我们可以从每条音频的标题下拉菜单中选择“Set Sample Format”下的“16-bit”命令，将采样位数设置为16位： 而采样频率的设置则可以通过Auda对话框底部的“Project rate”进行设置，我们的WAV播放模块最高只支持22Khz： 所有参数都设置好之后，我们就可以导出所需要的声音文件了。选择“Edit”菜单下的“Preferences&#8230;”命令，在打开的对话框中从“Uncompressed Export”下拉框中选择“WAV (Microsoft 16 bit PCM)”后单击“Ok”按钮： 最后选择“File”菜单下的“Export As WAV&#8230;”命令，导出我们所需要的WAV文件就可以了，为了确保之后Arduino能够正常处理，该WAV文件需要用字母命名，并且文件名称不能超过8个字节。为了确保产生的文件是正确的，我们还可以在Windows中右键单击该文件后，从弹出的菜单中选择“属性”命令打开属性对话框，然后从“摘要”中检查生产的文件是否符合我们的要求： 生成的文件我们可以通过读卡器将其复制到SD卡中，为了保证读取的正确性，可以考虑先格式化后再将WAV文件复制到SD卡中。注意SD卡应该格式化成FAT格式的，而不要格式化成FAT32格式的。 带有WAV文件的SD卡准备好之后，我们可以用Arduino IDC扩展板将SD卡模块和WAV声音播放模块都连接到Arduino上： 通过Arduino皤放SD卡中存储的WAV文件我们需要用到wavehc库（http://code.google.com/p/wavehc/）。我们测试时使用的是wavehc20101009.zip这个文件，你可以通过wavehc的官方网站下载该文件，也可以通过这个地址直接下载我们在测试时使用的库文件包。 在将下载后的wavhc库解压缩之后，将压缩包中的WaveHC上当复制到Arduino安装目录中的libraries目录下。wavhc库默认使用了Arduino上的2、3、4、5这4个引脚，但 我们的Arduino IDC扩展板上的IDC-6座则是与Arduino的6、7、8、9这4个引脚相连接的，因此我们需要对WaveHC目录下的WavePinDefs.h这个文件进行修改， 相应的对应关系为2-&#62;9、3-&#62;7、4-&#62;6、5-&#62;8。你可以手工修改这个文件中以MCP_DAC_开头的那些宏定义，也可以直接下载我们已经修改好的WavePinDefs.h文件。 测试时我们使用的是wavhc库压缩包examples目录下的daphc，其实现的功能是不断从SD卡中查找以.WAV为扩展名的WAV文件进行播放，相应的代码为： /* * This example plays every .WAV file it finds on the SD card in a loop */ #include "WaveHC.h" [...]]]></description>
			<content:encoded><![CDATA[<p>在Arduino上进行声音的播放可以有几种方案，一种是利用语音芯片对事先存储好的声音数据进行播放，这种方案一般只能进行语音数据的播放，音质比较差，面且播放的时长比较受限；第二种办法是播放MP3文件，但这种方式需要专门的MP3解压芯片；第三种可以借助的办法就是下面要介绍的WAV声音播放模块 ，其做法是将事先录制好的WAV文件存储到SD卡中，Arduino负责从SD卡中读出未经压缩的声音文件，再送到WAV模块中进行播放：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_sound_3.JPG" alt="" width="460" height="345" /></p>
<p>目前这一方案受限于所采用的DAC芯片精度的影响，最高只能做到16bit，22KHz，Mono格式的WAV文件，不过这对于大部分应用场合来讲已经足够了。</p>
<p>使用该模块时需要事先准备好符合我们要求WAV文件，有不少音频转换软件可以完成该任务。下面我们以Audacity（http://audacity.sourceforge.net/）为例，讲述如何讲MP3文件转换成我们所需要的格式。</p>
<p>运行Audacity之后，选择“File”菜单下的“Open”命令，打开需要进行转换的MP3文件：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_1.JPG" alt="" width="460" height="402" /></p>
<p>通常MP3文件都是立体声（Stereo）格式的，我们需要将其分离成两个单独的音轨，这可以通过选择左侧声音文件标题下拉框中的“Split Stereo Track”命令来完成：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_2.JPG" alt="" width="460" height="402" /></p>
<p>为了避免这两个音轨在混音之后音量过大，我们可以分在每个音轨上将增益（Gain）设置成-6dB，修改的方法是拖动相应音轨左侧标有正负号的滑动条：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_3.JPG" alt="" width="460" height="403" /></p>
<p>将下来我们需要从每条音频的标题下拉菜单下选择“Mono”命令，将其转换成单声道格式，注意每一路都需要做这个转换：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_4.JPG" alt="" width="460" height="402" /></p>
<p>现在我们可以选择“Project”菜单下的“Quick Mix”命令来完成单声道文件的混音：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_5.JPG" alt="" width="460" height="401" /></p>
<p>通过上述的步骤，我们已经将立体声（Stereo）格式的声音数据转化成单声道（Mono）格式的声音数据，此外我们还需要设置相应的采样位数和采样频率。对于采样位数的设置，我们可以从每条音频的标题下拉菜单中选择“Set Sample Format”下的“16-bit”命令，将采样位数设置为16位：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_6.JPG" alt="" width="460" height="402" /></p>
<p>而采样频率的设置则可以通过Auda对话框底部的“Project rate”进行设置，我们的WAV播放模块最高只支持22Khz：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_7.JPG" alt="" width="460" height="401" /></p>
<p>所有参数都设置好之后，我们就可以导出所需要的声音文件了。选择“Edit”菜单下的“Preferences&#8230;”命令，在打开的对话框中从“Uncompressed Export”下拉框中选择“WAV (Microsoft 16 bit PCM)”后单击“Ok”按钮：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_8.JPG" alt="" width="460" height="393" /></p>
<p>最后选择“File”菜单下的“Export As WAV&#8230;”命令，导出我们所需要的WAV文件就可以了，为了确保之后Arduino能够正常处理，该WAV文件需要用字母命名，并且文件名称不能超过8个字节。为了确保产生的文件是正确的，我们还可以在Windows中右键单击该文件后，从弹出的菜单中选择“属性”命令打开属性对话框，然后从“摘要”中检查生产的文件是否符合我们的要求：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_blog_9.JPG" alt="" width="369" height="474" /></p>
<p>生成的文件我们可以通过读卡器将其复制到SD卡中，为了保证读取的正确性，可以考虑先格式化后再将WAV文件复制到SD卡中。注意SD卡应该格式化成FAT格式的，而不要格式化成FAT32格式的。</p>
<p>带有WAV文件的SD卡准备好之后，我们可以用Arduino IDC扩展板将SD卡模块和WAV声音播放模块都连接到Arduino上：</p>
<p><img class="aligncenter" title="wav" src="http://image.flamingoeda.com/albums/userpics/febb_wav_sound_2.JPG" alt="" width="460" height="345" /></p>
<p>通过Arduino皤放SD卡中存储的WAV文件我们需要用到wavehc库（http://code.google.com/p/wavehc/）。我们测试时使用的是wavehc20101009.zip这个文件，你可以通过wavehc的官方网站下载该文件，也可以通过<a href="http://blog.flamingoeda.com/wp-content/uploads/2010/11/wavehc20101009.zip">这个地址</a>直接下载我们在测试时使用的库文件包。</p>
<p>在将下载后的wavhc库解压缩之后，将压缩包中的WaveHC上当复制到Arduino安装目录中的libraries目录下。wavhc库默认使用了Arduino上的2、3、4、5这4个引脚，但 我们的Arduino IDC扩展板上的IDC-6座则是与Arduino的6、7、8、9这4个引脚相连接的，因此我们需要对WaveHC目录下的WavePinDefs.h这个文件进行修改， 相应的对应关系为2-&gt;9、3-&gt;7、4-&gt;6、5-&gt;8。你可以手工修改这个文件中以MCP_DAC_开头的那些宏定义，也可以直接<a href="http://blog.flamingoeda.com/wp-content/uploads/2010/11/WavePinDefs.h">下载我们已经修改好的WavePinDefs.h文件</a>。</p>
<p>测试时我们使用的是wavhc库压缩包examples目录下的daphc，其实现的功能是不断从SD卡中查找以.WAV为扩展名的WAV文件进行播放，相应的代码为：</p>
<pre><span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * This example plays every .WAV file it finds on the SD card in a loop</span>
<span style="color: #7e7e7e;"> */</span>
#include <span style="color: #006699;">"WaveHC.h"</span>
#include <span style="color: #006699;">"WaveUtil.h"</span>

SdReader card;    <span style="color: #7e7e7e;">// This object holds the information for the card</span>
FatVolume vol;    <span style="color: #7e7e7e;">// This holds the information for the partition on the card</span>
FatReader root;   <span style="color: #7e7e7e;">// This holds the information for the volumes root directory</span>
WaveHC wave;      <span style="color: #7e7e7e;">// This is the only wave (audio) object, since we will only play one at a time</span>

uint8_t dirLevel; <span style="color: #7e7e7e;">// indent level for file/dir names    (for prettyprinting)</span>
dir_t dirBuf;     <span style="color: #7e7e7e;">// buffer for directory reads</span>

<span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * Define macro to put error messages in flash memory</span>
<span style="color: #7e7e7e;"> */</span>
#define error(msg) error_P(PSTR(msg))

<span style="color: #7e7e7e;">// Function definitions (we define them here, but the code is below)</span>
<span style="color: #cc6600;">void</span> play(FatReader &amp;dir);

<span style="color: #7e7e7e;">//////////////////////////////////// SETUP</span>
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);           <span style="color: #7e7e7e;">// set up Serial library at 9600 bps for debugging</span>

  putstring_nl(<span style="color: #006699;">"\nWave test!"</span>);  <span style="color: #7e7e7e;">// say we woke up!</span>

  putstring(<span style="color: #006699;">"Free RAM: "</span>);       <span style="color: #7e7e7e;">// This can help with debugging, running out of RAM is bad</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(FreeRam());

  <span style="color: #7e7e7e;">//  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you</span>
  <span style="color: #cc6600;">if</span> (!card.init()) {         <span style="color: #7e7e7e;">//play with 8 MHz spi (default faster!)  </span>
    error(<span style="color: #006699;">"Card init. failed!"</span>);  <span style="color: #7e7e7e;">// Something went wrong, lets print out why</span>
  }

  <span style="color: #7e7e7e;">// enable optimize read - some cards may timeout. Disable if you're having problems</span>
  card.partialBlockRead(<span style="color: #cc6600;">true</span>);

  <span style="color: #7e7e7e;">// Now we will look for a FAT partition!</span>
  uint8_t part;
  <span style="color: #cc6600;">for</span> (part = 0; part &lt; 5; part++) {   <span style="color: #7e7e7e;">// we have up to 5 slots to look in</span>
    <span style="color: #cc6600;">if</span> (vol.init(card, part))
      <span style="color: #cc6600;">break</span>;                           <span style="color: #7e7e7e;">// we found one, lets bail</span>
  }
  <span style="color: #cc6600;">if</span> (part == 5) {                     <span style="color: #7e7e7e;">// if we ended up not finding one  <img src='http://blog.flamingoeda.com/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> </span>
    error(<span style="color: #006699;">"No valid FAT partition!"</span>);  <span style="color: #7e7e7e;">// Something went wrong, lets print out why</span>
  }

  <span style="color: #7e7e7e;">// Lets tell the user about what we found</span>
  putstring(<span style="color: #006699;">"Using partition "</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(part, <span style="color: #006699;">DEC</span>);
  putstring(<span style="color: #006699;">", type is FAT"</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(vol.fatType(),<span style="color: #006699;">DEC</span>);     <span style="color: #7e7e7e;">// FAT16 or FAT32?</span>

  <span style="color: #7e7e7e;">// Try to open the root directory</span>
  <span style="color: #cc6600;">if</span> (!root.openRoot(vol)) {
    error(<span style="color: #006699;">"Can't open root dir!"</span>);      <span style="color: #7e7e7e;">// Something went wrong,</span>
  }

  <span style="color: #7e7e7e;">// Whew! We got past the tough parts.</span>
  putstring_nl(<span style="color: #006699;">"Files found (* = fragmented):"</span>);

  <span style="color: #7e7e7e;">// Print out all of the files in all the directories.</span>
  root.ls(LS_R | LS_FLAG_FRAGMENTED);
}

<span style="color: #7e7e7e;">//////////////////////////////////// LOOP</span>
<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
  root.rewind();
  play(root);
}

<span style="color: #7e7e7e;">/////////////////////////////////// HELPERS</span>
<span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * print error message and halt</span>
<span style="color: #7e7e7e;"> */</span>
<span style="color: #cc6600;">void</span> error_P(const <span style="color: #cc6600;">char</span> *str)
{
  PgmPrint(<span style="color: #006699;">"Error: "</span>);
  SerialPrint_P(str);
  sdErrorCheck();
  <span style="color: #cc6600;">while</span>(1);
}
<span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * print error message and halt if SD I/O error, great for debugging!</span>
<span style="color: #7e7e7e;"> */</span>
<span style="color: #cc6600;">void</span> sdErrorCheck(<span style="color: #cc6600;">void</span>)
{
  <span style="color: #cc6600;">if</span> (!card.errorCode()) <span style="color: #cc6600;">return</span>;
  PgmPrint(<span style="color: #006699;">"\r\nSD I/O error: "</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(card.errorCode(), <span style="color: #006699;">HEX</span>);
  PgmPrint(<span style="color: #006699;">", "</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(card.errorData(), <span style="color: #006699;">HEX</span>);
  <span style="color: #cc6600;">while</span>(1);
}
<span style="color: #7e7e7e;">/*</span>
<span style="color: #7e7e7e;"> * play recursively - possible stack overflow if subdirectories too nested</span>
<span style="color: #7e7e7e;"> */</span>
<span style="color: #cc6600;">void</span> play(FatReader &amp;dir)
{
  FatReader file;
  <span style="color: #cc6600;">while</span> (dir.readDir(dirBuf) &gt; 0) {    <span style="color: #7e7e7e;">// Read every file in the directory one at a time</span>

    <span style="color: #7e7e7e;">// Skip it if not a subdirectory and not a .WAV file</span>
    <span style="color: #cc6600;">if</span> (!DIR_IS_SUBDIR(dirBuf)
         &amp;&amp; strncmp_P((<span style="color: #cc6600;">char</span> *)&amp;dirBuf.name[8], PSTR(<span style="color: #006699;">"WAV"</span>), 3)) {
      <span style="color: #cc6600;">continue</span>;
    }

    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>();            <span style="color: #7e7e7e;">// clear out a new line</span>

    <span style="color: #cc6600;">for</span> (uint8_t i = 0; i &lt; dirLevel; i++) {
       <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">' '</span>);       <span style="color: #7e7e7e;">// this is for prettyprinting, put spaces in front</span>
    }
    <span style="color: #cc6600;">if</span> (!file.open(vol, dirBuf)) {        <span style="color: #7e7e7e;">// open the file in the directory</span>
      error(<span style="color: #006699;">"file.open failed"</span>);          <span style="color: #7e7e7e;">// something went wrong</span>
    }

    <span style="color: #cc6600;">if</span> (file.isDir()) {                   <span style="color: #7e7e7e;">// check if we opened a new directory</span>
      putstring(<span style="color: #006699;">"Subdir: "</span>);
      printEntryName(dirBuf);
      dirLevel += 2;                      <span style="color: #7e7e7e;">// add more spaces</span>
      <span style="color: #7e7e7e;">// play files in subdirectory</span>
      play(file);                         <span style="color: #7e7e7e;">// recursive!</span>
      dirLevel -= 2;
    }
    <span style="color: #cc6600;">else</span> {
      <span style="color: #7e7e7e;">// Aha! we found a file that isnt a directory</span>
      putstring(<span style="color: #006699;">"Playing "</span>);
      printEntryName(dirBuf);              <span style="color: #7e7e7e;">// print it out</span>
      <span style="color: #cc6600;">if</span> (!wave.create(file)) {            <span style="color: #7e7e7e;">// Figure out, is it a WAV proper?</span>
        putstring(<span style="color: #006699;">" Not a valid WAV"</span>);     <span style="color: #7e7e7e;">// ok skip it</span>
      } <span style="color: #cc6600;">else</span> {
        <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>();                  <span style="color: #7e7e7e;">// Hooray it IS a WAV proper!</span>
        wave.play();                       <span style="color: #7e7e7e;">// make some noise!</span>

        uint8_t n = 0;
        <span style="color: #cc6600;">while</span> (wave.isplaying) {<span style="color: #7e7e7e;">// playing occurs in interrupts, so we print dots in realtime</span>
          putstring(<span style="color: #006699;">"."</span>);
          <span style="color: #cc6600;">if</span> (!(++n % 32))<span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>();
          <span style="color: #cc6600;">delay</span>(100);
        }
        sdErrorCheck();                    <span style="color: #7e7e7e;">// everything OK?</span>
        <span style="color: #7e7e7e;">// if (wave.errors)Serial.println(wave.errors);     // wave decoding errors</span>
      }
    }
  }
}
</pre>
<p>如果一切正常，此时你应该就能够在WAV声音播放模块上接的耳机或者音箱中听到你存储在SD卡中的WAV文件在播放时的效果了。上述Arduino代码在运行的时候会试图通过串口传输一些调试信息，必要的时候可以打开Arduino的串口来查看相应的原因（比如SD卡中没有正常找到）。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/11/21/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-wav%e5%a3%b0%e9%9f%b3%e6%8f%92%e6%94%be%e6%a8%a1%e5%9d%97/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>电子积木 EEPROM 存储模块</title>
		<link>http://blog.flamingoeda.com/2010/07/18/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-eeprom-%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/</link>
		<comments>http://blog.flamingoeda.com/2010/07/18/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-eeprom-%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 05:39:38 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[EEPROM]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=616</guid>
		<description><![CDATA[如果你的Arduino中要做少量的数据存储，那么使用EEPROM可能是最简单易行的做法了。其实Arduino所使用的芯片ATmega本身就具备一定的EEPROM存储器，只不过数量有限罢了。我们设计的这款外置式EEPROM存储模块使用I2C总线来与Arduino进行连接，并且采用可插拔的芯片，直插式系列，这样在扩展容量时会比较容易，基本上只需要按一个更大容量的EEPROM芯片就可以了。 该存储模块上使用的是AT24C系列的EEPROM芯片，其I2C基地址为0&#215;50，最后三位地址可以根据应用需要进行设置。因此使用时我们首先要对其地址的最后三位进行设置，这是通过4位拨码开关上的A2，A1和A0来完成的，其中A0表示地址的最后一位。拨码开关向上推时相应的位为1，向下推时相应的位为0。也就是说，如果将A2，A1，A0都拨到上方时，相应的地址为0&#215;57；而如果将A2，A1，A0都拨到下方时，相应的地址为0&#215;50。 该存储模块上另外一个需要设置的地方就是开关RS，它是用来设置是否往I2C总线上的SDA和SCL上接入板载的上拉电阻。我们知道，I2C之所以被称为总线，就是因为可以连接多个I2C设备，接照I2C协议的规定，只允许在离控制器最近的一个I2C设备处接上拉电阻。说到这里你可能已经明白了，如果有多个这个的存储模块连接到Arduino的I2C总线上时，我们必须将第一个（离Arduino最近）存储模块的RS开关设置到ON的位置，而其它存储模块上的RS则不能设置到ON的位置： 如果使用的是Arduino专用传感器扩展扩展板V4，注意IIC/COM跳线的位置要设置到IIC这一边，因为此时我们需要用到I2C连接方式： 上述设置完成之后，我们只需要用I2C/COM连接线将EEPROM存储模块连接到传感器扩展板上就完成硬件的连接了： 至于软件部分，Arduino的官方网站上提供了两个不错的链接：I2CEEPROM和TWIPROM，需要的话可以参考。下面是我们测试时所用的代码： #include &#60;Wire.h&#62; #define EEPROM_ADDR 0x50 // I2C Buss address of 24LC256 256K EEPROM void setup() { Wire.begin(); // join I2C bus (address optional for master) Serial.begin(9600); // TESTS FOR EACH FUNCTION BEGIN HERE Serial.println("Writing Test:"); for (int i=0; i&#60;20; i++){ // loop for first 20 slots i2c_eeprom_write_byte(EEPROM_ADDR,i,i+65); // write [...]]]></description>
			<content:encoded><![CDATA[<p>如果你的Arduino中要做少量的数据存储，那么使用EEPROM可能是最简单易行的做法了。其实Arduino所使用的芯片ATmega本身就具备一定的EEPROM存储器，只不过数量有限罢了。我们设计的这款外置式EEPROM存储模块使用I2C总线来与Arduino进行连接，并且采用可插拔的芯片，直插式系列，这样在扩展容量时会比较容易，基本上只需要按一个更大容量的EEPROM芯片就可以了。<br />
<img class="aligncenter" title="eeprom" src="http://image.flamingoeda.com/albums/userpics/febb_eeprom_1.JPG" alt="" width="460" height="345" /><br />
该存储模块上使用的是AT24C系列的EEPROM芯片，其I2C基地址为0&#215;50，最后三位地址可以根据应用需要进行设置。因此使用时我们首先要对其地址的最后三位进行设置，这是通过4位拨码开关上的A2，A1和A0来完成的，其中A0表示地址的最后一位。拨码开关向上推时相应的位为1，向下推时相应的位为0。也就是说，如果将A2，A1，A0都拨到上方时，相应的地址为0&#215;57；而如果将A2，A1，A0都拨到下方时，相应的地址为0&#215;50。<br />
<img class="aligncenter" title="eeprom" src="http://image.flamingoeda.com/albums/userpics/febb_eeprom_2.JPG" alt="" width="230" height="173" /><br />
该存储模块上另外一个需要设置的地方就是开关RS，它是用来设置是否往I2C总线上的SDA和SCL上接入板载的上拉电阻。我们知道，I2C之所以被称为总线，就是因为可以连接多个I2C设备，接照I2C协议的规定，只允许在离控制器最近的一个I2C设备处接上拉电阻。说到这里你可能已经明白了，如果有多个这个的存储模块连接到Arduino的I2C总线上时，我们必须将第一个（离Arduino最近）存储模块的RS开关设置到ON的位置，而其它存储模块上的RS则不能设置到ON的位置：<br />
<img class="aligncenter" title="eeprom" src="http://image.flamingoeda.com/albums/userpics/febb_rtc_ds1307_2.JPG" alt="" width="230" height="173" /><br />
如果使用的是Arduino专用传感器扩展扩展板V4，注意IIC/COM跳线的位置要设置到IIC这一边，因为此时我们需要用到I2C连接方式：<br />
<img class="aligncenter" title="eeprom" src="http://image.flamingoeda.com/albums/userpics/febb_eeprom_3.JPG" alt="" width="230" height="173" /><br />
上述设置完成之后，我们只需要用I2C/COM连接线将EEPROM存储模块连接到传感器扩展板上就完成硬件的连接了：<br />
<img class="aligncenter" title="eeprom" src="http://image.flamingoeda.com/albums/userpics/febb_eeprom_4.JPG" alt="" width="460" height="345" /><br />
至于软件部分，Arduino的官方网站上提供了两个不错的链接：<a href="http://www.arduino.cc/playground/Code/I2CEEPROM">I2CEEPROM</a>和<a href="http://www.arduino.cc/playground/Code/TWIPROM">TWIPROM</a>，需要的话可以参考。下面是我们测试时所用的代码：</p>
<pre>#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;
#define EEPROM_ADDR 0x50           <span style="color: #7e7e7e;">// I2C Buss address of 24LC256 256K EEPROM</span>

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">begin</span>();                        <span style="color: #7e7e7e;">// join I2C bus (address optional for master)</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  <span style="color: #7e7e7e;">// TESTS FOR EACH FUNCTION BEGIN HERE</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Writing Test:"</span>);
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">int</span> i=0; i&lt;20; i++){            <span style="color: #7e7e7e;">// loop for first 20 slots</span>
    i2c_eeprom_write_byte(EEPROM_ADDR,i,i+65);   <span style="color: #7e7e7e;">// write address + 65 A or 97 a</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">". "</span>);
    <span style="color: #cc6600;">delay</span>(10);                         <span style="color: #7e7e7e;">// NEED THIS DELAY!</span>
  }
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">""</span>);
  <span style="color: #cc6600;">delay</span>(500);

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Reading Test:"</span>);
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">int</span> i=0; i&lt;20; i++){            <span style="color: #7e7e7e;">// loop for first 20 slots</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(i2c_eeprom_read_byte(EEPROM_ADDR, i),<span style="color: #006699;">BYTE</span>);
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">" "</span>);
  }

  <span style="color: #7e7e7e;">// setup for page tests . . .</span>
  <span style="color: #cc6600;">byte</span> PageData[30];                   <span style="color: #7e7e7e;">// array that will hold test data for a page</span>
  <span style="color: #cc6600;">byte</span> PageRead[30];                   <span style="color: #7e7e7e;">// array that will hold result of data for a page</span>
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">int</span> i=0; i&lt;30; i++){            <span style="color: #7e7e7e;">// zero both arrays for next test</span>
    PageData[i] = 0;
    PageRead[i] = 0;
  }
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">""</span>);
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">int</span> i=0; i&lt;30; i++) PageData[i] = i+33;  <span style="color: #7e7e7e;">// fill up array for next test char 33 = !</span>

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Writing Page Test:"</span>);
  i2c_eeprom_write_page(EEPROM_ADDR, 100, PageData, 28 ); <span style="color: #7e7e7e;">// 28 bytes/page is max</span>

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>(<span style="color: #006699;">"Reading Page Test:"</span>);
  i2c_eeprom_read_buffer( EEPROM_ADDR, 100, PageRead, 28);
  <span style="color: #cc6600;">for</span> (<span style="color: #cc6600;">int</span> i=0; i&lt;28; i++){
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(PageRead[i],<span style="color: #006699;">BYTE</span>);    <span style="color: #7e7e7e;">// display the array read</span>
    <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">" "</span>);
  }
}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{
}

<span style="color: #cc6600;">void</span> i2c_eeprom_write_byte( <span style="color: #cc6600;">int</span> deviceaddress, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> eeaddress, <span style="color: #cc6600;">byte</span> data )
{
  <span style="color: #cc6600;">int</span> rdata = data;
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(deviceaddress);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &gt;&gt; 8));    <span style="color: #7e7e7e;">// Address High Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &amp; 0xFF));  <span style="color: #7e7e7e;">// Address Low Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>(rdata);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
}

<span style="color: #7e7e7e;">// Address is a page address, 6-bit (63). More and end will wrap around</span>
<span style="color: #7e7e7e;">// But data can be maximum of 28 bytes, because the Wire library has a buffer of 32 bytes</span>
<span style="color: #cc6600;">void</span> i2c_eeprom_write_page( <span style="color: #cc6600;">int</span> deviceaddress, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> eeaddresspage, <span style="color: #cc6600;">byte</span>* data, <span style="color: #cc6600;">byte</span> length )
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(deviceaddress);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddresspage &gt;&gt; 8)); <span style="color: #7e7e7e;">// Address High Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddresspage &amp; 0xFF)); <span style="color: #7e7e7e;">// Address Low Byte</span>
  <span style="color: #cc6600;">byte</span> c;
  <span style="color: #cc6600;">for</span> ( c = 0; c &lt; length; c++)
    <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>(data[c]);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">delay</span>(10);                           <span style="color: #7e7e7e;">// need some delay</span>
}

<span style="color: #cc6600;">byte</span> i2c_eeprom_read_byte( <span style="color: #cc6600;">int</span> deviceaddress, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> eeaddress )
{
  <span style="color: #cc6600;">byte</span> rdata = 0xFF;
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(deviceaddress);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &gt;&gt; 8));    <span style="color: #7e7e7e;">// Address High Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &amp; 0xFF));  <span style="color: #7e7e7e;">// Address Low Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">requestFrom</span>(deviceaddress,1);
  <span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">available</span>()) rdata = <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">receive</span>();
  <span style="color: #cc6600;">return</span> rdata;
}

<span style="color: #7e7e7e;">// should not read more than 28 bytes at a time!</span>
<span style="color: #cc6600;">void</span> i2c_eeprom_read_buffer( <span style="color: #cc6600;">int</span> deviceaddress, <span style="color: #cc6600;">unsigned</span> <span style="color: #cc6600;">int</span> eeaddress, <span style="color: #cc6600;">byte</span> *buffer, <span style="color: #cc6600;">int</span> length )
{
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">beginTransmission</span>(deviceaddress);
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &gt;&gt; 8));    <span style="color: #7e7e7e;">// Address High Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">send</span>((<span style="color: #cc6600;">int</span>)(eeaddress &amp; 0xFF));  <span style="color: #7e7e7e;">// Address Low Byte</span>
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">endTransmission</span>();
  <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">requestFrom</span>(deviceaddress,length);
  <span style="color: #7e7e7e;">//int c = 0;</span>
  <span style="color: #cc6600;">for</span> ( <span style="color: #cc6600;">int</span> c = 0; c &lt; length; c++ )
    <span style="color: #cc6600;">if</span> (<span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">available</span>()) buffer[c] = <span style="color: #cc6600;">Wire</span>.<span style="color: #cc6600;">receive</span>();
}
</pre>
<p>上述代码运行时的效果如下图所示：</p>
<p><a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/febb_eeprom_5.jpg"><img class="aligncenter size-medium wp-image-620" title="febb_eeprom_5" src="http://blog.flamingoeda.com/wp-content/uploads/2010/07/febb_eeprom_5-260x300.jpg" alt="" width="260" height="300" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/07/18/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-eeprom-%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>电子积木 实时钟模块 RTC DS1307</title>
		<link>http://blog.flamingoeda.com/2010/07/16/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e5%ae%9e%e6%97%b6%e9%92%9f%e6%a8%a1%e5%9d%97-rtc-ds1307/</link>
		<comments>http://blog.flamingoeda.com/2010/07/16/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e5%ae%9e%e6%97%b6%e9%92%9f%e6%a8%a1%e5%9d%97-rtc-ds1307/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 15:45:25 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[DS1307]]></category>
		<category><![CDATA[RTC]]></category>
		<category><![CDATA[实时钟]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=607</guid>
		<description><![CDATA[实时钟通常也被称为实时时钟，它能够向电子电路提供日期和时间信息，包括年、月、日、时、分、秒，被广泛应用在需要进行计时的场合中。许多实时钟电路还提供电池供电的方式，这样在发生掉电时仍能准确计时。通常说来，功能稍多一点的实时钟电路还会提供包括警报、看门狗，以及支持高精度要求的校准寄存器等附加功能。 DS1307是DALLAS公司的一款实时种芯片，采用I2C协议与单片机通讯，而Arduino上正好有这一接口，因此连接起来就非常方便了。DS1307中有一个可编程波形输出口，它可以用来驱动LED小灯，或者作为中断来触发某些事件，不过用它去带一些大功率的东西的时候要注意。我们设计的这一款实时钟模块，将Ds1307的I2C接口和可编程波形输出接口SQW都连接出来了，不过一般情况下我们只会用到I2C接口来实现基本的时钟设置/读取功能。需要注意的是，该模块必须先安装上电池才可以正常工作。电池使用的是纽扣电池（型号CR1220），正极朝上： 在电路连接上我们可以使用Arduino专用传感器扩展板V4，不过要将相应的跳线设置到IIC的位置上： 剩下的工作就是用4芯的I2C/COM连接线将传感器扩展板上的专用接口，与实时钟模块上的IIC（I2C其实就是IIC的缩写）端口连接起来了： 硬件连接的工作完成之后，如何在Arduino里对该模块进行编程呢？上网搜索了一下，发现在Arduino上使用DS1307做为时钟芯片的玩家还真不少，而且还封装好了相应的Arduino库，实验时我使用的是Google Code上的这个DS1307库，你也可以在这里下载到我使用的版本。将下载好的压缩文件解压缩到Arduino 0018的libraries目录下后，重新启动Arduino并用它自带的测试程序进行测试： #include &#60;WProgram.h&#62; #include &#60;Wire.h&#62; #include &#60;DS1307.h&#62; // written by mattt on the Arduino forum and modified by D. Sjunnesson void setup() { Serial.begin(9600); RTC.stop(); RTC.set(DS1307_SEC,1); //set the seconds RTC.set(DS1307_MIN,23); //set the minutes RTC.set(DS1307_HR,12); //set the hours RTC.set(DS1307_DOW,4); //set the day of the week RTC.set(DS1307_DATE,15); //set the date RTC.set(DS1307_MTH,7); [...]]]></description>
			<content:encoded><![CDATA[<p>实时钟通常也被称为实时时钟，它能够向电子电路提供日期和时间信息，包括年、月、日、时、分、秒，被广泛应用在需要进行计时的场合中。许多实时钟电路还提供电池供电的方式，这样在发生掉电时仍能准确计时。通常说来，功能稍多一点的实时钟电路还会提供包括警报、看门狗，以及支持高精度要求的校准寄存器等附加功能。</p>
<p>DS1307是DALLAS公司的一款实时种芯片，采用I2C协议与单片机通讯，而Arduino上正好有这一接口，因此连接起来就非常方便了。DS1307中有一个可编程波形输出口，它可以用来驱动LED小灯，或者作为中断来触发某些事件，不过用它去带一些大功率的东西的时候要注意。我们设计的这一款实时钟模块，将Ds1307的I2C接口和可编程波形输出接口SQW都连接出来了，不过一般情况下我们只会用到I2C接口来实现基本的时钟设置/读取功能。需要注意的是，该模块必须先安装上电池才可以正常工作。电池使用的是纽扣电池（型号CR1220），正极朝上：</p>
<p><img class="aligncenter" title="rtc" src="http://image.flamingoeda.com/albums/userpics/febb_rtc_ds1307_1.JPG" alt="" width="460" height="345" /></p>
<p>在电路连接上我们可以使用Arduino专用传感器扩展板V4，不过要将相应的跳线设置到IIC的位置上：</p>
<p><img class="aligncenter" title="rtc" src="http://image.flamingoeda.com/albums/userpics/febb_rtc_ds1307_2.JPG" alt="" width="230" height="173" /></p>
<p>剩下的工作就是用4芯的I2C/COM连接线将传感器扩展板上的专用接口，与实时钟模块上的IIC（I2C其实就是IIC的缩写）端口连接起来了：</p>
<p><img class="aligncenter" title="rtc" src="http://image.flamingoeda.com/albums/userpics/febb_rtc_ds1307_3.JPG" alt="" width="460" height="345" /></p>
<p>硬件连接的工作完成之后，如何在Arduino里对该模块进行编程呢？上网搜索了一下，发现在Arduino上使用DS1307做为时钟芯片的玩家还真不少，而且还封装好了相应的Arduino库，实验时我使用的是<a href="http://code.google.com/p/ds1307/downloads/list">Google Code上的这个DS1307库</a>，你也可以<a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/DS1307.zip">在这里下载</a>到我使用的版本。将下载好的压缩文件解压缩到Arduino 0018的libraries目录下后，重新启动Arduino并用它自带的测试程序进行测试：</p>
<pre>#include &lt;<span style="color: #cc6600;">WProgram</span>.h&gt;
#include &lt;<span style="color: #cc6600;">Wire</span>.h&gt;
#include &lt;<span style="color: #cc6600;">DS1307</span>.h&gt; <span style="color: #7e7e7e;">// written by  mattt on the Arduino forum and modified by D. Sjunnesson</span>

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>setup</strong></span>()
{
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">begin</span>(9600);

  RTC.<span style="color: #cc6600;">stop</span>();
  RTC.set(DS1307_SEC,1);        <span style="color: #7e7e7e;">//set the seconds</span>
  RTC.set(DS1307_MIN,23);     <span style="color: #7e7e7e;">//set the minutes</span>
  RTC.set(DS1307_HR,12);       <span style="color: #7e7e7e;">//set the hours</span>
  RTC.set(DS1307_DOW,4);       <span style="color: #7e7e7e;">//set the day of the week</span>
  RTC.set(DS1307_DATE,15);       <span style="color: #7e7e7e;">//set the date</span>
  RTC.set(DS1307_MTH,7);        <span style="color: #7e7e7e;">//set the month</span>
  RTC.set(DS1307_YR,10);         <span style="color: #7e7e7e;">//set the year</span>
  RTC.start();

}

<span style="color: #cc6600;">void</span> <span style="color: #cc6600;"><strong>loop</strong></span>()
{

  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_HR,<span style="color: #cc6600;">true</span>)); <span style="color: #7e7e7e;">//read the hour and also update all the values by pushing in true</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">":"</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_MIN,<span style="color: #cc6600;">false</span>));<span style="color: #7e7e7e;">//read minutes without update (false)</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">":"</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_SEC,<span style="color: #cc6600;">false</span>));<span style="color: #7e7e7e;">//read seconds</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"      "</span>);                 <span style="color: #7e7e7e;">// some space for a more happy life</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_DATE,<span style="color: #cc6600;">false</span>));<span style="color: #7e7e7e;">//read date</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"/"</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_MTH,<span style="color: #cc6600;">false</span>));<span style="color: #7e7e7e;">//read month</span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(<span style="color: #006699;">"/"</span>);
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">print</span>(RTC.get(DS1307_YR,<span style="color: #cc6600;">false</span>)); <span style="color: #7e7e7e;">//read year </span>
  <span style="color: #cc6600;"><strong>Serial</strong></span>.<span style="color: #cc6600;">println</span>();

  <span style="color: #cc6600;">delay</span>(1000);
}
</pre>
<p>程序读起来应该不算困难，基本上就是使用RTC.set来对时钟进行设置，然后就可以通过RTC.get来读取相应的时间信息了，至于时钟怎么维护，那就是 DS1307 的工作了:)</p>
<p>将程序下载到Arduino里并运行起来之后，就可以通过串口监控窗口来查看相应的输出结果了：<br />
<a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/febb_rtc_ds1307_4.jpg"><img class="aligncenter size-medium wp-image-610" title="febb_rtc_ds1307_4" src="http://blog.flamingoeda.com/wp-content/uploads/2010/07/febb_rtc_ds1307_4-260x300.jpg" alt="" width="260" height="300" /></a>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/07/16/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e5%ae%9e%e6%97%b6%e9%92%9f%e6%a8%a1%e5%9d%97-rtc-ds1307/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>电子积木 无线数传模块 APC220</title>
		<link>http://blog.flamingoeda.com/2010/07/06/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e6%97%a0%e7%ba%bf%e6%95%b0%e4%bc%a0%e6%a8%a1%e5%9d%97-apc220/</link>
		<comments>http://blog.flamingoeda.com/2010/07/06/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e6%97%a0%e7%ba%bf%e6%95%b0%e4%bc%a0%e6%a8%a1%e5%9d%97-apc220/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 10:24:00 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[APC220]]></category>
		<category><![CDATA[无线]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=594</guid>
		<description><![CDATA[在使用APC220实现Arduino无线数据传输那篇文章里，我们介绍了如何使用APC220模块在PC和Arduino间实现无线数据传输。那时我们使用的是厂家提供的USB适配器。，由于这个适配器只能接APC220模块，而不能起到其它的作用，或多或少觉得有些浪费。更加重要的是，为此我们得提供两个不同的套件，一个给Arduino使用，一个给PC使用，两者之间不能实现互换。 正是基于上面的这些问题，我们针对电子积木系列开发了一款USB转串口的适配器Serial Dongle，使用它就可以通过PC机来连接和使用各种基于串口的电子积木模块了，比如这里介绍的无线数传模块APC220。 APC220模块的使用可以参考使用APC220实现Arduino无线数据传输那篇文章，两者间的唯一区别只在于如何对USB虚拟出来的串口进行设置，以便能够使用厂家提供的设置程序RF-ANET来对APC220的各个参数进行调整。首先我们将USB转串口适配器Serial Dongle连接到PC机上，然后从设备管理器中找到该串口，并打开其属性设置窗口： 点击Advanced按钮打开高级属性设置窗口，我们需要从Com Port Number列表中为Serial Dongle设置一个较小的COM号（如COM5），否则厂家给的设置程序会出现无法打开该串口的错识。另一个需要修改的地方是BM Options中的延时设置需要从16改为更小的值（如8）： 现在可以运行厂家给的设置程序了，此时特别需要注意的是操作顺序。应该先接好Serial Dongle，并将Serial Dongle右上角的开关拨到M的位置： 接着运行设置程序RF-ANET，最后再用连接线将APC220模块连接到Serial Dongle上，此时应该可以看到APC220设置程序窗口的最下面会显示Found device，表明APC220模块已经成功找到。如果设置程序没有找到APC220模块，可以试着断开APC220与Serial Dongle的连接，然后再次将APC220模块连接到SerialDongle上，直到设置程序成功找到APC220模块。 当APC220模块成功地被设置程序RF-ANET找到之后，我们就可以按照实际的需要来使用Serial Dongle对APC220模块进行各种参数配置了，而不再依赖厂家提供的USB适配器了;-) 至于随后的使用过程，那就完全一致了。一方面，我们可以将APC220模块通过4芯的串口连接线，与Arduino传感器扩展板相连接，这样Arduino就可以通过串口来操作APC220模块实现无线数据的收发： 另一方面，我们可以通过Serial Dongle连接APC220模块与电脑，并通过电脑的串口读写功能来操作APC220模块实现无线数据的收发： 下图就是利用两个APC220模块实现Arduino与电脑间无线数据传输的连接图：]]></description>
			<content:encoded><![CDATA[<p>在<a href="http://blog.flamingoeda.com/2009/06/14/%E4%BD%BF%E7%94%A8apc220%E5%AE%9E%E7%8E%B0arduino%E6%97%A0%E7%BA%BF%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93/" target="_blank">使用APC220实现Arduino无线数据传输</a>那篇文章里，我们介绍了如何使用APC220模块在PC和Arduino间实现无线数据传输。那时我们使用的是厂家提供的USB适配器。，由于这个适配器只能接APC220模块，而不能起到其它的作用，或多或少觉得有些浪费。更加重要的是，为此我们得提供两个不同的套件，一个给Arduino使用，一个给PC使用，两者之间不能实现互换。</p>
<p>正是基于上面的这些问题，我们针对电子积木系列开发了一款USB转串口的适配器Serial Dongle，使用它就可以通过PC机来连接和使用各种基于串口的电子积木模块了，比如这里介绍的无线数传模块APC220。</p>
<p><img class="aligncenter" title="APC220" src="http://image.flamingoeda.com/albums/userpics/febb_apc220_2.JPG" alt="" width="460" height="345" />APC220模块的使用可以参考<a href="../2009/06/14/%E4%BD%BF%E7%94%A8apc220%E5%AE%9E%E7%8E%B0arduino%E6%97%A0%E7%BA%BF%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93/" target="_blank">使用APC220实现Arduino无线数据传输</a>那篇文章，两者间的唯一区别只在于如何对USB虚拟出来的串口进行设置，以便能够使用厂家提供的设置程序RF-ANET来对APC220的各个参数进行调整。首先我们将USB转串口适配器Serial Dongle连接到PC机上，然后从设备管理器中找到该串口，并打开其属性设置窗口：</p>
<p><a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/2.jpg"><img class="aligncenter size-medium wp-image-595" title="2" src="http://blog.flamingoeda.com/wp-content/uploads/2010/07/2-277x300.jpg" alt="" width="277" height="300" /></a></p>
<p>点击Advanced按钮打开高级属性设置窗口，我们需要从Com Port Number列表中为Serial Dongle设置一个较小的COM号（如COM5），否则厂家给的设置程序会出现无法打开该串口的错识。另一个需要修改的地方是BM Options中的延时设置需要从16改为更小的值（如8）：</p>
<p><a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/3.jpg"><img class="aligncenter size-medium wp-image-596" title="3" src="http://blog.flamingoeda.com/wp-content/uploads/2010/07/3-300x214.jpg" alt="" width="300" height="214" /></a></p>
<p>现在可以运行厂家给的设置程序了，此时特别需要注意的是操作顺序。应该先接好Serial Dongle，并将Serial Dongle右上角的开关拨到M的位置：</p>
<p><img class="aligncenter" title="APC220" src="http://image.flamingoeda.com/albums/userpics/normal_febb_serial_dongle_1.JPG" alt="" width="399" height="295" /></p>
<p>接着运行设置程序RF-ANET，最后再用连接线将APC220模块连接到Serial Dongle上，此时应该可以看到APC220设置程序窗口的最下面会显示Found device，表明APC220模块已经成功找到。如果设置程序没有找到APC220模块，可以试着断开APC220与Serial Dongle的连接，然后再次将APC220模块连接到SerialDongle上，直到设置程序成功找到APC220模块。</p>
<p><a href="http://blog.flamingoeda.com/wp-content/uploads/2010/07/4.jpg"><img class="aligncenter size-medium wp-image-597" title="4" src="http://blog.flamingoeda.com/wp-content/uploads/2010/07/4-300x272.jpg" alt="" width="300" height="272" /></a></p>
<p>当APC220模块成功地被设置程序RF-ANET找到之后，我们就可以按照实际的需要来使用Serial Dongle对APC220模块进行各种参数配置了，而不再依赖厂家提供的USB适配器了;-)</p>
<p>至于随后的使用过程，那就完全一致了。一方面，我们可以将APC220模块通过4芯的串口连接线，与Arduino传感器扩展板相连接，这样Arduino就可以通过串口来操作APC220模块实现无线数据的收发：</p>
<p><img class="aligncenter" title="apc220" src="http://image.flamingoeda.com/albums/userpics/normal_febb_apc220_3.JPG" alt="" width="400" height="300" /></p>
<p>另一方面，我们可以通过Serial Dongle连接APC220模块与电脑，并通过电脑的串口读写功能来操作APC220模块实现无线数据的收发：</p>
<p><img class="aligncenter" title="apc220" src="http://image.flamingoeda.com/albums/userpics/normal_febb_serial_dongle_2.JPG" alt="" width="400" height="300" />下图就是利用两个APC220模块实现Arduino与电脑间无线数据传输的连接图：</p>
<p><img class="aligncenter" title="apc220" src="http://image.flamingoeda.com/albums/userpics/normal_febb_apc220_4.JPG" alt="" width="400" height="172" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2010/07/06/%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-%e6%97%a0%e7%ba%bf%e6%95%b0%e4%bc%a0%e6%a8%a1%e5%9d%97-apc220/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Arduino 电子积木 SD卡存储模块</title>
		<link>http://blog.flamingoeda.com/2009/12/25/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-sd%e5%8d%a1%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/</link>
		<comments>http://blog.flamingoeda.com/2009/12/25/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-sd%e5%8d%a1%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 16:08:30 +0000</pubDate>
		<dc:creator>flamingoeda</dc:creator>
				<category><![CDATA[Arduino]]></category>
		<category><![CDATA[电子积木]]></category>
		<category><![CDATA[SD卡]]></category>

		<guid isPermaLink="false">http://blog.flamingoeda.com/?p=549</guid>
		<description><![CDATA[SD卡是我们经常使用到的一种存储设备，像数码相机，MP3，阅读器，GPS导航仪等都会使用到它。在使用Arduino的时候，如何我们要将一些数据记录下来，就可以使用到SD卡。不过要让SD卡能够同Arduino配合使用可不是一件简单的事情，首先在硬件上我们要解决其与Arduino连接的问题，其次软件上我们还要解决文件的存储问题，以便使用读卡器之样的设备能够很方便地将保存在SD卡中的数据读出。 针对硬件上的需求，我们开发了SD卡模块，它通过SPI接口与Arduino进行通信： 同时，为了方便同Arduino的SPI接口进行连接，提供了相应的IDC扩展板，该扩展板上有一个专门为SPI设计的六芯插座： 电路的连接上则依然沿用了电子积木所一向强调的即插即用方式，我们只需要用6芯的IDC连接线，将IDC扩展板上的SPI插座与SD卡模块上的相应插座连接起来，就完成了电路部分的连接： 回到软件部分，我们的目标是要让SD卡上记录的数据能够在电脑上顺利地读出，因此在向SD卡上记录相应数据的时候需要遵循一定的规定，即文件系统的类型。对于像Arduino这样的小系统来讲，相对简单的FAT16是一个比较不错的选择。 在这里我们要用到读卡器来对SD卡进行相应的处理，将其格式化成FAT文件系统： Arduino上使用的软件则是基于SparkFun提供的FAT库，但根据硬件差异做了一定的修改，你可以从这里下载到修改过的FAT库。该库需要被解压缩到Arduino的hardware\libraries子目录中。 测试时使用的时FAT库里自带的示例程序： //Include all the libraries necessary for FAT32 #include &#60;byteordering.h&#62; #include &#60;fat.h&#62; #include &#60;FAT16.h&#62; #include &#60;fat_config.h&#62; #include &#60;partition.h&#62; #include &#60;partition_config.h&#62; #include &#60;sd-reader_config.h&#62; #include &#60;sd_raw.h&#62; #include &#60;sd_raw_config.h&#62; FAT TestFile; //This will be the file we manipulate in the sketch char buffer[512]; //Data will be temporarily stored to this buffer [...]]]></description>
			<content:encoded><![CDATA[<p>SD卡是我们经常使用到的一种存储设备，像数码相机，MP3，阅读器，GPS导航仪等都会使用到它。在使用Arduino的时候，如何我们要将一些数据记录下来，就可以使用到SD卡。不过要让SD卡能够同Arduino配合使用可不是一件简单的事情，首先在硬件上我们要解决其与Arduino连接的问题，其次软件上我们还要解决文件的存储问题，以便使用读卡器之样的设备能够很方便地将保存在SD卡中的数据读出。</p>
<p>针对硬件上的需求，我们开发了SD卡模块，它通过SPI接口与Arduino进行通信：<br />
<img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card.JPG" title="SD卡" class="aligncenter" width="460" height="345" /><br />
同时，为了方便同Arduino的SPI接口进行连接，提供了相应的IDC扩展板，该扩展板上有一个专门为SPI设计的六芯插座：<br />
<img alt="" src="http://image.flamingoeda.com/albums/userpics/arduino_shield_idc.JPG" title="SD卡" class="aligncenter" width="460" height="345" /><br />
电路的连接上则依然沿用了电子积木所一向强调的即插即用方式，我们只需要用6芯的IDC连接线，将IDC扩展板上的SPI插座与SD卡模块上的相应插座连接起来，就完成了电路部分的连接：<br />
<img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card_1.JPG" title="SD卡" class="aligncenter" width="460" height="345" /></p>
<p>回到软件部分，我们的目标是要让SD卡上记录的数据能够在电脑上顺利地读出，因此在向SD卡上记录相应数据的时候需要遵循一定的规定，即文件系统的类型。对于像Arduino这样的小系统来讲，相对简单的FAT16是一个比较不错的选择。</p>
<p>在这里我们要用到读卡器来对SD卡进行相应的处理，将其格式化成FAT文件系统：</p>
<p><img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card_2.JPG" title="SD卡" class="aligncenter" width="460" height="345" /><br />
<img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card_3.JPG" title="SD卡" class="aligncenter" width="460" height="345" /><br />
<img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card_4.JPG" title="SD卡" class="aligncenter" width="460" height="345" /></p>
<p>Arduino上使用的软件则是基于SparkFun提供的<a href="http://www.sparkfun.com/Code/FAT.zip">FAT库</a>，但根据硬件差异做了一定的修改，你可以从这里下载到<a href="http://blog.flamingoeda.com/wp-content/uploads/2009/12/FAT.zip">修改过的FAT库</a>。该库需要被解压缩到Arduino的hardware\libraries子目录中。</p>
<p>测试时使用的时FAT库里自带的示例程序：</p>
<pre>
<span style="color: #777755;">//Include all the libraries necessary for FAT32</span>
#include &lt;byteordering.h&gt;
#include &lt;fat.h&gt;
#include &lt;FAT16.h&gt;
#include &lt;fat_config.h&gt;
#include &lt;partition.h&gt;
#include &lt;partition_config.h&gt;
#include &lt;sd-reader_config.h&gt;
#include &lt;sd_raw.h&gt;
#include &lt;sd_raw_config.h&gt;

FAT TestFile;      <span style="color: #777755;">//This will be the file we manipulate in the sketch</span>
<span style="color: #996600;">char</span> buffer[512];  <span style="color: #777755;">//Data will be temporarily stored to this buffer before being written to the file</span>
<span style="color: #996600;">int</span> read_size=0;   <span style="color: #777755;">//Used as an indicator for how many characters are read from the file</span>
<span style="color: #996600;">int</span> count=0;       <span style="color: #777755;">//Miscellaneous variable</span>

<span style="color: #CC6600;">void</span> <span style="color: #993300;"><b>setup</b></span>()
{
  <span style="color: #996600;">Serial</span>.<span style="color: #996600;">begin</span>(9600);  <span style="color: #777755;">//Initiate serial communication at 9600 bps</span>

  TestFile.initialize();  <span style="color: #777755;">//Initialize the SD card and the FAT file system.</span>
  <span style="color: #996600;">Serial</span>.<span style="color: #996600;">println</span>(<span style="color: #CC0000;">"Starting..."</span>);
  TestFile.create_file(<span style="color: #CC0000;">"Sample.txt"</span>);  <span style="color: #777755;">//Create a file on the SD card named "Read_File_Test.txt"</span>
                                       <span style="color: #777755;">//NOTE: This function will return a 0 value if it was unable to create the file.</span>
  TestFile.open();  <span style="color: #777755;">//Now that the file has been created, open it so we can write to it.</span>
}

<span style="color: #CC6600;">void</span> <span style="color: #993300;"><b>loop</b></span>()
{
  TestFile.<span style="color: #996600;">write</span>(<span style="color: #CC0000;">"This is test data."</span>);  <span style="color: #777755;">//using the write function will always write to the beginning of the file. </span>
                                         <span style="color: #777755;">// Here we add some text to the file.</span>
  TestFile.close();  <span style="color: #777755;">//We are done writing to the file for now. Close it for later use.</span>

  <span style="color: #CC6600;">while</span>(1){
    TestFile.open();  <span style="color: #777755;">//Open the file. When the file is opened we will be looking at the beginning of the file.</span>
    read_size=TestFile.<span style="color: #996600;">read</span>(buffer); <span style="color: #777755;">//Read the contents of the file. This will only read the amount of data specified</span>
                                    <span style="color: #777755;">// by the size of 'buffer.'</span>

    <span style="color: #996600;">Serial</span>.<span style="color: #996600;">println</span>(read_size, <span style="color: #CC0000;">DEC</span>);  <span style="color: #777755;">//Print the number of characters read by the read function.</span>
    <span style="color: #CC6600;">for</span>(<span style="color: #996600;">int</span> i=0; i<read_size; i++)
    {
      <span style="color: #996600;">Serial</span>.<span style="color: #996600;">print</span>(buffer[i], <span style="color: #CC0000;">BYTE</span>);  <span style="color: #777755;">//Print out the contents of the buffer.</span>
    }
    <span style="color: #996600;">Serial</span>.<span style="color: #996600;">println</span>();

    sprintf(buffer, <span style="color: #CC0000;">"%d"</span>, count++); <span style="color: #777755;">//Now we'll use the buffer to write data back to the file. </span>
                                   <span style="color: #777755;">// Here's we'll only add one value to buffer, the 'count' variable. </span>
    TestFile.<span style="color: #996600;">write</span>(buffer);         <span style="color: #777755;">//Write the new buffer to the end of the file</span>
    TestFile.close();               <span style="color: #777755;">//Close the file for later use.</span>

    <span style="color: #996600;">delay</span>(1000);  <span style="color: #777755;">//Wait one second before repeating the loop.</span>
  }
}
</pre>
<p>这样Arduino在运行的时候，会不断地向SD卡模块上的Sample.txt文件中写入相应的数据，随后我们同样可以通过读卡器读出该文件中记录的内容。</p>
<p><img alt="" src="http://image.flamingoeda.com/albums/userpics/febb_sd_card_5.JPG" title="SD卡" class="aligncenter" width="460" height="345" /></p>
<p>需要注意的是，由于用来操作SD卡和文件系统的代码相对较多，目前该模块只能运行在带有ATmega328P的Arduino上面。另外，目前市场上可选的SD卡种类繁多，可能不是每种SD卡都能够被很好的兼容，目前我测试过通过的SD卡有：</p>
<ul>
<li>SanDisk 2GB SD2 Card</li>
<li>Apacer 60X 1GB SD Card</li>
</ul>
<p>测试没有通过的SD卡有：</p>
<ul>
<li>SanDisk 16MB SD Card</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.flamingoeda.com/2009/12/25/arduino-%e7%94%b5%e5%ad%90%e7%a7%af%e6%9c%a8-sd%e5%8d%a1%e5%ad%98%e5%82%a8%e6%a8%a1%e5%9d%97/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

