单片机原理课程设计报告题目:51单片机实现进制转换专业:信息工程班级:信息101学号:**********小组成员: 1004020103指导教师:***北京工商大学计算机与信息工程学院题目:51单片机实现进制转换1、设计目的1)熟悉51单片机的编程;2)熟悉单片机开发的基本焊接;3)熟悉单片机元件的使用方法;4)熟悉C51的软件开发环境(编程软件Keil、烧录软件STC_ISP_v479)2、设计要求1)按键输入数据,具有确定和清零功能;2)1602液晶屏幕显示,具有显示输入输出和提示功能;3)2,、8、10、16进制数可任意互相转化;3、硬件电路设计(包括电路图及说明)1)控制模块:控制模块是由1块STC89C52、1个12MHz无源晶振、1个复位电路22uF电容、1个1k欧姆电阻、1个8位1k欧姆排阻组成。
STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash存储器。
STC89C52使用经典的MCS-51内核,但做了很多的改进使得芯片具有传统51单片机不具备的功能。
在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。
另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。
空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。
掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
最高运作频率35MHz,6T/12T可选。
芯片实际选用的STC89C52与 protues模拟电路图中的AT89C52功能基本相同,区别在于烧录程序的方式。
2)显示模块:显示模块由1块1602液晶显示屏、16根数据线组成。
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。
它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此所以它不能很好地显示图形(用自定义CGRAM,显示效果也不好)。
1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
液晶显示屏际实际选用的是QC1602A与 protues模拟电路图中的LM016功能基本相同。
3)按键输入模块:按键输入模块由1块4*4矩阵键盘、8根数据线组成、2个独立按键。
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图1所示。
在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。
由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
矩阵式结构的键盘显然比直接法要复杂一些,识别也要复杂一些,上图中,列线通过电阻接正电源,并将行线所接的单片机的I/O口作为输出端,而列线所接的I/O口则作为输入。
这样,当按键没有按下时,所有的输入端都是高电平,代表无键按下。
行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。
实际电路中使用的是集成的1块4*4矩阵键盘,跟protues模拟电路图中的16个独立按键相比体积更小,实现的功能相同。
电路图(protues)4)全局设计:通过STC89C52的P3.0-P3.7口读入4*4矩阵键盘的按键输入数据,STC89C52的P0.0-P0.7先接入8位1k欧姆排阻作上拉电阻,再接入1602液晶屏幕的数据口D01-D07,输出数据到1602液晶屏幕,液晶屏幕显示读到的数据。
P2.1-P2.3口分别接入1602的RS、RW、E控制读写。
P2.4-P2.5口分别接入1独立按键最为“确定”键和“清零”键。
STC89C52的RST接VCC电源,即上点就复位。
XTAL1,XTAL2接12MHz无源晶振。
4、软件设计(包括流程图及程序)1)程序流程图:2)程序代码:#include<reg52.h> //#include<intrins.h>sbit RS = P2^1; //定义端口sbit RW = P2^2;sbit EN = P2^3;sbit QL = P2^4; //外接清零端口sbit QD = P2^5; //外接确定端口sbit wela=P2^7;//锁存器控制端定义unsigned int qlbz=0;unsigned int qdbz=0;#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#define KeyPort P3unsigned char code asc_code[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};//转换成液晶显示的字符/*------------------------------------------------uS延时函数------------------------------------------------*/void DelayUs2x(unsigned char t){while(--t);}/*------------------------------------------------ mS延时函数------------------------------------------------*/ void DelayMs(unsigned char t){while(t--){//大致延时1mSDelayUs2x(245);DelayUs2x(245);}}/*------------------------------------------------判忙函数------------------------------------------------*/ bit LCD_Check_Busy(void){DataPort= 0xFF;RS_CLR;RW_SET;EN_CLR;_nop_();EN_SET;return (bit)(DataPort & 0x80);}/*------------------------------------------------写入命令函数------------------------------------------------*/ void LCD_Write_Com(unsigned char com){while(LCD_Check_Busy()); //忙则等待RS_CLR;RW_CLR;EN_SET;DataPort= com;_nop_();EN_CLR;}/*------------------------------------------------写入数据函数------------------------------------------------*/void LCD_Write_Data(unsigned char Data){while(LCD_Check_Busy()); //忙则等待RS_SET;RW_CLR;EN_SET;DataPort= Data;_nop_();EN_CLR;}/*------------------------------------------------清屏函数------------------------------------------------*/void LCD_Clear(void){LCD_Write_Com(0x01);DelayMs(5);}/*------------------------------------------------写入字符串函数------------------------------------------------*/void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) {if (y == 0){LCD_Write_Com(0x80 + x);}else{LCD_Write_Com(0xC0 + x);}while (*s){LCD_Write_Data( *s);s ++;}}/*------------------------------------------------写入字符函数------------------------------------------------*/void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) {if (y == 0){LCD_Write_Com(0x80 + x);}else{LCD_Write_Com(0xC0 + x);}LCD_Write_Data( Data);}/*------------------------------------------------初始化函数------------------------------------------------*/void LCD_Init(void){LCD_Write_Com(0x38); /*显示模式设置*/DelayMs(5);LCD_Write_Com(0x38);DelayMs(5);LCD_Write_Com(0x38);DelayMs(5);LCD_Write_Com(0x38);LCD_Write_Com(0x08); /*显示关闭*/LCD_Write_Com(0x01); /*显示清屏*/LCD_Write_Com(0x06); /*显示光标移动设置*/DelayMs(5);LCD_Write_Com(0x0C); /*显示开及光标设置*/}/*------------------------------------------------按键扫描函数0,返回小键盘扫描键值------------------------------------------------*/unsigned char KeyScan(void) //键盘扫描函数,使用行列反转扫描法{unsigned char cord_h,cord_l;//行列值中间变量KeyPort=0x0f; //行线输出全为0cord_h=KeyPort&0x0f; //读入列线值if(cord_h!=0x0f) //先检测有无按键按下{DelayMs(100); //去抖if((KeyPort&0x0f)!=0x0f){cord_h=KeyPort&0x0f; //读入列线值KeyPort=cord_h|0xf0; //输出当前列线值cord_l=KeyPort&0xf0; //读入行线值while((KeyPort&0xf0)!=0xf0);//等待松开并输出return(cord_h+cord_l);//键盘最后组合码值}}return(0xff); //返回该值}/*------------------------------------------------按键扫描函数1,返回确定键扫描键值------------------------------------------------*/ unsigned char KeyScanQD(void) //键盘扫描函数{if(QD != 1) //先检测有无按键按下{DelayMs(100); //去抖if(QD != 1){while(QD == 0);//等待松开并输出}qdbz=1;}return(0); //返回该值}/*------------------------------------------------ 按键扫描函数2,返回清零键扫描键值------------------------------------------------*/ unsigned char KeyScanQL(void) //键盘扫描函数{if(QL != 1) //先检测有无按键按下{DelayMs(100); //去抖if(QL != 1){while(QL == 0);//等待松开并输出}qlbz=1;}return(0); //返回该值}/*------------------------------------------------ 按键值处理函数,返回扫键值------------------------------------------------*/ unsigned char KeyPro(void){switch(KeyScan()){case 0x7e:return 1;break;//0 按下相应的键显示相对应的码值 case 0x7d:return 2;break;//1case 0x7b:return 3;break;//2case 0x77:return 4;break;//3case 0xbe:return 5;break;//4case 0xbd:return 6;break;//5case 0xbb:return 7;break;//6case 0xb7:return 8;break;//7case 0xde:return 9;break;//8case 0xdd:return 0;break;//9case 0xdb:return 10;break;//acase 0xd7:return 11;break;//bcase 0xee:return 12;break;//ccase 0xed:return 13;break;//dcase 0xeb:return 14;break;//ecase 0xe7:return 15;break;//fdefault:return 0xff;break;}}/*------------------------------------------------主函数------------------------------------------------*/void main(void){unsigned int i,j,k,kk,Jz,num,n,t1,t2,a,b,x,y;unsigned char jinzhishu1[2],jinzhishu2[2];unsigned char dushu[16];unsigned char dushu2[16];LCD_Init();wela=1;P0=0Xff;wela=0;//关闭数码管LCD_Write_Com(0x0F);//光标开,光标闪烁开while (1){LCD_Clear();/*下为输入部分 *******************************************/A1:jinzhishu1[1]=' ';jinzhishu1[2]=' ';LCD_Write_String(0,0,"Enter IN system");i=0;while(qdbz==0){Jz=KeyPro();if(Jz!=0xff){LCD_Write_Char(i,1,asc_code[Jz]);//依次显示输入字符 jinzhishu1[i]=asc_code[Jz];i++;}KeyScanQD();KeyScanQL();if (qlbz==1){qlbz=0; LCD_Clear(); i=0; j=0;goto A1;}if(i==2) qdbz=1;}qdbz=0;LCD_Write_String(0,1," ");if (jinzhishu1[0]=='1'&&jinzhishu1[1]=='0') a=10;else if (jinzhishu1[0]=='2'&&jinzhishu1[1]==' ') a=2;else if (jinzhishu1[0]=='8'&&jinzhishu1[1]==' ') a=8;else if (jinzhishu1[0]=='1'&&jinzhishu1[1]=='6') a=16;else{LCD_Write_String(0,0,"Wrong IN system");while(qdbz==0){KeyScanQD();}qdbz=0;goto A1;}A2:for(i=0;i<16;i++){dushu2[i]=' ';dushu[i]=' ';}LCD_Write_String(0,0,"Enter IN number");i=0;while(qdbz==0){num=KeyPro();if(num!=0xff){LCD_Write_Char(i,1,asc_code[num]);//依次显示输入字符dushu2[i]=num;i++;}KeyScanQD();KeyScanQL();if (qlbz==1){qlbz=0; LCD_Clear(); i=0; j=0;goto A2;}if(i==15) qdbz=1;}n=i;qdbz=0;LCD_Write_String(0,1," ");A3:jinzhishu2[1]=' ';jinzhishu2[2]=' ';LCD_Write_String(0,0,"Enter OUT system");i=0;while(qdbz==0){Jz=KeyPro();if(Jz!=0xff){LCD_Write_Char(i,1,asc_code[Jz]);//依次显示输入字符jinzhishu2[i]=asc_code[Jz];i++;}KeyScanQD();KeyScanQL();if (qlbz==1){qlbz=0; LCD_Clear(); i=0; j=0;goto A3;}if(i==2) qdbz=1;}qdbz=0;LCD_Write_String(0,1," ");if (jinzhishu2[0]=='1'&&jinzhishu2[1]=='0') b=10;else if (jinzhishu2[0]=='2'&&jinzhishu2[1]==' ') b=2;else if (jinzhishu2[0]=='8'&&jinzhishu2[1]==' ') b=8;else if (jinzhishu2[0]=='1'&&jinzhishu2[1]=='6') b=16;else{LCD_Write_String(0,0,"Wrong OUT system");while(qdbz==0){KeyScanQD();}qdbz=0;goto A3;}/*下为运算部分 *******************************************/ n=n-1;t2=dushu2[0];for(j=0;j<n;j++){t1=t2*a;t2=t1+dushu2[j+1];}x=t2; //输入的10进制数先转为10进制for(j=0;x>=b;j++){y=x%b;x=x/b;dushu[j]= asc_code[y];}y=x;dushu[j]= asc_code[y];k=j;kk=j;for(i=0;i<=kk;i++,k--){dushu2[i]=dushu[k];}for(i=0;i<=kk;i++){dushu[i]=dushu2[i];}/*下为输出部分 *******************************************/ LCD_Write_String(0,0,"The OUT number");LCD_Write_String(0,1," ");LCD_Write_String(0,1,dushu);while(qdbz==0){KeyScanQD();KeyScanQL();}qdbz=0;}}5、调试过程(包括出现的问题及解决的方法,以及要改进的地方,体会)1)硬件调试:焊接最小系统板完成之后就开始测试是否有焊接错误,首先是检验单片机的底座针脚是否联通,通过LED灯测试证明了所有的底座针脚焊接无误。