单片机技能培训报告.docx
《单片机技能培训报告.docx》由会员分享,可在线阅读,更多相关《单片机技能培训报告.docx(31页珍藏版)》请在冰豆网上搜索。
单片机技能培训报告
单片机技能与认证培训设计报告
题目:
简易计算器
姓名:
学号:
系别专业:
班级:
完成时间:
华南理工大学广州学院电子信息工程学院
简易计算器
一、性能指标
A.至少能正常显示8位数;
B.能对整数进行加、减、乘、除运算;
C.能对小数进行加、减运算;
D.运算结果如果超出可显示位数时能进行出错提示;
键盘只有16个按键,安排如下:
|1|2|3|+|
|4|5|6|-|
|7|8|9|/|
|*|0|=|.|
二.设计方案
按照系统设计的功能的要求,确定设计系统由主控模块、显示模块、按键提示模块、键扫描接口电路、扩张功能模块共五个模块组成,主控芯片使用51系列STC89C52单片机。
键盘电路采用4*4矩阵键盘电路。
显示模块采用LCD1062。
提示电路采用5V扬声器。
方案论证与对比
方案1:
使用89C52单片机计算和LED数码管显示。
成本最为低廉,因显示的位数的限制,计算的数字位数较少,不方便支持小数显示。
方案2:
使用89C52单片机计算和1602LCD显示。
成本相对使用数码管要高一点,但能支持更多位数的显示计算。
方案论证:
因为简易计算器对硬件要求不高,所以两个方案的区别主要在于显示单元的不同。
用LCD显示的话能显示的位数比数码管的要多,理论能达成的计算能力比用数码管来显示要好。
方案选定:
因考虑到做出的作品可以不仅是作为简易计算器,通过刷写新的程序还可以实现更复杂的计算功能,经过组内讨论后达成一致意见,方案2相对方案1更为灵活,同时也能最大限度的利用现有的硬件资源,所以最后采用方案2.
三、硬件设计及说明
1、主控电路设计
STC89C52是一个低功耗,高性能CMOS8位单片机。
具有如下特点:
40个引脚(引脚图如图1所示),4kBytesFlash片内程序存储器,128bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。
同时该芯片还具有PDIP、TQFP和PLCC等三种封装形式,以适应不尌产品的需求。
图1STC89C52芯片引脚图
2、单片机最小系统
单片机最小系统就是支持主芯片正常工作的最小电路部分,包括主控芯片、复位电路和晶振电路。
晶振选取11.0592MHz,晶振旁电容选取20pF。
采用按键复位电路,电阻分别选取100Ω和10K,电容选取0.1μF。
以下为单片机最小系统硬件电路图。
3、LCD1602显示电路
1602采用标准的16脚接口,其中:
显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
第1脚:
VSS为电源地
第2脚:
VDD接5V电源正极
第3脚:
V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最
(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:
RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:
RW为读写信号线,高电平
(1)时进行读操作,低电平(0)时进行写操作。
第6脚:
E(或EN)端为使能(enable)端。
第7~14脚:
D0~D7为8位双向数据端。
第15~16脚:
空脚或背灯电源。
15脚背光正极,16脚背光负极
4、键盘电路设计
键盘输入采用4*4的矩阵键盘。
5、控制单元:
四、软件设计及说明
程序流程:
首先初始化参数和屏幕显示,调用键值扫描函数扫描输入的键值。
如果扫描到输入的值为数字“0~9”部分,对输入的连续的数值进行储存处理并显示在LCD上,超出限定位数自动清屏。
如果扫描到的键值为定义的“加减乘除”功能,判定输入的功能信号,进行相关函数处理,如果出现非法操作,进行清屏操作。
如果扫描到的键值为定义的“等于”功能,对先后输入储存的值进行对应的运算,并在LCD上显示出运算结果。
如果扫描到输入的值为定义的“归零”功能,进行归零操作,初始化储存的运算数值,清空屏幕,使显示归零。
程序流程图如下图显示。
五、测试方法与测试结果
测试方法:
进行加减乘除算法
测试结果表格:
测试算法
测试输入
显示结果
加法
0.5+2
2.5
2012+1991
4003
减法
95245-2345
92900
9.495-6.3358
3.1592
乘法
1991X414
5.4*7.9
42.66
除法
8606/2
4303
96.54/0.2
482.7
X
1.23469e+11
六、拓展功能
单片机与计算机实现串口通信
功能一:
字符串的发送和接收
功能二:
当前温度的发送和接收
RS-232串口模块DS18B20温度模块
MAX232芯片
MAX232是一种把电脑的串行口RS232信号电平(-10,+10v)转换为单片机所用到的TTL信号点平(0,+5)的芯片。
引脚介绍
第一部分是电荷泵电路。
由1、2、3、4、5、6脚和4只电容构成。
功能是产生+12v和-12v两个电源,提供给RS-232串口电平的需要。
第二部分是数据转换通道。
由7、8、9、10、11、12、13、14脚构成两个数据通道。
其中13脚(R1IN)、12脚(R1OUT)、11脚(T1IN)、14脚(T1OUT)为第一数据通道。
8脚(R2IN)、9脚(R2OUT)、10脚(T2IN)、7脚(T2OUT)为第二数据通道。
TTL/CMOS数据从T1IN、T2IN输入转换成RS-232数据从T1OUT、T2OUT送到电脑DB9插头;
DB9插头的RS-232数据从R1IN、R2IN输入转换成TTL/CMOS数据后从R1OUT、R2OUT输出。
第三部分是供电。
15脚GND、16脚VCC(+5v)。
DS18B20温度模块
(1)应用中不需要外部任何元器件即可实现测温电路。
(2)测温范围-55~+125℃,最大精度0.0625℃。
(3)只通过一条数据线即可实现通信。
(4)每个DS1820器件上都有独一无二的序列号,所以一条数据线上可以挂接很多该传感器。
(5)内部有温度上、下限告警功能。
DS18B20引脚定义:
(1)DQ为数字信号输入/输出端;
(2)
(2)GND为电源地;
(3)(3)VDD为外接供电电源输入端(在寄生电源接线方式时接地)。
七、总结
本次单片机技能与认证培训是学了单片机后的又一次实际应用,获益匪浅。
通过本次课程设计自己真正的完成了对给定要求系统的硬件选择及设计、电路设计、软件设计以及对成品的调试过程。
通过本次课程设计发现可以通过自己所学的知识做出可以实际应用的电子产品,增强自己的自信心。
在设计过程中发现问题,解决问题,虽然过程挺累的,但通过学习又扩张了我们的知识面,学到了新的单片机内容。
刚开始写程序时问题一大堆,就算是写个小程序验证下自己的某个想法都很吃力,但经过痛苦的好几天钻研后,才有了实质的进展,最后才能基本上写出程序,在最后一个星期完善了扩展功能同时消除了执行过程的按键稳定性问题,在调试过程中同样经历了诸多问题,但通过努力,最后解决了困难!
在收获的同时也发现了自己诸多方面的不足,基础知识不够扎实,实际操作还不够熟练,很多东西都只停留在理论上,对于实际的硬件器件及芯片不够了解,在应用时比较吃力,说明没有将理论很好的与实际联系,同时自己电子方面知识面还不够广,应该加强在电子方面的相关知识,提高自己的电子专业技能。
八、附录
#include
#include
#include
#defineuintunsignedint
#defineucharunsignedchar
#defineCHECK_BUSY
sbitSPK=P1^0;//定义喇叭端口
sbitled1=P2^1;//定义LED灯端口
sbitled2=P2^2;//定义LED灯端口
/*---------------LCD液晶显示定义-------------------*/
sbitRS=P2^4;//定义端口
sbitRW=P2^5;
sbitEN=P2^6;
#defineDataPortP0//LCD液晶D0~~D7
bitLCD_Check_Busy(void);//判断LCD忙还是空闲
voidLCD_Write_Com(ucharcom);//写入命令函数
voidLCD_Write_Data(ucharData);//写入数据函数
voidLCD_Clear(void);//LCD清屏
voidLCD_Write_String(ucharx,uchary,uchar*s);//写入字符串函数
voidLCD_Write_Char(ucharx,uchary,ucharData);//写入字符函数
voidLcd_User_Chr(void);//LCD设定自定义字符
voidLCD_Init(void);//LCD初始化函数
/*--------------------按键定义-----------------------------*/
#defineKeyPortP3//矩阵式键盘按键
ucharKeyScan(void);//键盘扫描函数
ucharKeyPro(void);//按键值处理函数
/*---------------------延时函数定义------------------------*/
voidDelayUs2x(uchart);//延时函数
voidDelayMs(uchart);//延时函数
/*------------------------温度定义---------------------------*/
sbitkey1=P2^7;//转换温度按键
sbitDQ=P2^3;//ds18b20端口
bitInit_DS18B20(void);
ucharReadOneChar(void);
voidWriteOneChar(uchardat);
uintReadTemperature(void);
bitReadTempFlag;//定义读时间标志
voidInit_Timer0(void);//定时器初始化
/*--------------------LCD液晶串口定义--------------------*/
sbitkey2=P2^0;//LCD液晶字符写入串口设置按键
ucharLCD_Buffer[16],*q,com_dat,ii,ss;//从串口接收的数据
voidSendByte(uchardat);//发送一个字节
voidSendStr(uchar*s);//发送一个字符串
/*------------------------串口通讯初始化-----------------*/
voidInitUART(void)
{
SCON=0x50;//SCON:
模式1,8-bitUART,使能接收
TMOD|=0x20;//TMOD:
timer1,mode2,8-bit重装
TH1=0xFD;//TH1:
重装值9600波特率晶振11.0592MHz
TR1=1;//TR1:
timer1打开
EA=1;//打开总中断
}
/*------------------------主程序---------------------*/
main()
{
ucharnum,i,sign,s,temp[16];
inttemp1;
floattemperature;
chardisplaytemp[16];//定义显示区域临时存储数组
bitfirstflag;
floata=0,b=0;
ucharcom_dat=0;
LCD_Init();//初始化液晶屏
DelayMs(10);//延时用于稳定液晶
LCD_Clear();//LCD清屏
LCD_Write_String(0,0,"Welcometoenjoy");//在LCD第一行写入信息
LCD_Write_String(0,1,"****ourwork****");//在LCD第二行写入信息
for(s=0;s<15;s++)//延时
DelayMs(150);
LCD_Clear();//LCD清屏
LCD_Write_String(0,0,"LCDcalculator");//写入第一行信息
LCD_Write_String(0,1,"Fun:
+-x/");//写入第二行信息
for(s=0;s<15;s++)//延时
DelayMs(150);
LCD_Clear();//LCD清屏
while
(1)//主循环
{
if(key1==0)
{
led1=0;
led2=1;
Init_Timer0();//定时器初始化
Lcd_User_Chr();//写入自定义字符
LCD_Write_String(0,0,"Todaytemperature");
LCD_Write_Char(14,1,0x01);//写入温度右上角点
LCD_Write_Char(15,1,'C');//写入字符C
for(s=0;s<15;s++)//延时
DelayMs(15);
if(ReadTempFlag==1)
{
ReadTempFlag=0;
temp1=ReadTemperature();
temperature=(float)temp1*0.0625;
sprintf(displaytemp,"%7.3f",temperature);//输出温度值
LCD_Write_String(0,1,displaytemp);//显示第二行
InitUART();
SendStr(displaytemp);//串口发送一个温度值
DelayMs(240);//延时循环发送
DelayMs(240);
}
}
if(key2==0)
{
led2=0;
led1=1;
LCD_Clear();//LCD清屏
InitUART();
ES=1;
P1=0x01;
q=LCD_Buffer;
LCD_Write_String(0,0,q);//显示第行
com_dat=0;
DelayMs(500);
}
else
{
led1=0;
led2=0;
EA=0;
num=KeyPro();//扫描键盘
if(num!
=0xff)//如果扫描是按键有效值则进行处理
{
if(i==0)//输入是第一个字符的时候需要把该行清空
LCD_Clear();
if(('+'==num)||(i==16)||('-'==num)||('x'==num)||('/'==num)||('='==num))//输入数字最大值,输入符号表示输入结束
{
i=0;//计数器复位
if(firstflag==0)//如果是输入的第一个数据,赋值给a,并把标志位置,到下一个数据输入时可以跳转赋值给b
{
sscanf(temp,"%f",&a);
firstflag=1;
}
else
sscanf(temp,"%f",&b);
for(s=0;s<16;s++)//赋值完成后把缓冲区清零,防止下次输入影响结果
temp[s]=0;
LCD_Write_Char(0,1,num);
if(num!
='=')//判断当前符号位并做相应处理
sign=num;//如果不是等号记下标志位
else
{
firstflag=0;//检测到输入=号,判断上次读入的符合
switch(sign)
{
case'+':
a=a+b;
break;
case'-':
a=a-b;
break;
case'x':
a=a*b;
break;
case'/':
a=a/b;
break;
default:
break;
}
sprintf(temp,"%g",a);//输出浮点型,无用的不输出
LCD_Write_String(1,1,temp);//显示到液晶屏
sign=0;a=b=0;//用完后所有数据清零
for(s=0;s<16;s++)
temp[s]=0;
}
}
elseif(i<16)
{
if((1==i)&&(temp[0]=='0'))//如果第一个字符是,判读第二个字符
{
if(num=='.')//如果是小数点则正常输入,光标位置加
{
temp[1]='.';
LCD_Write_Char(1,0,num);//输出数据
i++;
}
else
{
temp[0]=num;//如果是-9数字,说明没有用,则直接替换第一位
LCD_Write_Char(0,0,num);//输出数据
}
}
else
{
temp[i]=num;
LCD_Write_Char(i,0,num);//输出数据
i++;//输入数值累加
}
}
}
}
}
}
/*--------------------------串口中断程序----------------*/
voidUART_SER(void)interrupt4//串行中断服务程序
{
if(RI==1)//判断是接收中断产生
{
LCD_Buffer[com_dat]=SBUF;//把从串口读出的数存到数组
P1=0x00;
SBUF=LCD_Buffer[com_dat];//把从串口读出的数存到数组
RI=0;
com_dat++;
if(com_dat==16)com_dat=0;//当com_dat=16时,清,防止数组溢出
}
if(TI)//如果是发送标志位,清零
TI=0;
}
bitLCD_Check_Busy(void)//判断LCD忙还是空闲
{
#ifdefCHECK_BUSY
DataPort=0xFF;
RS=0;
RW=1;
EN=0;
_nop_();
EN=1;
return(bit)(DataPort&0x80);
#else
return0;
#endif
}
/*------------------------写入命令函数----------------------------*/
voidLCD_Write_Com(ucharcom)
{
while(LCD_Check_Busy());//忙则等待
RS=0;
RW=0;
EN=1;
DataPort=com;
_nop_();
EN=0;
}
/*-------------------写入数据函数---------------------------*/
voidLCD_Write_Data(ucharData)
{
while(LCD_Check_Busy());//忙则等待
RS=1;
RW=0;
EN=1;
DataPort=Data;
_nop_();
EN=0;
}
/*------------------清屏函数----------------------------------*/
voidLCD_Clear(void)
{
LCD_Write_Com(0x01);
DelayMs(5);
}
/*-------------------写入字符串函数--------------------------*/
voidLCD_Write_String(ucharx,uchary,uchar*s)
{
while(*s)
{
LCD_Write_Char(x,y,*s);
s++;x++;
}
}
/*--------------写入字符函数---------------------------*/
voidLCD_Write_Char(ucharx,uchary,ucharData)
{
if(y==0)
{
LCD_Write_Com(0x80+x);
}
else
{
LCD_Write_Com(0xC0+x);
}
LCD_Write_Data(Data);
}
/*------------------LCD初始化函数----------------------------*/
voidLCD_Init(void)
{
EN=0;
LCD_Write_Com(0x38);/*显示模式设置*/
DelayMs(10);
LCD_Write_Com(0x08);/*显示关闭*/
LCD_Write_Com(0x01);/*显示清屏*/
LCD_Write_Com(0x06);/*显示光标移动设置*/
DelayMs(5);
LCD_Write_Com(0x0C);/*显示开及光标设置*/
}
/*-------------------延时初始化函数---------------------------*/
voidDelayUs2x(uchart)
{
while(--t);
}
voidDelayMs(uchart)
{
while(t--)
{
//大致延时mS
DelayUs2x(245);
DelayUs2x(245);
}
}
ucharKeyScan(void)//键盘扫描函数
{
ucharcord_h,cord