单片机学习系统课程设计_secret_第1页
单片机学习系统课程设计_secret_第2页
单片机学习系统课程设计_secret_第3页
单片机学习系统课程设计_secret_第4页
单片机学习系统课程设计_secret_第5页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

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

文档简介

1、电子系统设计一设计要求设计一个单片机学习系统,能够进行简单的单片机实验,要求具有以下功能:(A)键盘输入功能;(B)数码管显示;(C)LED显示(8位);(D)声音报警功能;设计出完整的电路原理图;编写上述部分实验程序。二方案设计1根据题目要求只需设计出单片机的最小系统就可满足。本次设计在最小系统的基础上增加一些外设,以满足单片机学习的基本要求。本单片机最小系统采用At89S52单片机作为MCU本次设计的外设增加了DS1302时钟芯片共阳极数码管1602液晶显示LED流水灯(8位)LCD12864AD0832数模转换4×4键盘24C08的存储器串口通信扬声器等。2单片机系统设计分析(

2、1)复位电路:复位电路的基本功能是:系统上电时提供复位信号,直至电源稳定后,撤销复位信号。为可靠起见,电源稳定后还要经一定的延时(共大于两个机器周期)才撤销复位信号,以电源开关或电源插头分合过程中引起抖动而影响复位。复位后P0-P3口均表现为高电平,程序计数器和特殊功能寄存器SFR全部清零。本系统采用按键手动复位方式(2) 晶振电路:晶振是为电路提供频率基准的元器件,通常分为有源晶振和无源晶振两个大类,在引脚XTAL1和XTAL2跨接晶振X1和微调电容C1、C2就构成了内部震荡方式默认值是12MHz。(3) 发光二极管电路:八个LED导通端由VCC通过上拉电阻RP1加电,并由P1口高低电平控制

3、LED发光。这里对单片机内部四个并行I/O口进行说明:1)P0端口是一个8位漏级开路型双向I/O端口,端口置1(对端口写1)时作高阻抗输入端。作为输出口时能驱动8个TTL。对内部Flash程序存储器编程时,接收指令字节;检验程序时输出指令字节,要求外接上拉电阻。在访问外部程序和外部数据存储器时,P0口是分时转换的地址(低8位)/数据总线,访问期间内部的上拉电阻起作用。2)P1端口是一个带有内部上拉电阻的8位双向I/O端口。输出时可驱动4个TTL。端口置1时,内部上拉电阻将端口拉到高电平,做输入用。对内部FLASH程序存储器编程时,接收8位地址信息。3)P2端口是一个带有内部上拉电阻的8位双向I

4、/O端口。输出时可驱动4个TTL。端口置1时,内部上拉电阻将端口拉到高电平,做输入用。对内部FLASH程序存储器编程时,接收8位地址和控制信息。在访问外部程序和16位外部数据存储器时,P2口送出高8位地址。而在访问8位地址的外部数据存储器时其引脚上的内容在此期间不会改变。4)P3端口是一个带有内部上拉电阻的8位双向I/O端口。输出时可驱动4个TTL。端口置1时,内部上拉电阻将端口拉到高电平,做输入用。对内部FLASH程序存储器编程时,接收控制信息。(4) 蜂鸣器电路:P1.7端无法直接驱动SOUNDER,通过PNP放大电流来驱动蜂鸣器。(5) 键盘电路:采用4*4矩阵式键盘,程序编写的时候采用

5、线反转法。(6) 数码管电路:本电路数码管采用四位一体共阳数码管器件,1234为位选线,adp为段码线。(7) 存储器电路:采用24C08存储器。scl为时钟线 sda为数据线。(8) 液晶LCD显示接口:本系统采用字符点阵液晶显示模块LCD1602,接口设计32-39脚为数据接口脚。(9)DS1302时钟芯片:它可以对年、月、日、周日、时、分、秒进行计时,且具有闰年补偿等多种功能.控制字节的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入DS1302中,位6如果为0,则表示存取日历时钟数据,为1表示存取RAM数据;位5至位1指示操作单元的地址;最低有效位(位0)如为0表示要进行写

6、操作,为1表示进行读操作,控制字节总是从最低位开始输出需要注意的是应用DS1302编程时涉及到进制的转换,将16进制转换成10进制。(具体算法见后面程序)(10)LCD128×64:128×64带字库液晶是一种具有4位/8位并行、2线/3线串行口多种接口方式,内部含有国籍一级,二级简体中文字库的点阵图形液晶显示模块。其分辨率为128×64,内置8192个16×16点汉字和128个16×8点ASCII字符集。编程序时具体模块分为初始化子程序、控制命令子程序、写一页子程序、读一页子程序(具体详见后面程序)三、电路原理设计,包括原理框图和电路图本次设

7、计均在PROTEUS仿真中实现。(1)复位电路:(2) 晶振电路:(3) 蜂鸣器电路:(4)发光二极管电路:(5) 键盘电路:(6) 数码管电路:(7) 存储器电路:(8) 液晶LCD显示接口:(9)DS1302时钟芯片:(10)LCD128×64:总电路图,由于器件太多,如果直接用导线相连图会很乱,所以每个模块采用标号链接方式四、驱动程序及软件流程以下程序均通过Keil编译通过。(1) 4×4矩阵键盘程序及数码管的显示: 矩阵键盘接P2口,数码管设置接P0口(如图所示)#include <AT89X51.H>unsigned char code table=0

8、xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e;unsigned char temp;unsigned char key;unsigned char i,j;void delay() /延时程序 for(i=50;i>0;i-) for(j=200;j>0;j-);void main(void) while(1) P2=0xff; P2_4=0; temp=P2; temp=temp & 0x0f; if (temp!=0x0f) delay(); /防抖动 tem

9、p=P2; temp=temp & 0x0f; if (temp!=0x0f) temp=P2; temp=temp & 0x0f; switch(temp) case 0x0e: key=7; break; case 0x0d: key=8; break; case 0x0b: key=9; break; case 0x07: key=10; break; temp=P2; P1_0=P1_0; P0=tablekey; temp=temp & 0x0f; while(temp!=0x0f) /松手检测 temp=P2; temp=temp & 0x0f; P

10、2=0xff; P2_5=0; temp=P2; temp=temp & 0x0f; if (temp!=0x0f) delay(); temp=P2; temp=temp & 0x0f; if (temp!=0x0f) temp=P2; temp=temp & 0x0f; switch(temp) case 0x0e: key=4; break; case 0x0d: key=5; break; case 0x0b: key=6; break; case 0x07: key=11; break; temp=P2; P1_0=P1_0; P0=tablekey; tem

11、p=temp & 0x0f; while(temp!=0x0f) temp=P2; temp=temp & 0x0f; P2=0xff; P2_6=0; temp=P2; temp=temp & 0x0f; if (temp!=0x0f) delay(); temp=P2; temp=temp & 0x0f; if (temp!=0x0f) temp=P2; temp=temp & 0x0f; switch(temp) case 0x0e: key=1; break; case 0x0d: key=2; break; case 0x0b: key=3;

12、break; case 0x07: key=12; break; temp=P2; P1_0=P1_0; P0=tablekey; temp=temp & 0x0f; while(temp!=0x0f) temp=P2; temp=temp & 0x0f; P2=0xff; P2_7=0; temp=P2; temp=temp & 0x0f; if (temp!=0x0f) delay(); temp=P2; temp=temp & 0x0f; if (temp!=0x0f) temp=P2; temp=temp & 0x0f; switch(temp)

13、 case 0x0e: key=0; break; case 0x0d: key=13; break; case 0x0b: key=14; break; case 0x07: key=15; break; temp=P2; P1_0=P1_0; P0=tablekey; temp=temp & 0x0f; while(temp!=0x0f) temp=P2; temp=temp & 0x0f; (2)LED的移动显示:#include <AT89X51.H> /LED的左移右移unsigned char i;unsigned char temp;unsigned

14、char a,b;void delay(void) unsigned char m,n,s; for(m=20;m>0;m-) for(n=20;n>0;n-) for(s=248;s>0;s-); void main(void) while(1) temp=0xfe; P1=temp; delay(); for(i=1;i<8;i+) a=temp<<i; b=temp>>(8-i); P1=a|b; /利用或运算来使LED左移或右移 delay(); for(i=1;i<8;i+) a=temp>>i; b=temp<

15、<(8-i); P1=a|b; delay(); (3)声音报警功能;程序说明:用P1.7输出1KHz和500Hz的音频信号驱动扬声器,作报警信号,1KHz信号响100ms,500Hz信号响200ms,交替进行.#include <AT89X51.H>#include <INTRINS.H> /调用空函数所设的头文件bit flag;unsigned char count;void dely500(void) unsigned char i; for(i=250;i>0;i-) _nop_(); /空操作 void main(void) while(1) f

16、or(count=200;count>0;count-) P1_7=P1_7; /取反,产生声音。 dely500(); for(count=200;count>0;count-) P1_7=P1_7; dely500(); dely500(); (4)DS1302程序(应用若干模块来设计,方便浏览)#include <REG52.H> /主模块#include "LCD1602.h"#include "DS1302.h"void Delay1ms(unsigned int count)unsigned int i,j;for(i

17、=0;i<count;i+)for(j=0;j<120;j+);main()SYSTEMTIME CurrentTime;LCD_Initial();Initial_DS1302();GotoXY(0,0);Print("Date: ");GotoXY(0,1);Print("Time: ");while(1)DS1302_GetTime(&CurrentTime);DateToStr(&CurrentTime);TimeToStr(&CurrentTime);GotoXY(6,0);Print(CurrentTime

18、.DateString);GotoXY(6,1);Print(CurrentTime.TimeString);Delay1ms(300);/模块一#ifndef LCD_CHAR_1602_2005_4_9/这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等 #ifndef x 先测试x是否被定义过 #define x 如果没有定义下面就定义x并执行下面的语句 #endif 如果已经定义了则执行#endif后面的语句#define LCD_CHAR_1602_2005_4_9#include <intrins.h>/端口定义sbit LcdRs= P

19、20;sbit LcdRw= P21;sbit LcdEn = P22;sfr DBPort = 0x80;/P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口/ LCD内部定义unsigned char LCD_Wait(void)LcdRs=0;LcdRw=1;_nop_();LcdEn=1;_nop_();LcdEn=0;return DBPort;/ 向LCD内部写入数据或命令#define LCD_COMMAND0 / Command#define LCD_DATA1 / Data#define LCD_CLEAR_SCREEN0x01 / 清屏#define

20、LCD_HOMING 0x02 / 光标返回原点void LCD_Write(bit style, unsigned char input)LcdEn=0;LcdRs=style;LcdRw=0;_nop_();DBPort=input;_nop_();/注意顺序LcdEn=1;_nop_();/注意顺序LcdEn=0;_nop_();LCD_Wait();/设置显示模式#define LCD_SHOW0x04 /显示开#define LCD_HIDE0x00 /显示关 #define LCD_CURSOR0x02 /显示光标#define LCD_NO_CURSOR0x00 /无光标 #de

21、fine LCD_FLASH0x01 /光标闪动#define LCD_NO_FLASH0x00 /光标不闪动void LCD_SetDisplay(unsigned char DisplayMode)LCD_Write(LCD_COMMAND, 0x08|DisplayMode);/设置输入模式#define LCD_AC_UP0x02#define LCD_AC_DOWN0x00 / default#define LCD_MOVE0x01 / 画面可平移#define LCD_NO_MOVE0x00 /defaultvoid LCD_SetInput(unsigned char Input

22、Mode)LCD_Write(LCD_COMMAND, 0x04|InputMode);/初始化LCDvoid LCD_Initial()LcdEn=0;LCD_Write(LCD_COMMAND,0x38); /8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); /开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); /清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); /AC递增, 画面不动/*void

23、 GotoXY(unsigned char x, unsigned char y)if(y=0)LCD_Write(LCD_COMMAND,0x80|x);if(y=1)LCD_Write(LCD_COMMAND,0x80|(x-0x40);void Print(unsigned char *str)while(*str!='0')LCD_Write(LCD_DATA,*str);str+;/*void LCD_LoadChar(unsigned char user8, unsigned char place)unsigned char i;LCD_Write(LCD_COMM

24、AND,0x40|(place*8);for(i=0; i<8; i+)LCD_Write(LCD_DATA,useri);*/*#endif/模块二#ifndef _REAL_TIMER_DS1302_2003_7_21_ /#define _REAL_TIMER_DS1302_2003_7_21_sbit DS1302_CLK = P16; /实时时钟时钟线引脚 sbit DS1302_IO = P17; /实时时钟数据线引脚 sbit DS1302_RST = P15; /实时时钟复位线引脚sbit ACC0 = ACC0;sbit ACC7 = ACC7;typedef stru

25、ct _SYSTEMTIME_unsigned char Second;unsigned char Minute;unsigned char Hour;unsigned char Week;unsigned char Day;unsigned char Month;unsigned char Year;unsigned char DateString9;unsigned char TimeString9;SYSTEMTIME;/定义的时间类型#define AM(X)X#define PM(X)(X+12) / 转成24小时制#define DS1302_SECOND0x80#define D

26、S1302_MINUTE0x82#define DS1302_HOUR0x84 #define DS1302_WEEK0x8A#define DS1302_DAY0x86#define DS1302_MONTH0x88#define DS1302_YEAR0x8C#define DS1302_RAM(X)(0xC0+(X)*2) /用于计算 DS1302_RAM 地址的宏 void DS1302InputByte(unsigned char d) /实时时钟写入一字节(内部函数) unsigned char i; ACC = d; for(i=8; i>0; i-) DS1302_IO

27、= ACC0; /相当于汇编中的 RRC DS1302_CLK = 1; DS1302_CLK = 0; ACC = ACC >> 1; unsigned char DS1302OutputByte(void) /实时时钟读取一字节(内部函数) unsigned char i; for(i=8; i>0; i-) ACC = ACC >>1; /相当于汇编中的 RRC ACC7 = DS1302_IO; DS1302_CLK = 1; DS1302_CLK = 0; return(ACC); void Write1302(unsigned char ucAddr,

28、 unsigned char ucDa)/ucAddr: DS1302地址, ucData: 要写的数据 DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1; DS1302InputByte(ucAddr); / 地址,命令 DS1302InputByte(ucDa); / 写1Byte数据 DS1302_CLK = 1; DS1302_RST = 0; unsigned char Read1302(unsigned char ucAddr)/读取DS1302某地址的数据 unsigned char ucData; DS1302_RST = 0; DS

29、1302_CLK = 0; DS1302_RST = 1; DS1302InputByte(ucAddr|0x01); / 地址,命令 ucData = DS1302OutputByte(); / 读1Byte数据 DS1302_CLK = 1; DS1302_RST = 0; return(ucData);void DS1302_SetProtect(bit flag) /是否写保护if(flag)Write1302(0x8E,0x10);/?0x80elseWrite1302(0x8E,0x00);void DS1302_SetTime(unsigned char Address, uns

30、igned char Value) / 设置时间函数DS1302_SetProtect(0);Write1302(Address, (Value/10)<<4 | (Value%10); void DS1302_GetTime(SYSTEMTIME *Time)/获取时钟芯片的时钟数据到自定义的结构型数组unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time->Second = (ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);/16进制转

31、10进制ReadValue = Read1302(DS1302_MINUTE);Time->Minute = (ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time->Hour = (ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time->Day = (ReadValue&0x70)>>4)

32、*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_WEEK);Time->Week = (ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time->Month = (ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time->Year = (ReadVa

33、lue&0x70)>>4)*10 + (ReadValue&0x0F);void DateToStr(SYSTEMTIME *Time) /将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateStringTime->DateString0 = Time->Year/10 + '0'/ '0' ascii码Time->DateString1 = Time->Year%10 + '0'Time->DateString2 = '-'Time->DateStri

34、ng3 = Time->Month/10 + '0'Time->DateString4 = Time->Month%10 + '0'Time->DateString5 = '-'Time->DateString6 = Time->Day/10 + '0'Time->DateString7 = Time->Day%10 + '0'Time->DateString8 = '0'void TimeToStr(SYSTEMTIME *Time)Time-

35、>TimeString0 = Time->Hour/10 + '0'Time->TimeString1 = Time->Hour%10 + '0'Time->TimeString2 = ':'Time->TimeString3 = Time->Minute/10 + '0'Time->TimeString4 = Time->Minute%10 + '0'Time->TimeString5 = ':'Time->TimeString6

36、= Time->Second/10 + '0'Time->TimeString7 = Time->Second%10 + '0'Time->DateString8 = '0'void Initial_DS1302(void)unsigned char Second=Read1302(DS1302_SECOND);if(Second&0x80) /判断时钟芯片是否关闭DS1302_SetTime(DS1302_SECOND,0);由于本次单片机设计的系统无法满足本次试验要求,顾重新布线仿真: (5)12864显示程序

37、:#include<reg51.h>#include"zifuku.h"#define uchar unsigned char#define uint unsigned intsbit CS1=P20;/LCD右屏幕sbit CS2=P21;/LCD左屏幕sbit RS=P22;/LCD数据、指令寄存器sbit RW=P23;/LCD读、写操作sbit E=P24;/LCD使能信号,下降沿有效/*自定义延时子函数*/void delayms(uchar z) int x,y; for(x=z;x>0;x-) for(y=110;y>0;y-);/*判

38、断LCD忙信号状*/void buys() int dat; RW=1; RS=0; do P0=0x00; E=1;dat=P0;E=0;dat=0x80 & dat; while(!(dat=0x00);/*LCD写指令函数*/void w_com(uchar com) /buys(); RW=0; RS=0; E=1; P0=com; E=0; /*LCD写数据函数*/void w_date(uchar date) /buys(); RW=0; RS=1; E=1; P0=date; E=0;/*LCD选屏函数*/void select_screen(uchar screen)

39、switch(screen) case 0: /选择全屏 CS1=0; CS2=0; break; case 1: /选择左屏 CS1=0; CS2=1; break; case 2: /选择右屏 CS1=1; CS2=0; break;/* case 3: /选择右屏 CS1=1; CS2=1; break;*/ /*LCDx向上滚屏显示*/void lcd_rol() int x; for(x=0;x<64;x+) select_screen(0);w_com(0xc0+x); delayms(500); /*LCD清屏函数:清屏从第一页的第一列开始,总共8页,64列*/void c

40、lear_screen(screen) int x,y; select_screen(screen); /screen:0-选择全屏,1-选择左半屏,2-选择右半屏 for(x=0xb8;x<0xc0;x+)/从0xb8-0xbf,共8页 w_com(x);w_com(0x40);/列的初始地址是0x40for(y=0;y<64;y+) w_date(0x00); /*LCD显示汉字字库函数*/void lcd_display_hanzi(uchar screen,uchar page,uchar col,uint mun)/screen:选择屏幕参数,page:选择页参数0-3,

41、col:选择列参数0-3,mun:显示第几个汉字的参数 int a; mun=mun*32; select_screen(screen); w_com(0xb8+(page*2); w_com(0x40+(col*16); for (a=0;a<16;a+) w_date(hanzimun+); w_com(0xb8+(page*2)+1); w_com(0x40+(col*16); for (a=0;a<16;a+) w_date(hanzimun+); /*LCD显示字符字库函数*/void lcd_display_zifuk(uchar screen,uchar page,u

42、char col,uchar mun)/screen:选择屏幕参数,page:选择页参数0-3,col:选择列参数0-7,mun:显示第几个汉字的参数 int a; mun=mun*16; select_screen(screen); w_com(0xb8+(page*2); w_com(0x40+(col*8); for (a=0;a<8;a+) w_date(zifumun+); w_com(0xb8+(page*2)+1); w_com(0x40+(col*8); for (a=0;a<8;a+) w_date(zifumun+); /*LCD显示数字字库函数*/void l

43、cd_display_shuzi(uchar screen,uchar page,uchar col,uchar mun)/screen:选择屏幕参数,page:选择页参数0-3,col:选择列参数0-7,mun:显示第几个汉字的参数 int a; mun=mun*16; select_screen(screen); w_com(0xb8+(page*2); w_com(0x40+(col*8); for (a=0;a<8;a+) w_date(shuzimun+); w_com(0xb8+(page*2)+1); w_com(0x40+(col*8); for (a=0;a<8;

44、a+) w_date(shuzimun+); /*LCD初始化函数*/void lcd_init() w_com(0x3f); /LCD开显示 w_com(0xc0); /LCD行初始地址,共64行 w_com(0xb8); /LCD页初始地址,共8页 w_com(0x40); /LCD列初始地址,共64列 /*LCD显示主函数*/void main() /第一行 int x; lcd_init(); /LCD初始化 clear_screen(0); /LCD清屏幕 lcd_display_hanzi(1,0,2,0); /LCD显示汉字 lcd_display_hanzi(1,0,3,1);

45、 /LCD显示汉字 /LCD字符汉字 lcd_display_hanzi(2,0,0,2); /LCD显示汉字 /第二行 lcd_display_zifuk(1,1,0,0); /LCD显示字符 lcd_display_zifuk(1,1,1,1); /LCD显示字符 lcd_display_zifuk(1,1,2,2); /LCD显示字符 lcd_display_zifuk(1,1,3,3); /LCD显示字符 lcd_display_zifuk(1,1,4,0); lcd_display_zifuk(1,1,5,10); lcd_display_zifuk(1,1,6,5); lcd_display_zifuk(1,1,7,6); lcd_display_shuzi(2,1,0,1); lcd_display_shuzi(2,1,1,9); lcd_display_shuzi(2,1,2,8); lcd_display_shuzi(2,1,3,6); lcd_display_zifuk(2,1,4,11); lcd_display_zifuk(2,1,5,1

温馨提示

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

评论

0/150

提交评论