2008年12月19日 星期五
2008年12月14日 星期日
8051装上ZigBee的车轮,单片机进军无线大市场
一、 单片机的无线化和无线网络化大趋势
芯片巨人TI公司收购无线单片机的先锋CHIPCON公司后,推出了全新概念的新一代ZigBee无线单片机 CC2430/CC2431
系列和短距离通讯的新一代无线单片机CC2510/CC1110系列,这些以经典8051微处理器为内核无线单片机,也称“射频SoC(片上系统)”,以
其优异的无线性能,超低功耗,超低成本,在单片机技术领域,开创了单片机无线化和无线网络化的全新时代,采用这些新型无线单片机,进行无线通
讯,RFID,无线数传产品等产品设计,是开发低成本、低功耗单片机应用产品的非常理想方案。
以CC2430为代表的新一代射频SoC(片上系统)的特点是:
1 专门的设计,将全部的ZigBee/802.15.4 需要的高频部分电路全部集成到了电路内部,从无线单片机到天线之间,只有3-5个 0603的普通零件,系统设计者完成不必需要任何高频方面的经验;
2 采用特殊设计,使8051微处理器和高频线路间,实现完美的配合,数字电路对高频通讯的影响减低到最小(因为对于非常微小高频信号而言,8051就是一个很大的数字噪声源);
3
将高速8051微处理器,32K 到128K闪存,8k
SRAM多种外围电路,A/D,RTC和CC2420无线芯片等全部设计成一只非常小的芯片(48脚
7X7平方毫米大小),真正实现了单片机的无线化,微型化,使采用这类单片机的产品可以做成微型遥控器,信用卡一样薄的微型卡片,RFID长距离卡片,能
置入人体的微型传感器等等;
4 无线通讯中的需要的大量软件处理,包括纠错,防止空气中包装碰撞,IEEE
802.15.4标准通讯协议处理,网络路由,多种网络拓扑等等,都可以象“搭积木”一样,轻易放入无线单片机内部存储器中间去,由于CC2430这样的
新一代无线单片机具有较大的存储空间,以CC2430-F128 为例,如果将IEEE
802.15.4的协议软件放进去,大概只需要1/4存储空间,将完整ZigBee
无线网络协议栈放入进去,也只需要1/2空间,我们还有足够空间存储我们的应用代码;
5 功耗非常低,CC2430无线单片机待机是电流消耗仅0.2UA, 在32K晶体时钟下运行,电流消耗小于1UA; 使用小型电池寿命可以长达10年;
6
价格非常低: CC2430分别包括高速8051内核,ZigBee RF硬件部分,8K SRAM,128K/64K/32K
闪存,大量购买的分别是 4美元 到
2美元;而更加简化的CC2510/CC1100,价格会更低;从目前情况看,由于高频部分的硅成本非常低,加上非常大的生产数量,所以RF+MCU的总
体价格,可能会低于普通常见8051单片机的价格;
从以上的这些特点我们看到了单片机无线化,无线网络化的大趋势,对于准备学习使用无线技
术的广大单片机工程师和电子工程师而言,这是一个大好的消息,因为,从有线到无线的技术过渡中,将不再需要重新学习和熟悉单片机的结构/指令系统/编译开
发工具;而直接快速进入无线产品开发的实践中去;
二、 8051的单片机,装上802.15.4标准和ZigBee智慧
作为
8051兼容的无线单片机第一代产品的代表是chipcon 公司的cc1010, Nordic
公司的nRF24E1/nRF9E5。推出的时间是2004年;分别工作在300-1000mhz/2.4GHZ频道;价格在30-50人民币/每片左
右;这些无线单片机由于工作可靠,技术成熟,软件丰富,所以这几年获得了非常广泛的应用,对于一般的点到点,点到多点,无线数传,和各种类似无线键盘,无
线摇杆,简单遥控器,无线抄表等应用和学习无线通讯知识,教学实验等,直到今天应该仍然是很好的选择;
无线通讯(我们这里主要指短距离无线通讯和嵌入式无线通讯)的发展,需要将更多的节点通过无线联系起来,包括各种传感器网络,无线实时定位网络,射频识别网络,数字家庭网络,安全监视网络等等,这就需要解决两方面的问题:无线通讯的标准化和网络拓扑管理。
网
络标准化,通俗而言就是网络节点的互通性,各种不同功能的无线网络节点需要能相互交流,相互认识,举例而言,为来家庭中,各种家电将装有无线功能,汇集成
一个互通的无线网络,冰箱可能是日本的,电视是中国造,烟雾报警器可能来自美国,所有的家电通过无线汇集到家庭网关,必须要可以相互认识,才可以进行无线
数据通讯,这就需要一个所有制造厂家可以遵循的标准,目前这个标准就是IEEE 802.15.4, 一个专门针对这类应用的国际标准;
网
络拓扑管理,主要是建立在IEEE
802.15.4之上的网络层,包括各种网络的形态,无线网络节点可以象一个星状连接,也可以象一个葡萄串一样,串在一起,也可以象一张大网,相互连接,
相互间可以从任意节点间进行通讯;这就需要在网络层能相互兼容,这就有了ZigBee, ---- 一套标准化的网络层协议规范;
802.15.4标准和ZigBee网络,已经是当今世界的技术热点,你可以在网上发现数量巨大相关信息,也可以方便的学习到这方面知识;
实
现网络的标准化,管理越来越复杂的无线网络,需要有大量的软件代码来实现,也需要对无线通讯的技术的精通和大量的人力物力投入来进行开发,决非那家公司可
以独自包揽,自己来完成,所以
802.15.4标准和ZigBee网络实现的代码,都是由国际标准组织和ZigBee联盟这样的机构协助组织完成的,然后以软件库,源代码库的方式提供
给用户,由用户可以进行高层调用,用户加上自己的应用程序,固化到单片机中实现的;
而新一代无线单片机(象CC2430),就是具体了全部
802.15.4标准和ZigBee无线网络结构的8051单片机,当你用USB接口连接上cc2430仿真器,(好消息,这种仿真器目前已经有国产现货
了 )接上你的CC2430电路板,在IAR IDE调试环境上,装上 802.15.4标准和ZigBee网络现成软件项目文件(包括
802.15.4标准和ZigBee网络库文件,表演软件等),编译,下载,然后运行,几秒种的时间,敲几下按键,一切OK, 神奇无比的
802.15.4标准和ZigBee网络,(数万行C51语言写成的代码,组成的软件)就在你的弹指一挥间,被你驾驭了:
需要将节点加入无线网络吗?调用 “加入网络”功能就可以了;
需要传输数据吗?数据送送入指定的缓冲区,调用需要“发送数据”功能,你立刻会知道你的数据是否发送成功,无线信号强度是多少……
需
要将数据透过其他节点,向下跳棋一样,传输到远方的无线节点吗?指定节点的名字,准备好数据,调用“网状网络拓扑的数据传输”功能,数据就自动通过墙壁,
绕过天花板,从一楼到10楼,将数据自动传输到最远端的无线节点,同时,不到一秒时间,你可以得到回应“数据安全送到了!!”…
听起来好象不可能,但这正是802.15.4标准和ZigBee无线单片机带给你的,今天就可以在你手中实现的实实在在的现实场境;
面
对这样的场境,我们会感慨万千,这不正是电子工程师们多年来的“将一切用无线连接起来的”的梦想吗?在办公室,复印机坏了,这边你正着急,那边该公司的服
务人员已经赶到了现场,为什么这么快?复印机内的无线节点早就将故障的部分,维修需要的零件自动传输到了服务的公司;家里的地上管道漏水了,你并不在家,
但无线传感器迅速知道了情况,一边自动通知无线水表关闭进水阀门,一边发出短信,通知主人,这里出了什么问题……
802.15.4标准和ZigBee技术和8051无线单片机的结合,给单片机技术,带来了一场全新的革命,由此而产生的巨大市场和广泛的应用,是我们每个电子工程师都应该关注的;
三、 投身无线的大潮,你需要的“船”和“桥”
高频无线技术,单片机技术,C51编程,无线传感器技术,无线网络技术都属于实验技术和实用技术,具体的掌握这些技术,都需要实际的动手,通过编程序,实际调试,实际电路板,现场测试分析等,来真正了解技术的核心,来具备实际的经验;
基
本而言,你需要一套实际的系统,该系统可以在你的实验室,也可以在你家里,无论是化你老板的“银子”,还是你自己为未来进行技术投资而“自掏腰包”,这将
根据你的目标,实际起步的水平,而有很大的不同。当然,越是高级的系统,使用会越简单,但价格也会越不低;俗话说“舍不得孩子套不着狼”,如果你决心要尽
快掌握最先进的无线技术,化几千银子也是值得的事情;许多电子工程师/单片机工程师在熟悉8位单片及技术后,开始自己学习ARM等32位单片机技术,也自
己花费多达几千人民币购买ARM开发工具,在家建立自己的ARM开发平台;其实,从上面的讨论我们可以看出:从电子/单片机技术发展的眼光来,单片机从8
位到32位的的发展,主要是在运行速度上的量的改变,而单片机的无线化和无线网络化集成,才是单片机在质的方面的飞跃,如果讲到单片机工程师应该朝那方面
进一步发展的话,学无线比学ARM更重要,更紧迫;
从知识准备来讲,可以直接读无线单片机的各种数据手册,也可以看看有没有象《无线通讯的
入门和实战》这样类似的无线通俗读物,可惜目前这类实用的无线书籍太少了,希望我们的大学教授们,多出一些实用的书籍,目前书店的无线类书籍大多是理论,
各种复杂的计算公式,让人看起来非常吃力。但如何去象开发单片机一样,实实在在的做程序,做电路板,去调试。测试,最后做一个实际的无线产品,在这些书籍
中很难发现,而这才是我们电子工程师最需要的东西;
从硬件上讲,建立这个实验室需要的必须条件是:
1 一台PC机
能运行WINDOWS XP,任何中文/英文板本,
40G以上的硬盘,普通光盘驱动器,USB口,速度800M以上就可以工作;
不必很新的电脑,一台旧电脑工作也没有问题;
2 一台C51RF-3型cc2430无线单片机开发系统
这
也是目前是市面上唯一可以买到地地道道的高质量国产货(通过www.c51rf.com你可以立即买到现货),在今天这个信息时代,无线开发系统也不再只
是“老外”们的专利,地处西部的成都无线龙通讯公司,在CC2430芯片实际上市之日,同步完成了全部开发系统的设计工作,而且同时提供全部
802.15.4标准和ZigBee网络库文件/C51源代码,价格低于国外同类产品;
你只要将开发系统C51RF-3实时在线仿真器通过
USB接口直接连接到你的电脑,同时,通过10线仿真电缆连接到CC2430ZigBee无线单片及目标板,(无线龙C51RF-3开发系统随开发系统提
供了两个经过全部高频测试的CC2430无线目标模块)就方便的完成了连接;无需其他的直流电源;
3 IAR 7.20 以上C51开发环境
该开发平台非常类似KELL的开发平台,如果你熟悉KELL的C51开发平台,你应该非常容易去使用和非常喜欢这个功能强大的类似的IDE/DEBUG平台;
4 一个万用表
当
你完成连接后,你已经拥有了自己的无线网络产品开发平台,采用这个平台,你可以在家使用cc2430系列ZigBee
无线单片机(如果你选择c51rf-3)开发许多带有无线网络功能的无线产品;你完全不用去考虑这是工作在2.4Ghz的高频产品,只要你会8051,你
就可以在这个无线平台上,自由飞翔,开发你希望的无线产品;采用这个低价格的开发系统,你照样可以开发出国外在价值几十万的无线网络实验室里开发的,同样
功能的高级无线通讯产品;
当然,这只是一个基本的平台,如果你有条件,你可以选择下面的配备:
5 Protel 99等电路板设计软件,设计你自己的电路板;
6 一台示波器,观查微处理器的低频数字信号;
7
低成本的C51RF-3-F型ZigBee/802.15.4无线协议分析仪器,该协议分析仪和国外专业ZigBee/802.15.4无线协议分析仪器
相同,采用USB高速连接PC,可以方便/快捷观察在空气中间传输的无线数据包装,使你的无线网络调试/测试更加方便,而价格只有国外同类产品的1
/10。
2008年12月12日 星期五
8051卡拉OK
引言
在当今这样一个充满竞争与挑战的社会,人们的生活显得日益紧张而繁忙,同时也对休闲娱乐的要求越来越高。卡拉OK作为一种休闲娱乐项目一直备受人们青睐。但人们在唱歌时往往被局限于狭小的卡拉OK厅内,行动、思维、灵感上都大大受到影响,无法最佳发挥。针对这种现状,我们设计出一种基于U盘存储的体积小巧的移动卡拉OK系统。用户可以在精心设计的环境中随心所欲地引吭高歌,充分展示自己的激情与灵感,使人与音乐达到完美结合。
系统硬件实现
本系统以AT
| |
歌曲播放部分设计
歌曲播放部分主要实现歌曲播放与麦克风输入,即实现音乐与用户歌声的融合,是系统的核心部分。本系统采用AT
LM4832是具有I
值得注意的是:在整个音频功放实现过程中,要合理分配每级电路的增益,以免音频信号失真。 LCD实时显示部分设计
LCD用于实时歌词和状态显示。由于Windows 系统自带的字库有267K之多,因此选用容量为512K的Flash W
U盘设计部分
歌曲的存放与更新采用USB接口。存储器大小可以自选,作为代表性实验,本系统采用
| |
系统软件设计
系统软件主要包括歌曲播放和USB通信程序。系统上电后,根据P3_4口判断当前所处的状态而分别执行相应的程序代码。 歌曲播放软件设计
歌曲播放器程序要与键盘和LCD配合起来设计。程序流程大概可分为:硬件初始化→获取U盘中mp3歌曲列表→歌曲播放和LCD显示。
硬件初始化主要负责mp3解码器的时钟设置、Flash复位和LM4832的初始化,这是系统正常工作的关键。LM4832上电时,其声道音量和麦克风音量均为无声状态,表1为左声道的I
获取U盘中的mp3歌曲列表通过查找U盘根目录区中每个目录项来实现,同时将歌曲数目通过串口发送给LCD显示从处理器。
| |
歌曲播放和LCD显示是程序的核心部分。主处理器和LCD从处理器之间通过串口进行通信,以达到歌曲播放与歌词显示的同步以及键盘操作状态的及时刷新。其程序流程图如图3所示。
| |
MP3解码器一旦开始工作,就会一直向 CPU请求数据,直至歌曲结束。只有用键盘操作才能中断CPU。键盘操作总共4个按键(Menu/Previous/Next/Play)。Menu负责功能切换,共有5项功能:歌曲音量控制、高音调节、低音调节、麦克风音量控制和歌曲选择。在不同功能下Previous和Next分别代表不同的含义。在音量控制上为加/减音量,在歌曲选择上为上一首/下一首歌曲。LCD在显示歌词的同时实时显示键盘操作状态,以便用户操作。
USB海量存储设计
主处理器让USB海量存储设备在批量传输方式下工作,这样共需要3个端点。
0端点:控制端点。用于控制传输,PC机通过与端点0相对应的管道来读取设备描述符,完成对设备地址的设置,并完成配置。此端点为双向数据传输端点。
两个非0端点:批量传输端点。这种端点为单向数据传输端点,分别为批量输入端点和批量输出端点。
主处理器通过一个端点中断寄存器(UEPINT)和PC机通信。如果某个端点完成了相应的操作,就会引发中断。U盘主程序流程图如图4所示。
| |
当USB设备插入到PC机时,PC机一旦检测到设备后,就会通过控制管道向默认地址发送USB标准请求,进入设备配置阶段,即PC机向设备索取各种描述符的过程,如Get Descriptor、Set Address、Set Configuration等。每当设备收到主机发送的数据后,便会触发端点中断寄存器中端点0所代表的位。此时,应读取端点0的数据缓冲区,对照USB标准设备请求的数据格式,对请求类型进行识别,然后转向相应的标准请求处理函数。配置完成后,主机便使用在描述符中所选定的命令块向批量传输端点发送控制消息和数据。
在批量传输方式下,有3种类型的数据在USB和设备之间传送:CBW、CSW和普通数据。因此,批量传输阶段程序设计的任务就是要识别来自批量输出端点的CBW与数据,进行相应的处理,然后通过批量输入端点向主机回传相应的CSW或数据。PC机依次向设备发出Inquiry、Read Capacity、UFI Mode Sense、Read Format Capacity等请求,这几个命令用于告知PC这个设备的存储器情况,PC基于此创建一个存储器设备,即在浏览器中生成一个移动盘符,并可以复制、删除或创建文件等。系统自动将这些命令都转换成Read或Write两种命令,通过USB的READ或WRITE命令块描述符从Flash中相应扇区读取数据,或是将特定长度的数据写入Flash相应簇中。文件在U盘中按Fat16协议存储。由于PC对存储器的读写是按扇区(512字节/扇区)为最小单位进行的,但Bulk端点的最大传输能力为64字节。因此,主机读写操作的数据传输过程要分多次才能完成。而写操作比读操作更加繁琐一些,这是因为Flash在对某扇区进行写之前,必须要将其擦除,而擦之前存在已有数据的保存问题。为了加快主机与U盘之间数据传输率,读写操作的代码改用汇编来编写。测试表明,U盘的读写速度可达到450Kbps。
结束语
2008年12月10日 星期三
Excel 趨勢線的公式
Excel 趨勢線的公式
Linear Trendline
Equation: y = m * x + b
m: =SLOPE(y,x)
b: =INTERCEPT(y,x)
Logarithmic Trendline
Equation: y = (c * LN(x)) - b
c: =INDEX(LINEST(y,LN(x)),1)
b: =INDEX(LINEST(y,LN(x)),1,2)
Power Trendline
Equation: y=c*x^b
c: =EXP(INDEX(LINEST(LN(y),LN(x),,),1,2))
b: =INDEX(LINEST(LN(y),LN(x),,),1)
Exponential Trendline
Equation: y = c *e ^(b * x)
c: =EXP(INDEX(LINEST(LN(y),x),1,2))
b: =INDEX(LINEST(LN(y),x),1)
2nd Order Polynomial Trendline
Equation: y = (c2 * x^2) + (c1 * x ^1) + b
c2: =INDEX(LINEST(y,x^{1,2}),1)
C1: =INDEX(LINEST(y,x^{1,2}),1,2)
b = =INDEX(LINEST(y,x^{1,2}),1,3)
3rd Order Polynomial Trendline
Equation: y = (c3 * x^3) + (c2 * x^2) + (c1 * x^1) + b
c3: =INDEX(LINEST(y,x^{1,2,3}),1)
c2: =INDEX(LINEST(y,x^{1,2,3}),1,2)
C1: =INDEX(LINEST(y,x^{1,2,3}),1,3)
b: =INDEX(LINEST(y,x^{1,2,3}),1,4)
2008年12月5日 星期五
2008年12月4日 星期四
2008年12月3日 星期三
2008年11月17日 星期一
2008年11月13日 星期四
2008年11月12日 星期三
Arduino扩展板使用之RS485接口篇
RS485采用差分信号负逻辑,+2V~+6V表示“0”,- 6V~-
2V表示“1”。RS485有两线制和四线制两种接线,四线制只能实现点对点的通信方式,现很少采用,现在多采用的是两线制接线方式,这种接线方式为总线
式拓朴结构在同一总线上最多可以挂接32个结点。在RS485通信网络中一般采用的是主从通信方式,即一个主机带多个从机。很多情况下,连接RS-485
通信链路时只是简单地用一对双绞线将各个接口的“A”、“B”端连接起来。其理论的通讯距离是1200米,速率高达20Mbps,并可以用在强噪声的环境
中正常工作,在工业通讯领域中被广泛应用。
RS485通讯的点对点接法和主从机接法如下图:
以上2种接法建议都接上地线,以保证减小干扰。在主从网络中,通讯线必须手牵手地并联下去,不可以有星型连接或者分叉。
RS485协议只是把TTL的串口转换成差分方式的通讯接口,485芯片的端口还是接到Arduino的RX(PIN0)和TX(PIN1)端,两线制的
RS485是属于半双工网络,则需要有个端口来控制AB差分线上何时收何时发,这就会用到Arduino上的PIN2。Arduino扩展板上需要插上
485接口选择插针,红圈处的3个插针都要插上:
完成上面的操作,我们就可以玩代码了,2个简单的代码:
主机代码:
int EN = 2;
void setup()
{
pinMode(EN, OUTPUT);
Serial.begin(19200);
}
void loop()
{
// send data
digitalWrite(EN, HIGH);//使能发送
Serial.print('A');
delay(1000);
}
从机代码:
int ledPin = 13;
int EN = 2;
int val;
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(EN, OUTPUT);
Serial.begin(19200);
}
void loop()
{
// receive data
digitalWrite(EN, LOW);//使能接收
val = Serial.read();
if (-1 != val) {
if ('A' == val) {
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
}
}
}
代码编译后,分别下载到2个Arduino中(下载代码时请拔掉上图所示的485接口选择插针,因为它要占用串口,导致
下载失败),然后连接2个扩展板上的485接口,A-A,B-B,GND-GND。主机Arduino模块会向从机不停的发送字母A,然后从机接收到字母
A,并使数字PIN13上的发光二极管闪烁。
DS18B20
/* ds18B20_test<br /><br /> Test utility to configure resolution and read temp from the Dallas Semi 18B20 <br /> one-wire digital temp sensor.<br /> <br /> datasheet: http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf<br /><br /> Derived from sample code at http://www.arduino.cc/playground/Learning/OneWire<br /><br />*/<br /><br />#include <OneWire.h><br /><br />#define BAUDRATE 9600<br />#define TEMPSENSOR 3 // arduino i/o port connected to the ds18B20<br />//#define DEBUG // uncomment for verbose output<br /><br />/* some defines to make more legible checks into data read from the device <br /> * (see the DS18B20 datasheet for more detail)<br /> */ <br />#define TEMP_LSB 0<br />#define TEMP_MSB 1<br />#define TH_REG 2<br />#define USERBYTE_1 2<br />#define TL_REG 3<br />#define USERBYTE_2 3<br />#define CONFIG_REG 4<br />#define CRC 8<br /><br />OneWire ds(TEMPSENSOR); <br /><br />void setup() {<br /> Serial.begin(BAUDRATE);<br />}<br /><br />/* convert celsius to fahrenheit<br /> *<br /> * takes: float<br /> * returns: float<br /> */<br />float c2f(float cel) {<br /> return (cel * (9.0/5.0)) + (float)32;<br />}<br /><br />/* read temp from DS18B20 sensor using one-wire protocol */<br />void loop() {<br /><br /> byte i;<br /> byte present = 0;<br /> byte data[12];<br /> byte addr[8];<br /><br /> int temp_c_int;<br /> float temp_c_frac;<br /> float temp_c;<br /> float temp_f;<br /> int test_bit;<br /> int set_bit;<br /> int resolution_floor;<br /> float expon;<br /> <br /> if ( !ds.search(addr)) {<br /> ds.reset_search();<br /> return;<br /> }<br /><br /> /* print the address - might be useful for non-debug mode if you have<br /> * >1 devices on the bus<br /> */<br />#ifdef DEBUG<br /> Serial.print("R=");<br /> for( i = 0; i < 8; i++) {<br /> Serial.print(addr[i], HEX);<br /> Serial.print(" ");<br /> }<br />#endif<br /><br /> if ( OneWire::crc8( addr, 7) != addr[7]) {<br /> Serial.print("CRC is not valid!\n");<br /> return;<br /> }<br /><br /> if ( addr[0] != 0x28) {<br /> Serial.print("Device is not a DS18B20 family device.\n");<br /> return;<br /> }<br /><br /> /* modify scratchpad register to set temp sampling resolution */<br /> ds.reset();<br /> ds.select(addr); <br /> ds.write(0x4E); // write scratchpad (starts at byte 2)<br /> // note: set high/low temp alarms by changing the next two values <br /> ds.write(0x4B); // default value of TH reg (user byte 1)<br /> ds.write(0x46); // default value of TL reg (user byte 2)<br /> // uncomment one of the following<br /> //ds.write(0x7F); // 12-bit sampling resolution (default)<br /> //ds.write(0x5F); // 11-bit<br /> //ds.write(0x3F); // 10-bit<br /> ds.write(0x1F); // 9-bit<br /><br /> ds.reset();<br /> ds.select(addr);<br /> ds.write(0x44,1); // start conversion, with parasite power on at the end<br /><br /> delay(1000); // maybe 750ms is enough, maybe not<br /> // we might do a ds.depower() here, but the reset will take care of it.<br /><br /> present = ds.reset();<br /> ds.select(addr); <br /> ds.write(0xBE); // Read Scratchpad<br /><br /> if (!present) {<br /> Serial.print("ERROR: selected device not present\n");<br /> return;<br /> }<br /> <br /> for ( i = 0; i < 9; i++) { // we need 9 bytes<br /> data[i] = ds.read();<br />#ifdef DEBUG<br /> Serial.print(data[i], HEX);<br /> Serial.print(" ");<br />#endif<br /> }<br /><br /> if (data[8] != OneWire::crc8(data,8)) {<br /> Serial.print("ERROR: CRC didn't match\n");<br /> return;<br /> }<br /> <br /> /* print raw bytes from which we'll extract temp data */<br />#ifdef DEBUG <br /> Serial.print("[MSB:");<br /> Serial.print(data[TEMP_MSB],BIN);<br /> Serial.print(" LSB:");<br /> Serial.print(data[TEMP_LSB],BIN);<br /> Serial.print("] ");<br />#endif<br /> <br /> /* compute the degrees in celcius / integer part */<br /> temp_c_int = 0;<br /> <br /> /* The measured temp is spread across two bytes of the returned data.<br /> * The integer part of the temp value is spread across the least 3 significant<br /> * bits of the most significant byte (MSB) and the most significant 4 of <br /> * the LSB. Here we shift those 7 bits into their proper place in our<br /> * result byte. <br /> *<br /> * note: could do this with 2 bit-shift / mask operations, alternatively<br /> */<br /> set_bit = 6;<br /> for (test_bit = 2; test_bit >= 0; test_bit--) {<br /> temp_c_int |= ( ((data[TEMP_MSB] & (1 << test_bit)) >> test_bit) << set_bit );<br /> set_bit--;<br /> }<br /> for (test_bit = 7; test_bit >= 4; test_bit--) {<br /> temp_c_int |= ( ((data[TEMP_LSB] & (1 << test_bit)) >> test_bit) << set_bit );<br /> set_bit--;<br /> }<br /><br />#ifdef DEBUG<br /> Serial.print(temp_c_int,DEC);<br />#endif<br /><br /> /* compute the fractional part */<br /><br /> /* first figure out what resolution we're measuring in - varies between 1 and 4 bits<br /> * after the decimal (based on the contents of the CONFIG_REG byte):<br /> * bit 6 == 0 && bit 5 == 0 --> 9-bit resolution (ignore 3 least sig bits)<br /> * bit 6 == 0 && bit 5 == 1 --> 10-bit resolution (ignore 2 least sig bits)<br /> * bit 6 == 1 && bit 5 == 0 --> 11-bit resolution (ignore 1 least sig bits)<br /> * bit 6 == 1 && bit 5 == 1 --> 12-bit resolution <br /> */<br /> if ((data[CONFIG_REG] & (1 << 5)) > 0) { <br /> if ((data[CONFIG_REG] & (1 << 4)) > 0) { // bits 6 and 5 are set<br /> resolution_floor = 0;<br /> } else { // bit 6 is set, 5 is clear<br /> resolution_floor = 1;<br /> }<br /> } else {<br /> if ((data[CONFIG_REG] & (1 << 4)) > 0) { // bits 6 is clear, 5 is set<br /> resolution_floor = 2;<br /> } else { // bit 6 and 5 are clear<br /> resolution_floor = 3;<br /> }<br /> } <br /><br /> temp_c_frac = 0;<br /> for (test_bit = 3; test_bit >= resolution_floor; test_bit--) {<br /> if ((data[TEMP_LSB] & (1 << test_bit)) > 0) {<br /> expon = test_bit - 4; // will be negative<br /> temp_c_frac += pow(2,expon);<br /> }<br /> }<br />#ifdef DEBUG<br /> Serial.print(" ");<br /> Serial.print(temp_c_frac * 10000,DEC);<br />#endif<br /><br /> /* put it all together */<br /> temp_c = (float)temp_c_int + temp_c_frac; <br /><br /> if ((data[TEMP_MSB] & (1 << 7)) > 0) { // the temp is negative<br /> temp_c *= -1;<br /> }<br /><br /> temp_f = c2f(temp_c);<br /> <br /> Serial.print(" Cx10k=");<br /> Serial.print(temp_c * 10000,DEC); // Serial.print truncates after the decimal pt<br /> Serial.print(" Fx10k=");<br /> Serial.print(temp_f * 10000,DEC);<br /> <br /> Serial.print("\n"); <br />}<br />2008年11月10日 星期一
presice timing with arduino
int analogPin = 3; // potentiometer wiper (middle terminal) connected to analog pin 3
// outside leads to ground and +5V
int val = 0; // variable to store the value read
int sta = 0; // sta 0 =low 1 = high;
int counter = 0 ; // conter
int time = 0 ;
int i = 1;
int ii = 0;
int sample = 50;
void setup()
{
Serial.begin(115200); // setup serial
}
void loop()
{
// Serial.print(i);
val = analogRead(analogPin); // read the input pin
if (val >= 400){
if((i-ii) >= 5){
// Serial.print(" ");
// Serial.print(val); // debug value
ii = i ;
counter++ ;
}
// sta = 1;
}else{
// Serial.println(10);
// sta = 0;
// delay(1000); 1 sec
}
//Serial.println();
delay(50); // delay 0.05 sec
if (i >= 400) { // passs 20 sec;
time = counter * 3 ;
Serial.println(time);
i = 1;
ii = 1;
counter = 0;
}
i++;
}
2008年11月9日 星期日
Arduino Pulse Width Modulation
The digital pins on the Arduino board can be set (with code) to
output either HIGH (5V) or LOW (0V) — essentially ON or OFF. This is
great for applications like blinking LEDs or activating relays.
But what if we wanted an output voltage somewhere in between 0V and 5V? This might be useful in applications like controlling the speed of a DC motor, or “dimming” an LED.
Well, the digital pins cannot directly produce an analog voltage; as
we’ve said, they’re either HIGH or LOW. But it turns out we can simulate these “in-between” voltages using a technique called Pulse Width Modulation, or PWM.
First off, don’t panic. PWM sounds complicated, but as
we’ll see, the concept is very simple, and the implementation is even
easier, especially on the Arduino.
Let’s say we want to make an LED shine with half of its normal
intensity when supplied with 5 volts. Since we can’t use the Arduino’s
digital pins to directly supply 2.5V, we’ll “pulse” the
output pin on and off — really fast. You may have noticed this effect
when you played with the Arduino’s “Blink” sketch. If you blink an LED
fast enough — that is, if the delay between blinks is short enough — the LED will appear to be lit continuously, but just a little bit dimmer than it was originally.
It’s easy to visualize this concept using the graphs below. When you
plot voltage over time, you can see that the pin is pulsing between
HIGH and LOW at regular intervals. Since this on-off pulsing is
happening so quickly, the connected LED will “see” the result as a 50%
reduction in the normal voltage (in this example), and will glow at
roughly half its normal intensity.
We can vary the output voltage percentage (the “effective voltage”)
by regulating — or “modulating” — the width of the pulse. For example,
if we make the HIGH pulse 25% as “wide” (in time) as the LOW pulse, the
LED will appear to glow with 25% intensity.
“Okay, great,” you’re saying, “But how do I do this on the Arduino?”
Well, there are a couple of ways. First, you could write a sketch that
blinks the LED between HIGH and LOW really fast, as we discussed above.
However, this approach requires the full attention of the Arduino all
the time; that is, if you want the Arduino to do anything else, you’ll
be interrupting the pulse loop.
Luckily, the Arduino designers have already solved this problem for us with three dedicated pins and the analogWrite() command.
Notice on the Arduino board there are three digital pins (9-11)
which are labeled PWM. Devices (like LEDs) connected to these pins can
employ continuous pulse width modulation using only the analogWrite() command like so:
- /*
- * A simple PWM example
- */
- int pin = 11; // LED connected to PWM pin 11
- int pulsewidth = 127; // Any value between 0 and 255
- void setup() {
- // None required for analogWrite!
- }
- void loop() {
- analogWrite(pin, pulsewidth);
- }
/*
* A simple PWM example
*/
int pin = 11; // LED connected to PWM pin 11
int pulsewidth = 127; // Any value between 0 and 255
void setup() {
// None required for analogWrite!
}
void loop() {
analogWrite(pin, pulsewidth);
}
The example above should cause the connected LED to glow at about
50% intensity (255/2 = 127ish). Play around with the value of the pulsewidth variable and note the changes in LED brightness.
Now, let’s take this concept one step further. What if we varied the effective voltage to the LED over time? If we could devise a way to “fade” the pulsewidth
from zero to 255 and back again, then the LED would pulsate, as in the
video above. Here’s the code for that, using three LEDs this time,
connected to pins 9-11:
- /*
- * Pulsating LEDs with Pulse Width Modulation
- */
- int green = 11; // Digital pin 11 - Green LED
- int red = 10; // Digital pin 10 - Red LED
- int blue = 9; // Digital pin 9 - Blue LED
- int time = 5; // define delay element
- int pulsewidth; // define pulsewidth (0-255)
- void setup() {
- // None required for analogWrite!
- }
- void loop() {
- // slowly fade the LEDs to full brightness
- for (pulsewidth=0; pulsewidth <= 255; pulsewidth++){
- analogWrite(green, pulsewidth);
- analogWrite(red, pulsewidth);
- analogWrite(blue, pulsewidth);
- delay(time);
- }
- // slowly dim the LEDs
- for (pulsewidth=255; pulsewidth >= 0; pulsewidth--){
- analogWrite(green, pulsewidth);
- analogWrite(red, pulsewidth);
- analogWrite(blue, pulsewidth);
- delay(time);
- }
- }
/*
* Pulsating LEDs with Pulse Width Modulation
*/
int green = 11; // Digital pin 11 - Green LED
int red = 10; // Digital pin 10 - Red LED
int blue = 9; // Digital pin 9 - Blue LED
int time = 5; // define delay element
int pulsewidth; // define pulsewidth (0-255)
void setup() {
// None required for analogWrite!
}
void loop() {
// slowly fade the LEDs to full brightness
for (pulsewidth=0; pulsewidth <= 255; pulsewidth++){
analogWrite(green, pulsewidth);
analogWrite(red, pulsewidth);
analogWrite(blue, pulsewidth);
delay(time);
}
// slowly dim the LEDs
for (pulsewidth=255; pulsewidth >= 0; pulsewidth--){
analogWrite(green, pulsewidth);
analogWrite(red, pulsewidth);
analogWrite(blue, pulsewidth);
delay(time);
}
}