版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基础知识:C51单片机编程基础单片机的外部结构:.DIP40双列直插;.PO,PI,P2,P3四个8位准双向I/O引脚;(作为I/O输入时,要先输出高电平).电源V8(PIN40)和地线GND(PIN20);.髙电平复位RESET(PIN9);(10uF电容接V8与RESET,即可实现上电复位).内置振荡电路,外部只要接晶体至X1(PIN18)和XO(PIN19);(频率为主频的12倍).程序配置EA(PIN31)接高电平V8;(运行单片机内部ROM中的程序).P3支持第二功能:RXD、TXD、INTO、INT!、TO、T1单片机内部I/O部件:(所为学习单片机,实际上就是编程控制以下I/O部件,完成指定任务).四个8位通用I/O端口,对应引脚PO、PI、P2和P3;.两个16位定时计数器;(TMOD,TOON,TLO,THO,TL1,TH1).一个串行通信接口;(SOON,SBUF).ー个中断控制器;(IE,IP)针对AT89c52单片机,头文件AT89x52.h给出了SFR特殊功能寄存器所有端口的定义。C语言编程基础;
1.十六进制表示字节0x5a:二进制为0101101OB:0x6E为01101110。如果将一个16位二进数赋给ー个8位的字节变量,则自动截断为低8位,而丢掉髙8位。++var表示对变量var先增ー;var—表示对变量后减ー。x|=OxOf;表示为x=x|OxOf;TMOD=(TMOD&OxfO)|0x05;表示给变量TMOD的低四位赋值0x5,而不改变TMOD的高四位。While(1);表示无限执行该语句,即死循环。语句后的分号表示空循环体,也就是{;}在某引脚输出高电平的编程方法:(比如P1.3(PIN4)引脚)代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含P1.3.voidmain(void)//void发示没有输入参数,也没有函数返值,这入单片机运行的复位入口(.Pl_3=1; //给Pl_3赋值1,引脚P1.3就能输岀髙电平VCCWhile(1); //死循环,相当LOOP:gotoLOOP;1
注意:P0的每个引脚要输出高电平时,必须外接上拉电阻(如4K7)至V8电源。在某引脚输出低电平的编程方法:(比如P2.7引脚)代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含P2.7.voidmain(void)//void表示没仃输入参数,也没有函数返值,这入单片机运行的复位入口(P2_7=0; //给P2_フ赋值。,引脚P2.フ就能输出低电平GNDWhile(1); //死循环,相当LOOP:gotoLOOP;. }在某引脚输出方波编程方法:(比如P3.1引脚)代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含P3.1.voidmain(void)//void表示没有输入参数,也没仃函数返值,这入单片机运行的复位入口(While(1) //非零表示真,如果为真则执行ド面循环体的语句
P3_l=1; //给P3_l赋值1,引脚P3.1就能输出髙电平VCCP3_l=0;//给P3_l赋值0,引脚P3.1就能输出低电平•GND} //由于一直为真,所以不断输出髙、低、髙、低......,从而形成方波}将某引脚的输入电平取反后,从另ー个引脚输出:(比如P0.4=NOT(P1.1))代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含PO.4和Pl.1.voidmain(void)//void表示没仃输入参数,也没有函数返值,这入单片机运行的复位入口(Pl_l=1; //初始化。P1.1作为输入,必须输出髙电平While(1)//非零表示真,如果为真则执行下面循环体的语句1if( Pl_l ==1 ) //读取Pl.l,就是认为Pl.l为输入,如果Pl・l输入高电平VCC{ P0_4 = 0; } //给P0_4赋值〇,引脚P0.4就能输岀低电平GNDelse〃否则P1.1输入为低电平GND//{P0_4 =0; }〃给P0_4赋值0,弓I脚P0.4就能输出低电平GND{ P0_4 = 1; } //给P0_4赋值1,引脚P0.4就能输出髙电平VCC12.//由于一直为真,所以不断根据P1.1的输入情况,改变P0.4的输岀电平
12.13.}将某端口8个引脚输入电平,低四位取反后,从另ー个端口8个引脚输出:(比如P2=NOT(P3))代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含P2和P3.voidmain(void)//void表示没有输入参数,也没有函数返位,这入单片机运行的爱位入口(P3=Oxff;//初始化。P3作为输入,必须输出高电平,同时给P3口的8个引脚输出高电平While(1)〃非零表示真,如果为真则执行下面循环体的语句( //取反的方法是异或1,而不取反的方法则是异或。P2=P3へOxOf//读取P3,就是认为P3为输入,低四位异或者1,即取反,然后输出} //由于一直为真,所以不断将P3取反输出到P2)注意:ー个字节的8位D7、D6至DO,分别输出到P3.7、P3.6至P3.0,比如P3=0x0f,则P3.7、P3.6、P3.5、P3.4四个引脚都输出低电平,而P3.3、P3.2、P3.1、P3.0四个引脚都输出高电平。同样,输入一个端口P2,即是将P2.7、P2.6至P2.0,读入到ー个字节的8位D7、D6至DO。#eeOOOO;FONT-FAMILY:宋体”〉初始化。pi.1作为输入,必须输出高电平While(1) //非零表示真,如果为真则执行下面循环体的语句(if( Pl-l ==1 ) //读取P1.1,就是认为P1.1为输入,如果P1.1输入高电平VCC{ P0_4 =0; } //给P0_4赋值〇,引脚P0.4就能输出低电平GNDelse//否则Pl.1输入为低电平GND//{P0_4=0; }//给P0_4赋值0,引脚P0.4就能输出低电平GND{ P0_4 =1; } //给P0_4赋值1,リI脚P0.4就能输出高电平VCC} //由于一直为真,所以不断根据P1.1的输入情况,改变P0.4的输出电平}将某端口8个引脚输入电平,低四位取反后,从另ー个端口8个引脚输出:(比如P2=NOT(P3))代码#include〃该头文档中有单片机内部资源的符号化定义,其中包含P2和P3voidmain(void)//void表示没有输入参数,也没有函数返值,这入单片机运行的复位入口1P3=Oxff;//初始化。P3作为输入,必须输制髙电平,同时给P3”的8个引脚输岀髙电平
( //取反的方法是异或1,而不取反的方法则是异或〇P2=P3へ0xOf〃读収P3,就是认为P3为输入,低四位异或者1,即取反,然后输出} //由于一直为真,所以不断将P3取反输出到P2}注意:ー个字节的8位D7、D6至DO,分别输出到P3.7、P3.6至P3.0,比如P3=0x0f»则P3.7、P3.6、P3.5、P3.4四个引脚都输出低电平,而P3.3、P3.2、P3.1、P3.0四个引脚都输出高电平。同样,输入一个端口P2,即是将P2.7、P2.6至P2.0,读入到ー个字节的8位D7、D6至DO。第一节:单数码管按键显示单片机最小系统的硬件原理接线图:.接电源:V8(PIN4O)、GND(PIN20)。加接退耦电容0.1uF.接晶体:X1(PIN18),X2(PIN19)«注意标出晶体频率(选用12MHz),还有辅助电容30pF.接复位:RES(PIN9)〇接上电复位电路,以及手动复位电路,分析复位工作原理.接配置:EA(PIN31)»说明原因。发光二极的控制:单片机I/O输出将ー发光二极管LED的正极(阳极)接P1.1,LED的负极(阴极)接地GND。只要P1.1输出高电平V8,LED就正向导通(导通时LED上的压降大于1V),有电流流过LED,至发LED发亮。实际上由于P1.1高电平输出电阻为10K,起到输出限流的作用,所以流过LED的电流小于(5V-1V)/10K=0.4mAo只要P1.1输出低电平GND,实际小于0.3V,LED就不能导通,结果LED不亮。开关双键的输入:输入先输出高ー个按键KEY_ON接在P1.6与GND之间,另ー个按键KEYJDFF接P1.7与GND之间,按KEGON后LED亮,按KE£OFF后LED灭。同时按下LED半亮,LED保持后松开键的状态,即ON亮〇FF灭。代码#include#defineLEDP1A1〃用符号しED代替#defineKEY_ONP1A6 〃用符号KEY_ON代替Pl_6.#defineKEY_OFFP1A7 〃用符号KEY_OFF代替Pl_フ.voidmain(void) //单片机复位后的执行入口,void表示空,无输入参数,无返回值(KEY_ON=1;〃作为输入,首先输出髙,接下KEY_ON,P1.6则接地为0,杏则输入为1KEY_OFF=1;//作为输入,首先输出髙,接下KEY_OFF,P1.フ则接地为0,否则输入(.if(KEY_ON==0)LED=1;//是KEY_ON接下,所示Pl.1输出髙,LED亮if(KEY_OFF==0)LED=0;//是KEY_OFF接下,所示Pl.1输111低,LED灭}//松开键后,都不给LED赋值,所以LED保持最后按键状态。//同时按下时,LED不断亮火,各占一半时间,交替频率很快,由于人眼惯性,看上去为半亮态}数码管的接法和驱动原理ー支七段数码管实际由8个发光二极管构成,其中7个组形构成数字8的七段笔画,所以称为七段数码管,而余下的1个发光二极管作为小数点。作为习惯,分别给8个发光二极管标上记号:a,b,c,d,e,f,g,h。对应8的顶上一画,按顺时针方向排,中间一画为g,小数点为h。我们通常又将各二极与一个字节的8位对应,a(DO),b(D1),c(D2),d(D3),e(D4),f(D5),g(D6),h(D7),相应8个发光二极管正好与单片机ー个端口Pn的8个引脚连接,这样单片机就可以通过引脚输出高低电平控制8个发光二极的亮与灭,从而显示各种数字和符号;对应字节,引脚接法为:a(Pn.O),b(Pn.1),c(Pn.2),d(Pn.3),e(Pn.4),f(Pn.5),g(Pn.6),h(Pn.7)0如果将8个发光二极管的负极(阴极)内接在ー起,作为数码管的ー个引脚,这种数码管则被称为共阴数码管,共同的引脚则称为共阴极,8个正极则为段极。否则,如果是将正极(阳极)内接在ー起引出的,则称为共阳数码管,共同的引脚则称为共阳极,8个负极则为段极。以单支共阴数码管为例,可将段极接到某端口Pn,共阴极接GND,则可编写出对应十六进制码的七段码表字节数据如右图:16键码显示的程序我们在P1端口接ー支共阴数码管SLED,在P2、P3端口接16个按键,分别编号为KEY_O,KBC1到KBGF,操作时只能按ー个键,按键后SLED显示对应键编号。代码#include.#defineSLEDPl#defineKEY_0 P2Ao. #defineKEY_1 P2A1#defineKEY_2 P2A2#defineKEY_3 P2A3. #defineKEY_4 P2A4#defineKEY_5 P2A5#defineKEY_6 P2A6#defineKEY_7 P2A7#defineKEY_8P3A0
#defineKEY_9P3A1#defineKEY_AP3A2#defineKEY_BP3A3#defineKEY_CP3A4#defineKEY_DP3A5#defineKEY_EP3A618.#defineKEY_FP318.#defineKEY_FP3A7.CodeunsignedcharSeg7Code[16]=//用|一六进数作为数组下标,可直接取得对应的七段编码字节//0 1 2 3 4 5 6 7 89AbCdEF{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};voidmain(void)(.unsignedchari=0;//作为数组下标P2=Oxff;〃P2作为输入,初始化输出高P3=Oxff;//P3作为输入,初始化输出高
if(KEY_O==0)i=0;if(KEY」==0)i=l;TOC\o"1-5"\h\zif( KEY_2 == 0 ) i=2; if( KEY_3 == 0 ) i=3;if( KEY_4 == 0 ) i=4; if( KEY_5 == 0 ) i=5;if( KEY_6 == 0 ) i=6; if( KEY_7 == 0 ) i=7;if( KEY_8 == 0 ) i=8; if( KEY_9 == 0 ) i=9;if( KEY_A == 0 ) i=0xA; if( KEY_B == 0 ) i=OxB;if( KEY_C == 0 ) i=0xC; if( KEY_D == 0 ) i=OxD;if( KEY_E == 0 ) i=0xE; if( KEY_F == 0 ) i=0xF;SLED=Seg7Code[i];//开始时显示。,根据i取应七段编码}}第二节:双数码管可调秒表解:只要满足题冃要求,方法越简单越好。由于单片机I/O资源足够,所以双数码管可接成静态显示方式,两个共阴数码管分别接在P1(秒十位)和P2(秒个位)ロ,它们的共阴极都接地,安排两个按键接在P3.2(十位数调整)和P3.3(个位数调整)上,为了方便计时,选用12MHz的晶体。为了达到精确计时,
选用定时器方式2,每计数250重载一次,即250US,定义一整数变量计数重载
次数,这样计数4000次即为一秒。定义两个字节变量S10和S1分别计算秒十位和秒个位。编得如下程序:代码#include.CodeunsignedcharSeg7Code[16]=//用卜六进数作为数组下标,可直接取得对应的七段编码字节//0 1 2 3 4 5 6 7 8 9AbCdEF{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};.voidmain(void)(.unsignedintus250=0;unsignedcharslO=0;unsignedcharsi=0;.unsignedcharkeylO=0;//记忆按键状态,为1按下unsignedcharkeyl=0; //记忆按键状态,为1按下〃初始化定时器TimerOTMOD=(TMOD&0xF0)|0x02;TH1=-250;〃对于8位观数朿说,-250=6,也就是加250次1时为256,即为0Pl=Seg7Code[slO];//显示秒十位P2=Seg7Code[si];//显示秒个位while(1){ // 循环2//计时处理if(TFO==1){TFO=0;if(++US250>=4000)(us250=0;if(++sl>=10){si-0;if(++S10>=6)slO=0;TOC\o"1-5"\h\z}break;//,結朿、、循环2〃,修改显示}}//按十位键处理P3.2=1; //P3.2作为输入,先要输岀髙电平if(keylO==1){//等松键}else{//未按键if(P3.2==0){. keylO=1;if(++slO>-6)slO=0;break;//结束、、循环2”,修改显示}}//按个位键处理P3.3=1; //P3.3作为输入,先要输出高电平if(keyl==1)//等松键{if(P3.3==1)keyl=O;)else{ //未按键if(P3.3==0){keyl=1;if(++sl>=10)si=0;J. break;//”束、、循い、2〃,修改旧小52. }54.レ/循环l'end}//main*end第三节:十字路口交通灯如果ー个单位时间为1秒,这里设定的十字路口交通灯按如下方式四个步骤循环工作:60个单位时间,南北红,东西绿;X10个单位时间,南北红,东西黄;入60个单位时间,南北绿,东西红;X10个单位时间,南北黄,东西红;X解:用P1端口的6个引脚控制交通灯,高电平灯亮,低电平灯灭。代码.#include. //sbit用来定义ー个符号位地址,方便编程,提高可读性,和可移植性.sbitSNRed=P1A0;〃南北方向纟「.灯.sbitSNYellow=P1A1; //南北方向黄灯.sbitSNGreen=P1A2; //南北方向绿灯.sbitEWRed=P1A3; //东西方向红灯.sbitEWYellow=P1A4; //东西方向黄灯.sbitEWGreen=P1A5; //东西方向绿灯
9.10111213141516171819202122232425/・用软件产生延时ー个单位时间・/.voidDelaylUnit(void)・1.unsignedinti,j;.for(i=0;i<1000;i++).for(j<0;j<1000;j++);//通过实测,调整j循环次数,产生1ms延时.//还可以通过生成汇编程序来计算指令周期数,结合晶体频率来调整j循环次数,接近1ms.}./・延时n个单位时间・/.voidDelay(unsignedintn){for(;n!=0;n--)DelaylUnit();}.voidmain(void).(.while(1).(.SNRed=0;SNYellow=0;SNGreen=l;EWRed=l;EWYellow=0;EWGreen=0;Delay(60);.SNRed=0;SNYellow=l;SNGreen=0;EWRed=l;EWYellow=0;EWGreen=0;Delay(10);.SNRed=l;SNYellow=0;SNGreen=0;EWRed=0;EWYellow=0;EWGreen=l;Delay(60);
26.SNRed=l;SNYellow=0;SNGreen=O;EWRed=O;EWYellow=l;EWGreen=O;De26.lay(10);)}第四节:数码管驱动显示“12345678”P1端口接8联共阴数码管SLED8的段极:P1.7接段h,…,P1.0接段aP2端口接8联共阴数码管SLED8的段极:P2.7接左边的共阴极,…,P2.0接右边的共阴极方案说明:晶振频率fosc=12MHz,数码管采用动态刷新方式显示,在1ms定时断服务程序中实现代码#include.unsignedcharDisBuf[8]; //全局显示缓冲区,DisBuf[〇]对应右SLED,DisBuf[フ]对应左SLED,.voidDisplayBrush(void). {codeunsignedcharcathode[8]={0xfe,0xfd,0xfb,0xf7,0xefrOxdf,Oxbf,0x7f};//阴极控制码.CodeunsignedcharSeg7Code[16]=//用十六进数作为数组下标,可直接取得对应的七段编码字节
. {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,Ox5e,0x79,0x71);.staticunsignedchari=0;//(0<i^7)箱环刷新显示,由于是静态变量,此赋值只做一次。P2=Oxff;〃显示消隐,以免下一段码值显示在前ー支S耳陋Pl=Seg7Code[DisBuf[i]];〃从显示线冲区取出原始数据,査表变为七段码后送出显示.P2=cathode[i]; //将对应阴极置低,显示if(++i>=8)i=0; //指向下一个数码管和相应数据}voidTimerOIntRoute(void)interrupt1(TLO=-1000; //由于TLO只有8bits,所以將(-1000)低8位赋给TL0TH0=(-1000)>>8;//取(-1000)的髙8位赋给THO,®新定时1msDisplayBrush();}voidTimerOInit(void){TMOD=(TMOD&OxfO)|0x01;〃初始化,定时器TO,工作方式1TL0=-1000; //定时1ms22.TH0(-1000)»8;22.TH0(-1000)»8;23.TRO23.TRO1; //允许TO开始计数ETO=1; //允许TO计数溢出时产生中断请求}voidDisplay(unsignedcharindex,unsignedchardataValue){DisBuf[index]=dataValue;}2"1.voidmain(void)(9.unsignedchari;.for(i=0;i<8;i++){Display(i,8-i);}//DisBuf[〇]为右,DisBuf[7]为左TimerOInit();EA=1: 〃允许CPU响应中断请求While(1);}第五节:键盘驱动指提供ー些函数给任务调用,获取按键信息,或读取按键值。定义一个头文档,描述可用函数,如下:代码.#ifndef_KEY_H_〃防止重复引用该文档,如果没有定义过符号.KEY_H_,则编译下面语句.#define_KEY_H_〃只要引用过一次,即#include,则定义符号_KEY_H_. unsignedcharkeyHit(void);//如果按键,则返冋非〇,否则返回〇. unsignedcharkeyGet(void);//i实取按键值,如果没有按键则等待到按犍为止. voidkeyPut(unsignedcharucKeyVal);//保存按键值ucKeyVal至リ按键缓冲队列末. voidkeyBack(unsignedcharucKeyVal);//退冋键值ucKeyVal.到按键缓冲队列首.#endif定义函数体文档KEY.C,如下:代码#include''key.h/z.#defineKeyBufSize16//定义按键缓冲队列字节数. unsignedcharKeyBuf[KeyBufSize];//定义一个无符号?・符数组作为按键缓冲队歹リ。该队列为先进〃先出,循环存取,下标从。到KeyBufSize-1unsignedcharKeyBufWp=O;//作为数组下标变鼠,记录存入位置. unsignedcharKeyBufRp=O;//作为数组ド标变依,记录读出位置. //如果存入位置与读出位置相同,则表明队列中无按键数据unsignedcharkeyHit(void){if(KeyBufWp==KeyBufRp)return(0);elsereturn(1);}unsignedcharkeyGet(void){unsignedcharretVal;//暂存读出键值while(keyHit()==0);//等:待按键,因为函数keyHit()的返I川值为0表示无按键.retVal=KeyBuf[KeyBufRp];//从数组中读出键值.if(++KeyBufRp>=KeyBufSize)KeyBufRp=0;//读位置加1,超出队列则循环冋初始位置return(retVal);}voidkeyPut(unsignedcharucKeyVal){KeyBuf[KeyBufWp]=ucKeyVal;//键值存入数组if(++KeyBufWp>=KeyBufSize)KeyBufWp=0;〃存入位置加1,超出队列则循环冋初始位置}24.由于某种原因,读出的按键,没有用,但其它任务要用该按键,但传送又不方便“此时可以退回按键队列。就如取错了信件,有必要退回・样
voidkeyBack(unsignedcharucKeyVal)(/*如果KeyBufRp=O;减1后则为FFH,大于KeyBufSize,即从数组头退回到数组尾。或者由于干扰使得KeyBufRp超出队列位置,也要调整回到正常位置,*/if(―KeyBufRp>=KeyBufSize)KeyBufRp=KeyBufSize-l;KeyBuf[KeyBufRp]=ucKeyVal;//回存键值}下面渐进讲解键盘物理层的驱动。电路共同点:P2端口接ー共阴数码管,共阴极接GND,P2.0接a段、P2.1接b段 P2.7接h段。软件共同点:codeunsignedcharSeg7Code[10]是七段数码管共阴编码表。CodeunsignedcharSeg7Code[16]=//0 12 3 45 6 7 89AbCdEF{0x3f,0x06,0x5b,Ox4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71);例ー:P1.0接ー按键到GND,键编号为,6,,显示按键。代码#include#include"KEY.H".voidmain(void){Pl.。=1;//作为输入引脚,必须先输出高电平.while(1)〃永远为真,即死循环{if{Pl_0==0)//如果按键,则为低电平{keyPut(6);//保存按键编号值为按键队列while(Pl_0==0);〃如果一直按着键,则不停地执行该循环,实际是等待松键)if(keyHitO!=0)〃如果队列中有按键P2=Seg7Code[keyGetO];〃解8剧中取出按键值,并显示在数码管上)}例二:在例一中考虑按键20ms抖动问题。代码1.#include
.voidmain(void){Pl_0=1; //作为输入引脚,必须先输出髙电平while(1)〃永远为真,即死循环{if(Pl_0==0)〃如果按键,则为低电平{delay20ms();〃延时20ms,跳过接ド抖动keyPut(6);〃保存按键编号值为按键队列while(Pl_0==0);//如果一直按看键,则不停地执行该循环,实际是等待松键.delay20ms();〃延时20ms,跳过松开抖动)if(keyHit〇!=0)//如果队列中有按键P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上)}例三:在例二中考虑干扰问题。即小于20ms的负脉冲干扰。代码#include#include、、KEY.H〃{P1_O=1; //作为输入引脚,必须先输出髙电平while(1)〃永远为真,即死循环{if(P1_O==0)〃如果按键,则为低电平{delay20ms();〃延时20ms,跳过接下抖动if(Pl_0==1)continue;//假按键keyPut(6);//保存按键编号值为按键队列while(Pl_0==0);〃如果一宜按着键,则不停地执彳ハ亥常环,实际是等待松键delay20ms();//延时20ms,跳过松开抖动)if(keyHit()!=0)//如果队列中有按键P2=Seg7Code[keyGetO];//从队列中取出按键值,并显示在数码管上}}例四:状态图编程法。通过20ms周期中断,扫描按键。代码/****************************************************************************************.采用晶体为12KHz时,指令周期为1ms(即主频为IKHz),这样TO工作在定时器方式2,8位自动重载。计数值为20,即可产生20ms的周期性中断,在中断服务程序中实现按键扫描
3.4.5.6.8.9.1011121314151617181920#include#include''KEY.H"voidmain(void){TMOD=(TMOD&OxfO)|0x02;//イ(改变T1的I:作カ-3TO为定时器方式2TH0=-20; //计数周期为20个匕频咏,即20ms.TL0=TH0; //先软加载ー次计数值.TR0=l;〃允许TO开始计数.ETO=1; //允许TO计数溢出时产生中断请求.EA=1; //允许CPU响应中断请求.while(1)〃永远为真,即死循环.(.if(keyHit〇!=0)//如果队列中有按键.P2=Seg7Code[keyGet0];//从队列中取出按键值,并显示在数码管上.}voidtimerOint(void)interrupt1//20ms:TO的中断号为1
{staticunsignedcharsts=O;P1_O=1; //作为输入りI脚,必须先输出髙电平switch(sts)(case0:if(P1_O==O)sts=l;break;//按键则转入状态1case1:if(P1_O==1)sts=O;//假按错,或干扰,回状态0else{sts=2;keyPut(6);}//确实按键,键值入队列,并转状态2break;case2:if(P1_O==1)sts=3;break;//如果松键,则转状态3case3:if(P1_O==O)sts=2;//假松键,网状态2elsests=O;〃真松键,回状态0,等待下一次按键过程)}例五:状态图编程法。代码如果采用晶体为12MHz时,指令周期为lus(即主频为1MHz),要产生20ms左右的计时,则计数值达到20000,TO工作必须为定时器方式1,16位非自动重载,即可产生20ms的周期性中断,在中断服务程序中实现按键扌I描★★★★★★★★★★★★★★★★★★★★★/.#include#include"KEY.H".voidmain(void)(TMOD=(TMOD&OxfO)|0x01;//不改变T1的工作方式,TO为定时器方式1TL0=-20000; //计数周期为20000个主频脉,自动取低8位TH0=(-20000)»8; //右移8位,实际上是取髙8位TRO=1;〃允许TO开始计数ETO=1; //允许TO计数溢出时产生中断请求EA=1; //允许CPU响应中断请求while(1)//永远为真,即死循环(if(keyHit〇!=0)//如果队列中有按键17.P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上}}voidtimerOint(void)interrupt1//20ms;TO的中断号为1{staticunsignedcharsts=0;TLO=-20000; //方式1为软件重载----THO=(-20000)»8; //右移8位,实际上是取高8位Pl_0=1; //作为输入引脚,必须先输出髙电平.switch(sts)(case0:if{Pl_0==0)sts=l;break;〃按键则转入状态1.case1:if(Pl_0==l)sts=0;〃假按错,或干扰,回状态0.else{sts=2;keyPut(6);}//确实按键,键值入队列,并转状态2break;case2:if(Pl_0==l)sts=3;break;〃如果松键,则转状.case3:if(Pl_0==0)sts=2;//假松键,回状态235.elsests=O35.elsests=O;//真松键,回状态0,等待トー次按键过程37.}例六:4X4按键。代码.由P1端口的高4位和低4位构成4X4的矩阵键盘,本程序只认为单键操作为合法,同时按多键时无效。.这样卜面的X,Y的合法值为0x7,Oxb,Oxd,Oxe,Oxf»通过表keyCode影射变换可得按键值★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★**★★★★★★★★★*★★***★★★/.#include.#include''KEY.H".unsignedcharkeyScan(void)//返回。表示无按键,或无效按键,R它值为按键编码值. {codeunsignedcharkeyCode[16]=9.10111213141516171819202122232425/OxO,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,OxA,OxB,OxC,0xD,OxE,OxF{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3,01;.unsignedcharx,y,retVal;.Pl=OxOf; //低四位输入,高四位输出〇.x=Pl&OxOf; //Pl输入后,清高四位,作为X值.Pl=OxfO; //髙四位输入,低四位输出〇.y=(Pl>>4)&OxOf;〃P1输入后移位到低四位,并清髙四位,作为Y值.retVal=keyCode[x]*4+keyCode[y];//根据本公式倒算按键编码.if(retVal==0)return(0);elsereturn(retVal-4);■}.//比如按键、ン,得X=0x7,Y=0x7,算得retVal=5,所以返回函数值1。.//双如按键、7,,得X=0xb,Y=0xd,算得retVal=l1,所以返冋函数值7。.voidmain(void)•(.TMOD=(TMOD&OxfO)|0x01;〃不改变T1的工作方式,TO为定时器方式1.TL0=-20000; 〃计数周期为20000个主频脉,自动取低8位THO(-20000)»8;〃右移8THO(-20000)»8;〃右移8位,实际上是取高8位TRO=1; //允许TO开始计数ETO=1; //允许TO计数溢出时产生中断请求EA^1; 〃允许CPU响应中断请求while(1)//永远为真,即死循环(if(keyHit0!=0)〃如果队列中有按键.P2=Seg7Code[keyGet()];〃从队列中取出按键值,并显示,1:数码管上)}voidtimerOint(void)interrupt1//20ms:TO的中断号为1{staticunsignedcharsts=0;TLO=-20000; //方式:1为软件重载THO=(-20000)»8; //右移8位,实际上是取高8位Pl_0=1; //作为输入引脚,必须先输出高电平0.switch(sts). {.case0:if(keyScan()!=0)sts=l;break;//按键则转入斗犬态1.case1:.if(keyScan()==0)sts=0;〃假按错,或「扰,回状态0
45.else{sts=2;keyPut(keyScan());}//确实按键,键值入队列,并转状态2break;. case2:if(keyScan〇==0)sts=3;break;//如果松键,则转状态3case3:if(keyScan()!=0)sts=2;〃假松键,回状态2elsests=0; 〃真松键,回状态0,等待下一次按键过程)}第六节:低频频率计实例目的:学时定时器、计数器、中断应用说明:选用24MHz的晶体,主频可达2MHz。用T1产生100us的时标,T0作信号脉冲计数器。假设晶体频率没有误差,而且稳定不变(实际上可达万分之一);被测信号是周期性矩形波(正负脉冲宽度都不能小于0.5us),频率小于1MHz,大于1Hz。要求测量时标1S,测量精度为〇.1%。解:从测量精度要求来看,当频率超过1KHz时,可采用1S时标内计数信号脉冲个数来测量信号频,而信号频率低于1KHz时,可以通过测量信号的周期来求出信号频率。两种方法自动转换。对于低于1KHz的信号,信号周期最小为1ms,也就是说超过1000us,而我们用的定时器计时脉冲周期为0.5us,如果定时多计或少计ー个脉冲,误差为1us,所以相对误差为1usハ000us=0.1%。信号周期越大,即信号频率越低,相对误差就越小。
从上面描述来看,当信号频率超过1KHz后,信号周期就少于1000us,显然采用上面的测量方法,不能达到测量精度要求,这时我们采用1S单位时间计数信号的脉冲个数,最少能计到1000个脉冲,由于信号频率不超过1MHz,而我们定时脉冲为2MHz,最差多计或少计ー个信号脉冲,这样相对误差为1/1000,可见信号频率越高,相对误差越小。信号除输入到T1(P3.5)タト,还输入到INT1(P3.3)。代码.unsignedintuslOO;〃对lOQus时间间隔单位计数,即仃多少个100us。.unsignedcharSecond;.unsignedintK64; //对64K单位计数,即有多少个64K.unsignedcharoldTO;.unsignedintoldus,oldK64,oldTl;.unsignedlongfey; //存放频率值,単位.为Hz.bitHighLow=l; //l;去示储じ的过IKHz;0:表示信じ低「IKHz。.voidInitialHigh(void).(. IE=0;IP=0;HighLow=l;.TMOD=(TMOD&OxfO)|0x02;TH0=-200;TL0=TH0;PX0=l;T0=l;.TMOD=(TMOD&OxOf)|0x50;THl=0;TLl=0;Tl=l;ET1=1;
. oldK64=0;oldTl=0;TCON|=0x50;〃同时置TR0=l;TR1=1;EA=1;}.voidInitialLow(void)(. IE=0;IP=0;HighLow=0;TMOD=(TMOD&OxfO)|0x02;TH0=-200;TL0=TH0;ETO=1;TR0=l;INTI=1;IT1=1;EX1=1;. Usl00=0;Second=0;K64=0;oldK64=0;oldTl=0;EA=1;}voidTOintr(void)interrupt1{if(HighLow==0)++usl00;elseif(++US100>=10000){unsignedinttmpl,tmp2;TRl=0;tmpl=(THl«8)+(TL1);tmp2=K64;TR1=1;33.fcy=((tmp2-oldK64)<<16)+(tmpl-oldTl);.oldK64=tmpl;oldTl=tmp2;Second++;usl00=0;}}voidTlintr(void)interrupt3{++K64;)voidXlintr(void)interrupt2{staticunsignedcharsts=0;.switch(sts){case0:sts=1;break;case1:oldT0=TL0;oldus=usl00;sts=2;break;.case2:48.unsignedchartmpl,tmp2;49. TR0=0;tmpl=TL0;tmp2=usl00;TR0=l;50.fey=1000000L/((tmp2-oldus)*100L+(256-tmpl)/2);}Sts=0;break;}}voidmain(void)(.if(HighLow==l)InitialHigh();elseInitialLow();While(1)(if(Second!=0)(Second=0;//displayfey引用前面的数码管驱动程序,注意下面对T0中断服务程序的修改{unsignedchari;for(i=0;i<8;i++){Display(izfcy%10);fey/=10;}}.if(HighLow==1)if(fcy<1000L){InitalLow();)72.if(fcy>1000L){InitalHigh();})}}//修改TO的中断服务程序,让它在完成时标的功能时,同时完成数码管显示刷新voidTOintr(void)interrupt1(staticunsignedcharms=0;.if(HighLow==0)++usl00;elseif(++US100>=10000){unsignedinttmpl,tmp2;TR1=O;tmpl=(THl«8)+(TL1);tmp2=K64;TR1=1;.fcy=((tmp2-oldK64)<<16)+(tmpl-oldTl);.oldK64=tmpl;oldTl=tmp2;Second++;.usl00=0;90.if(++ms>=10){ms=0;DisplayBrush();}//1ms数码管刷新91.}第七节:电子表单键可调电子表:主要学习编程方法。外部中断应用,中断嵌解:电子表分为工作状态和调整状态。平时为工作状态,按键不足一秒,接键为换屏'S。按键超过一秒移位则进入调整状态C,而且调整光标在秒个位开始。调整状态时,按键不足一秒为光标移动'M',超过一秒则为调整读数,每0.5秒加一'A’,直到松键;如果10秒无按键则自动回到工作状态‘W'。如果有年、月、日、时、分、秒。四联数码管可分三屏显示,显示格式为“年月.”、“日.时.”、“分.秒”,从小数点的位置来区分显示内容。(月份的十位数也可以用"-”和“-1”表示)。代码.enumstatus={Work,Change,Add,Move,Screen}〃状态牧举.//计时和调整都是对下面时间数组Time进行修改.unsignedcharTime[12]={0,4,0,6,1,0,0,8,4,5,3,2)5〃04年06月10日08时45分32秒.unsignedcharcursor=12;//指向秒个位,=0时无光标.unsignedcharYmDhMs=3;//指向、、分秒”显示,=0时无屏显.staticunsignedcharsts=Work;
如果cursor不为0,装入DisBuf的对应数位,按0.2秒周期闪烁,即设ー个0.1秒计数器SOI,SOI为奇数时灭,S01为偶数时亮。小数点显示与YmDhMs变量相关。*/voidDisScan(void)〃动态刷新显示时调用。没编完,针对共阴数码管,只给出控控制算法(//DisBuf每个显示数据的髙四位为标志,最高位Dフ为负号,D6为小数点,D5为闪烁unsignedchartmp;tmp=Seg7Code[?x&Oxlf];〃段?x为显示数据,髙3位为控制位,格低5位变为七段码if(?x&0x40)tmp|=0x80;//添加小数点if(?x&0x20){if(SOI&0x01)tmp=0;}//闪烁,SOI奇数时不亮〃这里没有处理负号位〃将tmp送出显示,并控制对应数码管动作显示}voidDisplay(void) //根据状态进彳了显示{if(cursor!=0){YmDhMs=(cursor+3)/4;}//I..4=1;5..8=2;9..12=3
24.for(i=(YmDhMs-1)*4;i<(YmDhMs)*4;i++){unsignedcharj=i%4;Disbuf[j]=Time[i];if(i==(cursor-1))Disbuf[j]|=0x20;//闪,烁,cursor!=0H"闪烁if((i==9)II//小数点:分个位(i==7)II〃小数点:时个位(i==5)II〃小数点:日个位(i==3)〃小数点:月个位)Disbuf[j]I=0x40;//if(i==2){if(Time[2]==l)DisBuf[2] elseDisBuf=、、ー";}}.〃工作状态:根据YmDhMs将屏数据装入DisBuf. 〃调整状态:根据cursor将屏数据装入DisBuf}.voidKeyScan(void)〃根据状态扌I描按键.voidProcessKey(void)〃根据状态处理键信息(keyVal=KeyGet();42.42.if(keyVal0)return;switch(sts)TOC\o"1-5"\h\z
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 甲乙丙房屋买卖合同全解读
- 消防工程招投标文书
- 服务合同协议权威解读
- 童鞋品牌代理经销合同
- 施工安全保证书样本
- 信用担保借款合同的修改注意事项
- 标准借款协议书格式
- 粮油食品供应协议
- 室内外照明设计招标
- 批发兼零售合作劳务合同
- 2021年食品安全监督抽检培训完整版PPT课件
- 外研版(三起)小学英语四年级上册教案(全册)
- 部编二年级下册语文词语表带拼音
- 检测大纲-整车检验、过程检验、零部件入厂检验、关键部位检验、成品入库检验
- 托辊技术规格书
- 踝关节扭伤.ppt
- CRH2型动车组一级检修作业办法081222
- 研究生英语议论文范文模板
- 燃气安全知识测试题(含答案)
- 串宫压运推流年密技
- 拆迁安置房小区物业管理的问题与对策
评论
0/150
提交评论