51单片机C语言程序100例

 

目录

目录................................................................................................................................1

函数的使用和熟悉********************************/.......................................4

实例3:用单片机控制第一个灯亮.............................................................................4

实例4:用单片机控制一个灯闪烁:认识单片机的工作频率.................................4

实例5:将P1口状态分别送入P0P2P3口:认识I/O口的引脚功能............5

实例6:使用P3口流水点亮8LED.......................................................................5

实例7:通过对P3口地址的操作流水点亮8LED...............................................6

实例8:用不同数据类型控制灯闪烁时间.................................................................7

实例9:用P0口、P1口分别显示加法和减法运算结果.........................................8

实例10:用P0P1口显示乘法运算结果................................................................9

实例11:用P1P0口显示除法运算结果................................................................9

实例12:用自增运算控制P08LED流水花样..............................................10

实例13:用P0口显示逻辑""运算结果...............................................................10

实例14:用P0口显示条件运算结果.......................................................................11

实例15:用P0口显示按位"异或"运算结果...........................................................11

实例16:用P0显示左移运算结果...........................................................................11

实例17"万能逻辑电路"实验.................................................................................11

实例18:用右移运算流水点亮P18LED.......................................................12

实例19:用if语句控制P08LED的流水方向..............................................13

实例20:用swtich语句的控制P08LED的点亮状态..................................13

实例21:用for语句控制蜂鸣器鸣笛次数..............................................................14

实例22:用while语句控制LED...............................................................................16

实例23:用do-while语句控制P08LED流水点亮......................................16

实例24:用字符型数组控制P08LED流水点亮..........................................17

实例25P0口显示字符串常量.........................................................................18

实例26:用P0口显示指针运算结果......................................................................19

实例27:用指针数组控制P08LED流水点亮..............................................19

实例28:用数组的指针控制P08LED流水点亮........................................20

实例29:用P0P1口显示整型函数返回值........................................................21

实例30:用有参函数控制P08LED流水速度..............................................22

实例31:用数组作函数参数控制流水花样.............................................................23

实例32:用指针作函数参数控制P08LED流水点亮..................................23

实例33:用函数型指针控制P1口灯花样...............................................................25

实例34:用指针数组作为函数的参数显示多个字符串.........................................26

实例35:字符函数ctype.h应用举例.......................................................................27

实例36:内部函数intrins.h应用举例.....................................................................27

实例37:标准函数stdlib.h应用举例.......................................................................28

实例38:字符串函数string.h应用举例..................................................................29

实例39:宏定义应用举例2......................................................................................29

1/192


实例40:宏定义应用举例2......................................................................................30

实例41:宏定义应用举例3......................................................................................30

 

中断、定时器************************************************   .........31

实例42:用定时器T0查询方式P28位控制LED闪烁....................................31

实例43:用定时器T1查询方式控制单片机发出1KHz音频.................................31

实例44:将计数器T0计数的结果送P18LED显示....................................32

实例45:用定时器T0的中断控制1LED闪烁...................................................33

实例46:用定时器T0的中断实现长时间定时.......................................................34

实例47:用定时器T1中断控制两个LED以不同周期闪烁...................................34

实例48:用计数器T1的中断控制蜂鸣器发出1KHz音频.....................................36

实例49:用定时器T0的中断实现"渴望"主题曲的播放.......................................36

实例50-1:输出50个矩形脉冲...............................................................................39

实例50-2:计数器T0统计外部脉冲数...................................................................40

实例51-2:定时器T0的模式2测量正脉冲宽度...................................................40

实例52:用定时器T0控制输出高低宽度不同的矩形波.......................................41

实例53:用外中断0的中断方式进行数据采集.....................................................42

实例54-1:输出负脉宽为200微秒的方波.............................................................43

实例54-2:测量负脉冲宽度.....................................................................................43

实例55:方式0控制流水灯循环点亮.....................................................................44

实例56-1:数据发送程序.........................................................................................45

实例56-2:数据接收程序.........................................................................................47

实例57-1:数据发送程序.........................................................................................47

实例57-2:数据接收程序.........................................................................................49

实例58:单片机向PC发送数据..............................................................................50

实例59:单片机接收PC发出的数据......................................................................51

 

*********************************数码管显示       ...............................52

实例60:用LED数码显示数字5..............................................................................52

实例61:用LED数码显示器循环显示数字0~9......................................................52

实例62:用数码管慢速动态扫描显示数字"1234".................................................53

实例63:用LED数码显示器伪静态显示数字1234...............................................54

实例64:用数码管显示动态检测结果.....................................................................54

实例65:数码秒表设计.............................................................................................56

实例66:数码时钟设计.............................................................................................58

实例67:用LED数码管显示计数器T0的计数值...................................................62

实例68:静态显示数字“59”...................................................................................63

*****************************键盘控制


2


/


192


*****************************************************/...........................63

实例69:无软件消抖的独立式键盘输入实验.........................................................64

实例70:软件消抖的独立式键盘输入实验.............................................................64

实例71CPU控制的独立式键盘扫描实验.............................................................65

实例72:定时器中断控制的独立式键盘扫描实验.................................................68

实例73:独立式键盘控制的4级变速流水灯.........................................................71

实例74:独立式键盘的按键功能扩展:"以一当四".............................................73

实例75:独立式键盘调时的数码时钟实验.............................................................75

实例76:独立式键盘控制步进电机实验.................................................................79

实例77:矩阵式键盘按键值的数码管显示实验.....................................................82

//实例78:矩阵式键盘按键音..................................................................................85

实例79:简易电子琴.................................................................................................86

实例80:矩阵式键盘实现的电子密码锁.................................................................92

*********************************************************************

*****液晶显示LCD*********液晶显示LCD*****液晶显示LCD*************

***********************************************************/...............95

实例81:用LCD显示字符'A'....................................................................................96

实例82:用LCD循环右移显示"WelcometoChina"...............................................99

实例83:用LCD显示适时检测结果......................................................................102

实例84:液晶时钟设计...........................................................................................106

 

******************************************一些芯片的使用*****24c02   ........DS18B20   X5045   ADC0832   DAC0832   DS1302

红外遥控**********************************************/......................112

 

实例85:将数据"0x0f"写入AT24C02再读出送P1口显示..................................112

实例86:将按键次数写入AT24C02,再读出并用1602LCD显示.......................117

实例87:对I2C总线上挂接多个AT24C02的读写操作.......................................124

实例88:基于AT24C02的多机通信   读取程序..................................................129

实例88:基于AT24C02的多机通信写入程序....................................................133

实例90DS18B20温度检测及其液晶显示...........................................................144

实例91:将数据"0xaa"写入X5045再读出送P1口显示......................................153

实例92:将流水灯控制码写入X5045并读出送P1口显示................................157

实例93:对SPI总线上挂接多个X5045的读写操作............................................161

实例94:基于ADC0832的数字电压表..................................................................165

实例95:用DAC0832产生锯齿波电压..................................................................171

实例96:用P1口显示红外遥控器的按键值.........................................................171

实例97:用红外遥控器控制继电器.......................................................................174

实例98:基于DS1302的日历时钟........................................................................177

实例99:单片机数据发送程序...............................................................................185

实例100:电机转速表设计.....................................................................................186

模拟霍尔脉冲............................................................................................................192


 


3


/


192


 

/************************************************************

函数的使用和熟悉***************

************************************************/


 

//实例3:用单片机控制第一个灯亮

#include<reg51.h>   //包含51单片机寄存器定义的头文件

voidmain(void)

{

P1=0xfe;//P1=11111110B,即P1.0输出低电平

}


 


//


4


//实例4:用单片机控制一个灯闪烁:认识单片机的工作频率

#include<reg51.h>     //包含单片机寄存器的头文件

/****************************************

函数功能:延时一段时间

*****************************************/

voiddelay(void)          //两个void意思分别为无需返回值,没有参数传递

{

unsignedinti;         //定义无符号整数,最大取值范围65535

for(i=0;i<20000;i++)   //20000次空循环

;                  //什么也不做,等待一个机器周期

}

/*******************************************************

函数功能:主函数C语言规定必须有也只能有1个主函数)

********************************************************/

voidmain(void)

{

while(1)       //无限循环

{

P1=0xfe;   //P1=11111110BP1.0输出低电平

delay();   //延时一段时间

P1=0xff;   //P1=11111111BP1.0输出高电平

delay();  //延时一段时间

}

}

4/192


 


//


5


P1


P0


P2


P3


I/O


//实例5:将

#include<reg51.h>


P1口状态分别送入P0P2P3口:认识I/O

的引脚功能

//包含单片机寄存器的头文件


/*******************************************************

函数功能:主函数C语言规定必须有也只能有1个主函数)

********************************************************/

voidmain(void)

{

while(1)          //无限循环

{

P1=0xff;   //P1=11111111B,熄灭LED

P0=P1;     //  P1口状态送入P0

P2=P1;         //  P1口状态送入P2

P3=P1;     //  P1口状态送入P3

}

}


 

//实例6:使用P3口流水点亮8LED

#include<reg51.h>    //包含单片机寄存器的头文件

/****************************************

函数功能:延时一段时间

*****************************************/

voiddelay(void)

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

/*******************************************************

函数功能:主函数

********************************************************/

voidmain(void)

{

5/192


while(1)

{


P3=0xfe;

delay();

P3=0xfd;

delay();

P3=0xfb;

delay();

P3=0xf7;

delay();

P3=0xef;


//第一个灯亮

//调用延时函数

//第二个灯亮

//调用延时函数

//第三个灯亮

//调用延时函数

//第四个灯亮

//调用延时函数

//第五个灯亮


 


delay();


//调用延时函数


P3=0xdf;

delay();

P3=0xbf;


//第六个灯亮

//调用延时函数

//第七个灯亮


delay();


//调用延时函数


 


P3=0x7f;


//第八个灯亮


}


}


delay();


//调用延时函数


 

//实例7:通过对P3口地址的操作流水点亮8LED

#include<reg51.h>    //包含单片机寄存器的头文件

sfrx=0xb0;    //P3口在存储器中的地址是b0H通过sfr可定义8051内核单片

//的所有内部8位特殊功能寄存器,对地址x的操作也就是对P1口的

操作

/****************************************

函数功能:延时一段时间

*****************************************/

voiddelay(void)

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;    //利用循环等待若干机器周期,从而延时一段时间

}

/*****************************************

函数功能:主函数

6/192


******************************************/

voidmain(void)

{

while(1)

{

x=0xfe;   //第一个灯亮

delay();  //调用延时函数

x=0xfd;  //第二个灯亮

delay();  //调用延时函数

x=0xfb;  //第三个灯亮

delay();  //调用延时函数

x=0xf7;  //第四个灯亮

delay();  //调用延时函数

x=0xef;   //第五个灯亮

delay();  //调用延时函数

x=0xdf;   //第六个灯亮

delay();  //调用延时函数

x=0xbf;   //第七个灯亮

delay();  //调用延时函数

x=0x7f;   //第八个灯亮

delay();  //调用延时函数

}

}


 

//实例8:用不同数据类型控制灯闪烁时间

#include<reg51.h>    //包含单片机寄存器的头文件

/******************************************************

函数功能:用整形数据延时一段时间

******************************************************/

voidint_delay(void)//延时一段较长的时间

{

unsignedintm;     //定义无符号整形变量,双字节数据,值域为0~65535

for(m=0;m<36000;m++)

;            //空操作

}

/******************************************************

函数功能:用字符型数据延时一段时间

******************************************************/

7/192


voidchar_delay(void)//延时一段较短的时间

{

unsignedchari,j;    //定义无符号字符型变量,单字节数据,值域0~255

for(i=0;i<200;i++)

for(j=0;j<180;j++)

;         //空操作

}

/******************************************************

函数功能:主函数

******************************************************/

voidmain(void)

{

unsignedchari;

while(1)

{

for(i=0;i<3;i++)

{

P1=0xfe;      //P1.0口的灯点亮

int_delay();//延时一段较长的时间

P1=0xff;      //熄灭

int_delay();//延时一段较长的时间

}

for(i=0;i<3;i++)

{

P1=0xef;      //P1.4口的灯点亮

char_delay();//延时一段较长的时间

P1=0xff;      //熄灭

char_delay();//延时一段较长的时间

}

}

}


 


//实例9:用P0口、P1

#include<reg51.h>

voidmain(void)

{

unsignedcharm,n;


口分别显示加法和减法运算结果


m=43;


//即十进制数2x16+11=43

8/


192


n=60;

P1=m+n;


//即十进制数3x16+12=60

//P1=103=01100111B,结果P1.3P1.4P1.7


口的灯被点亮


}


P0=n-m;


//P0=17=00010001B,结果P0.0P0.4的灯被熄灭


 

//实例10:用P0P1口显示乘法运算结果

#include<reg51.h>//包含单片机寄存器的头文件

voidmain(void)

{

unsignedcharm,n;

unsignedints;

m=64;

n=71;

s=m*n;         //s=64*71=4544,需要16位二进制数表示,高8位送P1口,低

8位送P0

//由于4544=17*256+192=H3*16*16*16+H2*16*16+H1*16+H0

//两边同除以256,可得17+192/256=H3*16+H2+  H1*16+H0

/256

//因此,高816进制数H3*16+H2必然等于17,即4544

除以256的商

//816进制数H1*16+H0必然等于192,即4544除以

256的余数

P1=s/256;      //8位送P1P1=17=11H=00010001B,P1.0P1.4口灭

其余亮

P0=s%256;      //8位送P0,P3=192=c0H=11000000B,P3.1,P3.6,P3.7

灭,其余亮

}


 

//实例11:用P1P0口显示除法运算结果

#include<reg51.h>    //包含单片机寄存器的头文件

voidmain(void)

{

P1=36/5;            //求整数

P0=((36%5)*10)/5;//求小数

while(1)

9/192


}


;


//无限循环防止程序“跑飞”


 

//实例12:用自增运算控制P08LED流水花样

#include<reg51.h>    //包含单片机寄存器的头文件

/******************************************************

函数功能:延时一段时间

******************************************************/

voiddelay(void)

{

unsignedinti;

for(i=0;i<20000;i++)

;

}

/******************************************************

函数功能 :主函数

******************************************************/

voidmain(void)

{

unsignedchari;

for(i=0;i<255;i++)   //注意i的值不能超过255

{

P0=i;    //i的值送P0

delay();//调用延时函数

}

}


 

//实例13:用P0口显示逻辑""运算结果

#include<reg51.h>    //包含单片机寄存器的头文件

voidmain(void)

{

P0=(4>0)&&(9>0xab);//将逻辑运算结果送P0

while(1)

;    //设置无限循环,防止程序“跑飞”

}

110/192


 


//


14


P0


//实例14:用P0口显示条件运算结果

#include<reg51.h>    //包含单片机寄存器的头文件

voidmain(void)

{

P0=(8>4)?8:4;//将条件运算结果送P0口,P0=8=00001000B

while(1)

;    //设置无限循环,防止程序“跑飞”

}


 

//实例15:用P0口显示按位"异或"运算结果

#include<reg51.h>    //包含单片机寄存器的头文件

voidmain(void)

{

P0=0xa2^0x3c;//将条件运算结果送P0口,P0=8=00001000B

while(1)

;    //设置无限循环,防止程序“跑飞”

}


 


//


16


P0


//实例16:用P0显示左移运算结果

#include<reg51.h>    //包含单片机寄存器的头文件

voidmain(void)

{

P0=0x3b<<2;//将左移运算结果送P0口,P0=11101100B=0xec

while(1)

;    //无限循环,防止程序“跑飞”

}


 


#include<reg51.h>

sbitF=P1^4;


//实例17"万能逻辑电路"实验

//包含单片机寄存器的头文件

//F位定义为P1.4

111/192


sbitX=P1^5;

sbitY=P1^6;

sbitZ=P1^7;

voidmain(void)

{

while(1)

{


//X位定义为

//Y位定义为

//Z位定义为


P1.5

P1.6

P1.7


}


}


F=((~X)&Y)|Z;//将逻辑运算结果赋给F

;


 

//实例18:用右移运算流水点亮P18LED

#include<reg51.h>   //包含单片机寄存器的头文件

/*****************************

函数功能:延时一段时间

*****************************/

voiddelay(void)

{

unsignedintn;

for(n=0;n<30000;n++)

;

}

/*****************************

函数功能:主函数

*****************************/

voidmain(void)

{

unsignedchari;

while(1)

{

P1=0xff;

delay();

for(i=0;i<8;i++)//设置循环次数为8

{

P1=P1>>1;    //每次循环P1的各二进位右移1位,高位补0

delay();    //调用延时函数

}

}

}

112/192


 


//


19


iff


P0


8


LED


//实例19:用iff语句控制P08LED的流水方向

#include<reg51.h>   //包含单片机寄存器的头文件

sbitS1=P1^4;      //S1位定义为P1.4

sbitS2=P1^5;      //S2位定义为P1.5

/*****************************

函数功能:主函数

*****************************/

voidmain(void)

{

while(1)

{

if(S1==0)   //如果按键S1按下

P0=0x0f;  //P0口高四位LED点亮

if(S2==0)   //如果按键S2按下

P0=0xf0;  //P0口低四位LED点亮

}

}


 

//实例20:用swtich语句的控制P08LED的点亮状态

#include<reg51.h>   //包含单片机寄存器的头文件

sbitS1=P1^4;      //S1位定义为P1.4

/*****************************

函数功能:延时一段时间

*****************************/

voiddelay(void)

{

unsignedintn;

for(n=0;n<10000;n++)

;

}

/*****************************

函数功能:主函数

*****************************/

voidmain(void)

{

unsignedchari;

113/192


i=0;

while(1)

{


//i初始化为0


if(S1==0)

{

delay();


//如果S1键按下

//延时一段时间


 


}


if(S1==0)//如果再次检测到S1键按下

i++;    //i自增1

if(i==9)  //如果i=9,重新将其置为1

i=1;


}


switch(i)

}


{

}


//使用多分支选择语句

case1:P0=0xfe;   //第一个LED

break;

case2:P0=0xfd;   //第二个LED

break;

case3:P0=0xfb;    //第三个LED

break;

case4:P0=0xf7;    //第四个LED

break;

case5:P0=0xef;    //第五个LED

break;

case6:P0=0xdf;    //第六个LED

break;

case7:P0=0xbf;    //第七个LED

break;

case8:P0=0x7f;    //第八个LED

break;

default:   //缺省值,关闭所有LED

P0=0xff;


 


//


21


for


//实例21:用for语句控制蜂鸣器鸣笛次数

#include<reg51.h>   //包含单片机寄存器的头文件

sbitsound=P3^7;   //sound位定义为P3.7

/****************************************

函数功能:延时形成1600Hz音频

114/192


****************************************/

voiddelay1600(void)

{

unsignedcharn;

for(n=0;n<100;n++)

;

}

/****************************************

函数功能:延时形成800Hz音频

****************************************/

voiddelay800(void)

{

unsignedcharn;

for(n=0;n<200;n++)

;

}

/****************************************

函数功能:主函数

****************************************/

voidmain(void)

{

unsignedinti;

while(1)

{

for(i=0;i<830;i++)

{

sound=0;  //P3.7输出低电平

delay1600();

sound=1;  //P3.7输出高电平

delay1600();

}

for(i=0;i<200;i++)

{

sound=0;  //P3.7输出低电平

delay800();

sound=1;  //P3.7输出高电平

delay800();

}

}

}


 


115


/


192


 

//实例22:用whille语句控制LED


 


#include<reg51.h>


//包含单片机寄存器的头文件


 

/****************************************

函数功能:延时约60ms(3*100*200=60000μs)

****************************************/

voiddelay60ms(void)

{

unsignedcharm,n;

for(m=0;m<100;m++)

for(n=0;n<200;n++)

;

}

/****************************************

函数功能:主函数

****************************************/

voidmain(void)

{

unsignedchari;

while(1)    //无限循环

{

i=0;    //i初始化为0

while(i<0xff)    //i小于0xff255)时执行循环体

{

P0=i;          //iP0口显示

delay60ms();//延时

i++;           //i自增1

}

}

}


 

//实例23:用do-whiile语句控制P08LED流水点亮

#include<reg51.h>   //包含单片机寄存器的头文件

/****************************************

函数功能:延时约60ms(3*100*200=60000μs)

****************************************/

voiddelay60ms(void)

{

116/192


}


unsignedcharm,n;

for(m=0;m<100;m++)

for(n=0;n<200;n++)

;


 

/****************************************

函数功能:主函数

****************************************/

voidmain(void)

{

do

{

P0=0xfe;      //第一个LED

delay60ms();

P0=0xfd;      //第二个LED

delay60ms();

P0=0xfb;      //第三个LED

delay60ms();

P0=0xf7;      //第四个LED

delay60ms();

P0=0xef;      //第五个LED

delay60ms();

P0=0xdf;      //第六个LED

delay60ms();

delay60ms();

P0=0xbf;      //第七个LED

delay60ms();

P0=0x7f;      //第八个LED

delay60ms();

}while(1);      //无限循环,使8LED循环流水点亮

}


 

//实例24:用字符型数组控制P08LED流水点亮

#include<reg51.h>   //包含单片机寄存器的头文件

/****************************************

函数功能:延时约60ms(3*100*200=60000μs)

****************************************/

voiddelay60ms(void)

{

unsignedcharm,n;

for(m=0;m<100;m++)

117/192


}


for(n=0;n<200;n++)

;


 

/****************************************

函数功能:主函数

****************************************/

voidmain(void)

{

unsignedchari;

unsignedcharcodeTab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//定义无符

号字符型数组

while(1)

{

for(i=0;i<8;i++)

{

P0=Tab[i];//依次引用数组元素,并将其送P0口显示

delay60ms();//调用延时函数

}

}

}


 


//


25


P0


//实例25


P0口显示字符串常量


 


#include<reg51.h>


//包含单片机寄存器的头文件


 

/*************************************************

函数功能:延时约150ms(3*200*250=150000μs=150ms

*************************************************/

voiddelay150ms(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsignedcharstr[]={"Now,Temperatureis:"};   //将字符串赋给字符型全部元素

赋值

unsignedchari;

118/192


while(1)

{

i=0;


//i初始化为0,从第一个元素开始显示


}


}


while(str[i]!='\0')//只要没有显示到结束标志'\0'

{

P0=str[i];      //将第i个字符送到P0口显示

delay150ms();   //调用150ms延时函数

i++;             //指向下一个待显字符

}


 


//实例26:用P0

#include<reg51.h>

voidmain(void)

{


口显示指针运算结果


unsignedchar*p1,*p2;


//定义无符号字符型指针变量p1,p2


 


unsignedchari,j;


//定义无符号字符型数据


i=25;

j=15;

p1=&i;

p2=&j;


//i赋初值25

//使指针变量指向i

//使指针变量指向j


,对指针初始化

,对指针初始化


 


P0=*p1+*p2;


//*p1+*p2相当于i+j,所以P0=25+15=40=0x28


}


//P0=00101000B,结果P0.3P0.5引脚LED熄灭,其余点亮

while(1)

;             //无限循环,防止程序“跑飞”


 


//


27


P0


8


LED


//实例27:用指针数组控制P08LED流水点亮

#include<reg51.h>

/*************************************************

函数功能:延时约150ms(3*200*250=150000μs=150ms

*************************************************/

voiddelay150ms(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

119/192


}


for(n=0;n<250;n++)

;


 

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsignedcharcodeTab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

unsignedchar*p[]={&Tab[0],&Tab[1],&Tab[2],&Tab[3],&Tab[4],&Tab[5],

&Tab[6],&Tab[7]};

unsignedchari;      //定义无符号字符型数据

while(1)

{

for(i=0;i<8;i++)

{

P0=*p[i];

delay150ms();

}

}

}


 


//


28


P0


8


LED


//实例28:用数组的指针控制P0

#include<reg51.h>


8


LED流水点亮


 

/*************************************************

函数功能:延时约150ms(3*200*250=150000μs=150ms

*************************************************/

voiddelay150ms(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

220/192


}


unsignedchari;

unsignedcharTab[]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,

0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,

0xFE,0xFC,0xFB,0xF0,0xE0,0xC0,0x80,0x00,

0xE7,0xDB,0xBD,0x7E,0x3C,0x18,0x00,0x81,

0xC3,0xE7,0x7E,0xBD,0xDB,0xE7,0xBD,0xDB};

//流水灯控制码

unsignedchar*p;    //定义无符号字符型指针

p=Tab;                 //将数组首地址存入指针p

while(1)

{

for(i=0;i<32;i++)//32个流水灯控制码

{

P0=*(p+i);      //*p+i)的值等于a[i]

delay150ms();   //调用150ms延时函数

}

}


 


//


29


P0


P1


//实例29:用P0

#include<reg51.h>


P1口显示整型函数返回值


 

/*************************************************

函数功能:计算两个无符号整数的和

*************************************************/

unsignedintsum(inta,intb)

{

unsignedints;

s=a+b;

return(s);

}

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsignedz;

z=sum(2008,2009);

P1=z/256;        //取得z的高8

P0=z%256;     //取得z的低8

while(1)

;

221/192


}


 

//实例30:用有参函数控制P08LED流水速度

#include<reg51.h>

/*************************************************

函数功能:延时一段时间

*************************************************/

voiddelay(unsignedcharx)

{

unsignedcharm,n;

for(m=0;m<x;m++)

for(n=0;n<200;n++)

;

}

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsignedchari;

unsigned  charcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码

while(1)

{

//快速流水点亮LED

for(i=0;i<8;i++)//8个流水灯控制码

{

P0=Tab[i];

delay(100);   //延时约60ms,(3*100*200=60000μs

}

//慢速流水点亮LED

for(i=0;i<8;i++)//8个流水灯控制码

{

P0=Tab[i];

delay(250);   //延时约150ms,(3*250*200=150000μs

}

}

}


 


222


/


192


//


31


//实例31:用数组作函数参数控制流水花样

#include<reg51.h>

/*************************************************

函数功能:延时约150ms

*************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*************************************************

函数功能:流水点亮P08LED

*************************************************/

voidled_flow(unsignedchara[8])

{

unsignedchari;

for(i=0;i<8;i++)

{

P0=a[i];

delay();

}

}


 

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsigned  charcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码

led_flow(Tab);

}


 


//


32


P0


8


LED


//实例32:用指针作函数参数控制P08LED流水点亮

#include<reg51.h>

223/192


/*************************************************

函数功能:延时约150ms

*************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*************************************************

函数功能:流水点亮P08LED

*************************************************/

voidled_flow(unsignedchar*p)//形参为无符号字符型指针

{

unsignedchari;

while(1)

{

i=0;   //i置为0,指向数组第一个元素

while(*(p+i)!='\0')//只要没有指向数组的结束标志

{

P0=*(p+i);//  取的指针所指变量(数组元素)的值,送P0

delay();   //调用延时函数

i++;    //指向下一个数组元素

}

}

}


 

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsigned  charcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,

0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,

0xFF,0xFE,0xFC,0xFB,0xF0,0xE0,0xC0,0x80,

0x00,0xE7,0xDB,0xBD,0x7E,0xFF,0xFF,0x3C,

0x18,0x0,0x81,0xC3,0xE7,0xFF,

0xFF,0x7E};

//流水灯控制码

unsignedchar*pointer;

224/192


}


pointer=Tab;

led_flow(pointer);


 


//


33


P1


//实例33:用函数型指针控制P1口灯花样

#include<reg51.h>    //包含51单片机寄存器定义的头文件

unsignedcharcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码,该数组被定义为全局变量

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/**************************************************************

函数功能:流水灯左移

**************************************************************/

voidled_flow(void)

{

unsignedchari;

for(i=0;i<8;i++)   //8位控制码

{

P0=Tab[i];

delay();

}

}

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

void(*p)(void);//定义函数型指针,所指函数无参数,无返回值

p=led_flow;   //将函数的入口地址赋给函数型指针p

while(1)

225/192


}


(*p)();


//通过函数的指针p调用函数led_flow()


 


//


34


//实例34:用指针数组作为函数的参数显示多个字符串

#include<reg51.h>    //包含51单片机寄存器定义的头文件

unsignedcharcodestr1[]="TemperatureistestedbyDS18B20";//C语言中,字符串

是作为字符数组来处理的

unsignedcharcodestr2[]="Nowtemperatureis:";     //所以,字符串的名字就是

字符串的首地址

unsignedcharcodestr3[]="TheSystermisdesignedbyZhangSan";

unsignedcharcodestr4[]="Thedateis2008-9-30";

unsignedchar*p[]={str1,str2,str3,str4};//定义p[4]为指向4个字符串的字符型指

针数组

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/**************************************************************

函数功能:流水点亮P08LED

**************************************************************/

voidled_display(unsignedchar*x[])   //形参必须为指针数组

{

unsignedchari,j;

for(i=0;i<4;i++)//4个字符串要显示

{

j=0;  //指向待显字符串的第0号元素

while(*(x[i]+j)!='\0')//只要第i个字符串的第j号元素不是结束标志

{

P0=*(x[i]+j);//取得该元素值送到P0口显示

delay();  //调用延时函数

j++;   //指向下一个元素

}

}

}

226/192


/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

unsignedchari;

while(1)

{

for(i=0;i<4;i++)

led_display(p);//将指针数组名作实际参数传递

}

}


 

//实例35:字符函数ctype.h应用举例

#include<reg51.h>    //包含51单片机寄存器定义的头文件

#include<ctype.h>

voidmain(void)

{

while(1)

{

P3=isalpha('_')?0xf0:0x0f;//条件运算,若'_'是英文字母,P3=0xf0

}

}


 

//实例36:内部函数intrins..h应用举例

#include<reg51.h>    //包含51单片机寄存器定义的头文件

#include<intrins.h>    //包含函数isalpha()声明的头文件

/*************************************************

函数功能:延时约150ms

*************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

227/192


/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

P3=0xfe;  //P3=11111110B

while(1)

{

P3=_crol_(P3,1);//P3的二进制位循环左移1位后再赋给P3

delay();  //调用延时函数

}

}


 


//


37


stdlib.h


//实例37:标准函数stdliib.h应用举例

#include<reg51.h>    //包含51单片机寄存器定义的头文件

#include<stdlib.h>    //包含函数isalpha()声明的头文件

/*************************************************

函数功能:延时约150ms

*************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*************************************************

函数功能:主函数

*************************************************/

voidmain(void)

{

unsignedchari;

while(1)

{

for(i=0;i<10;i++)//产生10个随机数

{

P3=rand()/160;//将产生的随机数缩小160倍后送P3显示

delay();

}

}

228/192


}


 

//实例38:字符串函数striing.h应用举例

#include<reg51.h>    //包含51单片机寄存器定义的头文件

#include<string.h>    //包含函数isalpha()声明的头文件

voidmain(void)

{

unsignedcharstr1[]="Now,Thetemperatureis:";

unsignedcharstr2[]="Now,Thetemperatureis36Centgrade:";

unsignedchari;

i=strcmp(str1,str2);//比较两个字符串,并将结果存入i

if(i==0)//str1=str2

P3=0x00;

else

if(i<0)    //str1<str2

P3=0xf0;

else    //str1>str2

P3=0x0f;

while(1)

;    //防止程序“跑飞”

}


 


//


39


2


#include<reg51.h>


//实例39:宏定义应用举例2

//包含51单片机寄存器定义的头文件


#defineF(a,b)(a)+(a)*(b)/256+(b)

voidmain(void)

{

unsignedchari,j,k;

i=40;

j=30;

k=20;


//带参数的宏定义,ab为形参


}


P3=F(i,j+k);

while(1)

;


//ij+k分别为实参,宏展开时,实参将替代宏定义中的形

229/192


 

//实例40:宏定义应用举例2


 

#include<AT89X51.h>

#include<ctype.h>

voidmain(void)

{

P3_0=0;  //P3.0引脚置低电平,LED点亮

P3_1=0;  //P3.0引脚置低电平,LED点亮

P3_2=0;  //P3.0引脚置低电平,LED点亮

P3_3=0;  //P3.0引脚置低电平,LED点亮

P3_4=1;  //P3.4引脚置高电平,LED熄灭

P3_5=1;  //P3.5引脚置高电平,LED熄灭

P3_6=1;  //P3.7引脚置高电平,LED熄灭

P3_7=1;  //P3.7引脚置高电平,LED熄灭

while(1)

;

}


 

//实例41:宏定义应用举例3


 


#include<reg51.h>

#defineMAX100

voidmain(void)

{

#ifMAX>80

P3=0xf0;

#else

P3=0x0f;

#endif

}


//包含51单片机寄存器定义的头文件

//MAX宏定义为字符串100

//如果字符串100大于80

//P3口低四位LED点亮

//否则,P3口高四位LED点亮

//结束本次编译


 


330


/


192


/********************************************************

*********中断、定时器********断、定时器************

*********中断、定时器*********中断、定时************

********************************************************/


 

//实例42:用定时器T0查询方式P28位控制LED闪烁

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

//EA=1;                      //开总中断

//   ET0=1;                     //定时器T0中断允许

TMOD=0x01;               //使用定时器T0的模式1

TH0=(65536-46083)/256;   //定时器T0的高8位赋初值

TL0=(65536-46083)%256;   //定时器T0的高8位赋初值

TR0=1;                   //启动定时器T0

TF0=0;

P2=0xff;

while(1)//无限循环等待查询

{

while(TF0==0)

;

TF0=0;

P2=~P2;

TH0=(65536-46083)/256;   //定时器T0的高8位赋初值

TL0=(65536-46083)%256;   //定时器T0的高8位赋初值

}

}


 

//实例43:用定时器T1查询方式控制单片机发出1KHz音频

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

sbitsound=P3^7;    //sound位定义为P3.7引脚

331/192


/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

//EA=1;                      //开总中断

//   ET0=1;                     //定时器T0中断允许

TMOD=0x10;               //使用定时器T1的模式1

TH1=(65536-921)/256;   //定时器T1的高8位赋初值

TL1=(65536-921)%256;   //定时器T1的高8位赋初值

TR1=1;                   //启动定时器T1

TF1=0;

while(1)//无限循环等待查询

{

while(TF1==0)

;

TF1=0;

sound=~sound;   //P3.7引脚输出电平取反

TH1=(65536-921)/256;   //定时器T0的高8位赋初值

TL1=(65536-921)%256;   //定时器T0的高8位赋初值

}

}


 


//


44


T0


P1


8


LED


//实例44:将计数器T0计数的结果送P18LED显示

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

sbitS=P3^4;    //S位定义为P3.4引脚

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

//EA=1;                      //开总中断

//   ET0=1;                     //定时器T0中断允许

TMOD=0x02;               //使用定时器T0的模式2

TH0=256-156;   //定时器T0的高8位赋初值

TL0=256-156;   //定时器T0的高8位赋初值

TR0=1;                   //启动定时器T0

while(1)//无限循环等待查询

{

while(TF0==0)   //如果未计满就等待

332/192


{


if(S==0)


//按键S按下接地,电平为0


}


}


}

TF0=0;


P1=TL0;//计数器TL01后送P1口显示

//计数器溢出后,将TF00


 

//实例45:用定时器T0的中断控制1LED闪烁

#include<reg51.h>   //   包含51单片机寄存器定义的头文件

sbitD1=P2^0;   //D1位定义为P2.0引脚

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET0=1;                     //定时器T0中断允许

TMOD=0x01;                //使用定时器T0的模式2

TH0=(65536-46083)/256;//定时器T0的高8位赋初值

TL0=(65536-46083)%256;//定时器T0的高8位赋初值

TR0=1;                     //启动定时器T0

while(1)//无限循环等待中断

;

}

/**************************************************************

函数功能:定时器T0的中断服务程序

**************************************************************/

voidTime0(void)interrupt1using0//interrupt”声明函数为中断服务函数

//其后的1为定时器T0的中断编号;0表示使用第0组工作

寄存器

{

D1=~D1;  //按位取反操作,将P2.0引脚输出电平取反

TH0=(65536-46083)/256;//定时器T0的高8位重新赋初值

TL0=(65536-46083)%256;//定时器T0的高8位重新赋初值

}


 


333


/


192


//


46


T0


//实例46:用定时器T0的中断实现长时间定时

#include<reg51.h>   //   包含51单片机寄存器定义的头文件

sbitD1=P2^0;   //D1位定义为P2.0引脚

unsignedcharCountor;//设置全局变量,储存定时器T0中断次数

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET0=1;                     //定时器T0中断允许

TMOD=0x01;                //使用定时器T0的模式2

TH0=(65536-46083)/256;//定时器T0的高8位赋初值

TL0=(65536-46083)%256;//定时器T0的高8位赋初值

TR0=1;                     //启动定时器T0

Countor=0;               //0开始累计中断次数

while(1)//无限循环等待中断

;

}

/**************************************************************

函数功能:定时器T0的中断服务程序

**************************************************************/

voidTime0(void)interrupt1using0//interrupt”声明函数为中断服务函数

//其后的1为定时器T0的中断编号;0表示使用第0组工作

寄存器

{

Countor++;    //中断次数自加1

if(Countor==20)   //若累计满20次,即计时满1s

{

D1=~D1;      //按位取反操作,将P2.0引脚输出电平取反

Countor=0;  //Countor0,重新从0开始计数

}

TH0=(65536-46083)/256;//定时器T0的高8位重新赋初值

TL0=(65536-46083)%256;//定时器T0的高8位重新赋初值

}


 

//实例47:用定时器T1中断控制两个LED以不同周期闪烁

#include<reg51.h>   //   包含51单片机寄存器定义的头文件

sbitD1=P2^0;   //D1位定义为P2.0引脚

334/192


sbitD2=P2^1;


//D2位定义为P2.1引脚


 

unsignedcharCountor1;//设置全局变量,储存定时器T1中断次数

unsignedcharCountor2;//设置全局变量,储存定时器T1中断次数

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET1=1;                     //定时器T1中断允许

TMOD=0x10;                //使用定时器T1的模式1

TH1=(65536-46083)/256;//定时器T1的高8位赋初值

TL1=(65536-46083)%256;//定时器T1的高8位赋初值

TR1=1;                     //启动定时器T1

Countor1=0;               //0开始累计中断次数

Countor2=0;               //0开始累计中断次数

while(1)//无限循环等待中断

;

}

/**************************************************************

函数功能:定时器T1的中断服务程序

**************************************************************/

voidTime1(void)interrupt3using0//interrupt”声明函数为中断服务函数

//其后的3为定时器T1的中断编号;0表示使用第0组工作

寄存器

{

Countor1++;    //Countor1自加1

Countor2++;    //Countor2自加1

if(Countor1==2)   //若累计满2次,即计时满100ms

{

D1=~D1;      //按位取反操作,将P2.0引脚输出电平取反

Countor1=0;   //Countor10,重新从0开始计数

}

if(Countor2==8)   //若累计满8次,即计时满400ms

{

D2=~D2;      //按位取反操作,将P2.1引脚输出电平取反

Countor2=0;   //Countor10,重新从0开始计数

}

TH1=(65536-46083)/256;//定时器T1的高8位重新赋初值

TL1=(65536-46083)%256;//定时器T1的高8位重新赋初值

}


 


335


/


192


//


48


T1


1KHz


//实例48:用计数器T1的中断控制蜂鸣器发出1KHz音频

#include<reg51.h>   //   包含51单片机寄存器定义的头文件

sbitsound=P3^7;   //sound位定义为P3.7引脚

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET1=1;                     //定时器T1中断允许

TMOD=0x10;                //TMOD=0001000B,使用定时器T1的模式1

TH1=(65536-921)/256;    //定时器T1的高8位赋初值

TL1=(65536-921)%256;   //定时器T1的高8位赋初值

TR1=1;                     //启动定时器T1

while(1)//无限循环等待中断

;

}

/**************************************************************

函数功能:定时器T1的中断服务程序

**************************************************************/

voidTime1(void)interrupt3using0//interrupt”声明函数为中断服务函数

{

sound=~sound;

TH1=(65536-921)/256;    //定时器T1的高8位重新赋初值

TL1=(65536-921)%256;   //定时器T1的高8位重新赋初值

}


 


//


49


T0


"


"


//实例49:用定时器T0的中断实现"渴望"主题曲的播放

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitsound=P3^7;     //sound位定义为P3.7

unsignedintC;      //储存定时器的定时常数

//以下是C调低音的音频宏定义

#definel_dao262    //将“l_dao”宏定义为低音“1”的频率262Hz

#definel_re286     //将“l_re”宏定义为低音“2”的频率286Hz

#definel_mi311     //将“l_mi”宏定义为低音“3”的频率311Hz

#definel_fa349     //将“l_fa”宏定义为低音“4”的频率349Hz

#definel_sao392    //将“l_sao”宏定义为低音“5”的频率392Hz

#definel_la440     //将“l_a”宏定义为低音“6”的频率440Hz

#definel_xi494     //将“l_xi”宏定义为低音“7”的频率494Hz

336/192


//以下是C调中音的音频宏定义

#definedao523      //将“dao”宏定义为中音“1”的频率523Hz

#definere587       //将“re”宏定义为中音“2”的频率587Hz

#definemi659       //将“mi”宏定义为中音“3”的频率659Hz

#definefa698       //将“fa”宏定义为中音“4”的频率698Hz

#definesao784      //将“sao”宏定义为中音“5”的频率784Hz

#definela880       //将“la”宏定义为中音“6”的频率880Hz

#definexi987       //将“xi”宏定义为中音“7”的频率523H

//以下是C调高音的音频宏定义

#defineh_dao1046      //将“h_dao”宏定义为高音“1”的频率1046Hz

#defineh_re1174       //将“h_re”宏定义为高音“2”的频率1174Hz

#defineh_mi1318       //将“h_mi”宏定义为高音“3”的频率1318Hz

#defineh_fa1396      //将“h_fa”宏定义为高音“4”的频率1396Hz

#defineh_sao1567     //将“h_sao”宏定义为高音“5”的频率1567Hz

#defineh_la1760      //将“h_la”宏定义为高音“6”的频率1760Hz

#defineh_xi1975      //将“h_xi”宏定义为高音“7”的频率1975Hz

/*******************************************

函数功能:1个延时单位,延时200ms

******************************************/

voiddelay()

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

unsignedchari,j;

//以下是《渴望》片头曲的一段简谱

unsigned  intcodef[]={re,mi,re,dao,l_la,dao,l_la,    //每行对应一小节音符

l_sao,l_mi,l_sao,l_la,dao,

l_la,dao,sao,la,mi,sao,

re,

mi,re,mi,sao,mi,

l_sao,l_mi,l_sao,l_la,dao,

l_la,l_la,dao,l_la,l_sao,l_re,l_mi,

l_sao,

re,re,sao,la,sao,

fa,mi,sao,mi,

la,sao,mi,re,mi,l_la,dao,

337/192


//以下是简谱中每个音符的节拍


re,

mi,re,mi,sao,mi,

l_sao,l_mi,l_sao,l_la,dao,

l_la,dao,re,l_la,dao,re,mi,

re,

l_la,dao,re,l_la,dao,re,mi,

re,

0xff};//0xff作为音符的结束标志


//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位

unsignedcharcodeJP[]={4,1,1,4,1,1,2,

2,2,2,2,8,

4,2,3,1,2,2,

10,

4,2,2,4,4,

2,2,2,2,4,

2,2,2,2,2,2,2,

10,

4,4,4,2,2,

4,2,4,4,

4,2,2,2,2,2,2,

10,

4,2,2,4,4,

2,2,2,2,6,

4,2,2,4,1,1,4,

10,

4,2,2,4,1,1,4,

10

};

EA=1;           //开总中断

ET0=1;          //定时器T0中断允许

TMOD=0x00;     //  使用定时器T0的模式113位计数器)

while(1)         //无限循环

{

i=0;   //从第1个音符f[0]开始播放

while(f[i]!=0xff)               //只要没有读到结束标志就继续播放

{

C=460830/f[i];

TH0=(8192-C)/32;    //可证明这是13位计数器TH08位的赋

初值方法

TL0=(8192-C)%32;    //可证明这是13位计数器TL05位的赋初

值方法

TR0=1;                //启动定时器T0

338/192


}


}


}


for(j=0;j<JP[i];j++)

delay();

TR0=0;

i++;


//控制节拍数

//延时1个节拍单位

//关闭定时器T0

//播放下一个音符


/***********************************************************

函数功能:定时器T0的中断服务子程序,使P3.7引脚输出音频的方波

************************************************************/

voidTime0(void)interrupt1using1

{

sound=!sound;       //P3.7引脚输出电平取反,形成方波

TH0=(8192-C)/32;    //可证明这是13位计数器TH08位的赋初值方法

TL0=(8192-C)%32;    //可证明这是13位计数器TL05位的赋初值方法

}


 


//


50-1


50


#include<reg51.h>


//实例50-1:输出50个矩形脉冲

//包含51单片机寄存器定义的头文件


sbitu=P1^4;


//u位定义为P1.4


 

/*************************************************

函数功能:延时约30ms(3*100*100=30000μs=30m

*************************************************/

voiddelay30ms(void)

{

unsignedcharm,n;

for(m=0;m<100;m++)

for(n=0;n<100;n++)

;

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

unsignedchari;

u=1;    //初始化输出高电平

for(i=0;i<50;i++)//输出50个矩形脉冲

{

339/192


}


}


u=1;

delay30ms();

u=0;

delay30ms();

while(1)

;//无限循环,防止程序“跑飞”


 

//实例50-2:计数器T0统计外部脉冲数

#include<reg51.h>    //包含51单片机寄存器定义的头文件

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

TMOD=0x06;     //TMOD=00000110B,使用计数器T0的模式2

EA=1;           //开总中断

ET0=0;          //不使用定时器T0的中断

TR0=1;          //启动T0

TH0=0;         //计数器T08位赋初值

TL0=0;         //计数器T08位赋初值

while(1)  //无限循环,不停地将TL0计数结果送P1

P1=TL0;

}


 

//实例51-2:定时器T0的模式2测量正脉冲宽度

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitui=P3^2;   //ui位定义为P3.0INT0)引脚,表示输入电压

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

TMOD=0x0a;    //TMOD=00001010B,使用定时器T0的模式2GATE1

EA=1;           //开总中断

440/192


ET0=0;

TR0=1;

TH0=0;

TL0=0;

while(1)

{

while(ui==0)

;

TL0=0;


//不使用定时器T0的中断

//启动T0

//计数器T08位赋初值

//计数器T08位赋初值

//无限循环,不停地将TL0计数结果送P1

//INT0为低电平,T0不能启动

//INT0为高电平,启动T0计时,所以将TL00


 


}


}


while(ui==1)//INT0高电平期间,等待,计时

;

P1=TL0;    //将计时结果送P1口显示


 


//


52


T0


//实例52:用定时器T0控制输出高低宽度不同的矩形波

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitu=P3^0;       //u位定义为P3.0,从该引脚输出矩形脉冲

unsignedcharCountor;   //设置全局变量,储存负跳变累计数

/*************************************************

函数功能:延时约30ms(3*100*100=30000μs=30ms)

*************************************************/

voiddelay30ms(void)

{

unsignedcharm,n;

for(m=0;m<100;m++)

for(n=0;n<100;n++)

;

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

unsignedchari;

EA=1;   //开放总中断

EX0=1;  //允许使用外中断

IT0=1;  //选择负跳变来触发外中断

Countor=0;

441/192


for(i=0;i<100;i++)

{

u=1;

delay30ms();

u=0;

delay30ms();

}

while(1)


//输出100个负跳变


}


;//无限循环,


防止程序跑飞


 

/**************************************************************

函数功能:外中断T0的中断服务程序

**************************************************************/

voidint0(void)interrupt0using0//外中断0的中断编号为0

{

Countor++;

P1=Countor;

}


 


//


53


0


//实例53:用外中断0的中断方式进行数据采集

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitS=P3^2;       //S位定义为P3.2

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

EA=1;   //开放总中断

EX0=1;  //允许使用外中断

IT0=1;  //选择负跳变来触发外中断

P1=0xff;

while(1)

;//无限循环,防止程序跑飞

}

/**************************************************************

函数功能:外中断T0的中断服务程序

**************************************************************/

voidint0(void)interrupt0using0//外中断0的中断编号为0

{

442/192


}


P1=~P1;


//每产生一次中断请求,P1取反一次。


 

//实例54-1:输出负脉宽为200微秒的方波

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitu=P1^4;     //u位定义为P1.4

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

TMOD=0x02;               //TMOD=00000010B,使用定时器T0的模式2

EA=1;                        //开总中断

ET0=1;                      //定时器T0中断允许

TH0=256-200;    //定时器T0的高8位赋初值

TL0=256-200;   //定时器T0的高8位赋初值

TR0=1;                     //启动定时器T0

while(1)                   //无限循环,等待中断

;

}

/**************************************************************

函数功能:定时器T0的中断服务程序

**************************************************************/

voidTime0(void)interrupt1using0//"interrupt"声明函数为中断服务函数

{

u=~u;  //P1.4引脚输出电平取反,产生方波

}


 


//


54-2


#include<reg51.h>


//实例54-2:测量负脉冲宽度

//包含51单片机寄存器定义的头文件


sbitu=P3^2;


//u位定义为P3.2


 

/*******************************************

函数功能:主函数

******************************************/

443/192


voidmain(void)

{

TMOD=0x02;


//TMOD=00000010B,使用定时器T0的模式2


EA=1;

EX0=1;

IT0=1;

ET0=1;

TH0=0;

TL0=0;

TR0=0;


//开放总中断

//允许使用外中断

//选择负跳变来触发外中断

//允许定时器T0中断

//定时器T0赋初值0

//定时器T0赋初值0

//先关闭T0


 


}


while(1)

;//无限循环,


不停检测输入负脉冲宽度


/**************************************************************

函数功能:外中断0的中断服务程序

**************************************************************/

voidint0(void)interrupt0using0//外中断0的中断编号为0

{

TR0=1;   //外中断一到来,即启动T0计时

TL0=0;  //0开始计时

while(u==0)   //低电平时,等待T0计时

;

P1=TL0;//将结果送P1口显示

TR0=0;  //关闭T0

}


 

//实例55:方式0控制流水灯循环点亮

#include<reg51.h>    //包含51单片机寄存器定义的头文件

#include<intrins.h>//包含函数_nop_()定义的头文件

unsignedcharcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};//流水灯控

制码,该数组被定义为全局变量

sbitP17=P1^7;

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

444/192


}


for(n=0;n<250;n++)

;


 

/**************************************************************

函数功能:发送一个字节的数据

**************************************************************/

voidSend(unsignedchardat)

{

P17=0;     //P1.7引脚输出清0信号,对74LS1640

_nop_();   //延时一个机器周期

_nop_();  //延时一个机器周期,保证清0完成

P17=1;    //结束对74LS164的清0

SBUF=dat;  //将数据写入发送缓冲器,启动发送

while(TI==0)   //若没有发送完毕,等待

;

TI=0;   //发送完毕,TI被置“1”,需将其清0

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

unsignedchari;

SCON=0x00;  //SCON=00000000B,使串行口工作于方式0

while(1)

{

for(i=0;i<8;i++)

{

Send(Tab[i]);   //发送数据

delay();         //延时

}

}

}


 


#include<reg51.h>


//实例56-1:数据发送程序

//包含单片机寄存器的头文件


 

unsignedcharcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码,该数组被定义为全局变量

/*****************************************************

445/192


函数功能:向PC发送一个字节数据

***************************************************/

voidSend(unsignedchardat)

{

SBUF=dat;

while(TI==0)

;

TI=0;

}

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;

TMOD=0x20;  //TMOD=00100000B,定时器T1工作于方式2

SCON=0x40;  //SCON=01000000B,串口工作方式1

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;   //根据规定给定时器T1赋初值

TL1=0xfd;   //根据规定给定时器T1赋初值

TR1=1;       //启动定时器T1

while(1)

{

for(i=0;i<8;i++)    //模拟检测数据

{

Send(Tab[i]);          //发送数据i

delay();   //50ms发送一次检测数据

}

}

}


 


446


/


192


//


56-2


#include<reg51.h>


//实例56-2:数据接收程序

//包含单片机寄存器的头文件


 

/*****************************************************

函数功能:接收一个字节数据

***************************************************/

unsignedcharReceive(void)

{

unsignedchardat;

while(RI==0)   //只要接收中断标志位RI没有被置“1

;      //等待,直至接收完毕(RI=1

RI=0;      //为了接收下一帧数据,需将RI0

dat=SBUF;  //将接收缓冲器中的数据存于dat

returndat;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

TMOD=0x20;  //定时器T1工作于方式2

SCON=0x50;  //SCON=01010000B,串口工作方式1,允许接收(REN=1

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;  //根据规定给定时器T1赋初值

TL1=0xfd;  //根据规定给定时器T1赋初值

TR1=1;    //启动定时器T1

REN=1;    //允许接收

while(1)

{

P1=Receive();//将接收到的数据送P1口显示

}

}


 


//


57-1


#include<reg51.h>

sbitp=PSW^0;


//实例57-1:数据发送程序

//包含单片机寄存器的头文件


 

unsignedcharcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码,该数组被定义为全局变量

/*****************************************************

447/192


函数功能:向PC发送一个字节数据

***************************************************/

voidSend(unsignedchardat)

{

ACC=dat;

TB8=p;

SBUF=dat;

while(TI==0)

;

TI=0;

}

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;

TMOD=0x20;  //TMOD=00100000B,定时器T1工作于方式2

SCON=0xc0;  //SCON=11000000B,串口工作方式3,

//SM20,不使用多机通信,TB80

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;     //根据规定给定时器T1赋初值

TL1=0xfd;     //根据规定给定时器T1赋初值

TR1=1;       //启动定时器T1

while(1)

{

for(i=0;i<8;i++)    //模拟检测数据

{

Send(Tab[i]);          //发送数据i

delay();   //50ms发送一次检测数据

}

}

}


 


448


/


192


 


//


57-2


#include<reg51.h>

sbitp=PSW^0;


//实例57-2:数据接收程序

//包含单片机寄存器的头文件


/*****************************************************

函数功能:接收一个字节数据

***************************************************/

unsignedcharReceive(void)

{

unsignedchardat;

while(RI==0)     //只要接收中断标志位RI没有被置"1"

;        //等待,直至接收完毕(RI=1

RI=0;      //为了接收下一帧数据,需将RI0

ACC=SBUF;  //将接收缓冲器中的数据存于dat

if(RB8==p)

{

dat=ACC;

returndat;

}

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

TMOD=0x20;  //定时器T1工作于方式2

SCON=0xd0;  //SCON=11010000B,串口工作方式1,允许接收(REN=1

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;     //根据规定给定时器T1赋初值

TL1=0xfd;     //根据规定给定时器T1赋初值

TR1=1;       //启动定时器T1

REN=1;       //允许接收

while(1)

{

P1=Receive();//将接收到的数据送P1口显示

}

}


 


449


/


192


//


58


PC


#include<reg51.h>


//实例58:单片机向PC发送数据

//包含单片机寄存器的头文件


 

unsignedcharcodeTab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

//流水灯控制码,该数组被定义为全局变量

/*****************************************************

函数功能:向PC发送一个字节数据

***************************************************/

voidSend(unsignedchardat)

{

SBUF=dat;

while(TI==0)

;

TI=0;

}

/**************************************************************

函数功能:延时约150ms

**************************************************************/

voiddelay(void)

{

unsignedcharm,n;

for(m=0;m<200;m++)

for(n=0;n<250;n++)

;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;

TMOD=0x20;  //TMOD=00100000B,定时器T1工作于方式2

SCON=0x40;  //SCON=01000000B,串口工作方式1

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;     //根据规定给定时器T1赋初值

TL1=0xfd;     //根据规定给定时器T1赋初值

TR1=1;       //启动定时器T1

while(1)

{

for(i=0;i<8;i++)    //模拟检测数据

{

Send(Tab[i]);          //发送数据i

delay();   //150ms发送一次数据

}

550/192


}


}


 


//


59


PC


//实例59:单片机接收PC发出的数据

#include<reg51.h>         //包含单片机寄存器的头文件

/*****************************************************

函数功能:接收一个字节数据

***************************************************/

unsignedcharReceive(void)

{

unsignedchardat;

while(RI==0)   //只要接收中断标志位RI没有被置“1

;      //等待,直至接收完毕(RI=1

RI=0;      //为了接收下一帧数据,需将RI0

dat=SBUF;  //将接收缓冲器中的数据存于dat

returndat;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

TMOD=0x20;  //定时器T1工作于方式2

SCON=0x50;  //SCON=01010000B,串口工作方式1,允许接收(REN=1

PCON=0x00;  //PCON=00000000B,波特率9600

TH1=0xfd;  //根据规定给定时器T1赋初值

TL1=0xfd;  //根据规定给定时器T1赋初值

TR1=1;    //启动定时器T1

REN=1;    //允许接收

while(1)

{

P1=Receive();//将接收到的数据送P1口显示

}

}


 


551


/


192


/********************************************************

*********数码管显示*****数码管显示********************

数码管显示****************数码管显示

***************************************************/


 


#include<reg51.h>

voidmain(void)

{


//实例60:用LED数码显示数字5

//   包含51单片机寄存器定义的头文件


}


P2=0xfe;

P0=0x92;


//P2.0引脚输出低电平,数码显示器接通电源准备点亮

//P0口输出数字"5"的段码92H


 


//


61


LED


0~9


//实例61:用LED数码显示器循环显示数字0~9

#include<reg51.h>     //  包含51单片机寄存器定义的头文件

/**************************************************

函数功能:延时函数,延时一段时间

***************************************************/

voiddelay(void)

{

unsignedchari,j;

for(i=0;i<255;i++)

for(j=0;j<255;j++)

;

}

/**************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;


 


552


/


192


unsignedcharcode

Tab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数码管显示09的段码表,程序运行中当数组值不发生变化

时,

//前面加关键字code,可以大大节约单片机的存储空间

P2=0xfe;   //P2.0引脚输出低电平,数码显示器DS0接通电源工作

while(1)   //无限循环

{

for(i=0;i<10;i++)

{

P0=Tab[i];  //P0口输出数字的段码92H

delay();   //调用延时函数

}

}

}


 

//实例62:用数码管慢速动态扫描显示数字"1234"

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

voiddelay(void)          //延时函数,延时一段时间

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

voidmain(void)

{

while(1)    //无限循环

{

P2=0xfe;   //P2.0引脚输出低电平,DS0点亮

P0=0xf9;  //数字1的段码

delay();

P2=0xfd;   //P2.1引脚输出低电平,DS1点亮

P0=0xa4;  //数字2的段码

delay();

P2=0xfb;   //P2.2引脚输出低电平,DS2点亮

P0=0xb0;  //数字3的段码

delay();

P2=0xf7;   //P2.3引脚输出低电平,DS3点亮

P0=0x99;  //数字4的段码

553/192


}


}


delay();

P2=0xff;


 


//


63


LED


1234


//实例63:用LED数码显示器伪静态显示数字1234

#include<reg51.h>              //   包含51单片机寄存器定义的头文件

voiddelay(void)          //延时函数,延时约0.6毫秒

{

unsignedchari;

for(i=0;i<200;i++)

;

}

voidmain(void)

{

while(1)    //无限循环

{

P2=0xfe;   //P2.0引脚输出低电平,DS0点亮

P0=0xf9;  //数字1的段码

delay();

P2=0xfd;   //P2.1引脚输出低电平,DS1点亮

P0=0xa4;  //数字2的段码

delay();

P2=0xfb;   //P2.2引脚输出低电平,DS2点亮

P0=0xb0;  //数字3的段码

delay();

P2=0xf7;   //P2.3引脚输出低电平,DS3点亮

P0=0x99;  //数字4的段码

delay();

P2=0xff;

}

}


 

//实例64:用数码管显示动态检测结果

#include<reg51.h>     //  包含51单片机寄存器定义的头文件

554/192


#include<stdlib.h>

unsignedchari;

unsignedintx;


//包含随机函数rand()的定义文件

//记录中断次数

//随机检测的数据


 

unsignedcharcodeTab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数码管显示09的段码表

/********************************************************************

***

函数功能:快速动态扫描延时,延时约0.9毫秒

*********************************************************************

***/

voiddelay(void)

{

unsignedinti;

for(i=0;i<300;i++)

;

}

/********************************************************************

***

函数功能:4位数的数码显示器显示

入口参数:k

出口参数:无

*********************************************************************

***/

voiddisplay(unsignedintk)

{

P2=0xfe;   //P2=11111110BP2.0引脚输出低电平,数码显示器DS0

通电源

P0=Tab[k/1000];          //显示千位

delay();

P2=0xfd;   //P2=11111101BP2.1引脚输出低电平,数码显示器DS1接通

电源

P0=Tab[(k%1000)/100];            //显示百位

delay();

P2=0xfb;   //P2=11111011BP2.2引脚输出低电平,数码显示器DS2接通

电源

P0=Tab[(k%100)/10];   //显示十位

delay();

P2=0xf7;   //P2=11110111BP2.3引脚输出低电平,数码显示器DS3

通电源

P0=Tab[k%10];//显示个位

delay();

P2=0xff;  //关闭所有显示器

555/192


}

voidmain(void)

{


//主函数


TMOD=0x01;

TH0=(65536-46083)/256;

1.085微秒=50000微秒=50毫秒

TL0=(65536-46083)%256;

EA=1;

ET0=1;

TR0=1;

while(1)

{


//使用定时器T0

//将定时器计时时间设定为46083×

//开启总中断

//定时器T0中断允许

//启动定时器T0开始运行


}


}


display(x);


//调用检测结果的显示程序


 

/********************************************************

函数功能:定时器T0的中断服务程序

*******************************************************/

voidTime0(void)interrupt1using1

{

TR0=0;    //关闭定时器T0

i++;          //每来一次中断,i自加1

if(i==20)   //20次中断,即1秒钟进行一次检测结果采样

{

x=rand()/10;      //随机产生一个从032767的整数,再将其除以10

获得一个随机4位数,模拟检测结果

i=0;                //i0,重新统计中断次数

}

TH0=(65536-46083)/256;    //重新给计数器T0赋初值

TL0=(65536-46083)%256;

TR0=1;     //启动定时器T0

}


 


//


65


#include<reg51.h>


//


//实例65:数码秒表设计

包含51单片机寄存器定义的头文件

556/192


unsignedcharcodeTab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数码管显示09的段码表

unsignedcharint_time;          //记录中断次数

unsignedcharsecond;          //储存秒

/********************************************************************

***

函数功能:快速动态扫描延时,延时约0.6毫秒

*********************************************************************

***/

voiddelay(void)

{

unsignedchari;

for(i=0;i<200;i++)

;

}

/********************************************************************

***

函数功能:显示秒

入口参数:k

出口参数:无

*********************************************************************

***/

voidDisplaySecond(unsignedchark)

{

P2=0xfb;          //P2.6引脚输出低电平,DS6点亮

P0=Tab[k/10];            //显示十位

delay();

P2=0xf7;         //P2.7引脚输出低电平,DS7点亮

P0=Tab[k%10];           //显示个位

delay();

P2=0xff;      //关闭所有数码管


 


}


voidmain(void)

{

TMOD=0x01;


//主函数


//使用定时器T0



TH0=(65536-46083)/256;


//将定时器计时时间设定为46083×1.085


//=50000微秒=50毫秒

TL0=(65536-46083)%256;


557


/


192


EA=1;

ET0=1;

TR0=1;

int_time=0;

second=0;

while(1)

{


//开启总中断

//定时器T0中断允许

//启动定时器T0开始运行

//中断次数初始化

//秒初始化


}


}


DisplaySecond(second);


//调用秒的显示子程序


 

//********************************************************

//函数功能:定时器T0的中断服务程序

//*******************************************************

voidinterserve(void)interrupt1using1

{

TR0=0;    //关闭定时器T0

int_time++;          //每来一次中断,中断次数int_time自加1

if(int_time==20)    //20次中断,1秒钟进行一次检测结果采样

{

int_time=0;     //中断次数清0

second++;     //秒加1

if(second==60)

second=0;//秒等于60就返回0

}

TH0=(65536-46083)/256;    //重新给计数器T0赋初值

TL0=(65536-46083)%256;

TR0=1;     //启动定时器T0

}


 


#include<reg51.h>


//实例66:数码时钟设计

//   包含51单片机寄存器定义的头文件


 

unsignedcharTab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//control  shape

unsignedcharport[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

unsignedcharint_time;//中断次数计数变量

unsignedcharsecond;     //秒计数变量

unsignedcharminute;     //分钟计数变量

unsignedcharhour;      //小时计数变量

/////////////////////////////////////////////////////

558/192


 


voiddelay(void)

{

unsignedcharj;

for(j=0;j<200;j++)

;

}


//延时函数,延时约0.6ms


 

/******************************************************************

函数功能:显示秒的子程序

入口参数:s

********************************************************************/

voidDisplaySecond(unsignedchars)

{

P2=0xbf;          //P2.6引脚输出低电平,DS6点亮

P0=Tab[s/10];            //显示十位

delay();

P2=0x7f;         //P2.7引脚输出低电平,DS7点亮

P0=Tab[s%10];           //显示个位

delay();

P2=0xff;      //关闭所有数码管

}

/******************************************************************

函数功能:显示分钟的子程序

入口参数:m

********************************************************************/

voidDisplayMinute(unsignedcharm)

{

P2=0xf7;   //P2.3引脚输出低电平,DS3点亮

P0=Tab[m/10];//显示个位

delay();

P2=0xef;   //P2.4引脚输出低电平,DS4点亮

P0=Tab[m%10];

delay();

P2=0xdf;   //P2.5引脚输出低电平,DS5点亮

P0=0xbf;   //分隔符“-”的段码

delay();

P2=0xff;   //关闭所有数码管


 


559


/


192


}

/******************************************************************

函数功能:显示小时的子程序

入口参数:h

********************************************************************/

voidDisplayHour(unsignedcharh)

{

P2=0xfe;          //P2.0引脚输出低电平,DS0点亮

P0=Tab[h/10];            //显示十位

delay();

P2=0xfd;         //P2.1引脚输出低电平,DS1点亮

P0=Tab[h%10];     //显示个位

delay();

P2=0xfb;      //P2.2引脚输出低电平,DS2点亮

P0=0xbf;      //分隔符“-”的段码

delay();

P2=0xff;      //关闭所有数码管

}

/******************************************************************

函数功能:主函数

********************************************************************/

voidmain(void)

{

TMOD=0x01;                //使用定时器T0

EA=1;                      //开中断总允许

ET0=1;                     //允许T0中断

TH0=(65536-46083)/256;   //定时器高八位赋初值

TL0=(65536-46083)%256;   //定时器低八位赋初值

TR0=1;

int_time=0;     //中断计数变量初始化

second=0;       //秒计数变量初始化

minute=0;      //分钟计数变量初始化

hour=0;         //小时计数变量初始化

while(1)

{

DisplaySecond(second);     //调用秒显示子程序

delay();

DisplayMinute(minute);    //调用分钟显示子程序

660/192


}


}


delay();

DisplayHour(hour);

delay();


 

/******************************************************************

函数功能:定时器T0的中断服务子程序

********************************************************************/

voidinterserve(void)interrupt1using1   //usingTime0

{

int_time++;

if(int_time==20)

{

int_time=0;     //中断计数变量清0

second++;       //秒计数变量加1

}

if(second==60)

{

second=0;     //如果秒计满60,将秒计数变量清0

minute++;     //分钟计数变量加1

}

if(minute==60)

{

minute=0;     //如果分钟计满60,将分钟计数变量

0

hour++;       //小时计数变量加1

}

if(hour==24)

{

hour=0;    //如果小时计满24,将小时计数变量

0

}

TH0=(65536-46083)/256;    //定时器重新赋初值

TL0=(65536-46083)%256;


 

}


 


661


/


192


//


67


LED


T0


//实例67:用LED数码管显示计数器T0的计数值

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitS=P3^2;  //S位定义为P3.2引脚

unsignedcharTab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

码表

unsignedcharx;


//


/******************************************************************

函数功能:延时约0.6ms

********************************************************************/

voiddelay(void)

{

unsignedcharj;

for(j=0;j<200;j++)

;

}

/******************************************************************

函数功能:显示计数次数的子程序

入口参数:x

********************************************************************/

voidDisplay(unsignedcharx)

{

P2=0xf7;          //P2.6引脚输出低电平,DS6点亮

P0=Tab[x/10];    //显示十位

delay();

P2=0xfb;       //P2.7引脚输出低电平,DS7点亮

P0=Tab[x%10];   //显示个位

delay();

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

EA=1;   //开放总中断

EX0=1;  //允许使用外中断

IT0=1;  //选择负跳变来触发外中断

x=0;

while(1)

Display(x);

662/192


 

}

/**************************************************************

函数功能:外中断T0的中断服务程序

**************************************************************/

voidint0(void)interrupt0using0//外中断0的中断编号为0

{

x++;

if(x==100)

x=0;

}


 


//


68


59


#include<reg51.h>


//实例68:静态显示数字“59

//包含51单片机寄存器定义的头文件


 

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

P0=0x92;   //将数字5的段码送P0

P1=0x90;      //将数字9的段码送P1

while(1)   //无限循环,防止程序跑飞

;

}


 

/********************************************************

**************键盘控制*********键盘控制***************

***************键盘控制*********键盘控制*******************             **********

*****************************************************/


 


663


/


192


//


69


//实例69:无软件消抖的独立式键盘输入实验

#include<reg51.h>     //  包含51单片机寄存器定义的头文件

sbitS1=P1^4;          //S1位定义为P1.4引脚

sbitLED0=P3^0;         //LED0位定义为P3.0引脚

voidmain(void)   //主函数

{

LED0=0;         //P3.0引脚输出低电平

while(1)

{

if(S1==0)   //P1.4引脚输出低电平,按键S1被按下

LED0=!LED0;   //P3.0引脚取反

}

}


 

//实例70:软件消抖的独立式键盘输入实验

#include<reg51.h>     //  包含51单片机寄存器定义的头文件

sbitS1=P1^4;          //S1位定义为P1.4引脚

sbitLED0=P3^0;         //LED0位定义为P3.0引脚

/*************************************************

函数功能:延时约30ms

**************************************************/

voiddelay(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<100;j++)

;

}

/*************************************************

函数功能:主函数

**************************************************/

voidmain(void)   //主函数

{

LED0=0;         //P3.0引脚输出低电平

while(1)

{

if(S1==0)   //P1.4引脚输出低电平,按键S1被按下

{

664/192


}


}


}


delay();//延时一段时间再次检测

if(S1==0)   //按键S1的确被按下

LED0=!LED0;   //P3.0引脚取反


 

//实例71CPU控制的独立式键盘扫描实验

#include<reg51.h>     //包含51单片机寄存器定义的头文件

sbitS1=P1^4;          //S1位定义为P1.4引脚

sbitS2=P1^5;          //S2位定义为P1.5引脚

sbitS3=P1^6;          //S3位定义为P1.6引脚

sbitS4=P1^7;          //S4位定义为P1.7引脚

unsignedcharkeyval;   //储存按键值

/*************************************************

函数功能:流水灯延时

**************************************************/

voidled_delay(void)

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

/*************************************************

函数功能:软件消抖延时

**************************************************/

voiddelay30ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<100;j++)

;

}

/*************************************************

函数功能:正向流水点亮LED

**************************************************/

voidforward(void)

{

665/192


}


P3=0xfe;

led_delay();

P3=0xfd;

led_delay();

P3=0xfb;

led_delay();

P3=0xf7;

led_delay();

P3=0xef;

led_delay();

P3=0xdf;

led_delay();

P3=0xbf;

led_delay();

P3=0x7f;

led_delay();

P3=0xff;

P3=0xfe;

led_delay();


//第一个灯亮

//第二个灯亮

//第三个灯亮

//第四个灯亮

//第五个灯亮

//第六个灯亮

//第七个灯亮

//第八个灯亮

//第一个灯亮


 

/*************************************************

函数功能:反向流水点亮LED

**************************************************/

voidbackward(void)

{

P3=0x7f;            //第八个灯亮

led_delay();

P3=0xbf;            //第七个灯亮

led_delay();

P3=0xdf;            //第六个灯亮

led_delay();

P3=0xef;            //第五个灯亮

led_delay();

P3=0xf7;            //第四个灯亮

led_delay();

P3=0xfb;            //第三个灯亮

led_delay();

P3=0xfd;           //第二个灯亮

led_delay();

P3=0xfe;           //第一个灯亮

led_delay();

}

/*************************************************

666/192


函数功能:关闭所有LED

**************************************************/

voidstop(void)

{

P3=0xff;

}

/*************************************************

函数功能:闪烁点亮LED

**************************************************/

voidflash(void)

{

P3=0xff;

led_delay();

P3=0x00;

led_delay();

}

/*************************************************

函数功能:键盘扫描子程序

**************************************************/

voidkey_scan(void)

{

if((P1&0xf0)!=0xf0)           //第一次检测到有键按下

{

delay30ms();    //延时20ms再去检测

if(S1==0)        //按键S1被按下

keyval=1;

if(S2==0)        //按键S2被按下

keyval=2;

if(S3==0)        //按键S3被按下

keyval=3;

if(S4==0)        //按键S4被按下

keyval=4;

}

}

/*************************************************

函数功能:主函数

**************************************************/

voidmain(void)   //主函数

{

keyval=0;                 //按键值初始化为0,什么也不做

while(1)

{

key_scan();

667/192


}


}


switch(keyval)

{

case1:forward();

break;

case2:backward();

break;

case3:stop();

break;

case4:flash();

break;

}


 


//


72


//实例72:定时器中断控制的独立式键盘扫描实验

#include<reg51.h>     //包含51单片机寄存器定义的头文件

sbitS1=P1^4;          //S1位定义为P1.4引脚

sbitS2=P1^5;          //S2位定义为P1.5引脚

sbitS3=P1^6;          //S3位定义为P1.6引脚

sbitS4=P1^7;          //S4位定义为P1.7引脚

unsignedcharkeyval;   //储存按键值

/*************************************************

函数功能:流水灯延时

**************************************************/

voidled_delay(void)

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

/*************************************************

函数功能:软件消抖延时

**************************************************/

voiddelay20ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

668/192


}


for(j=0;j<60;j++)

;


 

/*************************************************

函数功能:正向流水点亮LED

**************************************************/

voidforward(void)

{

P3=0xfe;           //第一个灯亮

led_delay();

P3=0xfd;           //第二个灯亮

led_delay();

P3=0xfb;            //第三个灯亮

led_delay();

P3=0xf7;            //第四个灯亮

led_delay();

P3=0xef;            //第五个灯亮

led_delay();

P3=0xdf;            //第六个灯亮

led_delay();

P3=0xbf;            //第七个灯亮

led_delay();

P3=0x7f;            //第八个灯亮

led_delay();

P3=0xff;

P3=0xfe;           //第一个灯亮

led_delay();

}

/*************************************************

函数功能:反向流水点亮LED

**************************************************/

voidbackward(void)

{

P3=0x7f;            //第八个灯亮

led_delay();

P3=0xbf;            //第七个灯亮

led_delay();

P3=0xdf;            //第六个灯亮

led_delay();

P3=0xef;            //第五个灯亮

led_delay();

P3=0xf7;            //第四个灯亮

led_delay();

P3=0xfb;            //第三个灯亮

669/192


}


led_delay();

P3=0xfd;

led_delay();

P3=0xfe;

led_delay();


//第二个灯亮

//第一个灯亮


/*************************************************

函数功能:关闭所有LED

**************************************************/

voidstop(void)

{

P3=0xff;     //关闭8LED

}

/*************************************************

函数功能:闪烁点亮LED

**************************************************/

voidflash(void)

{

P3=0xff;        //关闭8LED

led_delay();

P3=0x00;       //点亮8LED

led_delay();

}


 

/*************************************************

函数功能:主函数

**************************************************/

voidmain(void)   //主函数

{

TMOD=0x01;        //使用定时器T0的模式1

EA=1;              //开总中断

ET0=1;            //定时器T0中断允许

TR0=1;            //启动定时器T0

TH0=(65536-1000)/256;     //定时器T0赋初值,每计数200次(217微秒)发

送一次中断请求

TL0=(65536-1000)%256;     //定时器T0赋初值

keyval=0;                 //按键值初始化为0,什么也不做

while(1)

{

switch(keyval)

{

case1:forward();

770/192


}


}


}


break;

case2:backward();

break;

case3:stop();

break;

case4:flash();

break;


 

/*************************************************

函数功能:定时器T0的中断服务子程序

**************************************************/

voidTime0_serve(void)interrupt1using1

{

if((P1&0xf0)!=0xf0)           //第一次检测到有键按下

{

delay20ms();    //延时20ms再去检测

if(S1==0)        //按键S1被按下

keyval=1;

if(S2==0)        //按键S2被按下

keyval=2;

if(S3==0)        //按键S3被按下

keyval=3;

if(S4==0)        //按键S4被按下

keyval=4;

}

TH0=(65536-1000)/256;

TL0=(65536-1000)%256;

}


 


//


73


4


//实例73:独立式键盘控制的4级变速流水灯

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

unsignedcharspeed;     //储存流水灯的流动速度

sbitS1=P1^4;            //位定义S1P1.4

sbitS2=P1^5;            //位定义S2P1.5

sbitS3=P1^6;            //位定义S3P1.6

sbitS4=P1^7;            //位定义S4P1.7

771/192


/**************************************************************

函数功能:延时20ms的子程序

**************************************************************/

voiddelay20ms(void)     //3*i*j+2*i=3*100*60+2*100=20000μs=20ms;

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<60;j++)

;

}

/**************************************************************

函数功能:延时可调子程序

入口参数:x

**************************************************************/

voiddelay(unsignedcharx)

{

unsignedchark;

for(k=0;k<x;k++)

delay20ms();

}

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

TMOD=0x02;      //使用定时器T0的模式2

EA=1;            //开总中断

ET0=1;           //定时器T0中断允许

TR0=1;           //定时器T0开始运行

TH0=256-200;    //定时器T0赋初值,200微妙来1次中断请求

TL0=256-200;

speed=3;          //默认流水灯流水点亮延时20ms×3=60ms

while(1)

{

P3=0xfe;           //第一个灯亮

delay(speed);     //调用延时可调子程序

P3=0xfd;           //第二个灯亮

delay(speed);

P3=0xfb;            //第三个灯亮

delay(speed);

P3=0xf7;            //第四个灯亮

delay(speed);

P3=0xef;            //第五个灯亮

delay(speed);

772/192


}


}


P3=0xdf;

delay(speed);

P3=0xbf;

delay(speed);

P3=0x7f;

delay(speed);

P3=0xff;


//第六个灯亮

//第七个灯亮

//第八个灯亮


/**************************************************************

函数功能:定时器T0的中断服务子程序,进行键盘扫描

**************************************************************/

voidintersev(void)interrupt1using1

{

TR0=0;               //关闭定时器T0/

P1=0xff;              //P1口的均置高电平"1"

if((P1&0xf0)!=0xf0)     //如果有键按下

{

delay20ms();         //延时20ms,软件消抖

if((P1&0xf0)!=0xf0)   //确实有键按下

{

if(S1==0)         //如果是按键S1按下

speed=5;   //流水灯流水点亮延时20ms×5=100ms

if(S2==0)        //如果是按键S2按下

speed=10;   //流水灯流水点亮延时20ms×10=200ms

if(S3==0)        //如果是按键S3按下

speed=25;  //流水灯流水点亮延时20ms×25=500ms

if(S4==0)        //如果是按键S4按下

speed=50;  //流水灯流水点亮延时20ms×50=1000ms

}

}

TR0=1;                  //启动定时器T0

}


 

//实例74:独立式键盘的按键功能扩展:"以一当四"

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

unsignedcharID;     //储存流水灯的流动速度

sbitS1=P1^4;            //位定义S1P1.4

/**************************************************************

773/192


函数功能:延时子程序

**************************************************************/

voiddelay(void)     //因为仅对一个按键扫描,所以延时时间较长约200ms

{

unsignedchari,j;

for(i=0;i<200;i++)

for(j=0;j<100;j++)

;

}


 

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

TMOD=0x02;      //使用定时器T0的模式2

EA=1;            //开总中断

ET0=1;           //定时器T0中断允许

TR0=1;           //定时器T0开始运行

TH0=256-200;    //定时器T0赋初值,每200微妙来1次中断请求

TL0=256-200;

ID=0;

while(1)

{

switch(ID)

{

case0:P3=0xfe;

break;

case1:P3=0xfd;

break;

case2:P3=0xfb;

break;

case3:P3=0xf7;

break;

}

}

}

/**************************************************************

函数功能:定时器T0的中断服务子程序,进行键盘扫描

**************************************************************/

voidintersev(void)interrupt1using1

{

774/192


TR0=0;

P1=0xff;

if(S1==0)

{


//关闭定时器T0

//如果是按键S1按下


}


delay();

if(S1==0)

ID=ID+1;


//延时20ms,软件消抖

//如果是按键S1按下


 


}


if(ID==4)

ID=0;

TR0=1;


//启动定时器T0


 


//


75


//实例75:独立式键盘调时的数码时钟实验

#include<reg51.h>     //  包含51单片机寄存器定义的头文件

unsignedcharcodeTab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数字0~9的段码

unsignedcharint_time;//中断次数计数变量

unsignedcharsecond;     //秒计数变量

unsignedcharminute;     //分钟计数变量

unsignedcharhour;      //小时计数变量

sbitS1=P1^4;            //S1位定义为P1.4

sbitS2=P1^5;            //S2位定义为P1.5

sbitS3=P1^6;            //S3位定义为P1.6

sbitS4=P1^7;            //S4位定义为P1.7

/******************************************************************

函数功能:数码管扫描延时

********************************************************************/

voiddelay(void)

{

unsignedcharj;

for(j=0;j<200;j++)

;

}

/******************************************************************

函数功能:键盘扫描延时

775/192


********************************************************************/

voiddelay60ms(void)

{

unsignedchari,j;

for(i=0;i<200;i++)

for(j=0;j<100;j++)

;

}

/******************************************************************

函数功能:显示秒

入口参数:s

********************************************************************/

voidDisplaySecond(unsignedchars)

{

P2=0xbf;          //P2.6引脚输出低电平,DS6点亮

P0=Tab[s/10];            //显示十位

delay();

P2=0x7f;         //P2.7引脚输出低电平,DS7点亮

P0=Tab[s%10];           //显示个位

delay();

P2=0xff;      //关闭所有数码管

}

/******************************************************************

函数功能:显示分钟

入口参数:m

********************************************************************/

voidDisplayMinute(unsignedcharm)

{

P2=0xf7;   //P2.3引脚输出低电平,DS3点亮

P0=Tab[m/10];//显示个位

delay();

P2=0xef;   //P2.4引脚输出低电平,DS4点亮

P0=Tab[m%10];

delay();

P2=0xdf;   //P2.5引脚输出低电平,DS5点亮

P0=0xbf;   //分隔符“-”的段码

delay();

P2=0xff;   //关闭所有数码管

}

/******************************************************************

776/192


函数功能:显示小时的子程序

入口参数:h

********************************************************************/

voidDisplayHour(unsignedcharh)

{

P2=0xfe;          //P2.0引脚输出低电平,DS0点亮

P0=Tab[h/10];            //显示十位

delay();

P2=0xfd;         //P2.1引脚输出低电平,DS1点亮

P0=Tab[h%10];     //显示个位

delay();

P2=0xfb;      //P2.2引脚输出低电平,DS2点亮

P0=0xbf;      //分隔符“-”的段码

delay();

P2=0xff;      //关闭所有数码管

}

/******************************************************************

函数功能:键盘扫描

********************************************************************/

voidkey_scan(void)

{

P1=0xf0;   //P1口高4位置高电平“1

if((P1&0xf0)!=0xf0)           //有键按下

{

delay60ms();           //延时60ms再检测

if((P1&0xf0)!=0xf0)           //确实有键按下

{

if(S1==0)        //如果是S1键按下

second++;   //秒加1

if(S2==0)        //如果是S2键按下

minute++;     //分钟加1

if(S3==0)      //如果是S3键按下

hour++;       //小时加1

if(S4==0)      //如果是S4键按下

{

second=0;   //秒清0

minute=0;   //分钟清0

hour=0;      //小时清0

}

}

}

777/192


}

/******************************************************************

函数功能:主函数

********************************************************************/

voidmain(void)

{

TMOD=0x01;                //使用定时器T0

EA=1;                      //开中断总允许

ET0=1;                     //允许T0中断

TH0=(65536-46083)/256;   //定时器高八位赋初值

TL0=(65536-46083)%256;   //定时器低八位赋初值

TR0=1;                     //启动定时器T0

int_time=0;     //中断计数变量初始化

second=0;       //秒计数变量初始化

minute=0;      //分钟计数变量初始化

hour=0;         //小时计数变量初始化

while(1)

{

DisplaySecond(second);     //调用秒显示子程序

DisplayMinute(minute);    //调用分钟显示子程序

DisplayHour(hour);         //调用小时显示子程序

}

}

/******************************************************************

函数功能:定时器T0的中断服务子程序

********************************************************************/

voidinterserve(void)interrupt1using1   //usingTime0

{

TR0=0;                     //关闭定时器T0

int_time++;             //中断次数加1

if(int_time==20)     //如果中断次数满20

{

int_time=0;     //中断计数变量清0

second++;       //秒计数变量加1

}

if(second==60)        //如果秒计满60

{

second=0;     //如果秒计满60,将秒计数变量清0

778/192


}


minute++;


//分钟计数变量加1


if(minute==60)

{

minute=0;

hour++;

}

if(hour==24)

{

hour=0;

}

key_scan();


//如果分钟计满60

//如果分钟计满60,将分钟计数变量清0

//小时计数变量加1

//如果小时计满24

//如果小时计满24,将小时计数变量清0

//执行键盘扫描


}


TH0=(65536-46083)/256;

TL0=(65536-46083)%256;

TR0=1;


//定时器T0高四位赋值

//定时器T0低四位赋值

//启动定时器T0


 


//


76


//实例76:独立式键盘控制步进电机实验

#include<reg51.h>         //包含51单片机寄存器定义的头文件

sbitS1=P1^4;             //S1位定义为P1.4引脚

sbitS2=P1^5;             //S2位定义为P1.5引脚

sbitS3=P1^6;             //S3位定义为P1.6引脚

unsignedcharkeyval;    //储存按键值

unsignedcharID;         //储存功能标号

/*************************************************

函数功能:软件消抖延时(约50ms

**************************************************/

voiddelay(void)

{

unsignedchari,j;

for(i=0;i<150;i++)

for(j=0;j<100;j++)

;

}

/************************************************

函数功能:步进电机转动延时,延时越长,转速越慢

*************************************************/

voidmotor_delay(void)

{

779/192


}


unsignedinti;

for(i=0;i<2000;i++)

;


/************************************************

函数功能:步进电机正转

*************************************************/

voidforward()

{

P0=0xfc;             //P0口低四位脉冲1100

motor_delay();

P0=0xf6;             //P0口低四位脉冲0110

motor_delay();

P0=0xf3;             //P0口低四位脉冲0011

motor_delay();

P0=0xf9;            //P0口低四位脉冲1001

motor_delay();

}

/************************************************

函数功能:步进电机反转

*************************************************/

voidbackward()

{

P0=0xfc;               //P0口低四位脉冲1100

motor_delay();

P0=0xf9;             //P0口低四位脉冲1001

motor_delay();

P0=0xf3;             //P0口低四位脉冲0011

motor_delay();

P0=0xf6;             //P0口低四位脉冲0110

motor_delay();

}

/************************************************

函数功能:步进电机停转

*************************************************/

voidstop(void)

{

P0=0xff;            //停止输出脉冲

}

/*************************************************

函数功能:主函数

**************************************************/

voidmain(void)

{

880/192


TMOD=0x01;

EA=1;

ET0=1;

TR0=1;

TH0=(65536-500)/256;

送一次中断请求

TL0=(65536-500)%256;

keyval=0;

ID=0;

while(1)

{

switch(keyval)

{


//使用定时器T0的模式1

//开总中断

//定时器T0中断允许

//启动定时器T0

//定时器T0赋初值,每计数200次(217微秒)发

//定时器T0赋初值

//按键值初始化为0,什么也不做

//根据按键值keyval选择待执行的功能


}


}


}


case1:forward();

break;

case2:backward();

break;

case3:stop();

break;


//按键S1按下,正转

//按键S2按下,反转

//按键S3按下,停转


/*************************************************

函数功能:定时器T0的中断服务子程序

**************************************************/

voidTime0_serve(void)interrupt1using1

{

TR0=0;                            //关闭定时器T0

if((P1&0xf0)!=0xf0)            //第一次检测到有键按下

{

delay();                 //延时一段时间再去检测

if((P1&0xf0)!=0xf0)    //确实有键按下

{

if(S1==0)          //按键S1被按下

keyval=1;

if(S2==0)          //按键S2被按下

keyval=2;

if(S3==0)          //按键S3被按下

keyval=3;

}

}

TH0=(65536-200)/256;           //定时器T0的高8位赋初值

TL0=(65536-200)%256;           //定时器T0的低8位赋初值

TR0=1;                            //启动定时器T0

881/192


}


 

//实例77:矩阵式键盘按键值的数码管显示实验

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitP14=P1^4;       //P14位定义为P1.4引脚

sbitP15=P1^5;       //P15位定义为P1.5引脚

sbitP16=P1^6;       //P16位定义为P1.6引脚

sbitP17=P1^7;       //P17位定义为P1.7引脚

unsignedcharcodeTab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

//数字0~9的段码

unsignedcharkeyval;     //定义变量储存按键值

/**************************************************************

函数功能:数码管动态扫描延时

**************************************************************/

voidled_delay(void)

{

unsignedcharj;

for(j=0;j<200;j++)

;

}

/**************************************************************

函数功能:按键值的数码管显示子程序

**************************************************************/

voiddisplay(unsignedchark)

{

P2=0xbf;               //点亮数码管DS6

P0=Tab[k/10];         //显示十位

led_delay();          //动态扫描延时

P2=0x7f;               //点亮数码管DS7

P0=Tab[k%10];         //显示个位

led_delay();         //动态扫描延时

}

/**************************************************************

函数功能:软件延时子程序

**************************************************************/

voiddelay20ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<60;j++)

882/192


}


;


/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET0=1;                    //定时器T0中断允许

TMOD=0x01;               //使用定时器T0的模式1

TH0=(65536-500)/256;   //定时器T0的高8位赋初值

TL0=(65536-500)%256;   //定时器T0的高8位赋初值

TR0=1;                   //启动定时器T0

keyval=0x00;            //按键值初始化为0

while(1)                   //无限循环

{

display(keyval);    //调用按键值的数码管显示子程序

}

}

/**************************************************************

函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位

**************************************************************/

voidtime0_interserve(void)interrupt1using1     //定时器T0的中断编号为1

使用第一组寄存器

{

TR0=0;                      //关闭定时器T0

P1=0xf0;                     //所有行线置为低电平“0”,所有列线置为高

电平“1

if((P1&0xf0)!=0xf0)        //列线中有一位为低电平“0”,说明有键按下

delay20ms();              //延时一段时间、软件消抖

if((P1&0xf0)!=0xf0)        //确实有键按下

{

P1=0xfe;                //第一行置为低电平“0”(P1.0输出低电平

0”)

if(P14==0)              //如果检测到接P1.4引脚的列线为低电平“0

keyval=1;               //可判断是S1键被按下

if(P15==0)                //如果检测到接P1.5引脚的列线为低电平

0

keyval=2;               //可判断是S2键被按下

if(P16==0)                //如果检测到接P1.6引脚的列线为低电平

0

keyval=3;               //可判断是S3键被按下

883/192


0

0”)

0

0

0

0”)

0”)


if(P17==0)

keyval=4;

P1=0xfd;

if(P14==0)

keyval=5;

if(P15==0)

keyval=6;

if(P16==0)

keyval=7;

if(P17==0)

keyval=8;

P1=0xfb;

if(P14==0)

keyval=9;

if(P15==0)

keyval=10;

if(P16==0)

keyval=11;

if(P17==0)

keyval=12;

P1=0xf7;

if(P14==0)

keyval=13;

if(P15==0)

keyval=14;

if(P16==0)

keyval=15;

if(P17==0)

keyval=16;


//如果检测到接P1.7引脚的列线为低电平

//可判断是S4键被按下

//第二行置为低电平“0”(P1.1输出低电平

//如果检测到接P1.4引脚的列线为低电平“0

//可判断是S5键被按下

//如果检测到接P1.5引脚的列线为低电平

//可判断是S6键被按下

//如果检测到接P1.6引脚的列线为低电平

//可判断是S7键被按下

//如果检测到接P1.7引脚的列线为低电平

//可判断是S8键被按下

//第三行置为低电平“0”(P1.2输出低电平

//如果检测到接P1.4引脚的列线为低电平“0

//可判断是S9键被按下

//如果检测到接P1.5引脚的列线为低电平“0

//可判断是S10键被按下

//如果检测到接P1.6引脚的列线为低电平“0

//可判断是S11键被按下

//如果检测到接P1.7引脚的列线为低电平“0

//可判断是S12键被按下

//第四行置为低电平“0”(P1.3输出低电平

//如果检测到接P1.4引脚的列线为低电平“0

//可判断是S13键被按下

//如果检测到接P1.5引脚的列线为低电平“0

//可判断是S14键被按下

//如果检测到接P1.6引脚的列线为低电平“0

//可判断是S15键被按下

//如果检测到接P1.7引脚的列线为低电平“0

//可判断是S16键被按下


 


}


}

TR0=1;

TH0=(65536-500)/256;

TL0=(65536-500)%256;


//开启定时器T0

//定时器T0的高8位赋初值

//定时器T0的高8位赋初值

884/192


 


#include<reg51.h>

sbitsound=P3^7;


//实例78:矩阵式键盘按键音

//包含51单片机寄存器定义的头文件

//sound位定义为P3.7


 

/**************************************************************

函数功能:蜂鸣器发声延时约120ms

**************************************************************/

voiddelay_sound(void)

{

unsignedchari;

for(i=0;i<250;i++)

;

}

/**************************************************************

函数功能:软件延时子程序约20ms

**************************************************************/

voiddelay20ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<60;j++)

;

}

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

EA=1;                      //开总中断

ET0=1;                     //定时器T0中断允许

TMOD=0x01;                //使用定时器T0的模式1

TH0=(65536-500)/256;    //定时器T0的高8位赋初值

TL0=(65536-500)%256;    //定时器T0的高8位赋初值

TR0=1;                     //启动定时器T0

while(1)                  //无限循环,等待键盘按下

;

}

/**************************************************************

885/192


函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位

**************************************************************/

voidtime0_interserve(void)interrupt1using1     //定时器T0的中断编号为1

使用第一组寄存器

{

unsignedchari;

TR0=0;                       //关闭定时器T0

P1=0xf0;                     //所有行线置为低电平“0”,所有列线置为高

电平“1

if((P1&0xf0)!=0xf0)        //列线中有一位为低电平“0”,说明有键按下

delay20ms();              //延时一段时间、软件消抖

if((P1&0xf0)!=0xf0)        //确实有键按下

{

for(i=0;i<200;i++)   //P3.7引脚电平不断取反输出音频

{

sound=0;

delay_sound();

sound=1;

delay_sound();

}

}

TR0=1;                        //开启定时器T0

TH0=(65536-500)/256;        //定时器T0的高8位赋初值

TL0=(65536-500)%256;       //定时器T0的高8位赋初值

}


 


//


79


#include<reg51.h>

sbitP14=P1^4;

sbitP15=P1^5;

sbitP16=P1^6;

sbitP17=P1^7;

unsignedcharkeyval;

sbitsound=P3^7;


//实例79:简易电子琴

//包含51单片机寄存器定义的头文件

//P14位定义为P1.4引脚

//P15位定义为P1.5引脚

//P16位定义为P1.6引脚

//P17位定义为P1.7引脚

//定义变量储存按键值

//sound位定义为P3.7


unsignedintC;

unsignedintf;


//全局变量,储存定时器的定时常数

//全局变量,储存音阶的频率


 

//以下是C调低音的音频宏定义

#definel_dao262    //将“l_dao”宏定义为低音“1”的频率262Hz

886/192


#definel_re286

#definel_mi311

#definel_fa349

#definel_sao392

#definel_la440

#definel_xi494


//将“l_re”宏定义为低音“2”的频率286Hz

//将“l_mi”宏定义为低音“3”的频率311Hz

//将“l_fa”宏定义为低音“4”的频率349Hz

//将“l_sao”宏定义为低音“5”的频率392Hz

//将“l_a”宏定义为低音“6”的频率440Hz

//将“l_xi”宏定义为低音“7”的频率494Hz


 

//以下是C调中音的音频宏定义

#definedao523      //将“dao”宏定义为中音“1”的频率523Hz

#definere587       //将“re”宏定义为中音“2”的频率587Hz

#definemi659       //将“mi”宏定义为中音“3”的频率659Hz

#definefa698       //将“fa”宏定义为中音“4”的频率698Hz

#definesao784      //将“sao”宏定义为中音“5”的频率784Hz

#definela880       //将“la”宏定义为中音“6”的频率880Hz

#definexi987       //将“xi”宏定义为中音“7”的频率53

//以下是C调高音的音频宏定义

#defineh_dao1046      //将“h_dao”宏定义为高音“1”的频率1046Hz

#defineh_re1174       //将“h_re”宏定义为高音“2”的频率1174Hz

#defineh_mi1318       //将“h_mi”宏定义为高音“3”的频率1318Hz

#defineh_fa1396      //将“h_fa”宏定义为高音“4”的频率1396Hz

#defineh_sao1567     //将“h_sao”宏定义为高音“5”的频率1567Hz

#defineh_la1760      //将“h_la”宏定义为高音“6”的频率1760Hz

#defineh_xi1975      //将“h_xi”宏定义为高音“7”的频率1975Hz

/**************************************************************

函数功能:软件延时子程序

**************************************************************/

voiddelay20ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<60;j++)

;

}


 

/*******************************************

函数功能:节拍的延时的基本单位,延时200ms

******************************************/

voiddelay()

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

887/192


}


;


/*******************************************

函数功能:输出音频

入口参数:F

******************************************/

voidOutput_Sound(void)

{

C=(46083/f)*10;       //计算定时常数

TH0=(8192-C)/32;      //可证明这是13位计数器TH08位的赋初值方法

TL0=(8192-C)%32;      //可证明这是13位计数器TL05位的赋初值方法

TR0=1;                  //开定时T0

delay();                //延时200ms,播放音频

TR0=0;                  //关闭定时器

sound=1;          //关闭蜂鸣器

keyval=0xff;        //播放按键音频后,将按键值更改,停止播放

}

/*******************************************

函数功能:主函数

******************************************/

voidmain(void)

{

EA=1;           //开总中断

ET0=1;           //定时器T0中断允许

ET1=1;          //定时器T1中断允许

TR1=1;          //定时器T1启动,开始键盘扫描

TMOD=0x10;     //分别使用定时器T1的模式1T0的模式0

TH1=(65536-500)/256;   //定时器T1的高8位赋初值

TL1=(65536-500)%256;   //定时器T1的高8位赋初值


 


while(1)

{

switch(keyval)

{


//无限循环


中音1的频率赋给f

低音7的频率赋给f


case1:f=dao;

Output_Sound();

break;

case2:f=l_xi;

Output_Sound();

break;


//如果第1个键按下,将

//转去计算定时常数

//如果第2个键按下,将

//转去计算定时常数


 


888


/


192


6的频率赋给f

低音5的频率赋给f


case3:f=l_la;

Output_Sound();

break;

case4:f=l_sao;


//如果第3个键按下,将低音

//转去计算定时常数

//如果第4个键按下,将


 


将中音5的频率赋给f

将中音4的频率赋给f


Output_Sound();

break;

case5:f=sao;

Output_Sound();

break;

case6:f=fa;

Output_Sound();

break;


//转去计算定时常数

//如果第5个键按下,

//转去计算定时常数

//如果第6个键按下,

//转去计算定时常数


3的频率赋给f

中音2的频率赋给f

高音2的频率赋给f


case7:f=mi;

Output_Sound();

break;

case8:f=re;

Output_Sound();

break;

case9:f=h_re;

Output_Sound();

break;

case10:f=h_dao;


//如果第7个键按下,将中

//转去计算定时常数

//如果第8个键按下,将

//转去计算定时常数

//如果第9个键按下,将

//转去计算定时常数

//如果第10个键按


 


下,将高音1的频率赋给f


Output_Sound();

break;


//转去计算定时常数


7的频率赋给f

中音6的频率赋给f

将高音6的频率赋给f


case11:f=xi;

Output_Sound();

break;

case12:f=la;

Output_Sound();

break;

case13:f=h_la;

Output_Sound();

break;

889/192


//如果第11个键按下,将中

//转去计算定时常数

//如果第12个键按下,将

//转去计算定时常数

//如果第13个键按下,

//转去计算定时常数


将高音5的频率赋给f

4的频率赋给f

将高音3的频率赋给f

}

}

}


case14:f=h_sao;

Output_Sound();

break;

case15:f=h_fa;

Output_Sound();

break;

case16:f=h_mi;

Output_Sound();

break;


//如果第14个键按下

//转去计算定时常数

//如果第15个键按下,将高

//转去计算定时常数

//如果第16个键按下

//转去计算定时常数


 

/**************************************************************

函数功能:定时器T0的中断服务子程序,使P3.7引脚输出音频方波

**************************************************************/

voidTime0_serve(void)interrupt1using1

{

TH0=(8192-C)/32;      //可证明这是13位计数器TH08位的赋初值

方法

TL0=(8192-C)%32;      //可证明这是13位计数器TL05位的赋初值方

sound=!sound;          //P3.7引脚取反,输出音频方波

}

/**************************************************************

函数功能:定时器T1的中断服务子程序,进行键盘扫描,判断键位

**************************************************************/

voidtime1_serve(void)interrupt3using2     //定时器T1的中断编号为3,使用

2组寄存器

{

TR1=0;                      //关闭定时器T0

P1=0xf0;                     //所有行线置为低电平“0”,所有列线置为高

电平“1

if((P1&0xf0)!=0xf0)        //列线中有一位为低电平“0”,说明有键按下

{

delay20ms();              //延时一段时间、软件消抖

if((P1&0xf0)!=0xf0)        //确实有键按下

{


 


990


/


192


输出低电平“0”)

为低电平“0

线为低电平“0

线为低电平“0

线为低电平“0

输出低电平“0”)

低电平“0

线为低电平“0

线为低电平“0

线为低电平“0

输出低电平“0”)

电平“0

为低电平“0

为低电平“0

为低电平“0


P1=0xfe;

if(P14==0)

keyval=1;

if(P15==0)

keyval=2;

if(P16==0)

keyval=3;

if(P17==0)

keyval=4;

P1=0xfd;

if(P14==0)

keyval=5;

if(P15==0)

keyval=6;

if(P16==0)

keyval=7;

if(P17==0)

keyval=8;

P1=0xfb;

if(P14==0)

keyval=9;

if(P15==0)

keyval=10;

if(P16==0)

keyval=11;

if(P17==0)

keyval=12;


991


/


//第一行置为低电平“0”(P1.0

//如果检测到接P1.4引脚的列线

//可判断是S1键被按下

//如果检测到接P1.5引脚的列

//可判断是S2键被按下

//如果检测到接P1.6引脚的列

//可判断是S3键被按下

//如果检测到接P1.7引脚的列

//可判断是S4键被按下

//第二行置为低电平“0”(P1.1

//如果检测到接P1.4引脚的列线为

//可判断是S5键被按下

//如果检测到接P1.5引脚的列

//可判断是S6键被按下

//如果检测到接P1.6引脚的列

//可判断是S7键被按下

//如果检测到接P1.7引脚的列

//可判断是S8键被按下

//第三行置为低电平“0”(P1.2

//如果检测到接P1.4引脚的列线为低

//可判断是S9键被按下

//如果检测到接P1.5引脚的列线

//可判断是S10键被按下

//如果检测到接P1.6引脚的列线

//可判断是S11键被按下

//如果检测到接P1.7引脚的列线

//可判断是S12键被按下

192


 


输出低电平“0”)

电平“0

为低电平“0

为低电平“0

为低电平“0

}

}


P1=0xf7;

if(P14==0)

keyval=13;

if(P15==0)

keyval=14;

if(P16==0)

keyval=15;

if(P17==0)

keyval=16;


//第四行置为低电平“0”(P1.3

//如果检测到接P1.4引脚的列线为低

//可判断是S13键被按下

//如果检测到接P1.5引脚的列线

//可判断是S14键被按下

//如果检测到接P1.6引脚的列线

//可判断是S15键被按下

//如果检测到接P1.7引脚的列线

//可判断是S16键被按下


}


TR1=1;

TH1=(65536-500)/256;

TL1=(65536-500)%256;


//开启定时器T1

//定时器T1的高8位赋初值

//定时器T1的高8位赋初值


 


//


80


//实例80:矩阵式键盘实现的电子密码锁

#include<reg51.h>    //包含51单片机寄存器定义的头文件

sbitP14=P1^4;       //P14位定义为P1.4引脚

sbitP15=P1^5;       //P15位定义为P1.5引脚

sbitP16=P1^6;       //P16位定义为P1.6引脚

sbitP17=P1^7;       //P17位定义为P1.7引脚

sbitsound=P3^7;     //sound位定义为P3.7

unsignedcharkeyval;     //储存按键值

/**************************************************************

函数功能:延时输出音频

**************************************************************/

voiddelay(void)

{

unsignedchari;

for(i=0;i<200;i++)

;

}

992/192


 

/**************************************************************

函数功能:软件延时子程序

**************************************************************/

voiddelay20ms(void)

{

unsignedchari,j;

for(i=0;i<100;i++)

for(j=0;j<60;j++)

;

}

/**************************************************************

函数功能:主函数

**************************************************************/

voidmain(void)

{

unsignedcharD[]={0,8,0,8,7,4,11};       //设定密码

EA=1;                      //开总中断

ET0=1;                     //定时器T0中断允许

TMOD=0x01;               //使用定时器T0的模式1

TH0=(65536-500)/256;   //定时器T0的高8位赋初值

TL0=(65536-500)%256;   //定时器T0的高8位赋初值

TR0=1;                   //启动定时器T0

keyval=0xff;            //按键值初始化

while(keyval!=D[0])    //第一位密码输入不正确,等待

;

while(keyval!=D[1])    //第二位密码输入不正确,等待

;

while(keyval!=D[2])    //第三位密码输入不正确,等待

;

while(keyval!=D[3])    //第四位密码输入不正确,等待

;

while(keyval!=D[4])    //第五位密码输入不正确,等待

;

while(keyval!=D[5])    //第六位密码输入不正确,等待

;

while(keyval!=D[6])   //没有输入“OK”,等待

;

P3=0xfe;             //P3.0引脚输出低电平,点亮LED

}

/**************************************************************

函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位

993/192


**************************************************************/

voidtime0_interserve(void)interrupt1using1     //定时器T0的中断编号为1

使用第一组寄存器

{

unsignedchari;

TR0=0;                      //关闭定时器T0

P1=0xf0;                     //所有行线置为低电平“0”,所有列线置为高

电平“1

if((P1&0xf0)!=0xf0)        //列线中有一位为低电平“0”,说明有键按下

delay20ms();              //延时一段时间、软件消抖

if((P1&0xf0)!=0xf0)        //确实有键按下

{

P1=0xfe;                //第一行置为低电平“0”(P1.0输出低电平

0”)

if(P14==0)              //如果检测到接P1.4引脚的列线为低电平“0

keyval=1;               //可判断是S1键被按下

if(P15==0)                //如果检测到接P1.5引脚的列线为低电平

0

keyval=2;               //可判断是S2键被按下

if(P16==0)                //如果检测到接P1.6引脚的列线为低电平

0

keyval=3;               //可判断是S3键被按下

if(P17==0)               //如果检测到接P1.7引脚的列线为低电平

0

keyval=4;             //可判断是S4键被按下

P1=0xfd;                //第二行置为低电平“0”(P1.1输出低电平

0”)

if(P14==0)              //如果检测到接P1.4引脚的列线为低电平“0

keyval=5;               //可判断是S5键被按下

if(P15==0)                //如果检测到接P1.5引脚的列线为低电平

0

keyval=6;               //可判断是S6键被按下

if(P16==0)                //如果检测到接P1.6引脚的列线为低电平

0

keyval=7;               //可判断是S7键被按下

if(P17==0)               //如果检测到接P1.7引脚的列线为低电平

0

keyval=8;             //可判断是S8键被按下

P1=0xfb;                //第三行置为低电平“0”(P1.2输出低电平

0”)

if(P14==0)            //如果检测到接P1.4引脚的列线为低电平“0

keyval=9;            //可判断是S9键被按下

994/192


if(P15==0)

keyval=0;

if(P16==0)

keyval=11;

if(P17==0)


//如果检测到接P1.5引脚的列线为低电平“0

//可判断是S10键被按下

//如果检测到接P1.6引脚的列线为低电平“0

//可判断是S11键被按下

//如果检测到接P1.7引脚的列线为低电平“0

keyval=12;          //可判断是S12键被按下


 


输出低电平“0”)

电平“0

为低电平“0

为低电平“0

为低电平“0


P1=0xf7;

if(P14==0)

keyval=13;

if(P15==0)

keyval=14;

if(P16==0)

keyval=15;

if(P17==0)

keyval=16;


//第四行置为低电平“0”(P1.3

//如果检测到接P1.4引脚的列线为低

//可判断是S13键被按下

//如果检测到接P1.5引脚的列线

//可判断是S14键被按下

//如果检测到接P1.6引脚的列线

//可判断是S15键被按下

//如果检测到接P1.7引脚的列线

//可判断是S16键被按下


 


}


for(i=0;i<200;i++)

{

sound=0;

delay();

sound=1;

delay();

}


//P3.7引脚电平不断取反输出音频


}


TR0=1;

TH0=(65536-500)/256;

TL0=(65536-500)%256;


//开启定时器T0

//定时器T0的高8位赋初值

//定时器T0的高8位赋初值


 

/********************************************************

******************液晶显LCD*********液晶显示LCDLCD*********              LCD

*****液晶显示LCD********************液晶显示LCD********************

LCD*********液晶显示LCD*****液晶显示LCD**********

995/192


*********************************************************

**/


 


#include<reg51.h>

#include<intrins.h>


//实例81:用LCD显示字符''A'

//包含单片机寄存器的头文件

//包含_nop_()函数定义的头文件


sbitRS=P2^0;

sbitRW=P2^1;

sbitE=P2^2;

sbitBF=P0^7;


//寄存器选择位,将RS位定义为P2.0引脚

//读写选择位,将RW位定义为P2.1引脚

//使能信号位,将E位定义为P2.2引脚

//忙碌标志位,,将BF位定义为P0.7引脚


 

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelay(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

996/192


RW=1;

E=1;

_nop_();

_nop_();

_nop_();

_nop_();

result=BF;

E=0;


//E=1,才允许读写

//空操作

//空操作四个机器周期,给硬件反应时间

//将忙碌标志电平赋给result


 


}


returnresult;


 

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);//如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置

"0"

_nop_();

_nop_();                //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=0;                      //E由高电平跳变成低电平时,液晶模块开始

执行命令

}

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

997/192


}


WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"


/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;            //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

E=0;               //E由高电平跳变成低电平时,液晶模块开始执行命令

}

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delay(15);                //延时15ms,首次写指令时应给LCD一段较长的反

应时间

WriteInstruction(0x38);   //显示模式设置:16×2显示,5×7点阵,8位数据

接口

delay(5);   //延时5ms

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x0f);   //显示模式设置:显示开,有光标,光标闪烁

delay(5);

WriteInstruction(0x06);   //显示模式设置:光标右移,字符不移

delay(5);

WriteInstruction(0x01);   //清屏幕指令,将以前的显示内容清除

998/192


}


delay(5);


voidmain(void)

{

LcdInitiate();

WriteAddress(0x07);

WriteData('A');

}


//主函数

//调用LCD初始化函数

//将显示地址指定为第1行第8

//将字符常量'A'写入液晶模块

//字符的字形点阵读出和显示由液晶模块自动完成


 

//实例82:用LCD循环右移显示"WelcometoChiina"

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitRS=P2^0;     //寄存器选择位,将RS位定义为P2.0引脚

sbitRW=P2^1;     //读写选择位,将RW位定义为P2.1引脚

sbitE=P2^2;      //使能信号位,将E位定义为P2.2引脚

sbitBF=P0^7;     //忙碌标志位,,将BF位定义为P0.7引脚

unsignedcharcodestring[]={"WelcometoChina"};

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelay(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

999/192


/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;

returnresult;

}

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);//如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置

"0"

_nop_();

_nop_();                //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间


 


100


/


192


E=0;

执行命令

}


//E由高电平跳变成低电平时,液晶模块开始


 

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;            //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

E=0;               //E由高电平跳变成低电平时,液晶模块开始执行命令

}

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delay(15);                //延时15ms,首次写指令时应给LCD一段较长的反

应时间

WriteInstruction(0x38);   //显示模式设置:16×2显示,5×7点阵,8位数据

接口

delay(5);   //延时5ms

101/192


}


WriteInstruction(0x38);

delay(5);

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x0f);

delay(5);

WriteInstruction(0x06);

delay(5);

WriteInstruction(0x01);

delay(5);


//显示模式设置:显示开,有光标,光标闪烁

//显示模式设置:光标右移,字符不移

//清屏幕指令,将以前的显示内容清除


voidmain(void)

{

unsignedchari;

LcdInitiate();

delay(10);

while(1)

{


//主函数

//调用LCD初始化函数


WriteInstruction(0x01);//清显示:清屏幕指令

WriteAddress(0x00);   //设置显示位置为第一行的第5个字

i=0;

while(string[i]!='\0')

{                         //  显示字符

WriteData(string[i]);

i++;

delay(150);

}

for(i=0;i<4;i++)

delay(250);

}


 

}


 


//


83


LCD


//实例83:用LCD显示适时检测结果

#include<reg51.h>     //包含单片机寄存器的头文件

#include<stdlib.h>    //包含随机函数rand()的定义文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitRS=P2^0;     //寄存器选择位,将RS位定义为P2.0引脚

102/192


sbitRW=P2^1;

sbitE=P2^2;

sbitBF=P0^7;


//读写选择位,将RW位定义为P2.1引脚

//使能信号位,将E位定义为P2.2引脚

//忙碌标志位,,将BF位定义为P0.7引脚


unsignedcharcodedigit[]={"0123456789"};//定义字符数组显示数字

unsignedcharcodestring[]={"TestResult"};//定义字符数组显示提示信息

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelay(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;           //E恢复低电平

returnresult;

}

103/192


/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);//如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置

"0"

_nop_();

_nop_();                //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=0;                      //E由高电平跳变成低电平时,液晶模块开始

执行命令

}

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

104/192


}


RW=0;

E=0;

P0=y;

_nop_();

_nop_();

_nop_();

_nop_();

E=1;

_nop_();

_nop_();

_nop_();

_nop_();

E=0;


//E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

//将数据送入P0口,即将数据写入液晶模块

//空操作四个机器周期,给硬件反应时间

//E置高电平

//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始执行命令


 

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delay(15);                //延时15ms,首次写指令时应给LCD一段较长的反

应时间

WriteInstruction(0x38);   //显示模式设置:16×2显示,5×7点阵,8位数据

接口

delay(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x38);//连续三次,确保初始化成功

delay(5);

WriteInstruction(0x0c);   //显示模式设置:显示开,无光标,光标不闪烁

delay(5);

WriteInstruction(0x06);   //显示模式设置:光标右移,字符不移

delay(5);

WriteInstruction(0x01);   //清屏幕指令,将以前的显示内容清除

delay(5);

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;    //定义变量i指向字符串数组元素

unsignedintx;     //定义变量,储存检测结果


 


105


/


192


unsignedcharD1,D2,D3,D4,D5;

万位数字


//分别储存采集的个位、十位、百位、千位和


LcdInitiate();

delay(10);

WriteAddress(0x02);

i=0;

while(string[i]!='\0')

{


//调用LCD初始化函数

//延时10ms,给硬件一点反应时间

//从第1行第3列开始显示

//指向字符数组的第1个元素


 


}

while(1)

{


WriteData(string[i]);

i++;                //指向下字符数组一个元素

//无限循环


}


}


x=rand();

D1=x%10;

D2=(x%100)/10;

D3=(x%1000)/100;

D4=(x%10000)/1000;

D5=x/10000;

WriteAddress(0x45);

WriteData(digit[D5]);

WriteData(digit[D4]);

WriteData(digit[D3]);

WriteData(digit[D2]);

WriteData('.');

WriteData(digit[D1]);

for(i=0;i<4;i++)

delay(250);


//模拟数据采集

//计算个位数字

//计算十位数字

//计算百位数字

//计算千位数字

//计算万位数字

//从第2行第6列开始显示

//将万位数字的字符常量写入LCD

//将千位数字的字符常量写入LCD

//将百位数字的字符常量写入LCD

//将十位数字的字符常量写入LCD

//将小数点的字符常量写入LCD

//将个位数字的字符常量写入LCD

//延时1s(每1s采集一次数据)

//延时250ms


 


#include<reg51.h>

#include<stdlib.h>

#include<intrins.h>


//实例84:液晶时钟设计

//包含单片机寄存器的头文件

//包含随机函数rand()的定义文件

//包含_nop_()函数定义的头文件


sbitRS=P2^0;

sbitRW=P2^1;

sbitE=P2^2;

sbitBF=P0^7;


//寄存器选择位,将RS位定义为P2.0引脚

//读写选择位,将RW位定义为P2.1引脚

//使能信号位,将E位定义为P2.2引脚

//忙碌标志位,,将BF位定义为P0.7引脚


unsignedcharcodedigit[]={"0123456789"};//定义字符数组显示数字

106/192


unsignedcharcodestring[]={"BeiJingTime"};//定义字符数组显示提示信息

unsignedcharcount;    //定义变量统计中断累计次数

unsignedchars,m,h;    //定义变量储存秒、分钟和小时

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelay(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;           //E恢复低电平

returnresult;

}

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

107/192


入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);//如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

_nop_();

_nop_();                //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=0;                      //E由高电平跳变成低电平时,液晶模块开始

执行命令

}

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

108/192


}


P0=y;

_nop_();

_nop_();

_nop_();

_nop_();

E=1;

_nop_();

_nop_();

_nop_();

_nop_();

E=0;


//将数据送入P0口,即将数据写入液晶模块

//空操作四个机器周期,给硬件反应时间

//E置高电平

//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始执行命令


/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delay(15);                //延时15ms,首次写指令时应给LCD一段较长的反

应时间

WriteInstruction(0x38);   //显示模式设置:16×2显示,5×7点阵,8位数据

接口

delay(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x38);//连续三次,确保初始化成功

delay(5);

WriteInstruction(0x0c);   //显示模式设置:显示开,无光标,光标不闪烁

delay(5);

WriteInstruction(0x06);   //显示模式设置:光标右移,字符不移

delay(5);

WriteInstruction(0x01);   //清屏幕指令,将以前的显示内容清除

delay(5);

}

/********************************************************************

**********

函数功能:显示小时

*********************************************************************

*********/

voidDisplayHour()

{

unsignedchari,j;

i=h/10;                    //取整运算,求得十位数字

109/192


}


j=h%10;

WriteAddress(0x44);

WriteData(digit[i]);

WriteData(digit[j]);


//取余运算,求得各位数字

//写显示地址,将十位数字显示在第2行第5

//将十位数字的字符常量写入LCD

//将个位数字的字符常量写入LCD


/********************************************************************

**********

函数功能:显示分钟

*********************************************************************

*********/

voidDisplayMinute()

{

unsignedchari,j;

i=m/10;                   //取整运算,求得十位数字

j=m%10;                   //取余运算,求得各位数字

WriteAddress(0x47);    //写显示地址,将十位数字显示在第2行第8

WriteData(digit[i]);   //将十位数字的字符常量写入LCD

WriteData(digit[j]);   //将个位数字的字符常量写入LCD

}

/********************************************************************

**********

函数功能:显示秒

*********************************************************************

*********/

voidDisplaySecond()

{

unsignedchari,j;

i=s/10;                   //取整运算,求得十位数字

j=s%10;                   //取余运算,求得各位数字

WriteAddress(0x4a);    //写显示地址,将十位数字显示在第2行第11

WriteData(digit[i]);   //将十位数字的字符常量写入LCD

WriteData(digit[j]);   //将个位数字的字符常量写入LCD

}

/********************************************************************

*

mainfunction

*********************************************************************

**/

110/192


voidmain(void)

{

unsignedchari;

LcdInitiate();

TMOD=0x01;


//调用LCD初始化函数

//使用定时器T0的模式1


 


TH0=(65536-46083)/256;

TL0=(65536-46083)%256;

EA=1;

ET0=1;

TR0=1;

count=0;

s=0;

m=0;

h=0;


//定时器T0的高8位设置初值

//定时器T0的低8位设置初值

//开总中断

//定时器T0中断允许

//启动定时器T0

//中断次数初始化为0

//秒初始化为0

//分钟初始化为0

//小时初始化为0


 


WriteAddress(0x03);

i=0;

while(string[i]!='\0')

{


//写地址,从第1行第4列开始显示

//从字符数组的第1个元素开始显示

//只要没有显示到字符串的结束标志'\0',就继续


}


WriteData(string[i]);//将第i个字符数组元素写入LCD

i++;                     //指向下一个数组元素


WriteAddress(0x46);

WriteData(':');

WriteAddress(0x49);

WriteData(':');

while(1)

{

DisplayHour();

delay(5);


//写地址,将第二个分号显示在第2行第7

//将分号的字符常量写入LCD

//写地址,将第二个分号显示在第2行第10

//将分号的字符常量写入LCD

//无限循环

//显示小时

//给硬件一点反应时间


}


}


DisplayMinute();

delay(5);

DisplaySecond();

delay(5);


//显示分钟

//给硬件一点反应时间

//显示秒

//给硬件一点反应时间


 

/*******************************************************

函数功能:定时器T0的中断服务函数

********************************************************/

voidTime0(void)interrupt1using1//定时器T0的中断编号为1,使用第1组工

作寄存器

{

111/192


count++;


//每产生1次中断,中断累计次数加1


 


if(count==20)

{


//如果中断次数计满20


}


count=0;

s++;


//中断累计次数清0

//秒加1


if(s==60)

{

s=0;

m++;

}

if(m==60)

{

m=0;

h++;

}

if(h==24)

{

h=0;

}


//如果计满60

//秒清0

//分钟加1

//如果计满60

//分钟清0

//小时加1

//如果计满24小时

//小时清0


}


TH0=(65536-46083)/256;

TL0=(65536-46083)%256;


//定时器T08位重新赋初值

//定时器T08位重新赋初值


 

/********************************************************

***********一些芯片的使用*****24c02    DS18B20

X5045  ADC0832   DAC0832   DS1302   红外遥控

**********************************************/


 


//


85


"0x0ff"


AT24C02


P1


//实例85:将数据"0x0ff"写入AT24C02再读出送P1口显示

#include<reg51.h>          //   包含51单片机寄存器定义的头文件

#include<intrins.h>        //包含_nop_()函数定义的头文件

#defineOP_READ    0xa1        //  器件地址以及读取操作,0xa1即为10100001B

#defineOP_WRITE0xa0      //  器件地址以及写入操作,0xa1即为10100000B

sbitSDA=P3^4;            //将串行数据总线SDA位定义在为P3.4引脚

sbitSCL=P3^3;           //将串行时钟总线SDA位定义在为P3.3引脚

112/192


 

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

//  开始位

{

SDA=1;     //SDA初始化为高电平“1

SCL=1;     //开始数据传送时,要求SCL为高电平“1

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;     //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SCL=0;     //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

递)

}

/***************************************************

113/192


函数功能:结束数据传送

***************************************************/

voidstop()

//  停止位

{

SDA=0;      //SDA初始化为低电平“0  _n

SCL=1;      //结束数据传送时,要求SCL为高电平“1

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SDA=1;     //SDA的上升沿被认为是结束信号

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SDA=0;

SCL=0;

}

/***************************************************

函数功能:从AT24Cxx读取数据

出口参数:x

***************************************************/

unsignedcharReadData()

//  AT24Cxx移入数据到MCU

{

unsignedchari;

unsignedcharx;    //储存从AT24Cxx中读出的数据

for(i=0;i<8;i++)

{

SCL=1;                   //SCL置为高电平

x<<=1;                      //x中的各二进位向左移一位

x|=(unsignedchar)SDA;   //SDA上的数据通过按位“或“运算存入x

SCL=0;                             //SCL的下降沿读出数据

}

return(x);                   //将读取的数据返回

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

***************************************************/

//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

114/192


{


unsignedchari;

bitack_bit;

for(i=0;i<8;i++)

{

SDA=(bit)(y&0x80);


//


//储存应答位

循环移入8个位

//通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在


_nop_();

SCL=1;

_nop_();

_nop_();

SCL=0;

据所需的8个脉冲

y<<=1;

}

SDA=1;

释放SDA线,


//


//等待一个机器周期

//SCL的上升沿将数据写入AT24Cxx

//等待一个机器周期

//等待一个机器周期

//SCL重新置为低电平,以在SCL线形成传送数

//y中的各二进位向左移一位

发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)


 


_nop_();

_nop_();

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();


//以让SDA线转由接收设备(AT24Cxx)控制

//等待一个机器周期

//等待一个机器周期

//根据上述规定,SCL应为高电平

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期


ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个

字节

//若送高电平,表示没有接收到,传送异常

SCL=0;         //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据

传递)

return  ack_bit;         //  返回AT24Cxx应答位

}

/***************************************************

函数功能:向AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet(unsignedcharadd,unsignedchardat)

//  在指定地址addr处写入数据WriteCurrent

{

start();                  //开始数据传递

WriteCurrent(OP_WRITE);   //选择要操作的AT24Cxx芯片,并告知要对其写

入数据

115/192


}


WriteCurrent(add);

WriteCurrent(dat);

stop();

delaynms(4);


//写入指定地址

//向当前地址(上面指定的地址)写入数据

//停止数据传递

//1个字节的写入周期为1ms,最好延时1ms以上


 

/***************************************************

函数功能:从AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent()

{

unsignedcharx;

start();                  //开始数据传递

WriteCurrent(OP_READ);    //选择要操作的AT24Cxx芯片,并告知要读其数

x=ReadData();           //将读取的数据存入x

stop();                   //停止数据传递

returnx;                 //返回读取的数据

}

/***************************************************

函数功能:从AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

***************************************************/

unsignedcharReadSet(unsignedcharset_addr)

//  在指定地址读取

{

start();                           //开始数据传递

WriteCurrent(OP_WRITE);         //选择要操作的AT24Cxx芯片,并告知要对

其写入数据

WriteCurrent(set_addr);         //写入指定地址

return(ReadCurrent());          //从指定地址读出数据并返回

}

/***************************************************

函数功能:主函数

***************************************************/

main(void)

{

SDA=1;             //SDA=1,SCL=1,使主从设备处于空闲状态

SCL=1;

WriteSet(0x36,0x0f);    //在指定地址“0x36”中写入数据“0x0f

P1=ReadSet(0x36);       //从指定地址“0x36中读取数据并送P1口显示

}


 


116


/


192


 

//实例86:将按键次数写入AT24C02,再读出并用1602LCD

显示

#include<reg51.h>         //包含单片机寄存器的头文件

#include<intrins.h>      //包含_nop_()函数定义的头文件

sbitRS=P2^0;              //寄存器选择位,将RS位定义为P2.0引脚

sbitRW=P2^1;              //读写选择位,将RW位定义为P2.1引脚

sbitE=P2^2;               //使能信号位,将E位定义为P2.2引脚

sbitBF=P0^7;              //忙碌标志位,,将BF位定义为P0.7引脚

sbitS=P1^4;               //S位定义为P1.4引脚

#defineOP_READ    0xa1    //  器件地址以及读取操作,0xa1即为10100001B

#defineOP_WRITE0xa0  //  器件地址以及写入操作,0xa1即为10100000B

sbitSDA=P3^4;            //将串行数据总线SDA位定义在为P3.4引脚

sbitSCL=P3^3;            //将串行时钟总线SDA位定义在为P3.3引脚

unsignedcharcodedigit[]={"0123456789"};//定义字符数组显示数字

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/********************************************************************

***********

以下是对液晶模块的操作程序

117/192


*********************************************************************

***********/

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;           //E恢复低电平

returnresult;

}

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);    //如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置

"0"

_nop_();

_nop_();                  //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

118/192


_nop_();

E=0;

执行命令

}


//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始


/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;            //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

E=0;               //E由高电平跳变成低电平时,液晶模块开始执行命令

}

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delaynms(15);                  //延时15ms,首次写指令时应给LCD一段较

长的反应时间

WriteInstruction(0x38);      //显示模式设置:16×2显示,5×7点阵,8

数据接口

119/192


delaynms(5);

WriteInstruction(0x38);

delaynms(5);


//延时5ms


,给硬件一点反应时间


}


WriteInstruction(0x38);

delaynms(5);

WriteInstruction(0x0c);

delaynms(5);

WriteInstruction(0x06);

delaynms(5);

WriteInstruction(0x01);

delaynms(5);


//连续三次,确保初始化成功

//显示模式设置:显示开,无光标,光标不闪烁

//显示模式设置:光标右移,字符不移

//清屏幕指令,将以前的显示内容清除


 

/***************************************************

函数功能:显示小时

***************************************************/

voidDisplay(unsignedcharx)

{

unsignedchari,j;

i=x/10;                      //取整运算,求得十位数字

j=x%10;                      //取余运算,求得各位数字

WriteAddress(0x44);       //写显示地址,将十位数字显示在第2行第5

WriteData(digit[i]);      //将十位数字的字符常量写入LCD

WriteData(digit[j]);      //将个位数字的字符常量写入LCD

}

/********************************************************************

***********

以下是对AT24C02的读写操作程序

*********************************************************************

***********/

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

//  开始位

{

SDA=1;     //SDA初始化为高电平“1

SCL=1;     //开始数据传送时,要求SCL为高电平“1

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;     //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

120/192


_nop_();

_nop_();

SCL=0;

递)

}


//等待一个机器周期

//等待一个机器周期

//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传


 

/***************************************************

函数功能:结束数据传送

***************************************************/

voidstop()

//  停止位

{

SDA=0;      //SDA初始化为低电平“0

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SCL=1;      //结束数据传送时,要求SCL为高电平“1

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SDA=1;     //SDA的上升沿被认为是结束信号

}

/***************************************************

函数功能:从AT24Cxx读取数据

出口参数:x

***************************************************/

unsignedcharReadData()

//  AT24Cxx移入数据到MCU

{

unsignedchari;

unsignedcharx;    //储存从AT24Cxx中读出的数据

for(i=0;i<8;i++)

{

SCL=1;                   //SCL置为高电平

x<<=1;                      //x中的各二进位向左移一位

x|=(unsignedchar)SDA;   //SDA上的数据通过按位“或“运算存入x

SCL=0;                             //SCL的下降沿读出数据

}

return(x);                   //将读取的数据返回

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

***************************************************/

121/192


//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

{

unsignedchari;

bitack_bit;                  //储存应答位

for(i=0;i<8;i++)        //  循环移入8个位

{

SDA=(bit)(y&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在

_nop_();               //等待一个机器周期

SCL=1;               //SCL的上升沿将数据写入AT24Cxx

_nop_();               //等待一个机器周期

_nop_();                //等待一个机器周期

SCL=0;               //SCL重新置为低电平,以在SCL线形成传送数

据所需的8个脉冲

y<<=1;              //y中的各二进位向左移一位

}

SDA=1;           //  发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)

释放SDA线,

//以让SDA线转由接收设备(AT24Cxx)控制

_nop_();          //等待一个机器周期

_nop_();          //等待一个机器周期

SCL=1;         //根据上述规定,SCL应为高电平

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个

字节

//若送高电平,表示没有接收到,传送异常

SCL=0;         //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据

传递)

return  ack_bit;         //  返回AT24Cxx应答位

}

/***************************************************

函数功能:向AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet(unsignedcharadd,unsignedchardat)

//  在指定地址addr处写入数据WriteCurrent

{

start();                  //开始数据传递

122/192


WriteCurrent(OP_WRITE);

入数据

WriteCurrent(add);

WriteCurrent(dat);


//选择要操作的AT24Cxx芯片,并告知要对其写

//写入指定地址

//向当前地址(上面指定的地址)写入数据


 


}


stop();

delaynms(4);


//停止数据传递

//1个字节的写入周期为1ms,


最好延时1ms以上


/***************************************************

函数功能:从AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent()

{

unsignedcharx;

start();                  //开始数据传递

WriteCurrent(OP_READ);    //选择要操作的AT24Cxx芯片,并告知要读其数

x=ReadData();           //将读取的数据存入x

stop();                   //停止数据传递

returnx;                 //返回读取的数据

}

/***************************************************

函数功能:从AT24Cxx中的指定地址读取数据

入口参数:set_add

出口参数:x

***************************************************/

unsignedcharReadSet(unsignedcharset_add)

//  在指定地址读取

{

start();                           //开始数据传递

WriteCurrent(OP_WRITE);         //选择要操作的AT24Cxx芯片,并告知要对

其写入数据

WriteCurrent(set_add);         //写入指定地址

return(ReadCurrent());          //从指定地址读出数据并返回

}

/********************************************************************

*

函数功能:主函数

*********************************************************************

**/

voidmain(void)

{

unsignedcharsum;     //储存计数值

unsignedcharx;       //储存从AT24C02读出的值

123/192


LcdInitiate();

sum=0;

while(1)

{

if(S==0)

{


//调用LCD初始化函数

//将计数值初始化为0

//无限循环

//如果该键被按下


delaynms(80);

if(S==0)

sum++;

if(sum==99)

sum=0;

}


//软件消抖,延时80ms

//确实该键被按下

//计件值加1

//如果计满99

//0,重新开始计数


}


}


WriteSet(0x01,sum);//将计件值写入AT24C02中的指定地址"0x01"

x=ReadSet(0x01);     //AT24C02中读出计件值

Display(x);         //将计件值用1602LCD显示


 


//


87


I2C


AT24C02


//实例87:对I2C总线上挂接多个AT24C02的读写操作

#include<reg51.h>           //   包含51单片机寄存器定义的头文件

#include<intrins.h>         //包含_nop_()函数定义的头文件

#defineOP_READ1  0xa1        //  器件1地址以及读取操作,0xa1即为1010

0001B

#defineOP_WRITE10xa0     //  器件1地址以及写入操作,0xa1即为10100000B

#defineOP_READ2  0xaf     //  器件2地址以及读取操作,0xa1即为10101111B

#defineOP_WRITE20xae     //  器件2地址以及写入操作,0xa1即为10101110B

sbitSDA=P3^4;                //将串行数据总线SDA位定义在为P3.4引脚

sbitSCL=P3^3;                //将串行时钟总线SDA位定义在为P3.3引脚

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

124/192


函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

//  开始位

{

SDA=1;     //SDA初始化为高电平“1

SCL=1;     //开始数据传送时,要求SCL为高电平“1

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;     //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SCL=0;     //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

递)

_nop_();    //等待一个机器周期

}

/***************************************************

函数功能:结束数据传送

***************************************************/

voidstop()

//  停止位

{

SDA=0;      //SDA初始化为低电平“0

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SCL=1;      //结束数据传送时,要求SCL为高电平“1

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

125/192


}


SDA=1;


//SDA的上升沿被认为是结束信号


/***************************************************

函数功能:从AT24Cxx读取数据

出口参数:x

***************************************************/

unsignedcharReadData()

//  AT24Cxx移入数据到MCU

{

unsignedchari;

unsignedcharx;             //储存从AT24Cxx中读出的数据

for(i=0;i<8;i++)

{

SCL=1;                   //SCL置为高电平

x<<=1;                      //x中的各二进位向左移一位

x|=(unsignedchar)SDA;   //SDA上的数据通过按位“或“运算存入x

SCL=0;                  //SCL的下降沿读出数据

}

return(x);                   //将读取的数据返回

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

***************************************************/

//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

{

unsignedchari;

bitack_bit;                  //储存应答位

for(i=0;i<8;i++)        //  循环移入8个位

{

SDA=(bit)(y&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

_nop_();                 //等待一个机器周期

SCL=1;                 //SCL的上升沿将数据写入AT24Cxx

_nop_();                 //等待一个机器周期

_nop_();                  //等待一个机器周期

SCL=0;                 //SCL重新置为低电平,以在SCL线形成传送

数据所需的8个脉冲

y<<=1;                 //y中的各二进位向左移一位

}


 


126


/


192


SDA=1;

释放SDA线,


//


发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)


_nop_();

_nop_();

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();


//以让SDA线转由接收设备(AT24Cxx)控制

//等待一个机器周期

//等待一个机器周期

//根据上述规定,SCL应为高电平

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期


ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个

字节

//若送高电平,表示没有接收到,传送异常

SCL=0;         //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据

传递)

return  ack_bit;//返回AT24Cxx应答位

}

/***************************************************

函数功能:向第一个AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet1(unsignedcharadd,unsignedchardat)

//  在指定地址addr处写入数据WriteCurrent

{

start();                      //开始数据传递

WriteCurrent(OP_WRITE1);   //选择要操作的第一个AT24Cxx芯片,并告知要

对其写入数据

WriteCurrent(add);          //写入指定地址

WriteCurrent(dat);          //向当前地址(上面指定的地址)写入数据

stop();                       //停止数据传递

delaynms(4);                  //1个字节的写入周期为1ms,最好延时1ms

}

/***************************************************

函数功能:向第二个AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet2(unsignedcharadd,unsignedchardat)

//  在指定地址addr处写入数据WriteCurrent

{

start();                      //开始数据传递

WriteCurrent(OP_WRITE2);   //选择要操作的AT24Cxx芯片,并告知要对其写

入数据

WriteCurrent(add);          //写入指定地址

127/192


}


WriteCurrent(dat);

stop();

delaynms(4);


//向当前地址(上面指定的地址)写入数据

//停止数据传递

//1个字节的写入周期为1ms,最好延时1ms


 

/***************************************************

函数功能:从第一个AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent1()

{

unsignedcharx;

start();                       //开始数据传递

WriteCurrent(OP_READ1);    //选择要操作的第一个AT24Cxx芯片,并告知要

读其数据

x=ReadData();                //将读取的数据存入x

stop();                       //停止数据传递

returnx;                     //返回读取的数据

}

/***************************************************

函数功能:从第二个AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent2()

{

unsignedcharx;

start();                       //开始数据传递

WriteCurrent(OP_READ2);     //选择要操作的第二个AT24Cxx芯片,并告知

要读其数据

x=ReadData();                 //将读取的数据存入x

stop();                        //停止数据传递

returnx;                      //返回读取的数据

}

/***************************************************

函数功能:从第一个AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

***************************************************/

unsignedcharReadSet1(unsignedcharset_addr)

//  在指定地址读取

{

start();                           //开始数据传递


 


128


/


192


WriteCurrent(OP_WRITE1);

告知要对其写入数据

WriteCurrent(set_addr);

return(ReadCurrent1());

并返回

}


//选择要操作的第一个AT24Cxx芯片,并

//写入指定地址

//从第一个AT24Cxx芯片指定地址读出数据


/***************************************************

函数功能:从第二个AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

***************************************************/

unsignedcharReadSet2(unsignedcharset_addr)

//  在指定地址读取

{

start();                            //开始数据传递

WriteCurrent(OP_WRITE2);         //选择要操作的第二个AT24Cxx芯片,并

告知要对其写入数据

WriteCurrent(set_addr);          //写入指定地址

return(ReadCurrent2());          //从第二个AT24Cxx芯片指定地址读出数据

并返回

}

/***************************************************

函数功能:主函数

***************************************************/

main(void)

{

unsignedcharx;

SDA=1;             //SDA=1,SCL=1,使主从设备处于空闲状态

SCL=1;

WriteSet1(0x36,0xaa);    //将数据"0xaa"写入第一个AT24C02的指定地址

"0x36"

x=ReadSet1(0x36);         //从第二个AT24C02中的指定地址"0x36"读出数据

WriteSet2(0x48,x);       //将读出的数据写入第二个AT24C02的指定地址

"0x48"?

P1=ReadSet2(0x48);       //将从第二个AT24C02的指定地址读出的数据送

P1口显示验证

}


 


//


88


AT24C02


//实例88:基于AT24C02的多机通信


读取程序


 


#include<reg51.h>


//


包含51单片机寄存器定义的头文件

129/192


#include<intrins.h>

#defineOP_READ

0001B


0xa1


//包含_nop_()函数定义的头文件

//  器件1地址以及读取操作,0xa1即为1010


#define


OP_WRITE0xa0


//


器件1地址以及写入操作,0xa1即为10100000B


 


sbitSDA=P3^4;

sbitSCL=P3^3;

sbitflag=P3^0;


//将串行数据总线SDA位定义在为P3.4引脚

//将串行时钟总线SDA位定义在为P3.3引脚


/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

//  开始位

{

SDA=1;     //SDA初始化为高电平“1

SCL=1;     //开始数据传送时,要求SCL为高电平“1

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;     //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期


 


130


/


192


SCL=0;

递)

_nop_();

}


//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

//等待一个机器周期


/***************************************************

函数功能:结束数据传送

***************************************************/

voidstop()

//  停止位

{

SDA=0;      //SDA初始化为低电平“0

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SCL=1;      //结束数据传送时,要求SCL为高电平“1

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SDA=1;     //SDA的上升沿被认为是结束信号

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

}

/***************************************************

函数功能:从AT24Cxx读取数据

出口参数:x

***************************************************/

unsignedcharReadData()

//  AT24Cxx移入数据到MCU

{

unsignedchari;

unsignedcharx;             //储存从AT24Cxx中读出的数据

for(i=0;i<8;i++)

{

SCL=1;                   //SCL置为高电平

x<<=1;                      //x中的各二进位向左移一位

x|=(unsignedchar)SDA;   //SDA上的数据通过按位“或“运算存入x

SCL=0;                  //SCL的下降沿读出数据

}

return(x);                   //将读取的数据返回

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

131/192


***************************************************/

//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

{

unsignedchari;

bitack_bit;                  //储存应答位

for(i=0;i<8;i++)        //  循环移入8个位

{

SDA=(bit)(y&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

_nop_();                 //等待一个机器周期

SCL=1;                 //SCL的上升沿将数据写入AT24Cxx

_nop_();                 //等待一个机器周期

_nop_();                  //等待一个机器周期

SCL=0;                 //SCL重新置为低电平,以在SCL线形成传送

数据所需的8个脉冲

y<<=1;                 //y中的各二进位向左移一位

}

SDA=1;           //  发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)

释放SDA线,

//以让SDA线转由接收设备(AT24Cxx)控制

_nop_();          //等待一个机器周期

_nop_();          //等待一个机器周期

SCL=1;         //根据上述规定,SCL应为高电平

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

_nop_();         //等待一个机器周期

ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个

字节

//若送高电平,表示没有接收到,传送异常

SCL=0;         //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据

传递)

return  ack_bit;//返回AT24Cxx应答位

}

/***************************************************

函数功能:从第一个AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent()

{

unsignedcharx;

132/192


}


start();

WriteCurrent(OP_READ);

x=ReadData();

stop();

returnx;


//开始数据传递

//选择要操作的AT24Cxx芯片,并告知要读其数

//将读取的数据存入x

//停止数据传递

//返回读取的数据


 

/***************************************************

函数功能:从AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

***************************************************/

unsignedcharReadSet(unsignedcharset_addr)

//  在指定地址读取

{

start();                           //开始数据传递

WriteCurrent(OP_WRITE);         //选择要操作的AT24Cxx芯片,并告知要对

其写入数据

WriteCurrent(set_addr);         //写入指定地址

return(ReadCurrent());          //从第一个AT24Cxx芯片指定地址读出数据并

返回

}

/***************************************************

函数功能:主函数

***************************************************/

main(void)

{

SDA=1;             //SDA=1,SCL=1,使主从设备处于空闲状态

SCL=1;

while(1)

{

while(flag==1)

;

P1=ReadSet(0x36);         //从第二个AT24C02中的指定地址"0x36"读出数

delaynms(90);

}

}


 


//


88


AT24C02


//实例88:基于AT24C02的多机通信

133/192


写入程序


#include<reg51.h>


//


包含51单片机寄存器定义的头文件


 


#include<intrins.h>

#defineOP_READ

0001B


0xa1


//包含_nop_()函数定义的头文件

//  器件1地址以及读取操作,0xa1即为1010


#define


OP_WRITE0xa0


//


器件1地址以及写入操作,0xa1即为10100000B


sbitSDA=P3^4;

sbitSCL=P3^3;

sbitflag=P3^0;


//将串行数据总线SDA位定义在为P3.4引脚

//将串行时钟总线SDA位定义在为P3.3引脚


 

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

//  开始位

{

SDA=1;     //SDA初始化为高电平“1

SCL=1;     //开始数据传送时,要求SCL为高电平“1

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;     //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

134/192


SCL=0;

递)

_nop_();

}


//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

//等待一个机器周期


/***************************************************

函数功能:结束数据传送

***************************************************/

voidstop()

//  停止位

{

SDA=0;      //SDA初始化为低电平“0

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SCL=1;      //结束数据传送时,要求SCL为高电平“1

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SDA=1;     //SDA的上升沿被认为是结束信号

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

***************************************************/

//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

{

unsignedchari;

bitack_bit;                  //储存应答位

for(i=0;i<8;i++)        //  循环移入8个位

{

SDA=(bit)(y&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

_nop_();                 //等待一个机器周期

SCL=1;                 //SCL的上升沿将数据写入AT24Cxx

_nop_();                 //等待一个机器周期

_nop_();                  //等待一个机器周期


 


135


/


192


SCL=0;

数据所需的8个脉冲

y<<=1;

}

SDA=1;

释放SDA线,


//


//SCL重新置为低电平,以在SCL线形成传送

//y中的各二进位向左移一位

发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)


 


_nop_();

_nop_();

SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();


//以让SDA线转由接收设备(AT24Cxx)控制

//等待一个机器周期

//等待一个机器周期

//根据上述规定,SCL应为高电平

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期


 

ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个

字节

//若送高电平,表示没有接收到,传送异常

SCL=0;         //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据

传递)

return  ack_bit;//返回AT24Cxx应答位

}

/***************************************************

函数功能:向AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet(unsignedcharadd,unsignedchardat)

//  在指定地址addr处写入数据WriteCurrent

{

start();                      //开始数据传递

WriteCurrent(OP_WRITE);   //选择要操作的第一个AT24Cxx芯片,并告知要

对其写入数据

WriteCurrent(add);          //写入指定地址

WriteCurrent(dat);          //向当前地址(上面指定的地址)写入数据

stop();                       //停止数据传递

delaynms(4);                  //1个字节的写入周期为1ms,最好延时1ms

}

/***************************************************

函数功能:主函数

***************************************************/

main(void)

{

TMOD=0x01;

136/192


TH0=(65536-46083)/256;

TL0=(65536-46083)%256;

EA=1;

ET0=1;

TR0=1;

flag=1;

while(1)

{

while(flag==1)

{

WriteSet(0x36,0xf0);

"0x36"

delaynms(50);

}

while(flag==0)

;

}

}


//将数据"0xf0"写入第一个AT24C02的指定地址

//延时50ms


 

/***************************************************

函数功能:定时器T0的中断函数,使P3.0引脚输出100ms方波

***************************************************/

voidTime0(void)interrupt1using1

{

TH0=(65536-46083)/256;

TL0=(65536-46083)%256;

flag=!flag;

}


 

//实例89:将"渴望"乐谱写入AT24C02并读出播放

#include<reg51.h>           //包含51单片机寄存器定义的头文件

#include<intrins.h>         //包含_nop_()函数定义的头文件

#defineOP_READ    0xa1        //  器件地址以及读取操作,0xa1即为10100001B

#defineOP_WRITE0xa0      //  器件地址以及写入操作,0xa1即为10100000B

sbitSDA=P3^4;                //将串行数据总线SDA位定义在为P3.4引脚

sbitSCL=P3^3;                //将串行时钟总线SDA位定义在为P3.3引脚

sbitsound=P3^7;             //sound位定义为P3.7,从该引脚输出音频

unsignedintC;               //储存定时器的定时常数

//以下是C调低音的音频宏定义

#definel_dao262    //将“l_dao”宏定义为低音“1”的频率262Hz

#definel_re286     //将“l_re”宏定义为低音“2”的频率286Hz

137/192


#definel_mi311

#definel_fa349

#definel_sao392

#definel_la440

#definel_xi494


//将“l_mi”宏定义为低音“3”的频率311Hz

//将“l_fa”宏定义为低音“4”的频率349Hz

//将“l_sao”宏定义为低音“5”的频率392Hz

//将“l_a”宏定义为低音“6”的频率440Hz

//将“l_xi”宏定义为低音“7”的频率494Hz


//以下是C调中音的音频宏定义

#definedao523      //将“dao”宏定义为中音“1”的频率523Hz

#definere587       //将“re”宏定义为中音“2”的频率587Hz

#definemi659       //将“mi”宏定义为中音“3”的频率659Hz

#definefa698       //将“fa”宏定义为中音“4”的频率698Hz

#definesao784      //将“sao”宏定义为中音“5”的频率784Hz

#definela880       //将“la”宏定义为中音“6”的频率880Hz

#definexi987       //将“xi”宏定义为中音“7”的频率523Hz

//以下是C调高音的音频宏定义

#defineh_dao1046      //将“h_dao”宏定义为高音“1”的频率1046Hz

#defineh_re1174       //将“h_re”宏定义为高音“2”的频率1174Hz

#defineh_mi1318       //将“h_mi”宏定义为高音“3”的频率1318Hz

#defineh_fa1396      //将“h_fa”宏定义为高音“4”的频率1396Hz

#defineh_sao1567     //将“h_sao”宏定义为高音“5”的频率1567Hz

#defineh_la1760      //将“h_la”宏定义为高音“6”的频率1760Hz

#defineh_xi1975      //将“h_xi”宏定义为高音“7”的频率1975Hz

/*******************************************

函数功能:节拍的延时的基本单位,延时200ms

******************************************/

voiddelay()

{

unsignedchari,j;

for(i=0;i<250;i++)

for(j=0;j<250;j++)

;

}

/********************************************************************

******

以下是对AT24C02进行读写操作的源程序

*********************************************************************

****/

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

138/192


}


for(i=0;i<10;i++)

for(j=0;j<33;j++)

;


/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/***************************************************

函数功能:开始数据传送

***************************************************/

voidstart()

{

SDA=1;      //SDA初始化为高电平"1"

SCL=1;      //开始数据传送时,要求SCL为高电平"1"

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SDA=0;      //SDA的下降沿被认为是开始信号

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

_nop_();    //等待一个机器周期

SCL=0;      //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

)

}

/***************************************************

函数功能:结束数据传送

***************************************************/

voidstop()

{

SDA=0;      //SDA初始化为低电平"0"

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

SCL=1;       //结束数据传送时,要求SCL为高电平"1"

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

139/192


}


SDA=1;


//SDA的上升沿被认为是结束信号


/***************************************************

函数功能:从AT24Cxx读取数据

出口参数:x

***************************************************/

unsignedcharReadData()

{

unsignedchari;

unsignedcharx;                  //储存从AT24Cxx中读出的数据

for(i=0;i<8;i++)

{

SCL=1;                     //SCL置为高电平

x<<=1;                      //x中的各二进位向左移一位

x|=(unsignedchar)SDA;//SDA上的数据通过按位""运算存入x

SCL=0;                   //SCL的下降沿读出数据

}

return(x);                      //将读取的数据返回

}

/***************************************************

函数功能:向AT24Cxx的当前地址写入数据

入口参数:y(储存待写入的数据)

***************************************************/

//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0

bitWriteCurrent(unsignedchary)

{

unsignedchari;

bitack_bit;                      //储存应答位

for(i=0;i<8;i++)         //  循环移入8个位

{

SDA=(bit)(y&0x80);//通过按位""运算将最高位数据送到S

//因为传送时高位在前,低位在后

_nop_();                 //等待一个机器周期

SCL=1;                   //SCL的上升沿将数据写入AT24Cxx

_nop_();                 //等待一个机器周期

_nop_();                 //等待一个机器周期

SCL=0;  //SCL重新置为低电平,以在SCL线形成传送数据所需的8个

脉冲

y<<=1;                //y中的各二进位向左移一位

}

SDA=1;//  发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,

//以让SDA线转由接收设备(AT24Cxx)控制

_nop_();      //等待一个机器周期

_nop_();      //等待一个机器周期

140/192


SCL=1;

_nop_();

_nop_();

_nop_();

_nop_();


//根据上述规定,SCL应为高电平

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期

//等待一个机器周期


)

}


ack_bit=SDA;//接受设备(AT24Cxx)SDA送低电平,表示已经接收到一个字

//若送高电平,表示没有接收到,传送异常

SCL=0;       //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传

return  ack_bit;//返回AT24Cxx应答位


/***************************************************

函数功能:向AT24Cxx中的指定地址写入数据

入口参数:add(储存指定的地址);dat(储存待写入的数据)

***************************************************/

voidWriteSet(unsignedcharadd,unsignedchardat)

{

start();                       //开始数据传递

WriteCurrent(OP_WRITE);   //选择要操作的AT24Cxx芯片,并告知要对其写入

数据

WriteCurrent(add);          //写入指定地址

WriteCurrent(dat);          //向当前地址(上面指定的地址)写入数据

stop();                      //停止数据传递

delaynms(4);                //1个字节的写入周期为1ms,最好延时1ms

}

/***************************************************

函数功能:从AT24Cxx中的当前地址读取数据

出口参数:x(储存读出的数据)

***************************************************/

unsignedcharReadCurrent()

{

unsignedcharx;

start();                       //开始数据传递

WriteCurrent(OP_READ);    //选择要操作的AT24Cxx芯片,并告知要读其数据

x=ReadData();               //将读取的数据存入x

stop();                       //停止数据传递

returnx;                       //返回读取的数据

}

/***************************************************

函数功能:从AT24Cxx中的指定地址读取数据

入口参数:set_addr

出口参数:x

141/192


***************************************************/

unsignedcharReadSet(unsignedcharset_addr)

{

start();                      //开始数据传递

WriteCurrent(OP_WRITE);//选择要操作的AT24Cxx芯片,并告知要对其写入数

WriteCurrent(set_addr);     //写入指定地址

return(ReadCurrent());    //从指定地址读出数据并返回

}

/***************************************************

函数功能:主函数

***************************************************/

main(void)

{

unsignedchari,j;

unsignedchartemp;    //储存压缩后的音频

unsignedcharJi;      //储存音符节拍

unsignedchar   N;    //储存音符的最大个数以在AT24C02中为音符和节拍分

配存储空间

unsignedintfr;      //储存解压缩后的音频

//以下是《渴望》片头曲的一段简谱

unsigned  intcodef[]={re,mi,re,dao,l_la,dao,l_la,

l_sao,l_mi,l_sao,l_la,dao,

l_la,dao,sao,la,mi,sao,

re,

mi,re,mi,sao,mi,

l_sao,l_mi,l_sao,l_la,dao,

l_la,l_la,dao,l_la,l_sao,l_re,l_mi,

l_sao,

re,re,sao,la,sao,

fa,mi,sao,mi,

la,sao,mi,re,mi,l_la,dao,

re,

mi,re,mi,sao,mi,

l_sao,l_mi,l_sao,l_la,dao,

l_la,dao,re,l_la,dao,re,mi,

re,

l_la,dao,re,l_la,dao,re,mi,

re,

0x00};   //以频率0x00作为简谱的结束标

//以下是简谱中每个音符的节拍

unsignedcharcodeJP[]={4,1,1,4,1,1,2,

2,2,2,2,8,

142/192


EA=1;


//开总中断


4,2,3,1,2,2,

10,

4,2,2,4,4,

2,2,2,2,4,

2,2,2,2,2,2,2,

10,

4,4,4,2,2,

4,2,4,4,

4,2,2,2,2,2,2,

10,

4,2,2,4,4,

2,2,2,2,6,

4,2,2,4,1,1,4,

10,

4,2,2,4,1,1,4,

10

};


ET0=1;

TMOD=0x00;

SDA=1;

SCL=1;

while(1)

{

i=0;


//定时器T0中断允许

//  使用定时器T0的模式113位计数器)

//SDA=1,SCL=1,使主从设备处于空闲状态

//无限循环

//从第1个音符频率f[0]开始写入AT24C02



while(f[i]!=0x01)

{


//只要没有读到结束标志就继续写


的音频


temp=(unsignedchar)(f[i]/8);//将音频压缩为较小的字符变

WriteSet(0x00+i,temp);         //在指定地址写入数据压缩后

i++;                              //指向下一个音符音频

}

N=i;      //将音符的最大个数存于N

i=0;       //从第一个音符节拍JP[0]开始写入AT24C02

while(f[i]!=0x00)

{

WriteSet(0x00+N+i,JP[i]);   //在指定地址写入音符的节拍

i++;                            //指向下一个音符音频

}

for(i=0;i<N;i++)

{

temp=ReadSet(0x00+i);   //读出音频

143/192


位的赋初值方法

位的赋初值方法


Ji=ReadSet(0x00+N+i);

fr=8*temp;

C=460830/fr;

TH0=(8192-C)/32;

TL0=(8192-C)%32;

TR0=1;


//读出节拍

//将音频解压

//定时常数的计算公式

//可证明这是13位计数器TH08

//可证明这是13位计数器TL05

//启动定时器T0


}


for(j=0;j<Ji;j++)

delay();

TR0=0;


//控制节拍数

//延时1个节拍单位

//关闭定时器T0


播放

}


}


sound=1;

for(i=0;i<8;i++)

delay();


//播放完毕后,关闭蜂鸣器

//播放完毕后,停顿一段时间后继续


 

/////////////////////////

/***********************************************************

函数功能:定时器T0的中断服务子程序,使P3.7引脚输出音频的方波

************************************************************/

voidTime0(void)interrupt1using1

{

TH0=(8192-C)/32;    //可证明这是13位计数器TH08位的赋初值方法

TL0=(8192-C)%32;    //可证明这是13位计数器TL05位的赋初值方法

sound=!sound;      //P3.7引脚输出电平取反,形成方波

}


 


//


90


DS18B20


//实例90DS18B20温度检测及其液晶显示

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

unsignedcharcodedigit[10]={"0123456789"};      //定义字符数组显示数字

unsignedcharcodeStr[]={"TestbyDS18B20"};     //说明显示的是温度

144/192


unsignedcharcodeError[]={"Error!Check!"};

unsignedcharcodeTemp[]={"Temp:"};

unsignedcharcodeCent[]={"Cent"};


//说明没有检测到DS18B20

//说明显示的是温度

//温度单位


 

/********************************************************************

***********

以下是对液晶模块的操作程序

*********************************************************************

**********/

sbitRS=P2^0;              //寄存器选择位,将RS位定义为P2.0引脚

sbitRW=P2^1;              //读写选择位,将RW位定义为P2.1引脚

sbitE=P2^2;               //使能信号位,将E位定义为P2.2引脚

sbitBF=P0^7;              //忙碌标志位,,将BF位定义为P0.7引脚

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

bitBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

145/192


}


_nop_();

_nop_();

_nop_();

result=BF;

E=0;

returnresult;


//空操作四个机器周期,给硬件反应时间

//将忙碌标志电平赋给result

//E恢复低电平


/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);    //如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

_nop_();

_nop_();                  //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=0;                      //E由高电平跳变成低电平时,液晶模块开始

执行命令

}

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

146/192


入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;             //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

E=0;               //E由高电平跳变成低电平时,液晶模块开始执行命令

}

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delaynms(15);                  //延时15ms,首次写指令时应给LCD一段较

长的反应时间

WriteInstruction(0x38);      //显示模式设置:16×2显示,5×7点阵,8

数据接口

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);      //连续三次,确保初始化成功

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x0c);      //显示模式设置:显示开,无光标,光标不闪烁

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x06);      //显示模式设置:光标右移,字符不移

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x01);      //清屏幕指令,将以前的显示内容清除

delaynms(5);                //延时5ms   ,给硬件一点反应时间

}


 


147


/


192


/********************************************************************

****

以下是DS18B20的操作程序

*********************************************************************

***/

sbitDQ=P3^3;

unsignedchartime;    //设置全局变量,专门用于严格延时

/*****************************************************

函数功能:将DS18B20传感器初始化,读取应答信号

出口参数:flag

***************************************************/

bitInit_DS18B20(void)

{

bitflag;           //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1

表示不存在

DQ=1;             //先将数据线拉高

for(time=0;time<2;time++)//略微延时约6微秒

;

DQ=0;             //再将数据线从高拉低,要求保持480~960us

for(time=0;time<200;time++)   //略微延时约600微秒

;          //以向DS18B20发出一持续480~960us的低电平复位脉冲

DQ=1;             //释放数据线(将数据线拉高)

for(time=0;time<10;time++)

;   //延时约30us(释放总线后需等待15~60usDS18B20输出存在脉冲)

flag=DQ;            //让单片机检测是否输出了存在脉冲(DQ=0表示存在)

for(time=0;time<200;time++)   //延时足够长时间,等待存在脉冲输出完毕

;

return(flag);     //返回检测成功标志

}

/*****************************************************

函数功能:从DS18B20读取一个字节数据

出口参数:dat

***************************************************/

unsignedcharReadOneChar(void)

{

unsignedchari=0;

unsignedchardat;   //储存读出的一个字节数据

for(i=0;i<8;i++)

{

DQ=1;         //先将数据线拉高

_nop_();      //等待一个机器周期


 


148


/


192


动读时序

平作准备


DQ=0;

dat>>=1;

_nop_();

DQ=1;


//单片机从DS18B20读书据时,将数据线从高拉低即启

//等待一个机器周期

//将数据线"人为"拉高,为单片机检测DS18B20的输出电


 


复期


}


for(time=0;time<2;time++)

;      //延时约6us,使主机在15us内采样

if(DQ==1)

dat|=0x80;  //如果读到的数据是1,则将1存入dat

else

dat|=0x00;//如果读到的数据是0,则将0存入dat

//将单片机检测到的电平信号DQ存入r[i]

for(time=0;time<8;time++)

;                 //延时3us,两个读时序之间必须有大于1us的恢


}


return(dat);


//返回读出的十进制数据


/*****************************************************

函数功能:向DS18B20写入一个字节数据

入口参数:dat

***************************************************/

WriteOneChar(unsignedchardat)

{

unsignedchari=0;

for(i=0;i<8;i++)

{

DQ=1;           //先将数据线拉高

_nop_();        //等待一个机器周期

DQ=0;            //将数据线从高拉低时即启动写时序

DQ=dat&0x01;    //利用与运算取出要写的某位二进制数据,

//并将其送到数据线上等待DS18B20采样

for(time=0;time<10;time++)

;//延时约30usDS18B20在拉低后的约15~60us期间从数据线上采

DQ=1;            //释放数据线

for(time=0;time<1;time++)

;//延时3us,两个写时序间至少需要1us的恢复期

dat>>=1;         //dat中的各二进制位数据右移1

}

for(time=0;time<4;time++)

;//稍作延时,给硬件一点反应时间

}

149/192


/********************************************************************

**********

以下是与温度有关的显示设置

*********************************************************************

*********/

/*****************************************************

函数功能:显示没有检测到DS18B20

***************************************************/

voiddisplay_error(void)

{

unsignedchari;

WriteAddress(0x00);     //写显示地址,将在第1行第1列开始显

i=0;                   //从第一个字符开始显示

while(Error[i]!='\0')   //只要没有写到结束标志,就继续写

{

WriteData(Error[i]);    //将字符常量写入LCD

i++;                     //指向下一个字符

delaynms(100);          //延时100ms较长时间,以看清关于

显示的说明

}

while(1)                 //进入死循环,等待查明原因

;

}

/*****************************************************

函数功能:显示说明信息

***************************************************/

voiddisplay_explain(void)

{

unsignedchari;

WriteAddress(0x00);     //写显示地址,将在第1行第1列开始显

i=0;                   //从第一个字符开始显示

while(Str[i]!='\0')   //只要没有写到结束标志,就继续写

{

WriteData(Str[i]);    //将字符常量写入LCD

i++;                     //指向下一个字符

delaynms(100);          //延时100ms较长时间,以看清关于

显示的说明

}

}

/*****************************************************

函数功能:显示温度符号

150/192


***************************************************/

voiddisplay_symbol(void)

{

unsignedchari;

WriteAddress(0x40);     //写显示地址,将在第2行第1列开始显

i=0;                   //从第一个字符开始显示

while(Temp[i]!='\0')   //只要没有写到结束标志,就继续写

{

WriteData(Temp[i]);    //将字符常量写入LCD

i++;                     //指向下一个字符

delaynms(50);          //延时1ms给硬件一点反应时间

}

}

/*****************************************************

函数功能:显示温度的小数点

***************************************************/

void    display_dot(void)

{

WriteAddress(0x49);       //写显示地址,将在第2行第10列开始显示

WriteData('.');       //将小数点的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示温度的单位(Cent)

***************************************************/

void    display_cent(void)

{

unsignedchari;

WriteAddress(0x4c);          //写显示地址,将在第2行第13列开

始显示

i=0;                        //从第一个字符开始显示

while(Cent[i]!='\0')      //只要没有写到结束标志,就继续写

{

WriteData(Cent[i]);      //将字符常量写入LCD

i++;                     //指向下一个字符

delaynms(50);          //延时1ms给硬件一点反应时间

}

}

/*****************************************************

函数功能:显示温度的整数部分

入口参数:x

151/192


***************************************************/

voiddisplay_temp1(unsignedcharx)

{

unsignedcharj,k,l;      //j,k,l分别储存温度的百位、十位和个位

j=x/100;                 //取百位

k=(x%100)/10;     //取十位

l=x%10;                //取个位

WriteAddress(0x46);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[j]);     //将百位数字的字符常量写入LCD

WriteData(digit[k]);     //将十位数字的字符常量写入LCD

WriteData(digit[l]);     //将个位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示温度的小数数部分

入口参数:x

***************************************************/

voiddisplay_temp2(unsignedcharx)

{

WriteAddress(0x4a);       //写显示地址,将在第2行第11列开始显示

WriteData(digit[x]);      //将小数部分的第一位数字字符常量写入LCD

delaynms(50);            //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:做好读温度的准备

***************************************************/

voidReadyReadTemp(void)

{

Init_DS18B20();      //DS18B20初始化

WriteOneChar(0xCC);//  跳过读序号列号的操作

WriteOneChar(0x44);//  启动温度转换

for(time=0;time<100;time++)

;   //温度转换需要一点时间

Init_DS18B20();      //DS18B20初始化

WriteOneChar(0xCC);//跳过读序号列号的操作

WriteOneChar(0xBE);//读取温度寄存器,前两个分别是温度的低位和高位

}


 

/*****************************************************

函数功能:主函数

***************************************************/


 


152


/


192


voidmain(void)

{

unsignedcharTL;

unsignedcharTH;

unsignedcharTN;

unsignedcharTD;

LcdInitiate();

delaynms(5);


//储存暂存器的温度低位

//储存暂存器的温度高位

//储存温度的整数部分

//储存温度的小数部分

//将液晶初始化

//延时5ms给硬件一点反应时间


 

if(Init_DS18B20()==1)

display_error();

display_explain();

display_symbol();     //显示温度说明

display_dot();         //显示温度的小数点

display_cent();       //显示温度的单位

while(1)                   //不断检测并显示温度

{

ReadyReadTemp();      //读温度准备

TL=ReadOneChar();     //先读的是温度值低位

TH=ReadOneChar();     //接着读的是温度值高位

TN=TH*16+TL/16;       //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16

//这样得出的是温度的整数部分,小数部分被丢

弃了

TD=(TL%16)*10/16;     //计算温度的小数部分,将余数乘以10再除以16

取整,

//这样得到的是温度小数部分的第一位数字(

1位小数)

display_temp1(TN);     //显示温度的整数部分

display_temp2(TD);     //显示温度的小数部分

delaynms(10);

}

}


 

//实例91:将数据"0xaa"写入X5045再读出送P1口显示

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitSCK=P3^4;         //SCK位定义为P3.4引脚

sbitSI=P3^5;          //SI位定义为P3.5引脚

sbitSO=P3^6;          //SO位定义为P3.6引脚

sbitCS=P3^7;          //SCK位定义为P3.7引脚

#defineWREN0x06     //写使能锁存器允许

153/192


#defineWRDI0x04

#defineWRSR0x01

#defineREAD0x03

#defineWRITE0x02


//写使能锁存器禁止

//写状态寄存器

//读出

//写入


 

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:从X5045的当前地址读出数据

出口参数:x

***************************************************/

unsignedcharReadCurrent(void)

{

unsignedchari;

unsignedcharx=0x00;       //储存从X5045中读出的数据

SCK=1;                         //SCK置于已知的高电平状态

for(i=0;i<8;i++)

{

SCK=1;                     //拉高SCK

SCK=0;                     //SCK的下降沿输出数据

x<<=1;   //x中的各二进位向左移一位,因为首先读出的是字节的最高

位数据

x|=(unsignedchar)SO;   //SO上的数据通过按位“或“运算存入x

}

return(x);    //将读取的数据返回

}

154/192


/*****************************************************

函数功能:写数据到X5045的当前地址

入口参数:dat

***************************************************/

voidWriteCurrent(unsignedchardat)

{

unsignedchari;

SCK=0;                     //SCK置于已知的低电平状态

for(i=0;i<8;i++)   //循环移入8个位

{

SI=(bit)(dat&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

SCK=0;

SCK=1;                  //SCK上升沿写入数据

dat<<=1;    //y中的各二进位向左移一位,因为首先写入的是字节的最高

}

}

/*****************************************************

函数功能:写状态寄存器,可以设置看门狗的溢出时间及数据保护

入口参数:rs;   //储存寄存器状态值

***************************************************/

voidWriteSR(unsignedcharrs)

{

CS=0;                     //拉低CS,选中X5045

WriteCurrent(WREN);    //写使能锁存器允许

CS=1;                     //拉高CS

CS=0;                     //重新拉低CS,否则下面的写寄存器状态指令将被

丢弃

WriteCurrent(WRSR);    //写状态寄存器

WriteCurrent(rs);      //写入新设定的寄存器状态值

CS=1;                     //拉高CS

}

/*****************************************************

函数功能:写数据到X5045的指定地址

入口参数:addr

***************************************************/

voidWriteSet(unsignedchardat,unsignedcharaddr)

{

SCK=0;                     //SCK置于已知状态

CS=0;                      //拉低CS,选中X5045

WriteCurrent(WREN);     //写使能锁存器允许

155/192


}


CS=1;

CS=0;

WriteCurrent(WRITE);

WriteCurrent(addr);

WriteCurrent(dat);

CS=1;

SCK=0;


//拉高CS

//重新拉低CS,否则下面的写入指令将被丢弃

//写入指令

//写入指定地址

//写入数据

//拉高CS

//SCK置于已知状态


 

/*****************************************************

函数功能:从X5045的指定地址读出数据

入口参数:addr

出口参数:dat

***************************************************/

unsignedcharReadSet(unsignedcharaddr)

{

unsignedchardat;

SCK=0;                     //SCK置于已知状态

CS=0;                      //拉低CS,选中X5045

WriteCurrent(READ);    //开始读

WriteCurrent(addr);    //写入指定地址

dat=ReadCurrent();     //读出数据

CS=1;                     //拉高CS

SCK=0;                   //SCK置于已知状态

returndat;             //返回读出的数据

}

/*****************************************************

函数功能:看门狗复位程序

***************************************************/

voidWatchDog(void)

{

CS=1;    //拉高CS

CS=0;    //CS引脚的一个下降沿复位看门狗定时器

CS=1;    //拉高CS

}

/*****************************************************

函数功能:主程序

***************************************************/

voidmain(void)

{

WriteSR(0x12);          //写状态寄存器(设定看门狗溢出时间为600ms,写不

保护)

delaynms(10);           //X5045的写入周期约为10ms

156/192


}


while(1)

{

WriteSet(0xaa,0x10);

delaynms(10);

P1=ReadSet(0x10);

WatchDog();

}


//将数据“0xaa”写入指定地址“0x10

//X5045的写入周期约为10ms

//将数据读出送P1口显示

//复位看门狗


 


//


92


X5045


P1


//实例92:将流水灯控制码写入X5045并读出送P1口显示

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitSCK=P3^4;         //SCK位定义为P3.4引脚

sbitSI=P3^5;          //SI位定义为P3.5引脚

sbitSO=P3^6;          //SO位定义为P3.6引脚

sbitCS=P3^7;          //SCK位定义为P3.7引脚

#defineWREN0x06     //写使能锁存器允许

#defineWRDI0x04     //写使能锁存器禁止

#defineWRSR0x01     //写状态寄存器

#defineREAD0x03     //读出

#defineWRITE0x02    //写入

unsignedcharlamp[]={0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F,

0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE,0xFF,

0xFF,0xFE,0xFC,0xFB,0xF0,0xE0,0xC0,0x80,0x00,

0xE7,0xDB,0xBD,0x7E,0xFF,0xFF,0x3C,0x18,0x00,

0x81,0xC3,0xE7,0xFF,0xFF,0x7E,0xBD,0xDB,0xE7,

0xBD,0xDB,0x7E,0xFF,0xAA};     //流水灯控制码

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

157/192


入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:从X5045的当前地址读出数据

出口参数:x

***************************************************/

unsignedcharReadCurrent(void)

{

unsignedchari;

unsignedcharx=0x00;       //储存从X5045中读出的数据

SCK=1;                         //SCK置于已知的高电平状态

for(i=0;i<8;i++)

{

SCK=1;                     //拉高SCK

SCK=0;                     //SCK的下降沿输出数据

x<<=1;   //x中的各二进位向左移一位,因为首先读出的是字节的最高

位数据

x|=(unsignedchar)SO;   //SO上的数据通过按位“或“运算存入x

}

return(x);    //将读取的数据返回

}

/*****************************************************

函数功能:写数据到X5045的当前地址

入口参数:dat

***************************************************/

voidWriteCurrent(unsignedchardat)

{

unsignedchari;

SCK=0;                     //SCK置于已知的低电平状态

for(i=0;i<8;i++)   //循环移入8个位

{

SI=(bit)(dat&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

SCK=0;

SCK=1;                  //SCK上升沿写入数据

dat<<=1;    //y中的各二进位向左移一位,因为首先写入的是字节的最高

}

158/192


}

/*****************************************************

函数功能:写状态寄存器,可以设置看门狗的溢出时间及数据保护

入口参数:rs;   //储存寄存器状态值

***************************************************/

voidWriteSR(unsignedcharrs)

{

CS=0;                     //拉低CS,选中X5045

WriteCurrent(WREN);    //写使能锁存器允许

CS=1;                     //拉高CS

CS=0;                     //重新拉低CS,否则下面的写寄存器状态指令将被

丢弃

WriteCurrent(WRSR);    //写状态寄存器

WriteCurrent(rs);      //写入新设定的寄存器状态值

CS=1;                     //拉高CS

}

/*****************************************************

函数功能:写数据到X5045的指定地址

入口参数:addr

***************************************************/

voidWriteSet(unsignedchardat,unsignedcharaddr)

{

SCK=0;                     //SCK置于已知状态

CS=0;                      //拉低CS,选中X5045

WriteCurrent(WREN);     //写使能锁存器允许

CS=1;                      //拉高CS

CS=0;                      //重新拉低CS,否则下面的写入指令将被丢弃

WriteCurrent(WRITE);    //写入指令

WriteCurrent(addr);     //写入指定地址

WriteCurrent(dat);      //写入数据

CS=1;                      //拉高CS

SCK=0;                     //SCK置于已知状态

}

/*****************************************************

函数功能:从X5045的指定地址读出数据

入口参数:addr

出口参数:dat

***************************************************/

unsignedcharReadSet(unsignedcharaddr)

{

unsignedchardat;

159/192


SCK=0;

CS=0;

WriteCurrent(READ);

WriteCurrent(addr);

dat=ReadCurrent();

CS=1;

SCK=0;

returndat;

}


//SCK置于已知状态

//拉低CS,选中X5045

//开始读

//写入指定地址

//读出数据

//拉高CS

//SCK置于已知状态

//返回读出的数据


 

/*****************************************************

函数功能:看门狗复位程序

***************************************************/

voidWatchDog(void)

{

CS=1;    //拉高CS

CS=0;    //CS引脚的一个下降沿复位看门狗定时器

CS=1;    //拉高CS

}

/*****************************************************

函数功能:主程序

***************************************************/

voidmain(void)

{

unsignedchari;

WriteSR(0x12);          //写状态寄存器(设定看门狗溢出时间为600ms,写不保

护)

delaynms(10);           //X5045的写入周期约为10ms


 


for(i=0;i<50;i++)

{

WriteSet(lamp[i],0x00+i);


//将数据“0xaa”写入指定地址“0x10


}

while(1)

{


delaynms(10);


//X5045的写入周期约为10ms


}


for(i=0;i<50;i++)

{

P1=ReadSet(0x00+i);

delaynms(100);

WatchDog();

}


//将数据读出送P1口显示

160/192


}


 

//实例93:对SPI总线上挂接多个X5045的读写操作

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitSCK=P3^4;         //SCK位定义为P3.4引脚

sbitSI=P3^5;          //SI位定义为P3.5引脚

sbitSO=P3^6;          //SO位定义为P3.6引脚

sbitCS1=P3^7;          //CS定义为P3.7引脚

sbitCS2=P3^3;          //CS1位定义为P3.7引脚

#defineWREN0x06     //写使能锁存器允许

#defineWRDI0x04     //写使能锁存器禁止

#defineREAD0x03     //读出

#defineWRITE0x02    //写入

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:从X5045的当前地址读出数据

出口参数:x

***************************************************/

unsignedcharReadCurrent(void)

{

161/192


unsignedchari;

unsignedcharx=0x00;

SCK=1;

for(i=0;i<8;i++)

{

SCK=1;

SCK=0;


//储存从X5045中读出的数据

//SCK置于已知的高电平状态

//拉高SCK

//SCK的下降沿输出数据


x<<=1;

高位数据


//x中的各二进位向左移一位,因为首先读出的是字节的最



x

}


x|=(unsignedchar)SO;


//SO上的数据通过按位“或“运算存


}


return(x);


//将读取的数据返回


/*****************************************************

函数功能:写数据到X5045的当前地址

入口参数:dat

***************************************************/

voidWriteCurrent(unsignedchardat)

{

unsignedchari;

SCK=0;                     //SCK置于已知的低电平状态

for(i=0;i<8;i++)   //循环移入8个位

{

SI=(bit)(dat&0x80);    //通过按位“与”运算将最高位数据送到S

//因为传送时高位在前,低位在后

SCK=0;

SCK=1;                  //SCK上升沿写入数据

dat<<=1;    //y中的各二进位向左移一位,因为首先写入的是字节的最高

}

}

/*****************************************************

函数功能:写数据到第一个X5045的指定地址

入口参数:addr

***************************************************/

voidWriteSet1(unsignedchardat,unsignedcharaddr)

{

CS2=1;                     //使第二个X5045的片选无效

SCK=0;                     //SCK置于已知状态

CS1=0;                      //拉低CS,选中X5045

WriteCurrent(WREN);     //写使能锁存器允许

162/192


}


CS1=1;

CS1=0;

WriteCurrent(WRITE);

WriteCurrent(addr);

WriteCurrent(dat);

CS1=1;

SCK=0;


//拉高CS

//重新拉低CS,否则下面的写入指令将被丢弃

//写入指令

//写入指定地址

//写入数据

//拉高CS

//SCK置于已知状态


 

/*****************************************************

函数功能:写数据到第二个X5045的指定地址

入口参数:addr

***************************************************/

voidWriteSet2(unsignedchardat,unsignedcharaddr)

{

CS1=1;                     //使第一个X5045的片选无效

SCK=0;                     //SCK置于已知状态

CS2=0;                      //拉低CS,选中X5045

WriteCurrent(WREN);     //写使能锁存器允许

CS2=1;                      //拉高CS

CS2=0;                      //重新拉低CS,否则下面的写入指令将被丢弃

WriteCurrent(WRITE);    //写入指令

WriteCurrent(addr);     //写入指定地址

WriteCurrent(dat);      //写入数据

CS2=1;                      //拉高CS

SCK=0;                     //SCK置于已知状态

}

/*****************************************************

函数功能:从第一个X5045的指定地址读出数据

入口参数:addr

出口参数:dat

***************************************************/

unsignedcharReadSet1(unsignedcharaddr)

{

unsignedchardat;

CS2=1;                     //使第二个X5045的片选无效

SCK=0;                     //SCK置于已知状态

CS1=0;                      //拉低CS,选中X5045

WriteCurrent(READ);    //开始读

WriteCurrent(addr);    //写入指定地址

dat=ReadCurrent();     //读出数据

CS1=1;                     //拉高CS

SCK=0;                   //SCK置于已知状态

returndat;             //返回读出的数据

163/192


}

/*****************************************************

函数功能:从第二个X5045的指定地址读出数据

入口参数:addr

出口参数:dat

***************************************************/

unsignedcharReadSet2(unsignedcharaddr)

{

unsignedchardat;

CS1=1;                     //使第一个X5045的片选无效

SCK=0;                     //SCK置于已知状态

CS2=0;                     //拉低CS,选中X5045

WriteCurrent(READ);    //开始读

WriteCurrent(addr);    //写入指定地址

dat=ReadCurrent();     //读出数据

CS2=1;                   //拉高CS

SCK=0;                   //SCK置于已知状态

returndat;             //返回读出的数据

}

/*****************************************************

函数功能:看门狗复位程序

***************************************************/

voidWatchDog1(void)

{

CS1=1;    //拉高CS

CS1=0;    //CS引脚的一个下降沿复位看门狗定时器

CS1=1;    //拉高CS

}

/*****************************************************

函数功能:看门狗复位程序

***************************************************/

voidWatchDog2(void)

{

CS2=1;    //拉高CS

CS2=0;    //CS引脚的一个下降沿复位看门狗定时器

CS2=1;    //拉高CS

}

/*****************************************************

函数功能:主程序

***************************************************/

voidmain(void)

{

unsignedcharx;

164/192


while(1)

{

WriteSet1(0xf0,0x10);

址“0x10

delaynms(10);

x=ReadSet1(0x10);

WriteSet2(x,0x20);

delaynms(10);

P1=ReadSet2(0x20);

,送P1口显示

delaynms(100);

WatchDog1();

WatchDog2();

}

}


//将数据“0xaa”写入第一个X5045的指定地

//X5045的写入周期为约10ms

//将数据从第一个X5045中的指定地址读出来

//将数据x写入第二个X5045的指定地址“0x20

//X5045的写入周期为约10ms

//将数据从第二个X5045中的指定地址读出来

//延时100ms

//复位第一个X5045的看门狗

//复位第二个X5045的看门狗


 


//


94


ADC0832


//实例94:基于ADC0832的数字电压表

#include<reg51.h>     //包含单片机寄存器的头文件

#include<intrins.h>   //包含_nop_()函数定义的头文件

sbitCS=P3^4;         //CS位定义为P3.4引脚

sbitCLK=P1^0;       //CLK位定义为P1.0引脚

sbitDIO=P1^1;         //DIO位定义为P1.1引脚

//////////////////////////////////////////////////////////////////

unsignedcharcodedigit[10]={"0123456789"};    //定义字符数组显示数字

unsignedcharcodeStr[]={"Volt="};               //说明显示的是电压

/********************************************************************

***********

以下是对液晶模块的操作程序

*********************************************************************

**********/

sbitRS=P2^0;              //寄存器选择位,将RS位定义为P2.0引脚

sbitRW=P2^1;              //读写选择位,将RW位定义为P2.1引脚

sbitE=P2^2;               //使能信号位,将E位定义为P2.2引脚

sbitBF=P0^7;              //忙碌标志位,,将BF位定义为P0.7引脚

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

165/192


voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

bitBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;           //E恢复低电平

returnresult;

}

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);    //如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

166/192


RW=0;

E=0;

_nop_();

_nop_();

P0=dictate;

_nop_();

_nop_();

_nop_();

_nop_();

E=1;

_nop_();

_nop_();

_nop_();

_nop_();

E=0;

执行命令

}


//E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

//空操作两个机器周期,给硬件反应时间

//将数据送入P0口,即写入指令或地址

//空操作四个机器周期,给硬件反应时间

//E置高电平

//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始


 

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;             //E置高电平

_nop_();

167/192


}


_nop_();

_nop_();

_nop_();

E=0;


//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始执行命令


 

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delaynms(15);                  //延时15ms,首次写指令时应给LCD一段较

长的反应时间

WriteInstruction(0x38);      //显示模式设置:16×2显示,5×7点阵,8

数据接口

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);      //连续三次,确保初始化成功

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x0c);      //显示模式设置:显示开,无光标,光标不闪烁

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x06);      //显示模式设置:光标右移,字符不移

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x01);      //清屏幕指令,将以前的显示内容清除

delaynms(5);                //延时5ms   ,给硬件一点反应时间

}

/********************************************************************

******

以下是电压显示的说明

*********************************************************************

*****/

/*****************************************************

函数功能:显示电压符号

***************************************************/

voiddisplay_volt(void)

{

unsignedchari;

WriteAddress(0x03);     //写显示地址,将在第2行第1列开始显示

i=0;                   //从第一个字符开始显示

while(Str[i]!='\0')   //只要没有写到结束标志,就继续写

{

WriteData(Str[i]);    //将字符常量写入LCD

i++;                     //指向下一个字符

168/192


}


}


 

/*****************************************************

函数功能:显示电压的小数点

***************************************************/

void    display_dot(void)

{

WriteAddress(0x09);       //写显示地址,将在第1行第10列开始显示

WriteData('.');         //将小数点的字符常量写入LCD

}

/*****************************************************

函数功能:显示电压的单位(V)

***************************************************/

void    display_V(void)

{

WriteAddress(0x0c);//写显示地址,将在第2行第13列开始显示

WriteData('V');      //将字符常量写入LCD

}

/*****************************************************

函数功能:显示电压的整数部分

入口参数:x

***************************************************/

voiddisplay1(unsignedcharx)

{

WriteAddress(0x08);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[x]);     //将百位数字的字符常量写入LCD

}

/*****************************************************

函数功能:显示电压的小数数部分

入口参数:x

***************************************************/

voiddisplay2(unsignedcharx)

{

unsignedchari,j;

i=x/10;               //取十位(小数点后第一位)

j=x%10;               //取个位(小数点后第二位)

WriteAddress(0x0a);       //写显示地址,将在第1行第11列开始显示

WriteData(digit[i]);      //将小数部分的第一位数字字符常量写入LCD

WriteData(digit[j]);      //将小数部分的第一位数字字符常量写入LCD

169/192


}

/*****************************************************

函数功能:将模拟信号转换成数字信号

***************************************************/

unsignedchar   A_D()

{

unsignedchari,dat;

CS=1;   //一个转换周期开始

CLK=0;  //为第一个脉冲作准备

CS=0;  //CS0,片选有效

DIO=1;    //DIO1,规定的起始信号

CLK=1;   //第一个脉冲

CLK=0;   //第一个脉冲的下降沿,此前DIO必须是高电平

DIO=1;   //DIO1通道选择信号

CLK=1;   //第二个脉冲,第23个脉冲下沉之前,DI必须跟别输入两位数

据用于选择通道,这里选通道CH0

CLK=0;   //第二个脉冲下降沿

DIO=0;   //DI0,选择通道0

CLK=1;    //第三个脉冲

CLK=0;    //第三个脉冲下降沿

DIO=1;    //第三个脉冲下沉之后,输入端DIO失去作用,应置1

CLK=1;    //第四个脉冲

for(i=0;i<8;i++)   //高位在前

{

CLK=1;           //第四个脉冲

CLK=0;

dat<<=1;         //将下面储存的低位数据向右移

dat|=(unsignedchar)DIO;      //将输出数据DIO通过或运算储存在dat

低位

}

CS=1;            //片选无效

returndat;  //将读书的数据返回

}

/*****************************************************

函数功能:主函数

***************************************************/

main(void)

{

unsignedintAD_val;     //储存A/D转换后的值

unsignedcharInt,Dec;    //分别储存转换后的整数部分与小数部分

LcdInitiate();           //将液晶初始化

delaynms(5);             //延时5ms给硬件一点反应时间

display_volt();          //显示温度说明

170/192


display_dot();

display_V();

while(1)

{

AD_val=A_D();

Int=(AD_val)/51;


//显示温度的小数点

//显示温度的单位

//进行A/D转换

//计算整数部分


 


Dec=(AD_val%51)*100/51;


//计算小数部分


}


}


display1(Int);

display2(Dec);

delaynms(250);


//显示整数部分

//显示小数部分

//延时250ms


 

//实例95:用DAC0832产生锯齿波电压

#include<reg51.h>         //包含单片机寄存器的头文件

#include<absacc.h>      //包含对片外存储器地址进行操作的头文件

sbitCS=P2^7;            //CS位定义为P2.7引脚

sbitWR12=P3^6;          //WR12位定义为P3.6引脚

voidmain(void)

{

unsignedchari;

CS=0;    //输出低电平以选中DAC0832

WR12=0;  //输出低电平以选中DAC0832

while(1)

{

for(i=0;i<255;i++)

XBYTE[0x7fff]=i;      //将数据i送入片外地址07FFFH  ,实际上就是通过

P0口将数据送入DAC0832

}

}


 


//


96


P1


//实例96:用P1口显示红外遥控器的按键值

#include<reg51.h>         //包含单片机寄存器的头文件

sbitIR=P3^2;             //IR位定义为P3.2引脚

unsignedchara[4];     //储存用户码、用户反码与键数据码、键数据反码

171/192


unsignedintLowTime,HighTime;//储存高、低电平的宽度

/************************************************************

函数功能:对4个字节的用户码和键数据码进行解码

说明:解码正确,返回1,否则返回0

出口参数:dat

*************************************************************/

bitDeCode(void)

{

unsignedchar   i,j;

unsignedchartemp;     //储存解码出的数据

for(i=0;i<4;i++)        //连续读取4个用户码和键数据码

{

for(j=0;j<8;j++)   //每个码有8位数字

{

temp=temp>>1;   //temp中的各数据位右移一位,因为先读出的是

高位数据

TH0=0;           //定时器清0

TL0=0;           //定时器清0

TR0=1;           //开启定时器T0

while(IR==0)    //如果是低电平就等待

;         //低电平计时

TR0=0;           //关闭定时器T0

LowTime=TH0*256+TL0;     //保存低电平宽度

TH0=0;           //定时器清0

TL0=0;           //定时器清0

TR0=1;           //开启定时器T0

while(IR==1)    //如果是高电平就等待

;

TR0=0;          //关闭定时器T0

HighTime=TH0*256+TL0;    //保存高电平宽度

if((LowTime<370)||(LowTime>640))

return0;          //如果低电平长度不在合理范围,则认

为出错,停止解码

if((HighTime>420)&&(HighTime<620))    //如果高电平时间在560

微秒左右,即计数5601.085516

temp=temp&0x7f;         //(520-100=420,

520+100=620),则该位是0

if((HighTime>1300)&&(HighTime<1800))//如果高电平时间在1680

微秒左右,即计数16801.0851548

temp=temp|0x80;

//(1550-250=1300,1550+250=1800),则该位是1

}


 


172


/


192


}


a[i]=temp;


//将解码出的字节值储存在a[i]


}


if(a[2]=~a[3])

return1;


//验证键数据码和其反码是否相等,一般情况下不必验证用户码

//解码正确,返回1


/************************************************************

函数功能:执行遥控功能

*************************************************************/

voidFunction(void)

{

P1=a[2];   //将按键数据码送P1口显示

}

/************************************************************

函数功能:主函数

*************************************************************/

voidmain()

{

EA=1;          //开启总中断

EX0=1;         //开外中断0

ET0=1;         //定时器T0中断允许

IT0=1;         //外中断的下降沿触发

TMOD=0x01;    //使用定时器T0的模式1

TR0=0;         //定时器T0关闭

while(1)    //等待红外信号产生的中断

;

}

/************************************************************

函数功能:红外线触发的外中断处理函数

*************************************************************/

voidInt0(void)interrupt0using0

{

EX0=0;       //关闭外中断0,不再接收二次红外信号的中断,只解码当前

红外信号

TH0=0;       //定时器T0的高8位清0

TL0=0;       //定时器T0的低8位清0

TR0=1;         //开启定时器T0

while(IR==0)            //如果是低电平就等待,给引导码低电平计时

;

TR0=0;                   //关闭定时器T0

LowTime=TH0*256+TL0;   //保存低电平时间

TH0=0;       //定时器T0的高8位清0

TL0=0;       //定时器T0的低8位清0

TR0=1;         //开启定时器T0

173/192


while(IR==1)

;

TR0=0;


//如果是高电平就等待,给引导码高电平计时

//关闭定时器T0


HighTime=TH0*256+TL0;


//保存引导码的高电平长度


 

if((LowTime>7800)&&(LowTime<8800)&&(HighTime>3600)&&(HighTime<4700))

{

//如果是引导码,就开始解码,否则放弃,引导码的低电平计时

//次数=9000us/1.085=8294,判断区间:830050078008300

5008800.

if(DeCode()==1)

Function();     //如果满足条件,执行遥控功能

}

EX0=1;   //开启外中断EX0

}


 

//实例97:用红外遥控器控制继电器

#include<reg51.h>         //包含单片机寄存器的头文件

sbitIR=P3^2;             //IR位定义为P3.2引脚

unsignedchara[4];     //储存用户码、用户反码与键数据码、键数据反码

unsignedintLowTime,HighTime;//储存高、低电平的宽度

sbitRelay=P1^3;       //Relay位定义为P1.3引脚

/************************************************************

函数功能:对4个字节的用户码和键数据码进行解码

说明:解码正确,返回1,否则返回0

出口参数:dat

*************************************************************/

bitDeCode(void)

{

unsignedchar   i,j;

unsignedchartemp;     //储存解码出的数据

for(i=0;i<4;i++)        //连续读取4个用户码和键数据码

{

for(j=0;j<8;j++)   //每个码有8位数字

{

temp=temp>>1;   //temp中的各数据位右移一位,因为先读出的是

高位数据

TH0=0;           //定时器清0

TL0=0;           //定时器清0

174/192


TR0=1;

while(IR==0)

;

TR0=0;


//开启定时器T0

//如果是低电平就等待

//低电平计时

//关闭定时器T0


 


LowTime=TH0*256+TL0;


//保存低电平宽度


TH0=0;

TL0=0;

TR0=1;

while(IR==1)

;

TR0=0;


//定时器清0

//定时器清0

//开启定时器T0

//如果是高电平就等待

//关闭定时器T0


 


HighTime=TH0*256+TL0;


//保存高电平宽度


if((LowTime<370)||(LowTime>640))

return0;          //如果低电平长度不在合理范围,则认

为出错,停止解码

if((HighTime>420)&&(HighTime<620))    //如果高电平时间在560

微秒左右,即计数5601.085516

temp=temp&0x7f;         //(520-100=420,

520+100=620),则该位是0

if((HighTime>1300)&&(HighTime<1800))//如果高电平时间在1680

微秒左右,即计数16801.0851548

temp=temp|0x80;

//(1550-250=1300,1550+250=1800),则该位是1

}

a[i]=temp;   //将解码出的字节值储存在a[i]

}

if(a[2]=~a[3])   //验证键数据码和其反码是否相等,一般情况下不必验证用户码

return1;      //解码正确,返回1

}

/************************************************************

函数功能:执行遥控功能

*************************************************************/

voidFunction(void)

{

Relay=!Relay;    //P1.3引脚取反,控制继电器的吸合、释放

}

/************************************************************

函数功能:主函数

*************************************************************/

voidmain()

{

EA=1;          //开启总中断

175/192


EX0=1;

ET0=1;

IT0=1;

TMOD=0x01;

TR0=0;


//开外中断0

//定时器T0中断允许

//外中断的下降沿触发

//使用定时器T0的模式1

//定时器T0关闭


}


while(1)

;


//等待红外信号产生的中断


 

/************************************************************

函数功能:红外线触发的外中断处理函数

*************************************************************/

voidInt0(void)interrupt0using0

{

EX0=0;       //关闭外中断0,不再接收二次红外信号的中断,只解码当前

红外信号

TH0=0;       //定时器T0的高8位清0

TL0=0;       //定时器T0的低8位清0

TR0=1;         //开启定时器T0

while(IR==0)            //如果是低电平就等待,给引导码低电平计时

;

TR0=0;                   //关闭定时器T0

LowTime=TH0*256+TL0;   //保存低电平时间

TH0=0;       //定时器T0的高8位清0

TL0=0;       //定时器T0的低8位清0

TR0=1;         //开启定时器T0

while(IR==1)   //如果是高电平就等待,给引导码高电平计时

;

TR0=0;          //关闭定时器T0

HighTime=TH0*256+TL0;   //保存引导码的高电平长度

if((LowTime>7800)&&(LowTime<8800)&&(HighTime>3600)&&(HighTime<4700))

{

//如果是引导码,就开始解码,否则放弃,引导码的低电平计时

//次数=9000us/1.085=8294,判断区间:830050078008300

5008800.

if(DeCode()==1)

Function();     //如果满足条件,执行遥控功能

}

EX0=1;   //开启外中断EX0

}


 


176


/


192


//


98


DS1302


//实例98:基于DS1302的日历时钟

#include<reg51.h>      //包含单片机寄存器的头文件

#include<intrins.h>    //包含_nop_()函数定义的头文件

/********************************************************************

***

以下是DS1302芯片的操作程序

*********************************************************************

***/

unsignedcharcodedigit[10]={"0123456789"};    //定义字符数组显示数字

sbitDATA=P1^1;    //位定义1302芯片的接口,数据输出端定义在P1.1引脚

sbitRST=P1^2;     //位定义1302芯片的接口,复位端口定义在P1.1引脚

sbitSCLK=P1^0;    //位定义1302芯片的接口,时钟输出端口定义在P1.1引脚

/*****************************************************

函数功能:延时若干微秒

入口参数:n

***************************************************/

voiddelaynus(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

;

}

/*****************************************************

函数功能:向1302写一个字节数据

入口参数:x

***************************************************/

voidWrite1302(unsignedchardat)

{

unsignedchari;

SCLK=0;               //拉低SCLK,为脉冲上升沿写入数据做好准备

delaynus(2);         //稍微等待,使硬件做好准备

for(i=0;i<8;i++)        //连续写8个二进制位数据

{

DATA=dat&0x01;     //取出dat的第0位数据写入1302

delaynus(2);         //稍微等待,使硬件做好准备

SCLK=1;             //上升沿写入数据

delaynus(2);        //稍微等待,使硬件做好准备

SCLK=0;             //重新拉低SCLK,形成脉冲

dat>>=1;            //dat的各数据位右移1位,准备写入下一个数

据位

}

}

177/192


/*****************************************************

函数功能:根据命令字,向1302写一个字节数据

入口参数:Cmd,储存命令字;dat,储存待写的数据

***************************************************/

voidWriteSet1302(unsignedcharCmd,unsignedchardat)

{

RST=0;             //禁止数据传递

SCLK=0;            //确保写数居前SCLK被拉低

RST=1;             //启动数据传输

delaynus(2);      //稍微等待,使硬件做好准备

Write1302(Cmd);   //写入命令字

Write1302(dat);   //写数据

SCLK=1;            //将时钟电平置于已知状态

RST=0;             //禁止数据传递

}

/*****************************************************

函数功能:从1302读一个字节数据

入口参数:x

***************************************************/

unsignedcharRead1302(void)

{

unsignedchari,dat;

delaynus(2);         //稍微等待,使硬件做好准备

for(i=0;i<8;i++)    //连续读8个二进制位数据

{

dat>>=1;         //dat的各数据位右移1位,因为先读出的是字节的最

低位

if(DATA==1)     //如果读出的数据是1

dat|=0x80;     //1取出,写在dat的最高位

SCLK=1;         //SCLK置于高电平,为下降沿读出

delaynus(2);   //稍微等待

SCLK=0;         //拉低SCLK,形成脉冲下降沿

delaynus(2);   //稍微等待

}

returndat;          //将读出的数据返回

}

/*****************************************************

函数功能:根据命令字,从1302读取一个字节数据

入口参数:Cmd

***************************************************/

unsignedchar   ReadSet1302(unsignedcharCmd)

{

unsignedchardat;

RST=0;                     //拉低RST

178/192


}


SCLK=0;

RST=1;

Write1302(Cmd);

dat=Read1302();

SCLK=1;

RST=0;

returndat;


//确保写数居前SCLK被拉低

//启动数据传输

//写入命令字

//读出数据

//将时钟电平置于已知状态

//禁止数据传递

//将读出的数据返回


 

/*****************************************************

函数功能:1302进行初始化设置

***************************************************/

voidInit_DS1302(void)

{

WriteSet1302(0x8E,0x00);                     //根据写状态寄存器命令字,写

入不保护指令

WriteSet1302(0x80,((0/10)<<4|(0%10)));    //根据写秒寄存器命令字,写入秒

的初始值

WriteSet1302(0x82,((0/10)<<4|(0%10)));    //根据写分寄存器命令字,写入分

的初始值

WriteSet1302(0x84,((12/10)<<4|(12%10)));//根据写小时寄存器命令字,写入

小时的初始值

WriteSet1302(0x86,((16/10)<<4|(16%10)));//根据写日寄存器命令字,写入日

的初始值

WriteSet1302(0x88,((11/10)<<4|(11%10)));//根据写月寄存器命令字,写入月

的初始值

WriteSet1302(0x8c,((8/10)<<4|(8%10)));    //根据写小时寄存器命令字,写入

小时的初始值

}

/********************************************************************

***********

以下是对液晶模块的操作程序

*********************************************************************

**********/

sbitRS=P2^0;              //寄存器选择位,将RS位定义为P2.0引脚

sbitRW=P2^1;              //读写选择位,将RW位定义为P2.1引脚

sbitE=P2^2;               //使能信号位,将E位定义为P2.2引脚

sbitBF=P0^7;              //忙碌标志位,,将BF位定义为P0.7引脚

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

179/192


}


for(i=0;i<10;i++)

for(j=0;j<33;j++)

;


/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelaynms(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

bitBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

_nop_();

_nop_();   //空操作四个机器周期,给硬件反应时间

result=BF;  //将忙碌标志电平赋给result

E=0;           //E恢复低电平

returnresult;

}

/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);    //如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

180/192


_nop_();

_nop_();

P0=dictate;

_nop_();

_nop_();

_nop_();

_nop_();

E=1;

_nop_();

_nop_();

_nop_();

_nop_();

E=0;

执行命令

}


//空操作两个机器周期,给硬件反应时间

//将数据送入P0口,即写入指令或地址

//空操作四个机器周期,给硬件反应时间

//E置高电平

//空操作四个机器周期,给硬件反应时间

//E由高电平跳变成低电平时,液晶模块开始


 

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;             //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

181/192


}


E=0;


//E由高电平跳变成低电平时,液晶模块开始执行命令


/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delaynms(15);                  //延时15ms,首次写指令时应给LCD一段较

长的反应时间

WriteInstruction(0x38);      //显示模式设置:16×2显示,5×7点阵,8

数据接口

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);      //连续三次,确保初始化成功

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x0c);      //显示模式设置:显示开,无光标,光标不闪烁

delaynms(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x06);      //显示模式设置:光标右移,字符不移

delaynms(5);                   //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x01);      //清屏幕指令,将以前的显示内容清除

delaynms(5);                //延时5ms   ,给硬件一点反应时间

}

/**************************************************************

以下是1302数据的显示程序

**************************************************************/

/*****************************************************

函数功能:显示秒

入口参数:x

***************************************************/

voidDisplaySecond(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x49);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示分钟

182/192


入口参数:x

***************************************************/

voidDisplayMinute(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x46);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示小时

入口参数:x

***************************************************/

voidDisplayHour(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x43);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示日

入口参数:x

***************************************************/

voidDisplayDay(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x0c);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示月

入口参数:x

***************************************************/

183/192


voidDisplayMonth(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x09);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:显示年

入口参数:x

***************************************************/

voidDisplayYear(unsignedcharx)

{

unsignedchari,j;      //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x06);     //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]);     //将百位数字的字符常量写入LCD

WriteData(digit[j]);     //将十位数字的字符常量写入LCD

delaynms(50);           //延时1ms给硬件一点反应时间

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedcharsecond,minute,hour,day,month,year;       //分别储存苗、分、小

时,日,月,年

unsignedcharReadValue;    //储存从1302读取的数据

LcdInitiate();                //将液晶初始化

WriteAddress(0x01);   //Date的显示地址,将在第1行第2列开始显示

WriteData('D');       //将字符常量写入LCD

WriteData('a');        //将字符常量写入LCD

WriteData('t');       //将字符常量写入LCD

WriteData('e');       //将字符常量写入LCD

WriteData(':');       //将字符常量写入LCD

WriteAddress(0x08);   //写年月分隔符的显示地址,显示在第1行第9

WriteData('-');       //将字符常量写入LCD

WriteAddress(0x0b);   //写月日分隔符的显示地址,显示在第1行第12

WriteData('-');       //将字符常量写入LCD

184/192


WriteAddress(0x45);

WriteData(':');


//写小时与分钟分隔符的显示地址,

//将字符常量写入LCD


显示在第2行第6


WriteAddress(0x48);

WriteData(':');

Init_DS1302();

while(1)

{


//写分钟与秒分隔符的显示地址,

//将字符常量写入LCD

//1302初始化


显示在第2行第9


ReadValue=ReadSet1302(0x81);


//从秒寄存器读数据


 


}


second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplaySecond(second);            //显示秒

ReadValue=ReadSet1302(0x83);   //从分寄存器读

minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplayMinute(minute);             //显示分

ReadValue=ReadSet1302(0x85);   //从分寄存器读

hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplayHour(hour);                //显示小时

ReadValue=ReadSet1302(0x87);   //从分寄存器读

day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplayDay(day);                   //显示日

ReadValue=ReadSet1302(0x89);   //从分寄存器读

month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplayMonth(month);               //显示月

ReadValue=ReadSet1302(0x8d);   //从分寄存器读

year=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//将读出数据转化

DisplayYear(year);                 //显示年

}


 


//


99


#include<reg51.h>


//实例99:单片机数据发送程序

//包含单片机寄存器的头文件


 

/*****************************************************

函数功能:向PC发送一个字节数据

***************************************************/

voidSend(unsignedchardat)

{

SBUF=dat;

while(TI==0)

;

TI=0;

}

185/192


/*****************************************************

函数功能:延时1ms

(3j+2)i=(3×33+2)  ×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

***************************************************/

voiddelaynms(unsignedcharx)

{

unsignedchari;

for(i=0;i<x;i++)

delay1ms();

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

unsignedchari;

TMOD=0x20;  //定时器T1工作于方式2

TH1=0xfd;   //根据规定给定时器T1赋初值

TL1=0xfd;   //根据规定给定时器T1赋初值

PCON=0x00;  //波特率9600

TR1=1;       //启动定时器t1

SCON=0x40;  //串口工作方式1

while(1)

{

for(i=0;i<200;i++)    //模拟检测数据

{

Send(i);          //发送数据i

delaynms(100);    //100ms发送一次检测数据

}

}

}


 


//


100


//实例100:电机转速表设计

186/192


#include<reg51.h>

#include<intrins.h>


//包含单片机寄存器的头文件

//包含_nop_()函数定义的头文件


sbitRS=P2^0;

sbitRW=P2^1;

sbitE=P2^2;

sbitBF=P0^7;


//寄存器选择位,将RS位定义为P2.0引脚

//读写选择位,将RW位定义为P2.1引脚

//使能信号位,将E位定义为P2.2引脚

//忙碌标志位,,将BF位定义为P0.7引脚


 

unsignedcharcodedigit[]={"0123456789"};//定义字符数组显示数字

unsignedintv;    //储存电机转速

unsignedcharcount;   //储存定时器T0中断次数

bitflag;       //计满1秒钟标志位

/*****************************************************

函数功能:延时1ms

(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

***************************************************/

voiddelay1ms()

{

unsignedchari,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/*****************************************************

函数功能:延时若干毫秒

入口参数:n

***************************************************/

voiddelay(unsignedcharn)

{

unsignedchari;

for(i=0;i<n;i++)

delay1ms();

}

/*****************************************************

函数功能:判断液晶模块的忙碌状态

返回值:resultresult=1,忙碌;result=0,不忙

***************************************************/

unsignedcharBusyTest(void)

{

bitresult;

RS=0;         //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1;          //E=1,才允许读写

_nop_();   //空操作

_nop_();

187/192


}


_nop_();

_nop_();

result=BF;

E=0;

returnresult;


//空操作四个机器周期,给硬件反应时间

//将忙碌标志电平赋给result

//E恢复低电平


/*****************************************************

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

***************************************************/

voidWriteInstruction(unsignedchardictate)

{

while(BusyTest()==1);//如果忙就等待

RS=0;                      //根据规定,RSR/W同时为低电平时,可以写

入指令

RW=0;

E=0;                       //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

_nop_();

_nop_();                //空操作两个机器周期,给硬件反应时间

P0=dictate;               //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=1;                       //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();                  //空操作四个机器周期,给硬件反应时间

E=0;                      //E由高电平跳变成低电平时,液晶模块开始

执行命令

}

/*****************************************************

函数功能:指定字符显示的实际地址

入口参数:x

***************************************************/

voidWriteAddress(unsignedcharx)

{

WriteInstruction(x|0x80);//显示位置的确定方法规定为"80H+地址码x"

}

/*****************************************************

函数功能:将数据(字符的标准ASCII)写入液晶模块

入口参数:y(为字符常量)

188/192


***************************************************/

voidWriteData(unsignedchary)

{

while(BusyTest()==1);

RS=1;             //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0;               //E置低电平(根据表8-6,写指令时,E为高脉冲,

//  就是让E01发生正跳变,所以应先置"0"

P0=y;             //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_();         //空操作四个机器周期,给硬件反应时间

E=1;            //E置高电平

_nop_();

_nop_();

_nop_();

_nop_();          //空操作四个机器周期,给硬件反应时间

E=0;               //E由高电平跳变成低电平时,液晶模块开始执行命令

}

/*****************************************************

函数功能:对LCD的显示模式进行初始化设置

***************************************************/

voidLcdInitiate(void)

{

delay(15);                //延时15ms,首次写指令时应给LCD一段较长的反

应时间

WriteInstruction(0x38);   //显示模式设置:16×2显示,5×7点阵,8位数据

接口

delay(5);                  //延时5ms   ,给硬件一点反应时间

WriteInstruction(0x38);

delay(5);

WriteInstruction(0x38);//连续三次,确保初始化成功

delay(5);

WriteInstruction(0x0c);   //显示模式设置:显示开,无光标,光标不闪烁

delay(5);

WriteInstruction(0x06);   //显示模式设置:光标右移,字符不移

delay(5);

WriteInstruction(0x01);   //清屏幕指令,将以前的显示内容清除

delay(5);

}

/********************************************************************

**********

189/192


函数功能:显示速度提示符

*********************************************************************

*********/

voiddisplay_sym(void)

{

WriteAddress(0x00);   //写显示地址,将在第1行第1列开始显示

WriteData('v');       //将字符常量v写入LCD

WriteData('=');       //将字符常量=写入LCD

}

/********************************************************************

**********

函数功能:显示速度数值

*********************************************************************

*********/

voiddisplay_val(unsignedintx)

{

unsignedchari,j,k,l;      //j,k,l分别储存温度的百位、十位和个位

i=x/1000;           //取千位

j=(x%1000)/100;    //取百位

k=(x%100)/10;      //取十位

l=x%10;             //取个位

WriteAddress(0x02);      //写显示地址,将在第1行第3列开始显示

WriteData(digit[i]);     //将千位数字的字符常量写入LCD

WriteData(digit[j]);     //将百位数字的字符常量写入LCD

WriteData(digit[k]);     //将十位数字的字符常量写入LCD

WriteData(digit[l]);     //将个位数字的字符常量写入LCD

}

/*******************************************************

函数功能:显示速度单位“r/min

********************************************************/

voiddisplay_unit(void)

{

WriteAddress(0x06);     //写显示地址,将在第2行第7列开始显示

WriteData('r');     //将字符常量r写入LCD

WriteData('/');     //将字符常量/写入LCD

WriteData('m');     //将字符常量m写入LCD

WriteData('i');     //将字符常量i写入LCD

WriteData('n');     //将字符常量n写入LCD

}

/*******************************************************

函数功能:主函数

190/192


********************************************************/

voidmain(void)

{

LcdInitiate();               //调用LCD初始化函数

TMOD=0x51;                    //定时器T1工作于计数模式1,定时器T0

作于计时模式1

TH0=(65536-46083)/256;     //定时器T0的高8位设置初值,每50ms产生一

次中断

TL0=(65536-46083)%256;     //定时器T0的低8位设置初值,每50ms产生

一次中断

EA=1;                          //开总中断

ET0=1;                        //定时器T0中断允许

TR0=1;                        //启动定时器T0

count=0;                      //T0中断次数初始化为0

display_sym();               //显示速度提示符

display_val(0000);           //显示器工作正常标志

display_unit();               //显示速度单位

while(1)                     //无限循环

{

TR1=1;               //定时器T1启动

TH1=0;               //定时器T18位赋初值0

TL1=0;               //定时器T18位赋初值0

flag=0;              //时间还未满1分钟

while(flag==0)     //时间未满等待

;

v=(TH1*256+TL1)*60/16;//计算速度,每周产生16个脉冲

display_val(v);          //显示速度

}

}

/*******************************************************

函数功能:定时器T0的中断服务函数

********************************************************/

voidTime0(void)interrupt1using1//定时器T0的中断编号为1,使用第1组工作

寄存器

{

count++;            //T0每中断1次,count1

if(count==20)      //若累计满20次,即计满1秒钟

{

flag=1;          //计满1秒钟标志位置1

count=0;         //0,重新统计中断次数

}

TH0=(65536-46083)/256;    //定时器T08位重新赋初值

TL0=(65536-46083)%256;    //定时器T08位重新赋初值

}

191/192


#include<reg51.h>


//模拟霍尔脉冲


sbitcp=P3^2;


//cp位定义为P3.2引脚,从此脚输出脉冲信号


 

/*****************************************************

函数功能:延时约600微秒

***************************************************/

voiddelay()

{

unsignedchari;

for(i=0;i<200;i++)

;

}

/*****************************************************

函数功能:主函数

***************************************************/

voidmain(void)

{

while(1)

{

cp=1;     //置高电平

delay();  //等待600微秒

cp=0;     //置低电平

delay();   //等待600微秒

}

}


 


192


/


192

猜你喜欢

转载自blog.csdn.net/whitenebula/article/details/79927374