系统简介
风速、风向的测量在气象预报、环境监测、风力发电、航空航天等领域中有着重要意义。随着传感器技术、微处理器技术和网络通信技术的发展,相比传统的人工观测,数字化、智能化的气象仪器在观测精度、速度和稳定性等方面都有较大优势,因此针对数字化的气象仪器进行设计具有较大意义,尤其是便携式小型化的仪器,虽然通过天气预报可以知道当前的风速风向信息,但是这些都是大范围的,无法感知某一局部区域的风速风向,因此本文围绕风速风向仪进行设计。
本次基于单片机的风速风向仪设计与实现,整个系统包括单片机最小系统STC89C52,RM-FS-N01风速传感器,RM-FX-N01风向传感器,压力传感器采集的数据变换并传送至单片机进行处理,再由液晶显示屏显示测量的风速值。对于风向系统利用编码器在0~360°范围内进行测量收集信号,在多圈旋转的情况下能够实现单圈自动归零,通过单片机进行数据的转化处理,测量风向也通过液晶显示屏显示。软件部分的设计采用模块化编程方式,方便程序的维护和改进。
关键词:风向风速的测量,单片机,传感器
1绪论
1.1课题研究背景及意义
风是由太阳辐射热所引起的一种普遍自然现象,在地球表面不同地方的空气冷热不一样致使其发生流动从而形成风,从气象学的角度讲,风主要是指空气运动时的水平分量,因为风是矢量,故有风速和风向之分,风速即为空气在单位时间内移动的水平距离,以米/秒国际单位为准;风向是指风吹来的方向,一般用十六方位法来表示,风速和风向在实验研究、天气预报、电站监测、航海、军事等很多领域均有应用。在我国,风速风向的测量对于高铁的设计及安全运行具有重要意义,在铁路运行的整个线路上,需要对风速风向进行实时的监控。对于航空领域来说,风与飞行的关系非常密切,因为风对飞机的起飞、着陆和飞行过程影响很大,在飞行过程中需要及时根据风向来修正飞机航向,也需要根据风速风向变化来选择合适的起飞和降落方式。无论在近海还是在远洋航行中,风速对于船航行安全的重要性具有重要意义,在所有航行过程中,均需要对船只附近的风速风向进行准确的测量。
作为一种绿色、清洁、可再生的能源,风能已经在风力提水,风力发电和风力助航方面得到了广泛的应用。在这些领域中,风速风向的准确测量扮演着重要的角色。例如,在风电提水系统的设计过程中,需要在风速的基础上建立数学模型,因为系统泵水的流量是风速的函数,随着风速的增加,系统泵水的流量将增加;风力助航的广泛应用也在一定程度上促进了环境保护和能源节约,风速风向的精确测量对于风力助航系统的可靠性和安全性至关重要;在设计风力发电系统之初,设计人员应首先选择目标地点,然后根据该区域内风速和风向的历史数据来选择相应的风机,同时,在风力发电系统运行时,需要实时地对风速风向信息进行监测以确保系统正常运行。在气象领域和科学实验中,风速风向的准确测量同样十分重要。由此可见,风作为一个重要的气象要素,能够对它进行准确测量意义很大。
1.2国内外研究现状
风速风向测量系统的应用多种多样,如气象、航海、农业、科研等,因应用领域广泛,风速风向测量系统的研究一直都是测量科学界的焦点。用压力传感器来做风速风向测量在国内和国外都还没有这方面的论文或研究,在国内外主要集中在以下几种方法研究上面:
(1)常规风杯式风速风向仪,此风向仪由风杯、转轴、支架、风向标构成,测风速的转轴和测风向的转轴都有机械结构,导致其有一定的摩擦误差,并且有机械运动,风杯和风向标的惯性质量也会影响到测量精度;
(2)超声波风速风向仪,一个传感头由两对超声波对管,其间距基本固定不变,由于超声波在空气中传播,风速会影响到超声波的传播,无风时两对超声波对管接收到自己发出的超声波信号时间是相等的,有风时接收到的信号时间有差异,通过这个差异的大小来间接测出风速,其精度高,但传感器头昂贵,研发成本高;
(3)基于微机械加工技术的风速风向传感器,传感器由四个相互正交的电容器构成,每个电容器包括可动极板和固定极板,此结构将风速和风向信息转换为可动极板的位移,通过测量四个电容器的电容来检测风速和风向;
(4)热电偶式的风速风向传感器,通过热电偶在风场中温度的变化,感知到电阻的变化,从而间接得出风速和风向;
(5)气槽气压式风速风向传感器,通过感知风从各方向的气槽中吹进风的压力来测风速风向值,缺点是进气口容易被异物堵塞,如灰尘、落叶、鸟类粪便等;
(6)五孔探头法测量流速流向是应用较为广泛的测量手段。这种方法方便、快速,所需的设备和技术简单,易于实现,但只能用来测量探头40范围内的气流偏角;
(7)热线/热膜法测量以热线/热膜为感受元件,随流速变化直接输出电信号,因而与前者相比,响应更快,滞后效应小,动态响应宽,可以用来测量非定常流的流动参数。但热线较为脆弱,不适合于流速较高或非气体流动的场合;
1.3本文主要内容
本次“基于单片机的风速风向仪设计与实现”的设计,在设计的过程中将全文分成了以下几个章节:首先是针对“基于单片机的风速风向仪设计与实现”课题,进行资料的归纳和总结,分析已有的类似课题中研究状况,并借此阐述本次写作的必要性。则是定调整个“基于单片机的风速风向仪设计与实现”课题的设计方案。“基于单片机的风速风向仪设计与实现”课题的程序编写部分,针对功能实现中需要的显示程序等分别进行阐述。最后则是结合软硬件的设计,对实物模型进行调试,详细的论述整个验证过程
2系统设计方案
2.1系统总体方案设计
本课题为“基于单片机的风速风向仪设计与实现”,在功能上设计如下:
(1)具有基本测量功能,可以检测风速,风向;(2)具有显示信息的功能,可以显示风速、风向的基本信息;(3)具有语音播报功能,可以播报当前的风速风向大小;(4)可以通过按键设定阈值,当风速风向超过阈值时,进行声音提示(5)具有无线传输功能,可以将检测的数据传输到手机APP;根据上述功能,设计了如图2.1所示的系统总体架构,整个系统包括单片机最小系统STC89C52,RM-FS-N01风速传感器,RM-FX-N01风向传感器,MY1680语音播报模块,OLED液晶,ESP8266无线通信模块,蜂鸣器,ADC0832模数转换器等等,在开发环境上,采用Altium完成系统原理图的设计,通过Keil平台和C语言完成软件程序的编写。
图2-1系统总体设计框图
2.2控制器方案选择
单片机作为系统控制的核心,其型号的选择直接影响到系统运行的稳定。在其型号的选择过程中,需要对其硬件配置、兼容能力以及成本支出进行考量。为此提出以下几种方案。
方案一:选用STC89C52作为系统主控制器的方案选型,STC89C52单片机设计时间长,设计成本较低,但在实际应用过程中,可支持的传感器类型较少,控制器运行速度缓慢,影响实际应用的控制运行。
方案二:选用ESP8266芯片模组作为系统主控制器的方案选型,ESP8266芯片模组被常用于嵌入式的系统研发中。自身具有良好的读写能力,外设接口数量较多,设有多个定时器。实际应用中,由于ESP8266拥有较多库文件的支持,因此用户可以根据自身需求进行库文件的选用,在处理多路信号的过程中比较便利。
方案三:选用Arduino Mega 2560作为系统主控制器的方案选型。作为Arudino系列的一款应用单片机,Arduino Mega 2560的外设IO接口数量较多,系统处理能力强。作为开源硬件,系统编译环境友好,对于实际应用中的传感器链接都设有对应的库文件,便于用户在系统程序编写过程中进行直接调取。
通过对以上三种形式的单片机类型进行区分,考虑到此次风速风量测量仪在实际设计过程中需要提升自身的处理能力,传感器应用类型较多,系统存储容量要求高,因此选用方案一中的STC89C52单片机作为系统主控制器的方案选择。
2.3风速测量模块和其他模块
无线通信模块选型:
作为物联网数据传输的重要组成部分,无线通信技术的选择直接影响到系统数据传输的稳定性,需要根据系统的设计需求进行方案的正确选型,针对此次系统设计,提出以下几种无线通信技术进行方案选型。
方案一:选择蓝牙通信模块作为系统无线通信的技术,蓝牙通信技术在实际生活中应用广泛,例如蓝牙通信、蓝牙遥控等,适用于短距离范围内的不需进行数据存储的场合。但是由于蓝牙通信技术两个固定设备之间的通信工作,且易受到传输过程中障碍物的影响,不能够实现点对面的实际通信需求,因此应用范围受限。
方案二:选择WIFI通信作为系统无线通信的技术,作为主流的无线通信技术,其应用场合最多,数据传输更为稳定。在使用不同服务器和云平台的过程中,可对固件进行烧写,便于接入。而且WIFI通信技术应用的芯片模块开发成本较低,能够缩短系统的研发周期,实用性强。
通过以上方案的对比,考虑到此次设计中的无线数据传输属于远距离的传输,为了提高系统数据传输的可靠性,综合各项因素,选择方案二中WIFI无线通信技术。
语音模块选型:
方案一:MY1680-12P 是深圳市迈优科技有限公司自主研发的一款小巧的微集成MP3模块。采用MY1680-SOP16 MP3主控 芯片,支持MP3、WAV格式双解码。模块内置FLASH存储芯片,1-16M容量可选;也可外接U盘或USB数据线连接电脑更 换FLASH的音频文件。该模块内置3W功放,可以直接驱动3W的喇叭,使用更方便。
方案二:采用国产YC系列语音芯片,该类语音芯片可以播放特定的语音信息,用户可以将需要播报的语音段发送给厂家,由厂家进行烧录,这种方式其最大的缺点就是播放的语音信息,用户无法自行修改,但是其成本低,使用也较为方便,并且由于国内网购发达,通过购物网站与厂家联系要求修改语音信息也较为方便。
综上所述,考虑到此次风速风向测量设计中,需要语音播报的风速风向情况,因此选择方案一更加合适。
风速测量系统方案与论证
方案一:三杯式风速计:
三杯风速传感器主要采用优质铝合金型材,表面经电镀喷塑处理,具有良好的防侵蚀,抗腐蚀特点。能有效的保证长期使用的仪表不起锈,同时配合内部顺滑的轴承系统一起使用,确保了采集信息的准确性。是一种使用方便,性能好,可靠性高的智能仪器仪表。可广泛用于测量温室,气象站,建筑施工等场所风速。
方案二:热式风速仪
热线风速仪具有探头体积小,对流场干扰小;响应快,能测量非定常流速;能测量很低速(低达0.3m/s)等优点。当在湍流中使用热敏式探头时,来自各个方向的气流同时冲击热元件,从而会影响到测量结果的准确性。在湍流中测量时,热敏式风速仪流速传感器的示值往往高于转轮式探头。基于三杯式风速传感器的风速测量具有动态性能好、线性高、测量范围广、抗雷电干扰能力强等特点 。综合测量功能、可靠性、使用领域、性价比等要素,三杯式风速仪利用 RS-FS-V05 风速变送器,完成风速测量。该测试仪相较其它风速仪,结构简单、抗干扰能力强,能够实现通过采集风能参数合理开发和利用风能的目的,因此本设计采用三杯式风速计。
2.4本章小结
在本章的内容中,是针对风速风量测量仪课题的功能要求进行需求上发分析,并对课题风速风量测量仪的总体架构按照模块进行划分,将整个风速风量测量仪进行了划分,并对核心器件单片机,无线通信模块,风速传感器,风向传感器的选型进行了分析,论述了其选择的原因,可以说在这个章节,完成了对风速风量测量仪的需求分析,架构设计,目标定性。
3硬件电路设计
3.1单片机最小系统设计
单片机介绍:
在本次风速风量测量仪的系统设计中,系统将STC89C52单片机作为系统的主控核心,如图3.1所示为单片机的最小系统图,其中包括单片机、晶振电路、复位电路三个模块。单片机执行指令的过程中需要晶振为其提供时钟频率,两者具有密切的联系。在实际应用中,STC89C52芯片的工作效率高、系统功耗低。芯片可以兼容cmcs-51指令,以此来提高系统工作过程中的便捷化程度。STC89C52芯片有8位的中央处理器以及用于信息数据存储的模块。STC89C52单片机可以完成多项信息处理,为其实际应用中的产品设计提供可靠的解决手段。
图3-1系统总体设计框图
4软件设计
4.1软件设计思路
本系统的软件设计包含3个部分,分别为风速及风向模块、显示模块以及按键模块。通过主程序将三个子程序连通,风速模块和风向模块作为输入,显示模块。单片机通过接收风速及风向模块的信息,来判断风速大小,并将风速及风向信息显示在OLED上。
4.2程序设计
本文软件设计是以一个主程序实现对各个子程序的协调调用,进而按照要求实现预设计的功能,本系统的风速风量测量仪主程序流程图如图4.1所示,在风速风量测量仪程序启动后,然后进行系统初始化,初始化函数包括:分串口初始化,液晶显示初始化。在系统的初始化工作完成后,首先由单片机发出工作开始信号,启动风速风向仪,进入循环调用ADC083采集程序以读取风向,读取风速风向,并通过显示模块显示,然后根据阈值进行报警判定,接着检测是否有按键按下,如果有则进行按键处理,之后再通过显示模块显示更新后的风速及风向。
4.3风速风向检测模块设计
风速风向检测子程序设计:
在此搭配了ADC0832模数转换器来对风速风向进行检测,其流程如图4.3所示,风向检测:当程序开始后,选择CH1通道,此时在第三个CLK时钟,DAT会给低低电平,然后读前8位数据,再读后8位数据,如果前后8位一致则输出结果,如果不一致则输出0,接着释放ADC0832,然后通过液晶进行显示风向。风速检测采用的是CH0通道,设计思路与风向相同。
图4-1风速风向检测子程序流程图
4.4显示模块
显示子程序设计:
此次采用的是OLED12864,该液晶在显示控制上,主要是通过SCK和SDA引脚,也就是常用的IIC通信,因此单片机在实现液晶的显示时,需要通过IIC协议来输出控制命令和数据,实现液晶的显示效果,当调用后,首先判断字符是否结束,若字符没有结束,则开始计算数据长度偏移量,来判定当前横坐标是否大于120,如果“是”则切换到下一行,然后确定坐标进行写数据,接着横坐标+8,指向下一个字符串,如果没有则继续运行程序,直到该数组的数据已经全部显示完毕。
图4-2液晶显示子程序流程图
4.5本章小结
本次是风速风量测量仪的软件程序设计程序,主要是对系统的开发环境Keil平台进行了介绍,并根据此次风速风量测量仪中采用的硬件电路来完成软件控制程序的编写,在此完成了OLED液晶显示,ESP8266通信,风扇风向检测等各个模块的程序流程设计。
主程序:
void main(void)
{
static u8 buff[20];//
unsigned char i,n;
uchar shezhi_flag=1,t;//设置变量
unsigned char Tx_Buf[7];
uint caiji_time=0;
int type;
float val=0,qs_fs=0;//风度
float qs_fx=0;//风向变量
InitUART();
OLED_Init(); //OLED初始化
sprintf((char*)buff,"fazhi:%2d",data1);
22
OLED_P8x16Str(0,0,buff);
sprintf((char*)buff,"fengsu:%2d.%1dm/s",(uint)qs_fs/10,(uint)qs_fs%10);
OLED_P8x16Str(0,4,buff);
while(1)
{
delayms(10);
/*输出值(V) 对应风向
≈0 北风
≈0.7143 东北风
≈1.4286 东风
≈2.1429 东南风
≈2.8571 南风
≈3.5714 西南风
≈4.2857 西风
≈5 西北风*/
//读取风向
qs_fx=adc0832(0)*5/25.5;
if(qs_fx>48)
{
type=1;
OLED_P8x16Str(0,2," xibei feng 315");
}
else if(qs_fx>40)
{
type=2;
OLED_P8x16Str(0,2," xi feng 270");
}
else if(qs_fx>33)
{
type=3;
OLED_P8x16Str(0,2," xinan feng 225");
}
else if(qs_fx>26)
{
type=4;
OLED_P8x16Str(0,2," nan feng 180");
}
else if(qs_fx>19)
{
type=5;
OLED_P8x16Str(0,2,"dongnan feng 135");
}
else if(qs_fx>12)
{
type=6;
OLED_P8x16Str(0,2," dong feng 90");
}
23
else if(qs_fx>5)
{
type=7;
OLED_P8x16Str(0,2," dongbei feng 45");
}
else if(qs_fx>=0)
{
type=8;
OLED_P8x16Str(0,2," bei feng 0");
}
//读取风速
val+=adc0832(1)*50/2.55;
if(++caiji_time>=15)
{
qs_fs=val/caiji_time;
qs_fs=qs_fs*0.27;
val=0;
caiji_time=0;
sprintf((char*)buff,"fengsu:%2d.%1dm/s",(uint)qs_fs/10,(uint)qs_fs%10);
OLED_P8x16Str(0,4,buff);
}
if((uint)qs_fs>data1*10)
{
buzzer=0;
}
else
{
buzzer=1;
}
if(Mode==0){
delayms(10);
if(Mode==0){
while(!Mode);
n=1;
while(n){
printf((char*)buff,"fazhi:%2d",data1);
OLED_P8x16Str(0,0,buff);
OLED_P8x16Str(80,0,"<");
if(Mode==0){
delayms(10);
if(Mode==0){
while(!Mode);
OLED_P8x16Str(0,0," ");
n=0;
while(!Mode);
}
}
24
if(Add==0){
delayms(10);
if(Add==0){
data1++;
}
}
if(Reduc==0){
delayms(10);
if(Reduc==0){
if(data1!=0){
data1--;
}
}
}
}
}
}
sprintf((char*)buff,"fazhi:%2d",data1);
OLED_P8x16Str(0,0,buff);
t++;
if(t>10){
int a;
if(buzzer==0){
a=0;
}else{
a=1;
}
t=0;
Tx_Buf[0]='S';
Tx_Buf[1]=(uint)qs_fs/100%10+0x30;
Tx_Buf[2]=(uint)qs_fs/10%10+0x30;
Tx_Buf[3]=(uint)qs_fs%10+0x30;
Tx_Buf[4]=type%10+0x30;
Tx_Buf[5]=a%10+0x30;
Tx_Buf[6]='E';
SendStr(Tx_Buf,7);
}
}
}
串口中断程序设计:
void UARTInterrupt(void) interrupt 4
{
ES=0; //关闭串行口中断
if(RI) //接收到数据
{
Rx_buf[Rxnum]=SBUF; //接收数据进数组
Rxnum++;
25
if(Rx_buf[0]=='S' && Rx_buf[4]=='E'){
Rxnum=0;
data1=(Rx_buf[1]%16)*100+(Rx_buf[2]%16)*10+(Rx_buf[3]%16);
for (ss=0; ss < strlen(Rx_buf); ss++)
Rx_buf[ss] = '\0' ;
}
if(Rx_buf[Rxnum - 1] == 'E'){
Rxnum=0;
for (ss=0; ss < strlen(Rx_buf); ss++)
Rx_buf[ss] = '\0' ;
}
if(Rxnum>=6){
Rxnum=0;
for (ss=0; ss < strlen(Rx_buf); ss++)
Rx_buf[ss] = '\0' ;
}
}
RI=0;
ES=1; //启动串行口中断
}
风速风向检测程序设计:
unsigned char adc0832(unsigned char CH)
{
unsigned char dat = 0x00; //AD值
unsigned char i,test,adval;
adval = 0x00;
test = 0x00;
Clk = 0; //初始化
DATI = 1;
_nop_();
CS = 0;
_nop_();
Clk = 1;
_nop_();
if ( CH == 0x00 ) //通道选择
{
Clk = 0;
DATI = 1; //通道0的第一位
_nop_();
Clk = 1;
_nop_();
Clk = 0;
DATI = 0; //通道0的第二位
_nop_();
Clk = 1;
_nop_();
}
26
else
{
Clk = 0;
DATI = 1; //通道1的第一位
_nop_();
Clk = 1;
_nop_();
Clk = 0;
DATI = 1; //通道1的第二位
_nop_();
Clk = 1;
_nop_();
}
Clk = 0;
DATI = 1;
for( i = 0;i < 8;i++ ) //读取前8位的值
{
_nop_();
adval <<= 1;
Clk = 1;
_nop_();
Clk = 0;
if (DATO)
adval |= 0x01;
else
adval |= 0x00;
}
for (i = 0; i < 8; i++) //读取后8位的值
{
test >>= 1;
if (DATO)
test |= 0x80;
else
test |= 0x00;
_nop_();
Clk = 1;
_nop_();
Clk = 0;
}
if (adval == test) //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
dat = test;
_nop_();
CS = 1; //释放ADC0832
DATO = 1;
Clk = 1;
return dat;
}
显示程序设计:
void OLED_P8x16Str(unsigned char x, y,unsigned char ch[])
{
unsigned char c=0,i=0,j=0;
while (ch[j]!='\0')
{
c =ch[j]-32;
if(x>120){x=0;y++;}
OLED_Set_Pos(x,y);
for(i=0;i<8;i++)
OLED_WrDat(F8X16[c*16+i]);
OLED_Set_Pos(x,y+1);
for(i=0;i<8;i++)
OLED_WrDat(F8X16[c*16+i+8]);
x+=8;
j++;
}
}
风速程序
PCF8591 AD转化器读程序
#include "i2c.h"
#include "delay.h"
#define _Nop() _nop_() //定义空指令
#define AddWr 0x90 //写数据地址
#define AddRd 0x91 //读数据地址
bit ack; //应答标志位
sbit SDA=P2^1;
sbit SCL=P2^0;
/*------------------------------------------------
启动总线
------------------------------------------------*/
void Start_I2c()
{
SDA=1; //发送起始条件的数据信号
_Nop();
SCL=1;
15
_Nop(); //起始条件建立时间大于4.7us,延时
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; //发送起始信号
_Nop(); //起始条件锁定时间大于4ì
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; //钳住I2C总线,准备发送或接收数据
_Nop();
_Nop();
}
/*------------------------------------------------
结束总线
------------------------------------------------*/
void Stop_I2c()
{
SDA=0; //发送结束条件的数据信号
_Nop(); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4us
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; //发送I2C总线结束信号
_Nop();
_Nop();
_Nop();
_Nop();
}
/*----------------------------------------------------------------
字节数据写函数
函数原型: void SendByte(unsigned char c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0 假)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
------------------------------------------------------------------*/
void SendByte(unsigned char c)
{
unsigned char BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((c<<BitCnt)&0x80)SDA=1; //判断发送位
else SDA=0;
_Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
_Nop();
_Nop(); //保证时钟高电平周期大于4ì
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; //8位发送完后释放数据线,准备接收应答位
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; //判断是否接收到应答信号
SCL=0;
_Nop();
_Nop();
}
/*----------------------------------------------------------------
字节数据读函数
函数原型: unsigned char RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
------------------------------------------------------------------*/
unsigned char RcvByte()
{
unsigned char retc;
unsigned char BitCnt;
retc=0;
SDA=1; //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; //置时钟线为低,准备接收数据位
_Nop();
_Nop(); //时钟低电平周期大于4.7us
_Nop();
_Nop();
_Nop();
17
SCL=1; //置时钟线为高使数据线上数据有效
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/*----------------------------------------------------------------
应答子函数
----------------------------------------------------------------*/
void Ack_I2c(void)
{
SDA=0;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4ì
_Nop();
_Nop();
_Nop();
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/*----------------------------------------------------------------
非应答子函数
----------------------------------------------------------------*/
void NoAck_I2c(void)
{
SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); //时钟低电平周期大于4ì
_Nop();
_Nop();
_Nop();
18
SCL=0; //清时钟线,钳住I2C总线以便继续接收
_Nop();
_Nop();
}
/*----------------------------------------------------------------
向有子地址器件读取多字节数据函数
函数原型: bit ISendStr(unsigned char sla,unsigned char suba,ucahr *s,unsigned char no);
功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
----------------------------------------------------------------*/
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
unsigned char i;
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i<no-1;i++)
{
*s=RcvByte(); //发送数据
Ack_I2c(); //发送就答位
s++;
}
*s=RcvByte();
NoAck_I2c(); //发送非应位
Stop_I2c(); //结束总线
return(1);
}
/*------------------------------------------------
读AD转值程序
输入参数 Chl 表示需要转换的通道,范围从0-3
返回值范围0-255
------------------------------------------------*/
unsigned char ReadADC(unsigned char Chl)
{
unsigned char Val;
Start_I2c(); //启动总线
SendByte(AddWr); //发送器件地址
if(ack==0)return(0);
SendByte(0x40|Chl); //发送器件子地址
if(ack==0)return(0);
19
Start_I2c();
SendByte(AddWr+1);
if(ack==0)return(0);
Val=RcvByte();
NoAck_I2c(); //发送非应位
Stop_I2c(); //结束总线
return(Val);
}
风向程序
格雷码转化二进制码程序部分:
Unsigned int Wind_Drct=0 ; //二进制码初始化
Unsigned int Wind_Gray=0; //格雷码初始化
if (KBA1==1)
Wind_Gray+=0x0001;
if (KBA2==1)
Wind_Gray+=0x0002;
If (KBA3==1)
Wind_Gray+=0x0004;
if (KBA4==1)
Wind_Gray+=0x0008;
Wind_Gray=Wind_Gray&0x4F;
Wind_Drct=Wind_Gray;
while (Wind_Gray>>1)
Wind_Drct^=Wind_Gray;
Wind_Drct=Wind_TB1[Wind_Drct]; //查表求出风向值
显示程序
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h>
sbit RS = P2^4; //定义端口
sbit RW = P2^5;
sbit EN = P2^6;
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
#define DataPort P0
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
20
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
判忙函数
------------------------------------------------*/
bit LCD_Check_Busy(void)
{
DataPort= 0xFF;
RS_CLR;
RW_SET;
EN_CLR;
_nop_();
EN_SET;
return (bit)(DataPort & 0x80);
}
5系统测试
5.1系统测试
硬件调试:
根据风速风量测量仪的设计要求,在完成系统硬件电路以及软件程序的设计工作之后需要对系统模型进行制作,更好地验证整体系统各个功能的实现情况。在实物制作过程中需要根据系统原理图采用模块化的方式逐一进行相应元器件的选择购买,同时还需要购买实物制作过程中应用到的电阻电容等器件。选择合适的实物焊接工具。在焊接工具与元器件准备完毕之后进行线路板的焊接工作。需要注意在焊接过程中,不能够出现虚焊、漏焊、线路短路等情况的发生。这些问题都会造成系统电路无法正常进行工作。在实际焊接过程中需要注意焊接的温度,合理控制焊接每一个引脚的时间,避免造成器件出现破坏的情况。焊接顺序可按照整个线路板的布板位置进行逐个焊接。
根据系统原理图进行整个实物的焊接工作之后,需要对焊接点进行仔细检查,避免出现漏焊或线路短路的问题,及时进行线路补充,随后进行线路板的清洁,并进行上电测试。
软件调试:
在完成硬件制作和软件编写后,需要进行系统的联调,在开始设计时主要是对一些简单的功能模块进行程序编写,尤其是人机交互模块,这样方便后续进行调试。在完成编写后,通过平台的编译系统进行编译,并根据提示进行软件程序的修改,直到整个程序没有在KEIL软件上进行报错。然后通过JTAG或者串口下载器将编译生成的HEX文件下载到单片机中,首次程序下载可以选择简单的程序,以便进行程序功能的基础性判断,随后逐渐增加程序,来完成整体系统的功能设计。在程序下载完成之后需要及时进行功能调试,可以利用在线调试系统来观察单片机内部寄存器的状态或者执行单步运行,更加有助于找到问题点,以便快速解决问题。
系统进入后,可以通过在菜单栏中的选择,来对需要检测的数据变量,寄存器值等进行监测,在此以监控count变量为例,通过在watch窗口输入该变量值就可以看到其默认值为0X0000,在运行后,其数值就会随着系统的运行而产生改变。如图5.1所示,通过工具栏上的按钮还可以执行单步,跳出循环等多种方式的执行操作,方便设计人员进行调试。
图5-1下载界面
在完成所有的程序编写和调试后,就可以将程序烧录至STC89C52的芯片中,进行各个部分及整体程序的调试。将选好的元器件根据设计的电路图进行焊接组装,并把编好的程序烧写进去。本节通过4部分演示。作品静态图如图5.2示,主要部分有RM-FS-N01风速传感器、RM-FX-N01风向传感器、OLED液晶、ADC0832模数转换器、以及电容和电阻。
图5-2静态实物图
5.2测试结果
在经过硬件设计,软件设计后就需要进行硬件和软件的调试,并对关键的功能进行测试,而本章正是对风速风量测量仪的系统调试环节,在此分别从硬件调试和软件调试两个方面开始论述,在硬件调试方面主要采用了万用板来对风速风量测量仪进行实物的制作,并通过电烙铁来进行焊接,在软件调试方面则通过Keil软件自带的在线调试功能进行逐个的对功能进行测试和修改,最终完成了整个风速风量测量仪的设计,达到了课题任务需求。
6结论
本次基于单片机的风速风向仪设计与实现设计,整个系统包括单片机最小系统STC89C52,RM-FS-N01风速传感器,RM-FX-N01风向传感器,OLED液晶,蜂鸣器,ADC0832模数转换器等等,在功能上实现了风速,风向的检测,并且可以通过显示风速、风向的基本信息,并带有提示功能,当风速大于按键设定阈值时会进行报警提示。通过实物的功能测试,此次风速风量测量仪能够实现风速风量测量仪的目标,满足实际设计目的。
本系统设计依旧存在一些缺陷,可以进一步改进的地方,如加入新的功能,检测新的环境变量,同时加入自动化控制,在检测数据异常时,可以通过外部手段进行局部地区环境的自动化控制。本次毕业设计让我对硬件设计以及软件设计方面有了更多的经验,为以后的项目设计积累了经验。同时也让我变的更加有耐心,遇到问题不会在浮躁的面对,而是静下心来认真分析并解决问题。同时对于这个课题,也让我发现了现在科技的飞速发展,风速风向仪在未来的发展过程中可以结合不同情景下的应用需求,针对性地制定实际应用功能,技术的快速革新为风速风向仪的发展创造动力。