目录
目录................................................................................................................................1
函数的使用和熟悉********************************/.......................................4
实例3:用单片机控制第一个灯亮.............................................................................4
实例4:用单片机控制一个灯闪烁:认识单片机的工作频率.................................4
实例5:将P1口状态分别送入P0、P2、P3口:认识I/O口的引脚功能............5
实例6:使用P3口流水点亮8位LED.......................................................................5
实例7:通过对P3口地址的操作流水点亮8位LED...............................................6
实例8:用不同数据类型控制灯闪烁时间.................................................................7
实例9:用P0口、P1口分别显示加法和减法运算结果.........................................8
实例10:用P0、P1口显示乘法运算结果................................................................9
实例11:用P1、P0口显示除法运算结果................................................................9
实例12:用自增运算控制P0口8位LED流水花样..............................................10
实例13:用P0口显示逻辑"与"运算结果...............................................................10
实例14:用P0口显示条件运算结果.......................................................................11
实例15:用P0口显示按位"异或"运算结果...........................................................11
实例16:用P0显示左移运算结果...........................................................................11
实例17:"万能逻辑电路"实验.................................................................................11
实例18:用右移运算流水点亮P1口8位LED.......................................................12
实例19:用if语句控制P0口8位LED的流水方向..............................................13
实例20:用swtich语句的控制P0口8位LED的点亮状态..................................13
实例21:用for语句控制蜂鸣器鸣笛次数..............................................................14
实例22:用while语句控制LED...............................................................................16
实例23:用do-while语句控制P0口8位LED流水点亮......................................16
实例24:用字符型数组控制P0口8位LED流水点亮..........................................17
实例25:用P0口显示字符串常量.........................................................................18
实例26:用P0口显示指针运算结果......................................................................19
实例27:用指针数组控制P0口8位LED流水点亮..............................................19
实例28:用数组的指针控制P0口8位LED流水点亮........................................20
实例29:用P0、P1口显示整型函数返回值........................................................21
实例30:用有参函数控制P0口8位LED流水速度..............................................22
实例31:用数组作函数参数控制流水花样.............................................................23
实例32:用指针作函数参数控制P0口8位LED流水点亮..................................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查询方式P2口8位控制LED闪烁....................................31
实例43:用定时器T1查询方式控制单片机发出1KHz音频.................................31
实例44:将计数器T0计数的结果送P1口8位LED显示....................................32
实例45:用定时器T0的中断控制1位LED闪烁...................................................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
实例71:CPU控制的独立式键盘扫描实验.............................................................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
实例90:DS18B20温度检测及其液晶显示...........................................................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=11111110B,P1.0输出低电平
delay(); //延时一段时间
P1=0xff; //P1=11111111B,P1.0输出高电平
delay(); //延时一段时间
}
}
4/192
//
5
P1
P0
P2
P3
I/O
//实例5:将
#include<reg51.h>
P1口状态分别送入P0、P2、P3口:认识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口流水点亮8位LED
#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口地址的操作流水点亮8位LED
#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.3、P1.4、P1.7
口的灯被点亮
}
P0=n-m;
//P0=17=00010001B,结果P0.0、P0.4的灯被熄灭
//实例10:用P0、P1口显示乘法运算结果
#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
//因此,高8位16进制数H3*16+H2必然等于17,即4544
除以256的商
//低8位16进制数H1*16+H0必然等于192,即4544除以
256的余数
P1=s/256; //高8位送P1口,P1=17=11H=00010001B,P1.0和P1.4口灭,
其余亮
P0=s%256; //低8位送P0口,P3=192=c0H=11000000B,P3.1,P3.6,P3.7口
灭,其余亮
}
//实例11:用P1、P0口显示除法运算结果
#include<reg51.h> //包含单片机寄存器的头文件
voidmain(void)
{
P1=36/5; //求整数
P0=((36%5)*10)/5;//求小数
while(1)
9/192
}
;
//无限循环防止程序“跑飞”
//实例12:用自增运算控制P0口8位LED流水花样
#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:用右移运算流水点亮P1口8位LED
#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语句控制P0口8位LED的流水方向
#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语句的控制P0口8位LED的点亮状态
#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小于0xff(255)时执行循环体
{
P0=i; //将i送P0口显示
delay60ms();//延时
i++; //i自增1
}
}
}
//实例23:用do-whiile语句控制P0口8位LED流水点亮
#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); //无限循环,使8位LED循环流水点亮
}
//实例24:用字符型数组控制P0口8位LED流水点亮
#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.3、P0.5引脚LED熄灭,其余点亮
while(1)
; //无限循环,防止程序“跑飞”
//
27
P0
8
LED
//实例27:用指针数组控制P0口8位LED流水点亮
#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:用有参函数控制P0口8位LED流水速度
#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++)
;
}
/*************************************************
函数功能:流水点亮P0口8位LED
*************************************************/
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:用指针作函数参数控制P0口8位LED流水点亮
#include<reg51.h>
223/192
/*************************************************
函数功能:延时约150ms
*************************************************/
voiddelay(void)
{
unsignedcharm,n;
for(m=0;m<200;m++)
for(n=0;n<250;n++)
;
}
/*************************************************
函数功能:流水点亮P0口8位LED
*************************************************/
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++)
;
}
/**************************************************************
函数功能:流水点亮P0口8位LED
**************************************************************/
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;
//带参数的宏定义,a和b为形参
参
}
P3=F(i,j+k);
while(1)
;
//i和j+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查询方式P2口8位控制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计数的结果送P1口8位LED显示
#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;//计数器TL0加1后送P1口显示
//计数器溢出后,将TF0清0
//实例45:用定时器T0的中断控制1位LED闪烁
#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; //将Countor清0,重新从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; //将Countor1清0,重新从0开始计数
}
if(Countor2==8) //若累计满8次,即计时满400ms
{
D2=~D2; //按位取反操作,将P2.1引脚输出电平取反
Countor2=0; //将Countor1清0,重新从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的模式1(13位计数器)
while(1) //无限循环
{
i=0; //从第1个音符f[0]开始播放
while(f[i]!=0xff) //只要没有读到结束标志就继续播放
{
C=460830/f[i];
TH0=(8192-C)/32; //可证明这是13位计数器TH0高8位的赋
初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初
值方法
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位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
}
//
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; //计数器T0高8位赋初值
TL0=0; //计数器T0低8位赋初值
while(1) //无限循环,不停地将TL0计数结果送P1口
P1=TL0;
}
//实例51-2:定时器T0的模式2测量正脉冲宽度
#include<reg51.h> //包含51单片机寄存器定义的头文件
sbitui=P3^2; //将ui位定义为P3.0(INT0)引脚,表示输入电压
/*******************************************
函数功能:主函数
******************************************/
voidmain(void)
{
TMOD=0x0a; //TMOD=00001010B,使用定时器T0的模式2,GATE置1
EA=1; //开总中断
440/192
ET0=0;
TR0=1;
TH0=0;
TL0=0;
while(1)
{
while(ui==0)
;
TL0=0;
//不使用定时器T0的中断
//启动T0
//计数器T0高8位赋初值
//计数器T0低8位赋初值
//无限循环,不停地将TL0计数结果送P1口
//INT0为低电平,T0不能启动
//INT0为高电平,启动T0计时,所以将TL0清0
}
}
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信号,对74LS164清0
_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; //为了接收下一帧数据,需将RI清0
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,
//SM2置0,不使用多机通信,TB8置0
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; //为了接收下一帧数据,需将RI清0
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; //为了接收下一帧数据,需将RI清0
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};
//数码管显示0~9的段码表,程序运行中当数组值不发生变化
时,
//前面加关键字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};
//数码管显示0~9的段码表
/********************************************************************
***
函数功能:快速动态扫描延时,延时约0.9毫秒
*********************************************************************
***/
voiddelay(void)
{
unsignedinti;
for(i=0;i<300;i++)
;
}
/********************************************************************
***
函数功能:4位数的数码显示器显示
入口参数:k
出口参数:无
*********************************************************************
***/
voiddisplay(unsignedintk)
{
P2=0xfe; //即P2=11111110B,P2.0引脚输出低电平,数码显示器DS0接
通电源
P0=Tab[k/1000]; //显示千位
delay();
P2=0xfd; //即P2=11111101B,P2.1引脚输出低电平,数码显示器DS1接通
电源
P0=Tab[(k%1000)/100]; //显示百位
delay();
P2=0xfb; //即P2=11111011B,P2.2引脚输出低电平,数码显示器DS2接通
电源
P0=Tab[(k%100)/10]; //显示十位
delay();
P2=0xf7; //即P2=11110111B,P2.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; //随机产生一个从0到32767的整数,再将其除以10,
获得一个随机4位数,模拟检测结果
i=0; //将i清0,重新统计中断次数
}
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};
//数码管显示0~9的段码表
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引脚取反
//实例71:CPU控制的独立式键盘扫描实验
#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; //关闭8个LED
}
/*************************************************
函数功能:闪烁点亮LED
**************************************************/
voidflash(void)
{
P3=0xff; //关闭8个LED
led_delay();
P3=0x00; //点亮8个LED
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; //位定义S1为P1.4
sbitS2=P1^5; //位定义S2为P1.5
sbitS3=P1^6; //位定义S3为P1.6
sbitS4=P1^7; //位定义S4为P1.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; //位定义S1为P1.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位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
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的模式1,T0的模式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位计数器TH0高8位的赋初值
方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方
法
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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置
"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置
"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置
"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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;
//定时器T0高8位重新赋初值
//定时器T0低8位重新赋初值
/********************************************************
***********一些芯片的使用*****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
*********************************************************************
***********/
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置
"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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的模式1(13位计数器)
//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位计数器TH0高8
//可证明这是13位计数器TL0低5
//启动定时器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位计数器TH0高8位的赋初值方法
TL0=(8192-C)%32; //可证明这是13位计数器TL0低5位的赋初值方法
sound=!sound; //将P3.7引脚输出电平取反,形成方波
}
//
90
DS18B20
//实例90:DS18B20温度检测及其液晶显示
#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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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~60us让DS18B20输出存在脉冲)
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++)
;//延时约30us,DS18B20在拉低后的约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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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; //CS置0,片选有效
DIO=1; //DIO置1,规定的起始信号
CLK=1; //第一个脉冲
CLK=0; //第一个脉冲的下降沿,此前DIO必须是高电平
DIO=1; //DIO置1,通道选择信号
CLK=1; //第二个脉冲,第2、3个脉冲下沉之前,DI必须跟别输入两位数
据用于选择通道,这里选通道CH0
CLK=0; //第二个脉冲下降沿
DIO=0; //DI置0,选择通道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
微秒左右,即计数560/1.085=516次
temp=temp&0x7f; //(520-100=420,
520+100=620),则该位是0
if((HighTime>1300)&&(HighTime<1800))//如果高电平时间在1680
微秒左右,即计数1680/1.085=1548次
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,判断区间:8300-500=7800,8300+
500=8800.
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
微秒左右,即计数560/1.085=516次
temp=temp&0x7f; //(520-100=420,
520+100=620),则该位是0
if((HighTime>1300)&&(HighTime<1800))//如果高电平时间在1680
微秒左右,即计数1680/1.085=1548次
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,判断区间:8300-500=7800,8300+
500=8800.
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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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();
}
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=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; //根据规定,RS和R/W同时为低电平时,可以写
入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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为高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"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; //定时器T1高8位赋初值0
TL1=0; //定时器T1低8位赋初值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次,count加1
if(count==20) //若累计满20次,即计满1秒钟
{
flag=1; //计满1秒钟标志位置1
count=0; //清0,重新统计中断次数
}
TH0=(65536-46083)/256; //定时器T0高8位重新赋初值
TL0=(65536-46083)%256; //定时器T0低8位重新赋初值
}
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