玩LM3S8962有一段时间了,感觉很爽,但也没有写出很好的资料出来,因为研究别人写好的实验程序,别人也把研究资料也几乎写光写烂了,所以更多的时候是参考,自己再总结,遇到需要做笔记的地方再记下来,所以真的总结的也不多。但是,不多不代表不认真和没有效果,前不久,从拿到美信气象站开始,就已经动心了,正好可以两者结合做一个的项目,融会贯通检验自己。物尽其用,不能陈列在橱窗里当摆设。
一、研究目的:
①通过TI公司的LM3S8962开发板和控制MAXIM气象仪;
②实现读写基于1-Wire总线器件和板载OLED液晶实时显示功能;
③完成1-Wire通讯协议研究,弄清楚1-Wire总线到底是怎么一回事;
④完成相关资料整理;
⑤总结并检验前阶段学习效果。
二、研究器材:
①TI公司的LM3S8962开发板;
②基于1-Wire总线结构的MAXIM气象仪,包括:
DS1820(温度计)、DS2450(4通道A/D转换器(ADC))、DS2423(带外部计数器的4Kb非易失RAM存储器);
三,原理阐述:
说实话,LM3S8962的资料多的是看不过来,网上一大堆,精华很多。但是美信的这个气象仪,可能由于时间太过久远的原因,或者当时推广的力度不够?反正资料是那个相当难收集。一开始,除了气象仪和它包装上的一些说明,什么也没有,网上论坛上也找过,也不多。拆开来,才能知道板上到底有些什么,连原理图都没有。花了将近一个星期的时间,认真的收集了些资料,慢慢的才明了起来,拨开这气象仪的神秘面纱。
没有原理图什么都白搭,网上有部分不全的资料,是这个气象仪的一部分,通过参考、往美信网站上扒再自己核对PCB走线,大概搞清楚了气象仪的整个的原理图。
这是我自己总结的气象仪原理图,正确率96%以上吧,方便大家学习,少走弯路:
1)这是测风向部分电路(原理和气象仪一样,实际走线稍有不同,不影响理解)
DS2450是一个四通道的AD转换器,右边八个干簧管在磁铁通过时会搭在一起而导通由此造成电压的改变被DS2450检测。
当某一个干簧管上方正好正好有磁铁时,电路导通,AD采样为0V。
当某一个干簧管上方没有磁铁时,电路断,AD采样为5V。
当磁铁位于两个管之间时,会出现电阻并联的情况,AD采样为3.3V或2.5V。
下图是四个通道的采样表:
需要说明的是,采样电压与你电路上的最大电压有关,如果你最大电压为4V,则你采样到的电压可能值会有4V、2V、2.6V、0V。
在这个美信气象仪中,由于只有数据线DQ与地线GND两条线,所以采样的时候电压值达不到5V,根据我实测的结果,最大电压为4V左右,因此各种情况的采样所得电压都会据此调整。
2)测风速电路原理
测风速电路原理类似于上面这幅图,正确电路图请看我画的那张,原理就是当磁铁靠近时,A、B通道的干簧管将被导通,电平每改变为低电平时计数器就计数一次,这样,根据一定时间内统计到的计数次数和气象仪内部旋转磁铁的半径就可以算出风速的大小了。
3)测温度电路的原理
测温度就是用了一个温度传感器DS1820,基于1-Wire计数原理直接读取温度传感器内部的数据即可。
四,1-wire总线技术原理简述
1-Wire总线是一种简单的信号交换架构,通过一条线路在主机与外围器件之间进行双向通信。所有的
所有通信的第一步都需要总线控器器发出一个复位信号以使总线同步,然后选择一个受控器件进行随后的通信,这可以通过选择所有的受控器件或者选择一个特定的受控器件(利用该器件的序列号进行选择),或者通过对半检索法找到总线上的下一个受控器件来实现。上文所提到的这些指令都是网络指令或者只读存储器(ROM)指令。一旦一个特定的器件被选中,那么在下次复位信号发出之前,所有其它器件都被挂起而忽略随后的通信。
一旦一个器件被用于总线通信,主机就能向它发出特定的器件指令,对它进行数据读写。这是因为每类器件具有不同的功能和不同的用途,而且一旦器件被选定,就有了唯一的协议。虽然每类器件具有不同的协议和特征,但其工作过程却是相同的并且遵循如图1所示的工作流程。
图1. 典型的1-Wire通信流程
以DS2450为例:
DS2450 需要严格的协议来保证数据的完整性。该协议由一根信号线上的4种信令组成:由复位脉冲和从机应答信号组成的复位过程、写0 时隙、写1 时隙、读数据时隙。除应答脉冲外,所有信号都由总线主机发出。DS2450可以标准和高速两种模式进行通信。如果没有明确设置为高速模式,则DS2450将以标准速率通信。高速模式下所有波形均使用快速时序。
与DS2450 进行通信时所需的初始化时序如图10 所示。若主机在发出复位脉冲后检测到响应信号,则表明DS2450已经做好准备且只要主机正确地发送后续的ROM或Memory功能命令,那么DS2450就将接收或发出数据。总线主机发送(TX) 一个复位脉冲(tRSTL,标准速率下最短时间为480μs,高速模式下最短时间为48μs),然后总线主机释放总线并进入接收(RX)模式,这时1-Wire 总线被上拉电阻拉至高电平。当在检测到数据引脚上的上升沿后,DS2450 将等待一段时间(tPDH,标准速率下15μs 至60μs,高速模式下2μs至6μs)后发送在线应答脉冲(tPDL,标准速率下60μs 至240μs,高速模式下8μs至24μs)。
480μs或更长的复位脉冲将中止高速模式并使器件返回标准速率。如果DS2450处于高速模式且复位脉冲小于80μs,器件将保持在高速模式。
读/写时隙
读、写时隙的定义如图11所示。主机通过拉低数据线来启动所有时隙。数据线的下降沿通过触发内部延迟电路使DS2450 与主机同步。在写时隙中,延迟电路将确定DS2450 何时采样数据线。对读数据时隙来说,如果DS2450将要发送的是“0”,那么延迟电路将决定DS2450 维持数据线为低多长时间以覆盖由主机产生的“1”。如果DS2450将要发送的是“1”,则DS2450 将维持主机产生的读时隙不变。
五,程序讲解
1-Wire总线技术最重要的是时序,时间间隙的长度要满足上述要求,最基本的几个环节做好了,控制从器件将是手到擒来的事情。
为了准确控制时序,首先我根据LM3S8962开发板上的晶振资源设计了一个比较精确的延时程序作为最基本的定时单元。
//调用消耗1.6us
//计数一次消耗0.62us
void delay(int useconds)
{
int s;
for (s=0; s<useconds;s++);
}
然后,需要两个控制电平无延时的函数单元。
//设置总线电平状态,0:低电平,1:高电平,无延迟
void SetWireState(unsigned char value)
{
GPIOPinWrite(GPIO_PORTB_BASE,WIRE_WR,value<<2);
}
//获得总线电平状态,0:低电平,1:高电平,无延迟
unsigned char GetWireState(void)
{
unsigned char value;
value = GPIOPinRead(GPIO_PORTB_BASE,WIRE_RD);
return value>>3;
}
以上三个函数是最基本的时序控制函数,其他的函数都是基于此来编写。
根据1-Wire的复位、读和写的时序规则我设计了三个基本函数。
复位函数
//复位函数
//presence:返回复位后总线上的信号状态
// 0=presence, 1 = no part(总线上无器件)
unsigned char wire_reset(void)
{
unsigned char presence;
SetWireState(0); //pull line low
delay(772); // leave it low for 480us
SetWireState(1); // allow line to return high
delay(110); // 延迟70us,wait for presence
presence = GetWireState(); // get presence signal
delay(674); // 延迟420us,wait for end of timeslot
return(presence); // presence signal returned
}
读函数
//读位函数,增加必要延迟
//返回值:0x00,0x01
unsigned char ReadBit(void)
{
unsigned char value;
SetWireState(0); // pull DQ low to start timeslot
delay(2); //延迟3us
SetWireState(1); // then return high
delay(29); //延迟20us
value = GetWireState();
delay(72); //延迟50us
return value; // return value of DQ line
}
写函数
//写位函数,增加必要延迟
void WriteBit(unsigned char value)
{
SetWireState(0); // pull line low to start timeslot
delay(2); //延迟3us
if(value==1) SetWireState(1); // return DQ high if write 1
delay(158); // 延迟100us
SetWireState(1);
delay(2); //延迟3us
}
有了读写位函数,我们就可以写出读写字节函数,为以后调用操作提供方便。
//读字节函数
unsigned char ReadByte(void)
{
unsigned char i;
unsigned char value = 0;
for (i=0;i<8;i++)
{
if(ReadBit()) value|=0x01<<i; // reads byte in, one byte at a time and then shifts it left
delay(6); // wait for rest of timeslot
}
return(value);
}
//写字节函数
void WriteByte(char value)
{
unsigned char i;
unsigned char temp;
for (i=0; i<8; i++) // writes byte, one bit at a time
{
temp = value>>i; // shifts val right 'i' spaces
temp &= 0x01; // copy that bit to temp
WriteBit(temp); // write bit in temp into
}
// delay(5);
}
以上就是最基本的几个关键的时序控制函数。以它们为基础,结合各器件的数据手册,就可以做到通过1-Wire控制的目的。
下面上传几张测试美图照片:
下面上传我的源程序,里面注释详尽,方便大家理解吧,里面的文件夹层次大家不要随意改变,除非你知道怎么能改动,大家直接下到板子里应该就能跑了,我LM3S8962开发板上用了PB2(WR)和PB3(RD)以及5V和GND四个个管脚。
(下载次数: 500, 2011-2-8 22:35 上传)
下面上传一段我的测试视频:
(我不会把视频导进来,明天问问SOSO姐)
[media]http://player.youku.com/player.php/sid/XMjQyMzcxOTAw/v.swf[/media]
最后是我找到的一些有帮助的设计资料:
(下载次数: 99, 2011-2-8 22:55 上传)