嵌入式课程设计_第1页
嵌入式课程设计_第2页
嵌入式课程设计_第3页
嵌入式课程设计_第4页
嵌入式课程设计_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

嵌入式课程设计学院:计算机与通信工程学院专业:物联网工程班级:物联1501姓名:王强学号:41501602实验日期:2023年12月25日实验名称:嵌入式课程设计实验目的:以STC89开发板为硬件平台,开发温度采集、动态数码管显示、按键响应、与PC串口通讯的综合程序,实现以下功能:1)PC上的串口调试助手通过串口给STC89开发板发送“GetTemp”命令。2)STC89开发板从串口接受到“GetTemp”命令后启动温度传感器DS18B20的测温程序获取当前温度,测试完毕时将所测得温度数据显示在动态数码管上。(动态数码管在温度获取之前应当显示“FFFFFFFF”,只有在获取温度后才显示温度值)3)动态数码管显示出温度数据后,请通过按键触发STC89开发板通过串口回送环节2所测的温度数据给PC上串口调试助手,同时恢复动态数码管显示为“FFFFFFFF”。为保证每个同学的实验都独立完毕,规定回送的数据包含自己的学号,即假如你的学号是20230809,当前温度值是19.6摄氏度,那么在PC上的串口调试助手应当显示:20230809:19.6°C。硬件电路说明:1)STC89解决器管脚和晶振电路2)独立按键独立按键一共5个,分别连接在单片机的P3.0到P3.4口。去抖动的方式,我们采用软件延时的方法。过程如下:先设立IO口为高电平(一般上电默认就为高),读取IO口电平确认是否有按键按下,如有IO电平为低电平后,延时几个ms,再读取该IO电平,假如任然为低电平,说明相应按键按下,执行相应按键的程序。3)DS18B20温度传感器部分DS18B20内部的低温度系数振荡器是一个振荡频率随温度变化很小的振荡器,为计数器1提供一频率稳定的计数脉冲。高温度系数振荡器是一个振荡频率对温度很敏感的振荡器,为计数器2提供一个频率随温度变化的计数脉冲。初始时,温度寄存器被预置成-55℃,每当计数器1从预置数开始减计数到0时,温度寄存器中寄存的温度值就增长1℃,这个过程反复进行,直到计数器2计数到0时便停止。初始时,计数器1预置的是与-55℃相相应的一个预置值。以后计数器1每一个循环的预置数都由斜率累加器提供。为了补偿振荡器温度特性的非线性性,斜率累加器提供的预置数也随温度相应变化。计数器1的预置数也就是在给定温度处使温度寄存器寄存值增长1℃计数器所需要的计数个数。DS18B20内部的比较器以四舍五入的量化方式拟定温度寄存器的最低有效位。在计数器2停止计数后,比较器将计数器1中的计数剩余值转换为温度值后与0.25℃进行比较,若低于0.25℃,温度寄存器的最低位就置0;若高于0.25℃,最低位就置1;若高于0.75℃时,温度寄存器的最低位就进位然后置0。这样,通过比较后所得的温度寄存器的值就是最终读取的温度值了,其最后位代表0.5℃,四舍五入最大量化误差为±1/2LSB,即0.25℃。温度寄存器中的温度值以9位数据格式表达,最高位为符号位,其余8位以二进制补码形式表达温度值。测温结束时,这9位数据转存到暂存存储器的前两个字节中,符号位占用第一字节,8位温度数据占据第二字节。DS18B20测量温度时使用特有的温度测量技术。DS18B20内部的低温度系数振荡器能产生稳定的频率信号;同样的,高温度系数振荡器则将被测温度转换成频率信号。当计数门打开时,DS18B20进行计数,计数门开通时间由高温度系数振荡器决定。芯片内部尚有斜率累加器,可对频率的非线性度加以补偿。测量结果存入温度寄存器中。一般情况下的温度值应当为9位,但因符号位扩展成高8位,所以最后以16位补码形式读出。电路图及管脚如下:4)串口通信串行通信是将数据字节提成一位一位的形式在一条传输线上逐个地传送,此时只需要一条数据线,外加一条公共信号地线和若干控制信号线。由于一次只能传送一位,所以对于一个字节的数据,至少要分S位才干传送完毕。串行通信的必要过程是:发送时,要把并行数据变成串行数据发送到线路上去,接受时,要把串行信号再变成并行数据,这样才干被计算机及其他设备解决。在串行通信中,收、发双方对发送或接受数据的速率要有约定。通过编程可对单片机串行口设定为4种工作方式,其中方式0和方式2的波特率是固定的,而方式1和方式3的波特率是可变的,由定期器T1的溢出率来决定。串行口的4种工作方式相应三种波特率。由于输入的移位时钟的来源不同,所以各种方式的波特率计算公式也不相同,以下是4种方式波特率的计算公式。开发板的电路图如下图5)动态数码管显示数码管的显示原理是靠点亮内部的发光二极管来发光,下面就来我们讲解一个数码管是如何亮起来的。数码管内部电路如下图所示,从右图可看出,一位数码管的引脚是10个,显示一个8字需要7个小段,此外尚有一个小数点,所以其内部一共有8个小的发光二极管,最后尚有一个公共端,生产商为了封装统一,单位数码管都封装10个引脚,其中第3和第8引脚是连接在一起的。而它们的公共端又可分为共阳极和共阴极,中间图为共阴极内部原理图,右图为共阳极内部原理图。上图展出了常用的两种数码管的引脚排列和内部结构。总所周知,点亮发光二极管就是要给予它足够大的正向压降。所以点亮数码管其实也就是给它内部相应的发光二极管正向压降。如上图左(一共a、b、c、d、e、f、g、DP八段),假如要显示“1”则要点亮b、c两段LED;显示“A”则点亮a、b、c、e、f、g这六段LED;动态显示是多个数码管,交替显示,运用人的视觉暂停作用使人看到多个数码管同时显示的效果。完整程序代码: 主程序文献main.c:#include"temp.h" //引用temp.h头文献,涉及一些有关温度传感器的函数#include"reg51.h" //引用reg51.h头文献,说明引脚地址#defineGPIO_DIGP0 //将P0端口定义为GPIO_DIG#defineGPIO_LEDP2 //将P2端口定义为GPIO_LEDsbitLSA=P2^2; //位选,P2^2定义为LSAsbitLSB=P2^3; //同上位选定义变量 sbitLSC=P2^4; //同上位选定义变量sbitK3=P3^2; //位选,P3^2定义为K3按键unsignedintdisp[8]={0x71,0x71,0x71,0x71,0x71,0x71,0x71,0x71}; //显示FFFFFFFFunsignedcharcodeDIG_CODE[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0、1、2、3、4、5、6、7、8、9的显示码unsignedcharcheck1[7]={'0','0','0','0','0','0','0'}; //用来存放串口通信传送字符unsignedcharcheck2[7]={'G','e','t','T','e','m','p'}; //用来比较串口通信传送字符unsignedcharmessage[17]={'4','1','5','0','1','6','0','2',':','0','0','0','0','0','0','0','0'};//显示学号为41501602:unsignedcharDisplayData[8]; //用来存放要显示的8位数的值unsignedcharKeyValue=0; //是否按下独立按键的标志位voidDigDisplay(); //动态数码管显示函数voidUsartConfiguration(); //串口设立函数voidLcdDisplay(int); //数码管显示读取到的温度voidIntConfiguration(); //设立外部中断voidDelay(unsignedintn); //延时函数voidTimer0Configuration(); //定期器初始设立voidCheckMessage(charm); //逐字检查串口通信字符是否对的unsignedintflag=0; //数码管显示标志位unsignedintj=0; //用于CheckMessage逐字检查发送字符unsignedcharNum=0; //动态数码管位选/*******************************************************************************主函数模块*******************************************************************************/voidmain() //主函数{ unsignedinti; IntConfiguration(); //初始化外部中断设立 UsartConfiguration(); //初始化串口设立 Timer0Configuration(); //初始化定期器设立 while(1) { if(flag==1) //当flag为1时数码管直接显示当前温度 { LcdDisplay(Ds18b20ReadTemp()); //调用温度传感器函数并在数码管显示温度 } if(flag==0) //当flag为0时数码管显示FFFFFFFF { for(i=0;i<8;i++) //循环给disp[]数组赋值 { disp[i]=0x71; //disp[i]赋值 } } }}/*******************************************************************************独立按键模块*******************************************************************************/voidIntConfiguration() //设立外部中断{ //设立INT0 IT0=1; //跳变沿触发方式(下降沿) EX0=1; //打开INT0的中断允许。 //设立INT1 IT1=1; //跳变沿触发方式为下降沿 EX1=1; //打开INT1的中断允许 EA=1; //打开总中断 }voidDelay(unsignedintn)//延时50us误差0us {unsignedchara,b; for(;n>0;n--) { for(b=1;b>0;b--)for(a=22;a>0;a--); }}voidInt0() interrupt0 //外部中断0的中断函数K3按键中断{ unsignedintk=0; Delay(1); //延时消抖 if(K3==0) //假如K3按键被按下的话,动态数码管就显示FFFFFFFF { KeyValue=1; flag=0; for(k=0;k<17;k++) //逐字将message[]字符数组中字符送入SBUF { SBUF=message[k]; //将接受到的数据放入到发送寄存器 while(!TI); //等待发送数据完毕 TI=0; //清除发送完毕标志位 } if(k==17) //假如message数组发送完毕就归零准备下一次 { k=0; } } else KeyValue=0; //K3按键没被按下的时候就一直保持当前状态,显示当前温度}/*******************************************************************************串口通信模块*******************************************************************************/voidUsartConfiguration() //串口设立{ SCON=0X50; //设立为工作方式1 TMOD=0X20; //设立计数器工作方式2,也就是自动重装模式 PCON=0X80; //波特率加倍 TH1=0XF3; //计数器初始值设立,注意波特率是4800的 TL1=0XF3; ES=1; //打开接受中断 EA=1; //打开总中断 TR1=1; //打开计数器}voidUsart()interrupt4 //串口中断{ unsignedcharreceiveData; receiveData=SBUF; //出去接受到的数据 RI=0; //清除接受中断标志位 CheckMessage(receiveData); //判断发送字节是否对的}voidCheckMessage(charm) //逐字检查串口通信字符是否对的{ check1[j]=m; //将串口接受到的字符一位一位的赋给check1[] if(check1[j]!=check2[j]) //按位逐字检查发送字符是否符合规定 { flag=-1; //不符合直接退出 } if(j==6) //符合时改变显示标志位,数码管显示当前温度 { flag=1; } j++; //按位检查}/*******************************************************************************动态数码管模块*******************************************************************************/voidDigDisplay()interrupt1 //动态数码管显示{ //定期器在工作方式二会自动重装初,所以不用在赋值。 TH0=0X9c; //给定期器赋初值,定期1ms TL0=0X00; GPIO_DIG=0; //消隐 switch(Num) //位选,选择点亮的数码管, { case(7): LSA=0;LSB=0;LSC=0;break;//显示第7位 case(6): LSA=1;LSB=0;LSC=0;break;//显示第6位 case(5): LSA=0;LSB=1;LSC=0;break;//显示第5位 case(4): LSA=1;LSB=1;LSC=0;break;//显示第4位 case(3): LSA=0;LSB=0;LSC=1;break;//显示第3位 case(2): LSA=1;LSB=0;LSC=1;break;//显示第2位 case(1): LSA=0;LSB=1;LSC=1;break;//显示第1位 case(0): LSA=1;LSB=1;LSC=1;break;//显示第0位 } GPIO_DIG=disp[Num]; //发送段码 Num++; //动态数码管从0到7循环点亮 if(Num>7) Num=0; }voidTimer0Configuration() //定期器初始设立{ TMOD=0X20; //选择为定期器模式,工作方式2,仅用TRX打启动动。 TH0=0X9C; //给定期器赋初值,定期100us TL0=0X9C; ET0=1; //打开定期器0中断允许 EA=1; //打开总中断 TR0=1; //打开定期器 }/*******************************************************************************温度传感器DS18B20模块*******************************************************************************/voidLcdDisplay(inttemp) //数码管显示读取到的温度{ unsignedchardatas[]={0,0,0,0,0};//定义数组 floattp; if(temp<0) //当温度值为负数 { disp[2]=0x40; //假如温度值为负数的时候,disp[2]数码管显示负号- //由于读取的温度是实际温度的补码,所以减1,再取反求出原码 temp=temp-1; temp=~temp; tp=temp; temp=tp*0.0625*100+0.5; //留两个小数点就*100,+0.5是四舍五入,由于C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算由?.5,还是在小数点后面。 } else { disp[2]=0; //假如温度不是负数,就置零 tp=temp;//由于数据解决有小数点所以将温度赋给一个浮点型变量 //假如温度是正的那么,那么正数的原码就是补码它自身 temp=tp*0.0625*100+0.5; //留两个小数点就*100,+0.5是四舍五入,由于C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算加上0.5,还是在小数点后面。 } message[9]=(temp/10000)+'0'; //具体温度的百位 message[10]=(temp%10000/1000)+'0'; //具体温度的十位 message[11]=(temp%1000/100)+'0'; //具体温度的个位 message[12]='.'; //小数点字符 message[13]=(temp%100/10)+'0'; //具体温度的十分位 message[14]=(temp%10)+'0'; //具体温度的千分位 message[15]='o'; //message[15]和[16]字符串代表°C摄氏度符号 message[16]='C'; disp[0]=0; //disp[0]和disp[1]直接置零disp[1]=0;disp[3]=DIG_CODE[temp/10000]; //数码管显示具体温度的百位 disp[4]=DIG_CODE[temp%10000/1000]; //数码管显示具体温度的十位 disp[5]=DIG_CODE[temp%1000/100]|0x80; //数码管显示具体温度的个位 //共阴接法,数码管为高电平驱动,且小数点的段接在IO的bit7,所以用|0x80来点亮小数点 disp[6]=DIG_CODE[temp%100/10]; //数码管显示具体温度的十分位 disp[7]=DIG_CODE[temp%10]; //数码管显示具体温度的千分位} 温度传感器temp.c:#include"temp.h"/********************************************************************************函数名:Delay1ms*函数功能 :延时函数*输入:无*输出 :无*******************************************************************************/voidDelay1ms(unsignedinty){ unsignedintx; for(y;y>0;y--) for(x=110;x>0;x--);}/********************************************************************************函数名:Ds18b20Init*函数功能 :初始化*输入:无*输出 :初始化成功返回1,失败返回0*******************************************************************************/unsignedcharDs18b20Init(){ unsignedinti; DSPORT=0; //将总线拉低480us~960us i=70; while(i--);//延时642us DSPORT=1; //然后拉高总线,假如DS18B20做出反映会将在15us~60us后总线拉低 i=0; while(DSPORT) //等待DS18B20拉低总线 { i++; if(i>5000)//等待>5MS return0;//初始化失败 } return1;//初始化成功}/********************************************************************************函数名:Ds18b20WriteByte*函数功能 :向18B20写入一个字节*输入:com*输出 :无*******************************************************************************/voidDs18b20WriteByte(unsignedchardat){ unsignedinti,j; for(j=0;j<8;j++) { DSPORT=0; //每写入一位数据之前先把总线拉低1us i++; DSPORT=dat&0x01;//然后写入一个数据,从最低位开始 i=6; while(i--);//延时68us,连续时间最少60us DSPORT=1; //然后释放总线,至少1us给总线恢复时间才干接着写入第二个数值 dat>>=1; }}/********************************************************************************函数名:Ds18b20ReadByte*函数功能 :读取一个字节*输入:com*输出 :无*******************************************************************************/unsignedcharDs18b20ReadByte(){ unsignedcharbyte,bi; unsignedinti,j; for(j=8;j>0;j--) { DSPORT=0;//先将总线拉低1us i++; DSPORT=1;//然后释放总线 i++; i++;//延时6us等待数据稳定 bi=DSPORT; //读取数据,从最低位开始读取 /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/ byte=(byte>>1)|(bi<<7); i=4; //读取完之后等待48us再接着读取下一个数 while(i--); } returnbyte;}/********************************************************************************函数名:Ds18b20ChangTemp*函数功能 :让18b20开始转换温度*输入:com*输出 :无*******************************************************************************/voidDs18b20ChangTemp(){ Ds18b20Init();

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论