
前言
目前单片机渗透到我们生活的各个领域,几乎很难找到哪个领域没有单片机的踪迹。导弹的导航装置,飞机上各种仪表的控制,计算机的网络通讯与数据传输,工业自动化过程的实时控制和数据处理,广泛使用的各种智能IC卡,民用豪华轿车的安全保障系统,录像机、摄像机、全自动洗衣机的控制,以及程控玩具、电子宠物等等,这些都离不开单片机。
这次课程设计,需要实现数码管显示(静态,动态)、矩阵LED,1602LCD、电机调速、扬声器、键盘等控制方法。以及51单片机的外部中断,定时器的综合应用。
1 数码管显示系统
1.1 系统工作原理
利用数码管动态显示,显示123456。
1.2 总体设计
单片机P1口段选,P2口位选。软件方面用动态循环显示法。
1.3 硬件设计
使用器件:7SEG-MPX6-CC-BLUE(6位共阳极数码管)
1.4 软件设计
#include unsigned char code table0[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//对应数码管显示数字0--9; unsigned char code table2[]={0x3e,0x3d,0x3b,0x37,0x2f,0x1f};//对应数码管的位选1--6 void display(char value); void delayms(int xms) //延时 { while(xms--); } void main() //主函数 { while(1) { display(); } } void display(char value) //显示子函数 { P2=0xff; //防干扰 P1=table0[1]; //送段选数据 P2=table2[0]; //送位选数据 delayms(800); //延时 P2=0xff; P1=table0[2]; P2=table2[1]; delayms(800); P2=0xff; P1=table0[3]; P2=table2[2]; delayms(800); P2=0xff; P1=table0[4]; P2=table2[3]; delayms(800); P2=0xff; P1=table0[5]; P2=table2[4]; delayms(800); P2=0xff; P1=table0[6]; P2=table2[5]; delayms(800); } 2 步进电机控制系统 2.1系统工作原理 通过I/O口控制步进电机运转,实现正转和反转。 2.2总体设计 P2.0—P2.3接电机励磁端驱动电机转动,P0.0—P0.1分别接正反转。 2.3硬件设计 使用芯片:ULN2003A反向放大器 2.4 软件设计 #include #define uchar unsigned char sbit reverse_key=P0^1; sbit forward_key=P0^0; uchar i; uchar const sequence[8] = {0x02,0x06,0x04,0x0c,0x08,0x09,0x01,0x03}; // 励磁表顺序表 void delay(uchar i) //延时 { uchar j,k; for(j=i;j>0;j--) for(k=125;k>0;k--); } void dispose() { if(!forward_key) //正转 { for(i=0;i<8;i++) { P2=sequence[i]; delay(500); } } if(!reverse_key) //反转 { for(i=7;i>0;i--) { P2=sequence[i]; delay(500); } } } void main() //主函数 { while(1) { dispose(); } } 2.5 系统操作说明 按下Reverse电机反转,按下Forward电机正转 3 直流电机PWM调速 3.1系统工作原理 利用单片机控制直流电机,掌握PWM调速方法。通过调节脉冲宽度,改变占空比,从而改变输出,达到改变直流电机转速目的。 3.2总体设计 P0.0和P0.1控制PWM信号波的占空比,P2.0控制波形输出以此来控制电机,软件方面,用不同延时时间改变脉冲信号占空比。 3.3硬件设计 使用芯片:ULN2003A反向放大器 3.4 软件设计 #include sbit INC=P0^0; sbit DEC=P0^1; sbit PWM=P2^0; typedef unsigned char uchar; typedef unsigned int uint; void delay(uchar i) ; void main(void) { int speed=0; while(1) { if(DEC==0) // 减速 speed = speed > 0 ? speed - 1 : 0; if(INC==0) // 加速 speed = speed < 500 ? speed + 1 : 500; PWM=1; delay(speed); PWM=0; delay(500-speed); } } void delay(uchar i) //延时 { uchar j,k; for(j=i;j>0;j--) for(k=200;k>0;k--); } 3.5系统操作说明 按下INC加速,使占空比变大。按下DEC减速,占空比减小。 4 点阵LED广告屏设计 4.1系统工作原理 用四块8*8LED点阵组成16*16LED点阵,用单片机控制点阵循环显示汉字。 4.2. 总体设计 单片机控制LED共阴极和共阳极引线,软件程序控制逐行扫描文字。 4.3硬件设计 AD0~AD15为16*16LED点阵的16个共阳极引线,分别从右到左16列二极管的共阳极电平。R0~R15为共阴极引线。P2口高四位接到8位移位寄存器(74HC595),然后输出接到LED共阳极。低四位接到74HC154上,输出接到LED的R0~R15(行选接口) 使用芯片:74HC154 4线—16线译码器,可以实现地址的扩展。 74HC595 8位串行输入/输出或者并行输出移位寄存器,具有高阻关断状态。 4.4软件设计 #include #include "intrins.h" #define uchar unsigned char sbit clk=P2^5; //74hc595 的移位脉冲sh_cp sbit sclk=P2^6; //74hc595 的并行输出脉冲st_cp sbit en=P2^4; //74hc595 的清零端mr sbit dat=P2^7; //74hc595 的数据输入端ds void hang(uchar a) { uchar k; for(k=0;k<8;k++) { dat=a&0x80; //把数组a中的一个字节与上0x80,保留最高位到P2.7 clk=1; //产生一个位移脉冲 clk=0; a<<=1; //数组a中数据左移一位 } } delay(uchar m) { uchar n; while(m--) { for(n=0;n<122;n--); } } void main() { uchar i,j,q; uchar code a[]={0x00,0x80,0x3F,0xFE,0x24,0x10,0x3F,0x7C,0x26,0x38,0x2D,0x54,0x35,0x12,0x2F,0xF8, 0x28,0x88,0x2F,0xF8,0x28,0x88,0x2F,0xF8,0x21,0x50,0x42,0xF8,0x4C,0x8A,0xB0,0x7E,}; //魔 uchar code b[]={0x08,0x20,0x04,0x40,0x3F,0xF8,0x21,0x08,0x3F,0xF8,0x21,0x08,0x3F,0xF8,0x00,0x00, 0xFF,0xFE,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,}; //兽 uchar code c[]={0x02,0x20,0x12,0x20,0x12,0x20,0x12,0x20,0x12,0x20,0xFF,0xFE,0x12,0x20,0x12,0x20, 0x12,0x20,0x12,0x20,0x13,0xE0,0x10,0x00,0x10,0x00,0x10,0x00,0x1F,0xFC,0x00,0x00,}; //世 uchar code d[]={0x00,0x00,0x1F,0xF0,0x11,0x10,0x11,0x10,0x1F,0xF0,0x11,0x10,0x11,0x10,0x1F,0xF0, 0x02,0x80,0x0C,0x60,0x34,0x58,0xC4,0x46,0x04,0x40,0x08,0x40,0x08,0x40,0x10,0x40,}; //界 while(1) { P2=0; en=1; for(j=0;j<62;j++) //第一个字,循环显示62次,造成延时效果 { for(i=0;i<32;i=i+2) //依次取32个字节 { hang(a[i]); //调数组a中一个字节点阵数据(对应点阵左半部) hang(a[i+1]); //调数组a中相邻下一个字节点阵数据(对应点阵左半部) q=(31-i)/2; //计算该行显示的编码 P2=P2&0xf0; //P2口低四位清零,高四位不变 P2=P2|q; //P2口输出对应编码值 sclk=1; sclk=0; //给74HC595一个并行数据输出脉冲,把一行显示数据同时送出 delay(100); } } for(j=0;j<62;j++) //第二个字 { for(i=0;i<32;i=i+2) { hang(b[i]); hang(b[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } for(j=0;j<62;j++) //第三个字 { for(i=0;i<32;i=i+2) { hang(c[i]); hang(c[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } for(j=0;j<62;j++) //第四个字 { for(i=0;i<32;i=i+2) { hang(d[i]); hang(d[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } } } 5 温度显示系统设计 5.1 系统工作原理 利用数字温度传感器DS18B20,测量环境温度,并在数码管上显示。低于温度下限发出长音警报,高于上限温度发出短嘀声警报并启动风扇。 5.2总体设计 单片机P0口控制数码管段选,P1口控制数码管位选,P2口分别接上警报器和风扇(直流电机)。P3.4接上DS18B20。软件方面,分为显示,警报控制,数据采集三部分程序。 5.3 硬件设计 使用芯片:DS18B20 5.4 软件设计 #include #include #include typedef unsigned char uchar; typedef unsigned int uint; sbit warn=P2^0; sbit warn1=P2^2; sbit fun=P2^1; #define C8255_A XBYTE[0x7f00] #define C8255_B XBYTE[0x7f01] #define C8255_CON XBYTE[0x7f03] sbit dq = P3^4; bit flag; uint Temperature; uchar temp_buff[9]; //存储读取的字节,read scratchpad为9字节 uchar id_buff[8]; //read rom ID为8字节 uchar *p; unsigned char code table0[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//对应数码管显示数字0--9; unsigned char code table2[]={0x3e,0x3d,0x3b,0x37,0x2f,0x1f};//对应数码管的位选1--6 /************************************************************ *Function:延时处理 *************************************************************/ void Display(); void TempDelay (uint us) { while(us--); } void TempDelay1 (uint us) { while(us--); } /************************************************************ *Function:显示程序 ************************************************************/ void Display() { uchar bai,shi,ge,k=20000; bai = Temperature/100; // 百位 shi= (Temperature%100)/10; // 十位 ge = (Temperature%100)%10; // 个位 P1=0xff; //防干扰 P0=table0[bai]; //送段选数据 P1=table2[0]; //送位选数据 TempDelay(800); //延时 P1=0xff; P0=table0[shi]; P1=table2[1]; TempDelay(800); P1=0xff; P0=table0[ge]; P1=table2[2]; TempDelay(800); } /************************************************************ *Function:18B20初始化 *************************************************************/ void Init18b20 (void) { dq=1; _nop_(); dq=0; TempDelay(86); //delay 530 uS _nop_(); dq=1; TempDelay(14); //delay 100 uS _nop_(); _nop_(); _nop_(); if(dq==0) flag = 1; //detect 1820 success! else flag = 0; //detect 1820 fail! TempDelay(20); //20 _nop_(); _nop_(); dq = 1; } /************************************************************ *Function:向18B20写入一个字节 *************************************************************/ void WriteByte (uchar wr) //单字节写入 { uchar i; for (i=0;i<8;i++) { dq = 0; _nop_(); dq=wr&0x01; TempDelay(5); //delay 45 uS //5 _nop_(); _nop_(); dq=1; wr >>= 1; } } /************************************************************ *Function:读18B20的一个字节 *************************************************************/ uchar ReadByte (void) //读取单字节 { uchar i,u=0; for(i=0;i<8;i++) { dq = 0; u >>= 1; dq = 1; if(dq==1) u |= 0x80; TempDelay (4); _nop_(); } return(u); } /************************************************************ *Function:读18B20 多字节读 *************************************************************/ void read_bytes (uchar j) { uchar i; for(i=0;i *p = ReadByte(); p++; } } /************************************************************ *Function:读取温度 *************************************************************/ void GemTemp (void) { unsigned char temp1; read_bytes (9); // 读取scratchpad中的值 temp1 = (temp_buff[0]>>4)&0x0f; // 舍去小数点 if((temp_buff[0]&0x08)==0x08) // 四舍五入 temp1 += 1; temp1 = ((temp_buff[1]<<4)&0x70)|temp1; Temperature = temp1; TempDelay(1); } /************************************************************ *Function:内部配置 *************************************************************/ void Config18b20 (void) //重新配置报警限定值和分辨率 { Init18b20(); WriteByte(0xcc); //skip rom WriteByte(0x4e); //写 scratchpad, 后跟3个字节数据 WriteByte(0x1E); //上限: 30(TH) WriteByte(0x0A); //下限: 10(TL) WriteByte(0x7f); //设置分辨率: 12 bit Init18b20(); WriteByte(0xcc); //skip rom WriteByte(0x48); //保存设定值, 写EERAM Init18b20(); WriteByte(0xcc); //skip rom WriteByte(0xb8); //回调设定值, 读EERAM } /************************************************************ *Function:读18B20ID *************************************************************/ void ReadID (void)//读取器件 id { Init18b20(); WriteByte(0x33); //read rom read_bytes(8); } /************************************************************ *Function:18B20 测温处理 *************************************************************/ void TemperatuerResult(void) { Init18b20 (); WriteByte(0xcc); //skip rom WriteByte(0x44); //温度转换指令 TempDelay(300); Init18b20 (); WriteByte(0xcc); //skip rom WriteByte(0xbe); //读取温度指令, 即读 scratchpad p = temp_buff; GemTemp(); } void main(void) { p = id_buff; ReadID(); Config18b20(); C8255_CON = 0x81; // 初始化8255 Display(); while(1) { TemperatuerResult(); // 测温 Display(); // 显示 if(Temperature>80) //大于80度程序 { while(1) { fun=0; //开风扇 warn=0; //开警报 Display(); TempDelay1(60000); Display(); warn=1; TempDelay1(60000); Display(); TemperatuerResult(); if(Temperature<=80) break; } } warn=1; //关警报 fun=1; //关风扇 //小于70度 if(Temperature<70) { while(1) { warn1=0; //开警报 Display(); TemperatuerResult(); if(Temperature>=70) break; } } warn1=1; //关警报 } } 5.5系统操作说明 超过温度上限,电机转,警报嘀嘀响,高温警报灯亮。低于温度下限,警报长时间响,低温警报灯亮。 5.6 调试结果 当超过温度上限时,数码管无法稳定显示,原因是警报延时程序干扰了显示。 6 字符型LCD显示 6.1系统工作原理 在液晶显示器上显示字符串、数字等,并循环动态显示。按下按键,改变显示。 6.2 总体设计 用单片机驱动LCD,通过软件进行控制。 6.3 硬件设计 P3.5控制LED的RS,P3.4控制LED的EN 6.4 软件设计 #include #define uchar unsigned char #define uint unsigned int uchar code table[]="Hello everyone!"; uchar code table1[]="Welcome to here!"; uchar code table2[]="My name is Huangchen!"; uchar code table3[]="I am a boy! "; int flag=1; sbit lcden=P3^4; //液晶使能端 sbit lcdrs=P3^5; //液晶数据命令选择端 sbit dula=P2^6; //申明U1锁存器的锁存端 sbit wela=P2^7; //申明U2锁存器的锁存端 uchar num; void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com) //送命令 { lcdrs=0; P0=com; delay(5); lcden=1; delay(5); lcden=0; } void write_data(uchar date) //送数据 { lcdrs=1; P0=date; delay(5); lcden=1; delay(5); lcden=0; } void init() { IT0=1; EX0=1; EA=1; lcden=0; write_com(0x38);//设置16X2显示,5X7点阵,8位数据接口 write_com(0x0c);//设置开显示,不显示光标 write_com(0x06);//写一个字符后地址指针加1 write_com(0x01);//显示清零,数据指针清零 } void main() { while(1) { if(flag%2==1) //flag为偶数,显示第一组字符串 { init(); //初始化 write_com(0x80+0x10); //设定第一行第一个字符指针位置 for(num=0;num<15;num++) { write_data(table[num]); delay(5); } write_com(0x80+0x50); //第二行...... for(num=0;num<16;num++) { write_data(table1[num]); delay(5); } for(num=0;num<16;num++) //全屏幕移动 { write_com(0x1c); delay(200); } } if(flag%2==0) //flag为奇数时显示第二组字符串 { init(); write_com(0x80+0x10); for(num=0;num<15;num++) { write_data(table2[num]); delay(5); } write_com(0x80+0x50); for(num=0;num<16;num++) { write_data(table3[num]); delay(5); } for(num=0;num<16;num++) { write_com(0x1c); delay(200); } } } } void change() interrupt 0 { flag++; //显示标志 } 6.5系统操作说明 按下按钮,即可改变显示字符串。 7 数字钟设计 7.1系统工作原理 系统从00:00:00开始计时,数码管六位动态显示时、分、钞。当他计时到00:00:10时,闹钟启动。并且,此数字钟也可用按键调整时间。该系统由指示灯指示它的工作状态。 7.2总体设计 单片机P1和P3控制数码管,其余I/O口控制按钮、蜂鸣器、指示灯。 7.3 硬件设计 7.4 软件设计 #include unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71,0x00}; unsigned char dispbitcode[]={0xfe,0xfd,0xfb,0xf7, 0xef,0xdf,0xbf,0x7f}; unsigned char dispbuf[8]={0,0,16,0,0,16,0,0}; unsigned char dispbitcnt; unsigned char second; unsigned char minite; unsigned char hour; unsigned int tcnt; unsigned char mstcnt; unsigned char i,j; sbit red=P2^0; //红灯,计时指示灯 sbit stop=P2^1; //停止 sbit start=P2^2; //开始 sbit green=P2^3; //绿灯,调整时间指示灯 sbit warn=P2^7; //闹钟 int ms=20,m; void main(void) { TMOD=0x02; TH0=0x06; TL0=0x06; TR0=1; ET0=1; EA=1; hour=0; while(1) { while(1) { if(stop==0) //按下停止键,停止计时,转入下一个if { TR0=0; break; } if((second==10)&&(minite==0)&&(hour==0)) //到达指定时间,闹钟响 while(ms--) { for(m=0;m<20;m++) warn=0; } ms=20; warn=1; } if(stop==0) { while(1) { green=0; //继续显示 P3=0xff; P1=dispcode[dispbuf[dispbitcnt]]; P3=dispbitcode[dispbitcnt]; dispbitcnt++; if(dispbitcnt==8) { dispbitcnt=0; } if(P0_0==0) //加1小时 { for(i=5;i>0;i--) for(j=248;j>0;j--); if(P0_0==0) { second++; if(second==60) { second=0; } dispbuf[0]=second%10; dispbuf[1]=second/10; while(P0_0==0); } } if(P0_1==0) //加1分钟 { for(i=5;i>0;i--) for(j=248;j>0;j--); if(P0_1==0) { minite++; if(minite==60) { minite=0; } dispbuf[3]=minite%10; dispbuf[4]=minite/10; while(P0_1==0); } } if(P0_2==0) //加1秒 { for(i=5;i>0;i--) for(j=248;j>0;j--); if(P0_2==0) { hour++; if(hour==24) { hour=0; } dispbuf[6]=hour%10; dispbuf[7]=hour/10; while(P0_2==0); } } if(start==0) { TR0=1; green=1; break; } } } } } void t0(void) interrupt 1 using 0 //计数器 { mstcnt++; if(mstcnt==8) { mstcnt=0; P3=0xff; //关闭所有显示 P1=dispcode[dispbuf[dispbitcnt]]; //开显示 P3=dispbitcode[dispbitcnt]; dispbitcnt++; if(dispbitcnt==8) { dispbitcnt=0; } } tcnt++; if(tcnt==4000) //计时算法 { tcnt=0; second++; red=!red; if(second==60) { second=0; minite++; if(minite==60) { minite=0; hour++; if(hour==24) { hour=0; } } } dispbuf[0]=second%10; //把时间入数组,传到数码管 dispbuf[1]=second/10; dispbuf[3]=minite%10; dispbuf[4]=minite/10; dispbuf[6]=hour%10; dispbuf[7]=hour/10; } } 7.5 系统操作说明 系统一上电,开始计时。按下STOP,停止计时,此时可以调整时间。按下START,继续计时。当达到指定时间,闹钟响。 7.6 调试结果 此程序无法自定义闹钟时间,还需要拓展。为了调试简化所以没用7:30:00作为闹铃响的时间。 8 电梯控制系统简易设计 8.1系统工作原理 电梯起始位置1层,按下开始按钮可不停上下循环(0~9层),当需要停时,按下停止键后在下一层停止(因为电梯有可能已通过本层的中点)。电梯的上下,有指示灯指示。 8.2 总体设计 用单片机驱动数码管显示,通过外部中断0来监测电梯是否停止。 8.3 硬件设计 8.4 软件设计 #include unsigned char code table0[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//对应数码管显示数字0--9; int num,flag=0; sbit up_led=P2^0; sbit down_led=P2^1; sbit start=P1^0; int stop=1; void main(void) { while(1) { if(start==0) { int i=1; IT0=1; EX0=1; P0=0x06; TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256 ; EA=1; ET0=1; TR0=1; while(1) { if(num==20) //上升 { down_led=1; //关下降灯 num=0; up_led=0; //开上升灯 P0= table0[i]; i++; flag++; //楼层标志器 if(stop==0) //停止程序 { while(1) { if(start==0) { num=0; stop=1; break; } } } } if(flag==8) //到达顶层 { while(1) { if(num==20) //下降 { up_led=1; // 关上升灯 num=0; down_led=0; //开下降灯 P0= table0[i]; i--; if(i==1) break; //到底层,退出循环重新开始 if(stop==0) //停止程序 { while(1) { if(start==0) { num=0; //num清零,让它多走一层 stop=1; break; } } } } } flag=0; // 楼层标志器清零 } } } } } void T0time() interrupt 1 { TH0=(65535-50000)/256; TL0=(65536-50000)%256 ; num++; } void change() interrupt 0 { stop=0; } 8.5 系统操作说明 启动电梯时,按下开时键。停止电梯时,按下停止键。 8.6 调试结果 为了方便调试,电梯没上/下一层用1秒。 9 智力竞赛抢答器 9.1系统工作原理 当主持人按下抢答器K发布抢答命令,8位参赛选手通过按下各自抢答器进行抢答。哪位选手最先按下抢答按钮,数码管显示其号码,蜂鸣器发声。表明抢答成功,所有选手的按键锁定。最后由主持人再次按下抢答器,重新开始抢答。 9.2 总体设计 用单片机I/O口控制选手按键和数码管,开始按键用外部中断0控制。 9.3 硬件设计 所用器件:74HC153,8位锁存器 9.4 软件设计 #include unsigned char code table0[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//对应数码管显示数字0--9; sbit dula=P2^6; sbit FM=P2^3; int i,key=0,flag=0; void display(); void warn(); void ini(); void main() { int temp; ini(); while(1) { if(flag==1) //如果在解锁状态 { while(1) { temp=P1; switch(temp) //选择选手 { case 0xfe: key=1; warn(); //蜂鸣器响 break; case 0xfd: key=2; warn(); break; case 0xfb: key=3; warn(); break; case 0xf7: key=4; warn(); break; case 0xef: key=5; warn(); break; case 0xdf: key=6; warn(); break; case 0xbf: key=7; warn(); break; case 0x7f: key=8; warn(); break; } display(); //显示 break; } } } } void display() //显示函数 { dula=1; //开寄存器 P0=table0[key]; dula=0; //关寄存器 } void warn() //蜂鸣器 { int k=20000; while(k--) {FM=0;} FM=1; flag=0; //锁定 } void ini() //初始化 { P0=0x00; IT0=1; EX0=1; EA=1; } void change() interrupt 0 { flag=1; //解锁 } 9.5系统操作说明 主持人按下开时键,然后选手抢答。一旦抢答结束,锁定抢答器,直至复位。 10 进制转换器 10.1系统工作原理 开始时数码管显示四个0,输入不多于四位的十进制数,然后按转换键进行转换。 10.2 总体设计 分别用单片机控制数码管和矩阵键盘,可使相应I/O口循环扫描键盘是否有件按下。数码管显示用动态显示算法。 10.3 硬件设计 10.4 软件设计 #include #define uint unsigned int #define uchar unsigned char uchar a=0,b=0,c=0,d=0,e=0,t1,t2,t3,t4; int k,num,ms=2000; uchar code KEY_TABLE[]={0xee,0xde,0xbe,0x7e, //键盘吗 0xed,0xdd,0xbd,0x7d, 0xeb,0xdb,0xbb,0x7b, 0xe7,0xd7,0xb7,0x77 }; uchar code TABLE[]={ 0x3f,0x06,0x5b,0x4f, //数码管7段吗 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71 }; sbit p00=P0^0; sbit p14=P1^4; void delay(int z) { int x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void main() { uchar temp,key,i; while(1) { P3=0xf0; //键盘检测 if(P3!=0xf0) { delay(100); //防抖 if(e<4) //存数最大值 { temp=P3; //把高四位给temp P3=0x0f; //把第四位给P3 key=temp|P3; //把八位值给key,得到键盘唯一代码 for(i=0;i<10;i++) //0~9位有效数 { if(key==KEY_TABLE[i]) //存数 { e++; //计数器加一 num=i; //记录数 delay(500);//防长按 } } if(e==1) //存数 {a=num;} if(e==2) {b=num;} if(e==3) {c=num;} if(e==4) {d=num;} } } P1=0xfe; //个位 P2=TABLE[a]; delay(1); P1=0xfd; //十位 P2=TABLE[b]; delay(1); P1=0xfb; //百位 P2=TABLE[c]; delay(1); P1=0xf7; //千位 P2=TABLE[d]; delay(1); if(p00==0) //转化键 break; } while(1) //转化 { k=a*1000+b*100+c*10+d; t1=k/4096; t2=(k%4096)/256; t3=(k%256)/16; t4=k%16; P1=0xfe; P2=TABLE[t1]; delay(1); P1=0xfd; P2=TABLE[t2]; delay(1); P1=0xfb; P2=TABLE[t3]; delay(1); P1=0xf7; P2=TABLE[t4]; delay(1); } } 10.5 系统操作说明 首先用矩阵键盘输入不高于四位的十进制数,从高位开始输入。如果小于四位高位输入0。如果输入“A”~“F”或超过四位则无效。输入好后按转换键,最后显示出16进制数。 10.6 调试结果 因为时间和算法复杂度等原因,本系统未能实现输错报警。 11 简易秒表设计 11.1系统工作原理 采用两位LED显示,显示时间为00~99秒。可有按键控制开始,暂停,复位,查看记录时间的功能。 11.2 总体设计 用单片机控制按键和数码管显示,通过程序启动单片机内部计时器用于计时。 11.3 硬件设计 11.4 软件设计 #include #define uint unsigned int #define uchar unsigned char sbit key1=P3^2; sbit key2=P3^3; sbit key3=P3^4; sbit key4=P3^5; int shu=0,t1,num,shi,ge,t0=0,i=0,tshi,tge,m=1000; unsigned char code table0[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//对应数码管显示数字0--9; unsigned char code table2[]={0x3e,0x3d,0x3b,0x37,0x2f,0x1f};//对应数码管的位选1--8 int cun[5]={0,0,0,0,0},RT; //计中间值 void display(int,int); void init(); void delay(int z) { int x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void main() { int k; init(); while(1) { display(shi,ge); if(key1==0) //翻页 { delay(5); //防抖 if(key1==0) { TR0=0; //关定时器 while(1) { i=0 ; for(k=0;k<5;k++) { tshi=0; tge=0; RT=cun[i]; tshi=RT/10; tge=RT%10; while(m--) { display(tshi,tge); } m=1000; i++; if(key3==0) //按开时键,停止翻页 break; } if(key3==0) break; } } } if(key2==0) // 暂停 { delay(5); if(key2==0) { while(!key2) display(shi,ge); TR0=0; cun[i]=shu; //把数存入数组 i++; if(i==5) i=0; } } if(key3==0) // 开始计时 { delay(5); if(key3==0) { while(!key3) display(shi,ge); TR0=1; } } } } void init() { while(1) { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; ET0=1; TR0=1; if(key3==0) { EA=1; break; } } } void timer0() interrupt 1 //定时器 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; num++; if(num==20) { num=0; shu++; if(shu==100) shu=0; shi=shu/10; ge=shu%10; } } void display(int sh,int g) //显示函数 { P2=0xff; P0=table0[sh]; P2=0xfd; delay(1); P2=0xff; P0=table0[g]; P2=0xfe; delay(1); } 11.5 系统操作说明 按下开时键,系统开始计时。需要暂停,按下暂停键。当需要查看暂停时间时,按翻页键,可看最近五次暂停结果,再次按下计时键,返回计时。系统清零,可按下复位键。 12 按键控制点阵LED广告屏 12.1系统工作原理 用四块8*8LED点阵组成16*16LED点阵,用单片机控制点阵循环显示汉字。有键盘选择不同文字。 12.2 总体设计 单片机控制LED共阴极和共阳极引线,软件程序控制逐行扫描文字。在实验4基础上,增加按键控制。 12.3 硬件设计 使用芯片:74HC154 4线—16线译码器,可以实现地址的扩展。 74HC595 8位串行输入/输出或者并行输出移位寄存器,具有高阻关断状态。 12.4 软件设计 #include #include "intrins.h" #define uchar unsigned char sbit clk=P2^5; //74hc595 的移位脉冲sh_cp sbit sclk=P2^6; //74hc595 的并行输出脉冲st_cp sbit en=P2^4; //74hc595 的清零端mr sbit dat=P2^7; //74hc595 的数据输入端ds sbit mo=P1^0; sbit shou=P1^1; sbit shi=P1^2; sbit jie=P1^3; int flag=0; void hang(uchar a) { uchar k; for(k=0;k<8;k++) { dat=a&0x80; clk=1; clk=0; a<<=1; } } delay(uchar m) { uchar n; while(m--) { for(n=0;n<122;n--); } } void main() { uchar i,j,q; uchar code a[]={0x00,0x80,0x3F,0xFE,0x24,0x10,0x3F,0x7C,0x26,0x38,0x2D,0x54,0x35,0x12,0x2F,0xF8, 0x28,0x88,0x2F,0xF8,0x28,0x88,0x2F,0xF8,0x21,0x50,0x42,0xF8,0x4C,0x8A,0xB0,0x7E,}; //魔 uchar code b[]={0x08,0x20,0x04,0x40,0x3F,0xF8,0x21,0x08,0x3F,0xF8,0x21,0x08,0x3F,0xF8,0x00,0x00, 0xFF,0xFE,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,}; //兽 uchar code c[]={0x02,0x20,0x12,0x20,0x12,0x20,0x12,0x20,0x12,0x20,0xFF,0xFE,0x12,0x20,0x12,0x20, 0x12,0x20,0x12,0x20,0x13,0xE0,0x10,0x00,0x10,0x00,0x10,0x00,0x1F,0xFC,0x00,0x00,}; //世 uchar code d[]={0x00,0x00,0x1F,0xF0,0x11,0x10,0x11,0x10,0x1F,0xF0,0x11,0x10,0x11,0x10,0x1F,0xF0, 0x02,0x80,0x0C,0x60,0x34,0x58,0xC4,0x46,0x04,0x40,0x08,0x40,0x08,0x40,0x10,0x40,}; //界 IT0=1; EX0=1; EA=1; while(1) { if(mo==0) //选择“魔” flag=1; if(shou==0) //选择“兽” flag=2; if(shi==0) //选择“世” flag=3; if(jie==0) //选择“界” flag=4; /*以下程序设计思路参考实验四*/ P2=0; en=1; if(flag==1) { for(j=0;j<62;j++) { for(i=0;i<32;i=i+2) { hang(a[i]); hang(a[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } flag=0; } if(flag==2) { for(j=0;j<62;j++) { for(i=0;i<32;i=i+2) { hang(b[i]); hang(b[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } flag=0; } if(flag==3) { for(j=0;j<62;j++) { for(i=0;i<32;i=i+2) { hang(c[i]); hang(c[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } flag=0; } if(flag==4) { for(j=0;j<62;j++) { for(i=0;i<32;i=i+2) { hang(d[i]); hang(d[i+1]); q=(31-i)/2; P2=P2&0xf0; P2=P2|q; sclk=1; sclk=0; delay(100); } } flag=0; } } } 12.5 系统操作说明 按下不同按键显示不同的字,延时一会后消失。 课程设计体会 通过这次单片机课程设计,我不仅加深了对单片机理论的理解,将理论很好地应用到实际当中去,在基本程序的基础上进行改进,使之功能不断完善,成为真己的东西。 同时在具体的制作过程中我们发现现在书本上的知识与实际的应用存在着不小的差距,书本上的知识很多都是理想化后的结论,忽略了很多实际的因素,或者涉及的不全面,可在实际的应用时这些是不能被忽略的,我们不得不考虑这方的问题,这让我们无法根据书上的理论就轻易得到预想中的结果,有时结果甚至很差别很大。通过这次实践使我更深刻的体会到了理论联系实际的重要性,我们在今后的学习工作中会更加的注重实际。 参考文献 [1] 郭天祥。 新概念51单片机C语言教程——入门、提高、开发、拓展。 北京:电子工业出版社,2009-1-1。 [2]竹青慧。 Proteus显示控制系统设计与实例。 北京:清华大学出版社,2011-5-1
