51单片机应用:8只数码管同时显示多个不同字符设计要求单片机控制8只数码管,同时显示8个字符。例如,从左至右显示“12345678”,接着显示“23456781”,在接着显示“34567812”,……“81234567”,“12345678”,分析及方案设计:本题可以采用扩展I/O口或直接用单片机自身的I/O口的方法实现。为节省硬件设施并使电路连线尽量简单,采用直接使用单片机自身I/O口的方式,8个数码管同时显示数字则需采用动态显示方法,初步设定以P0口给出数码管显示字段,P1口选中某一时刻动态点亮的数码管。软件设计可以有以下几种方案:a)将全部显示状态列出,放在主程序中不断循环b)将显示状态放入8个数组中,每个状态循环一次后主程序重新开始循环c)只设置两个数组,其中一个取值不变,为正序的从1到8的共阳极数码管段码,另一个数组中的数值不断被修改,即每次显示状态改变的时候都相应改变一次,如从12345678的段码改为23456781的段码。从上述方案可以看出,若设置太多的数组或列出所有显示状态,程序虽然清晰易懂但占用程序存储空间明显较大,且用delay()函数延时的话会不断占用CPU;用两个数组和两个定时器虽然算法略复杂,但程序可以达到最简化。详细的方案说明:1)采用数码管动态显示方法。2)8个数码管由P3控制位选,即决定某一时刻哪一个数码管亮,由P0发出的总线控制显示的段码。3)定时器T0和T1同时工作,定时时间均为0.5毫秒,采用方式1定时,每次溢出后由软件重装初值。4)设置中间变量temp,用于不断左移并给P3赋值;数组display[]为code即取之不变的数组,数组show[]中的取值变化。5)每次T0计数溢出时,temp左移一次,相应的P3左移一次,数码管由第i个点亮变为第i+1个点亮,与此同时赋给P0口的值由show[i]变为show[i+1],达到动态显示的效果。6)定时器T1也是每0.5毫秒计数溢出一次,但只有到1秒时才执行定时器1中断中修改数组show[]取值的程序,用变量t记录T1溢出的次数,达到200次时数组show[]中的内容开始进行修改并且t清零。假设showp[0]到show[7]中的取值分别为共阳极数码管显示1、2、3、4、5、6、7、8的段码,修改后分别变为显示2、3、4、5、6、7、8、1的段码,这样显示状态自然发生了改变。7)修改show[]中的取值为本程序中细节最多的部分,设置无符号长整型变量n(无符号长整型变量的取值为0到4294967295,按1秒增加1的速度计算,在实验范围内不会溢出)为显示状态总共改变的次数,易知show[0]的值为display[p],p为n除以8的余数,从此处开始循环给show[]重新赋值。硬件电路设计:程序:#includereg51.h#includeintrins.hinti,t,m,a;unsignedlongn;unsignedcharcodedisplay[]={0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};unsignedcharshow[]={0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};//数组display的取值不变,数组show的取值每次显示状态改变时均改变一次,T0中断程序只管流水使得位选从0到7时依次显示show[]中从0到7的取值//unsignedchartemp;//定时器T1中断程序控制数组show[]取值的改变,使得现实状态相应改变//unsignedcharmiddle;//i用于T0的计时循环,取值从0到7,控制P1口位选的流水;t用于T1的循环,控制每个显示状态(12345678或23456781等)的时间,1s改变一次,即t的取值从0到200////n记录显示状态改变的次数,每次改变时m从0到7为数组show循环赋值,a为中间变量,保证第n次显示状态时show[]的第0个取值恰好为n除以8的余数被记录下来//voidmain(){TMOD=0x11;//设置定时器T0、T1均为方式1工作TH0=0xee;//写入定时器T0的高8位TL0=0x00;//写入定时器T0的低8位TH1=0xee;//写入定时器T1的高8位TL1=0x00;//写入定时器T1的低8位EA=1;//打开总中断ET0=1;ET1=1;//定时器中断允许位置1TR0=1;TR1=1;//定时器开始工作i=0;temp=0x01;P3=temp;//给变量设定初值P0=show[i];//第一个数码管开始显示数字1while(1){//空的循环作为主程序,中断返回后回到主程序;}}voidt0int(void)interrupt1//定时器T0中断服务程序{TH0=0xee;//给T0重新装入16位初值,重新开始计数TL0=0x00;i++;//预备动态点亮下一个数码管if(i==8){//判断i的数值,若超过0到7的范围,清零i=0;}temp=_crol_(temp,1);//给即将动态点亮的数码管位选加高电平P3=temp;//位选从P3送出,数码管被选中P0=show[i];//P0发送总线信息为改点亮的数码管的编码,第i个数码管显示show[i]}voidt1int(void)interrupt3//定时器T1的中断服务程序,内容为数组show[]的改写,从而改变显示状态{TH1=0xee;TL1=0x00;//定时器T1重新装初值if(t200){//判断t的数值,若t200,即没到1秒钟,显示状态不改变,t增一计数;若t到200,开始修改显示状态t++;}else{t=0;//定时器T1计数溢出200次,到达时间1秒钟,t清零重新开始1秒钟计时n++;//n为总的显示状态改变次数,每次改变显示状态,n加1a=n%8;//a为n除以8的余数,记录不断变化数组show[]应取的第一个值在不变的数组display[]中的位置for(m=0;m8;m++){if(a8)//若a小于8,display[a]赋值给show[0],display[a+1]赋值给show[1]...{middle=display[a];//middle做中间变量,在数组display[]和show[]之间传递数值show[m]=middle;//每次赋值之后a加1a++;}else//a的值需要不断进行判断,若a到达8则将a清零,否则数组出错{a=a-8;middle=display[a];show[m]=middle;a++;}}}}