单片机最小系统设计制作训练_第1页
单片机最小系统设计制作训练_第2页
单片机最小系统设计制作训练_第3页
单片机最小系统设计制作训练_第4页
单片机最小系统设计制作训练_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

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

文档简介

单片机最小系统设计制作训练3.1单片机最小系统设计制作3.1.1单片机最小系统电路板硬件设计单片机的主要功能是负责整个系统的控制,不承担复杂的数据处理任务,因此在设计单片机最小系统时通常选用AT89C5l、AT89C52、AT89S51、AT89S52(S系列芯片支持ISP功能)等型号的8位单片机作为MCU。一个典型的单片机最小系统一般由时钟电路、复位电路、片外RAM、片外ROM、按键、数码管、液晶显示器、外部扩展接口等部分组成,图3.1、图3.2分别给出了单片机最小系统的结构框图、原理图。图3.1单片机最小系统的结构框图图3.2原理图单片机最小系统时钟、复位、译码电路简介1、时钟源电路单片机内部具有一个高增益反相放大器,用于构成振荡器。通常在引脚XTALl和XTAL2跨接石英晶体和两个补偿电容构成自激振荡器,结构如图2中Y1、C16、C17。可以根据情况选择6MHz、12MHz或24MHz等频率的石英晶体,补偿电容通常选择30pF左右的瓷片电容。2、复位电路单片机小系统采用上电自动复位和手动按键复位两种方式实现系统的复位操作。上电复位要求接通电源后,自动实现复位操作。手动复位要求在电源接通的条件下,在单片机运行期间,用按钮开关操作使单片机复位。其结构如图2中R24、R26、C18和K17。上电自动复位通过电容C18充电来实现。图3.6数码管显示程序流程在编写程序时考虑到单片机的资源利用情况,使用一个定时器为键盘扫描和数码管显示更新提供定时服务,定时中断函数流程如图3.7所示。定时器定时间隔为2ms,每次进入中断调用一次显示更新函数,每两次进入中断调用一次扫描键盘函数。图3.8给出了利用以上给出的键盘扫描和数码管显示以及中断函数实现一个最简单系统的主程序流程图。在主程序中通过查询方式判断getkey(获得有效按键标志位,当获得一个有效按键后键盘扫描函数讲其置为1),当获得有效按键后令所有的数码管显示按键的数值。图3.7定时中断函数流程图3.8主程序流程图C程序代码如下:#include<absacc.h>#include<reg51.h>#include<intrins.h>#defineucharunsignedchar/*数码管物理地址*/#defineLED1XBYTE[0xA000]#defineLED2XBYTE[0xA001]#defineLED3XBYTE[0xA002]#defineLED4XBYTE[0xA003]#defineLED5XBYTE[0xA004]#defineLED6XBYTE[0xA005]#defineLED7XBYTE[0xA006]#defineLED8XBYTE[0xA007]/*键盘物理地址*/#defineKEYXBYTE[0xA100]/*扫描键盘使用的变量*/sbitfirst_row=P1^4;//键盘第一行控制sbitsecond_row=P1^3;//键盘第二行控制bitfirst_getkey=0,control_readkey=0;//读键盘过程中的标志位bitgetkey=0;//获得有效键值标志位,等于1时代表得到一个有效键值bitkeyon=0;//防止按键冲突标志位ucharkeynum=0;//获得的有效按键值寄存器/*数码管显示使用的变量和常量*/ucharlednum=0;//数码管显示位控制寄存器ucharled[8]={0,0,0,0,0,0,0,0};//数码管显示内容寄存器ucharcodesegtab[18]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x8c,0xff};//七段码段码表//"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","P","black"/*函数声明*/voidleddisp(void);//数码管显示更新函数voidreadkey(void);//键盘扫描函数/*T0定时中断处理函数*/voidintT0()interrupt1{TH0=-4230/256;//定时器中断时间间隔2msTL0=-4230%256;leddisp();//每次定时中断显示更新一次if(control_readkey==1)//每两次定时中断扫描一次键盘{readkey();}control_readkey=!control_readkey;}/*主函数*/voidmain(void){TMOD=0x01;//设定定时器T0工作模式为模式1TH0=-4230/256;//定时器中断时间间隔2msTL0=-4230%256;TCON=0x10;ET0=1;EA=1;while(1)//等待获得有效按键{if(getkey==1)//判断是否获得有效按键{getkey=0;//当获得有效按键时,清除标志位。led[0]=keynum;//令全部数码管显示按键值led[1]=keynum;led[2]=keynum;led[3]=keynum;led[4]=keynum;led[5]=keynum;led[6]=keynum;led[7]=keynum;}}}/***************************************************键盘扫描函数原型:voidreadkey(void);功能:当获得有效按键时,令getkey=1,keynum为按键值****************************************************/voidreadkey(void){ucharM_key=0;////键盘数值暂存单元first_row=0;second_row=0;M_key=KEY;if(M_key!=0xff)//如果有连续两次按键按下,认为有有效按键按下。消除按键抖动{if(first_getkey==0){first_getkey=1;}else//当有有效按键按下时,进一步识别是哪一个按键{if(keyon==0)//防止按键冲突,当还有未释放的按键时不对其它按键动作响应{first_row=0;//扫描第一行按键second_row=1;M_key=KEY;if(M_key!=0xff){switch(M_key){case0xfe:keynum=0x00;break;case0xfd:keynum=0x01;break;case0xfb:keynum=0x02;break;case0xf7:keynum=0x03;break;case0xef:keynum=0x04;break;case0xdf:keynum=0x05;break;case0xbf:keynum=0x06;break;case0x7f:keynum=0x07;break;}}else{second_row=0;//扫描第二行按键first_row=1;M_key=KEY;switch(M_key){case0xfe:keynum=0x08;break;case0xfd:keynum=0x09;break;case0xfb:keynum=0x0a;break;case0xf7:keynum=0x0b;break;case0xef:keynum=0x0c;break;case0xdf:keynum=0x0d;break;case0xbf:keynum=0x0e;break;case0x7f:keynum=0x0f;break;}}getkey=1;//获得有效按键数值keyon=1;//防止按键冲突,当获得有效按键时将其置1}}}else{first_getkey=0;keyon=0;//防止按键冲突,当所有的按键都释放时将其清0}}/***************************************************数码管显示函数原型:voidleddisp(void);功能:每次调用轮流显示一位数码管****************************************************/voidleddisp(void){switch(lednum)//选择需要显示的数码位{case0:LED1=segtab[led[0]];break;case1:LED2=segtab[led[1]];break;case2:LED3=segtab[led[2]];break;case3:LED4=segtab[led[3]];break;case4:LED5=segtab[led[4]];break;case5:LED6=segtab[led[5]];break;case6:LED7=segtab[led[6]];break;case7:LED8=segtab[led[7]];break;}if(lednum==0)//更新需要显示的数码管位置{lednum=7;}else{lednum=lednum-1;}}3.2.3液晶接口电路及程序设计传统的显示器件数码管已经不能满足显示复杂操作界面的要求。因此最小系统中除了数码管显示器以外,还接入了一个液晶显示模块,其型号为SGM12864C,可以显示64行128列的点阵数据,通过编写相应的程序可以显示英文、汉字或图形,可以实现比较复杂的用户操作界面。硬件接口电路如图3.9所示。液晶模块的结构及操作控制请参阅SMG12864C.PDF。图3.9硬件接口电路在硬件设计中使用译码电路提供的LCD_R_CS、LCD_L_CS、LCD_E为液晶模块提供片选及使能信号。使用系统的地址信号A0控制向液晶写入的是命令字还是数据字。此外将液晶的读写控制端接地,禁止从液晶中读数据,在向液晶中写入一个数据或命令后延时一段时间再向其中写入新的数据,避免由于液晶处在忙状态导致写入错误的情况发生。根据地址译码器提供的地址以及信号A0,可以得出向液晶左右两个控制器中写入命令和数据的物理地址,下面给出在C语言中的具体定义:#defineLCD_L_DATAXBYTE[0xA201]//左半边液晶数据地址#defineLCD_R_DATAXBYTE[0xA301]//右半边液晶数据地址#defineLCD_L_CommandXBYTE[0xA200]//左半边液晶命令地址#defineLCD_R_CommandXBYTE[0xA300]//右半边液晶命令地址为了使液晶能够显示字符、汉字以及图形,需要对其进行正确的设置,具体过程如下:(1)在系统上电后对其进行初始化设置。向左右两部分控制器写入控制字0xC0,设置显示的初始行。向左右两部分控制器写入控制字0x3F,将液晶的左右两部分显示开启。此部分功能由后面给出程序中的lcd_initial()函数完成。(2)在液晶指定位置显示给定的数据。完成液晶的初始化以后,通过写入命令字确定显示的列地址和页地址,然后写入需要显示的数据。以下给出了在液晶指定位置显示大小为8*8字符、16*16汉字以及128*64图形的C语言程序,用户可以根据需要利用函数lcd_write_byte()编写显示任意大小图形和文字的函数。#include<absacc.h>#include<reg51.h>#include<intrins.h>#defineucharunsignedchar#defineLCD_L_DATAXBYTE[0xA201]//左半边液晶数据地址#defineLCD_R_DATAXBYTE[0xA301]//右半边液晶数据地址#defineLCD_L_CommandXBYTE[0xA200]//左半边液晶命令地址#defineLCD_R_CommandXBYTE[0xA300]//右半边液晶命令地址ucharcodeG[8]={0x00,0x00,0x3e,0x41,0x49,0x49,0x7a,0x00};/*G*/ucharcodeU[8]={0x00,0x00,0x3f,0x40,0x40,0x40,0x3f,0x00};/*U*/ucharcodeO[8]={0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00};/*O*//*--宋体12;此字体下对应的点阵为:宽x高=16x16--*//*--文字:国--*/ucharcodeguo[32]={0x00,0xFE,0x02,0x0A,0x8A,0x8A,0x8A,0xFA,0x8A,0x8A,0x8A,0x0A,0x02,0xFE,0x00,0x00,0x00,0xFF,0x40,0x48,0x48,0x48,0x48,0x4F,0x48,0x49,0x4E,0x48,0x40,0xFF,0x00,0x00};/*--文字:防--*/ucharcodefang[32]={0x00,0xFE,0x22,0x5A,0x86,0x02,0x08,0x08,0xF9,0x8E,0x88,0x88,0x88,0x08,0x08,0x00,0x00,0xFF,0x04,0x08,0x47,0x20,0x18,0x07,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00};/*--文字:科--*/ucharcodeke[32]={0x10,0x12,0x92,0x72,0xFE,0x51,0x91,0x00,0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00,0x04,0x02,0x01,0x00,0xFF,0x00,0x04,0x04,0x04,0x02,0x02,0x02,0xFF,0x01,0x01,0x00};/*--文字:技--*/ucharcodeji[32]={0x08,0x08,0x88,0xFF,0x48,0x28,0x00,0xC8,0x48,0x48,0x7F,0x48,0xC8,0x48,0x08,0x00,0x01,0x41,0x80,0x7F,0x00,0x40,0x40,0x20,0x13,0x0C,0x0C,0x12,0x21,0x60,0x20,0x00};/*--文字:大--*/ucharcodeda[32]={0x20,0x20,0x20,0x20,0x20,0x20,0xA0,0x7F,0xA0,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x01,0x06,0x08,0x30,0x60,0xC0,0x40,0x00};/*--文字:学--*/ucharcodexue[32]={0x40,0x30,0x10,0x12,0x5C,0x54,0x50,0x51,0x5E,0xD4,0x50,0x18,0x57,0x32,0x10,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x00};/**********************************液晶驱动函数声明***********************************/voidlcd_initial(void);voidlcd_write_byte(ucharxpos,ucharypos,uchar*byte);voidlcd_write_char(ucharchar_xpos,ucharchar_ypos,uchar*char_source_addr);voidlcd_write_hanzi(ucharhanzi_xpos,ucharhanzi_ypos,uchar*hanzi_source_addr);voidlcd_clear(void);voidlcd_fill(void);voiddelay(uchartime_nop);voidmain(void){lcd_initial();//初始化液晶lcd_clear();//液晶清屏lcd_write_char(0,0,G);//显示"A"lcd_write_char(1,0,U);//显示"B"lcd_write_char(2,0,O);//显示"C"lcd_write_hanzi(2,2,guo);//显示"国"lcd_write_hanzi(4,2,fang);//显示"防"lcd_write_hanzi(6,2,ke);//显示"科"lcd_write_hanzi(8,2,ji);//显示"技"lcd_write_hanzi(10,2,da);//显示"大"lcd_write_hanzi(12,2,xue);//显示"学"while(1){}}/*******************************************************************延时函数函数原型:voiddelay(uchartime_nop);功能:延时time_nop个nop********************************************************************/voiddelay(uchartime_nop){uchari;for(i=0;i<time_nop;i++){_nop_();}}/******************************************************************************LCD初始化原型:voidlcd_initial(void);功能:将LCD进行初始化,设置初始行并开显示******************************************************************************/voidlcd_initial(void){delay(5);LCD_L_Command=0xC0;//设置显示初始行delay(5);LCD_R_Command=0xC0;delay(5);LCD_L_Command=0x3F;//开显示delay(5);LCD_R_Command=0x3F;delay(5);}/******************************************************************************向LCD中写入一个字节数据函数原型:voidlcd_write_byte(ucharxpos,ucharypos,ucharbyte);功能:将一个字节数据byte写入液晶的(xpos,ypos)的位置处此处将液晶的显示区按照二维坐标进行定义,xpos为横坐标从左到右顺序为0-127,ypos为纵坐标从上到下顺序为0-7。******************************************************************************/voidlcd_write_byte(ucharxpos,ucharypos,uchar*byte){if(xpos<=63)//坐标位置处在液晶的左半部分{delay(5);LCD_L_Command=xpos+0x40;//设定写入数据的列地址delay(5);LCD_L_Command=ypos+0xB8;//设定写入数据的行地址delay(5);LCD_L_DATA=*byte;//向(xpos,ypos)处写数据delay(5);}else//坐标位置处在液晶的右半部分{delay(5);LCD_R_Command=(xpos-64)+0x40;//设定写入数据的列地址delay(5);LCD_R_Command=ypos+0xB8;//设定写入数据的行地址delay(5);LCD_R_DATA=*byte;//向(xpos,ypos)处写数据delay(5);}}/******************************************************************************在LCD指定位置显示一个ASIIC字符函数字符大小为8*8原型:voidlcd_write_char(ucharchar_xpos,ucharchar_ypos,uchar*char_source_addr);功能:将一个字符数据写入液晶的(char_xpos,char_ypos)的位置处此处将液晶的显示区按照二维坐标进行定义,char_xpos为横坐标从左到右顺序为0-15,char_ypos为纵坐标从上到下顺序为0-7。******************************************************************************/voidlcd_write_char(ucharchar_xpos,ucharchar_ypos,uchar*char_source_addr){uchari=0;for(i=0;i<=7;i++){lcd_write_byte(char_xpos*8+i,char_ypos,char_source_addr+i);}}/******************************************************************************在LCD指定位置显示一个汉字函数字符大小为16*16原型:voidlcd_write_hanzi(ucharhanzi_xpos,ucharhanzi_ypos,uchar*hanzi_source_addr);功能:将一个汉字数据写入液晶的(hanzi_xpos,hanzi_ypos)的位置处,此处将液晶的显示区按照二维坐标进行定义,hanzi_xpos为横坐标从左到右顺序为0-14(以半个汉字符为单位),hanzi_ypos为纵坐标从上到下顺序为0-6(以半个汉字符为单位)。******************************************************************************/voidlcd_write_hanzi(ucharhanzi_xpos,ucharhanzi_ypos,uchar*hanzi_source_addr){uchari=0;for(i=0;i<=15;i++)//写汉字的上半部分{lcd_write_byte(hanzi_xpos*8+i,hanzi_ypos,hanzi_source_addr+i);}for(i=0;i<=15;i++)//写汉字的下半部分{lcd_write_byte(hanzi_xpos*8+i,hanzi_ypos+1,hanzi_source_addr+16+i);}}/******************************************************************************LCD清屏原型:voidlcd_clear(void);功能:将LCD清屏******************************************************************************/voidlcd_clear(void){uchari,j;ucharbyte[1]={0x00};for(i=0;i<=127;i++){for(j=0;j<=7;j++){lcd_write_byte(i,j,byte);}}}/******************************************************************************LCD填充原型:voidlcd_fill(void);功能:将LCD填充为黑色******************************************************************************/voidlcd_fill(void){uchari,j;ucharbyte[1]={0xFF};for(i=0;i<=127;i++){for(j=0;j<=7;j++){lcd_write_byte(i,j,byte);}}}3.4单片机与D/A、A/D转换电路制作A/D、D/A转换器是单片机电路经常要用到的器件。在电子设计中,很多时候需要处理模拟量,对模拟量进行控制。这就要使用到A/D、D/A转换器,将模拟量转换成数字量,由单片计进行处理,再将数字量转换为模拟量,对外围设备进行控制。由于单片机本身工作速度慢,不能连接高速A/D、D/A转换器,同时为了节省单片机IO口资源,本节仅就低速串行转换器进行介绍。如果需要使用高速A/D、D/A转换器,请使用FPGA对其进行控制。3.4.1串行模数转换器应用串行输出的A/D芯片由于节省单片机的I/O口线,越来越多地被采用。如具有SPI三线接口的TLC1549、TLC1543、TLC2543、MAX187等,具有2线IIC接口的MAX127、PCF8591(4路8位A/D,还含1路8位D/A)等。本小节以串行A/D转换器芯片TLC1549为例简要介绍串行A/D转换器的接口电路以及驱动程序的设计。1、TLC1549的工作方式及时序TLC1549有6种工作方式,如表2所示。其中方式1和方式3属同一类型,方式2和方式4属同一类型。一般来说,时钟频率高于280kHz时,可认为是快速工作方式;低于280kHz时,可认为是慢速工作方式。因此,如果不考虑I/OCLOCK周期大小,方式5与方式3相同,方式6与方式4相同。表2TLC1549的工作方式工作方式1工作时序图如图3.10所示。图中从EQ\*jc2\o\ad(\s\up17(————),CS)下跳到DATA输出数据要有1.3μs的延时;连续进行A/D转换时,在上次转换结果输出的过程中,同时完成本次转换的采样,这样大大提高了A/D转换的速率。如果I/OCLOCK的时钟频率为2.1MHz,则完成一次A/D转换的时间大约为26μs。如果用连续模拟信号进行采样转换,显然其转换速率是很高的。图3.10方式1工作时序2、TLC1549与单片机最小系统的接口电路设计使用单片机小系统控制TLC1549,主要通过扩展接口J4完成,J4各管脚信号定义请参见图3.2小系统原理图。需要控制的芯片管脚有三个,分别为EQ\*jc2\o\ad(\s\up17(————),CS)、I/OCLOCK和DATAOUT,选用J4中的P10、P11和P12(实际是单片机P1口中的三个I/O管脚)分别控制TLC1549三个管脚。使用单片机的I/O模拟图12中的操作时序,完成对TLC1549的控制。接口电路如图3.11所示。在电路中使用VCC作为A/D的参考电平,由于VCC的不稳定会降低转换精度,因此可以选用专用的参考电压芯片,提高转换精度。图3.11接口电路3、A/D转换接口程序设计编写驱动TLC1549的程序,就是通过软件的方法控制P10、P11和P12,产生如图3.10中的操作时序,完成一次A/D转换。使用C编写的采样函数如下:#include<absacc.h>#include<reg51.h>#include<intrins.h>#defineucharunsignedchar#defineuintunsignedintsbitAD_CS=P1^0;//TLC1549片选信号sbitAD_IOCLOCK=P1^1;//TLC1549时钟信号sbitAD_DATAOUT=P1^2;//TLC1549数据输出信号/*A/D转换函数声明*/uintad_convert(void);voiddelay(uchartime_nop);voidmain(void){uintad_data_10bit;//低10位为有效数据AD_CS=1;//初始化TLC1549AD_IOCLOCK=0;while(1){ad_data_10bit=ad_convert();delay(50);//完成一次采样后要延时21us,等待下一次采样结果转换完成}}/*************************************************************AD转换函数函数原型:uintad_convert(void);功能:驱动TLC1549完成一次A/D采样返回值为AD转换结果,使用16bit的uint型数据表示,低10位有效.*************************************************************/uintad_convert(void){uchari;uintAD_DATA=0;AD_CS=0;for(i=0;i<=9;i++){AD_IOCLOCK=0;if(AD_DATAOUT==1){AD_DATA=AD_DATA*2+1;}else{AD_DATA=AD_DATA*2;}AD_IOCLOCK=1;}AD_IOCLOCK=0;AD_CS=0;return(AD_DATA);}/*******************************************************************延时函数函数原型:voiddelay(uchartime_nop);功能:延时time_nop个nop********************************************************************/voiddelay(uchartime_nop){uchari;for(i=0;i<time_nop;i++){_nop_();}}3.4.2串行数模转换器应用单片机实现控制是以数字信号或模拟信号的形式通过I/O口送给被控对象的。模拟信号的产生通常需要D/A转换器的参与。本小节以串行D/A转换芯片TLC5615为例简要介绍串行D/A转换器的接口电路以及驱动程序的设计。1、芯片性能10位CMOS电压输出;5V单电源工作;与微处理器3线串行接口(SPI);最大输出电压是基准电压的2倍;输出电压具有和基准电压相同的极性;建立时间12.5μs;内部上电复位;低功耗,最高为1.75mW;更具体的性能参数请参阅TLC5615.PDF2、管脚及其功能TLC5615的引脚排列及功能说明

温馨提示

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

评论

0/150

提交评论