目录
目录............................................................................................................................... 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 { P1=0xfe;//P1=1111 1110B,即 P1.0 输出低电平 } // 4 //实例 4:用单片机控制一个灯闪烁:认识单片机的工作频率 #include *****************************************/ 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:将 P1 口状态分别送入 P0、P2、P3 口:认识 I/O 口 的引脚功能 #include /******************************************************* 函数功能:主函数 (C 语言规定必须有也只能有 1 个主函数) ********************************************************/ voidmain(void) { while(1) { P1=0xff; P0=P1; P2=P1; P3=P1; } } //无限循环 // P1=11111111B,熄灭 LED // 将 P1 口状态送入 P0 口 // 将 P1 口状态送入 P2 口 // 将 P1 口状态送入 P3 口 //实例 6:使用 P3 口流水点亮 8 位 LED #include *****************************************/ voiddelay(void) { unsignedchar i,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 sfrx=0xb0; //P3 口在存储器中的地址是 b0H, 通过 sfr 可定义 8051 内核单片 机 //的所有内部 8 位特殊功能寄存器,对地址 x 的操作也就是对 P1 口的 操作 /**************************************** 函数功能:延时一段时间 *****************************************/ voiddelay(void) { unsignedchar i,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 ******************************************************/ voidint_delay(void) //延时一段较长的时间 { unsignedintm; //定义无符号整形变量,双字节数据,值域为 0~65535 for(m=0;m<36000;m++) ; //空操作 } /****************************************************** 函数功能:用字符型数据延时一段时间 ******************************************************/ 7/ 192 . . voidchar_delay(void) //延时一段较短的时间 { unsignedchar i,j; //定义无符号字符型变量,单字节数据,值域 0~255 for(i=0;i<200;i++) for(j=0;j<180;j++) ; //空操作 } /****************************************************** 函数功能:主函数 ******************************************************/ voidmain(void) { unsignedchar i; 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 unsignedcharm,n; m=43; // 即 十 进 制数 2x16+11=43 8/ . 192 . } n=60; //即十进制数 3x16+12=60 P1=m+n; //P1=103=0110 0111B,结果 P1.3、P1.4、P1.7 口的灯被点亮 P0=n-m; //P0=17=00010001B,结果 P0.0、P0.4 的灯被熄灭 //实例 10:用 P0、P1 口显示乘法运算结果 #include 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; 其余亮 P0=s%256; 灭,其余亮 } //高 8 位送 P1 口 ,P1=17=11H=00010001B, P1.0 和 P1.4 口灭, //低 8 位送 P0 口 ,P3=192=c0H=1100 0000B,P3.1,P3.6,P3.7 口 //实例 11:用 P1、P0 口显示除法运算结果 #include P1=36/5; //求整数 P0=((36%5)*10)/5; //求小数 while(1) 9/ 192 . . ; } //无限循环防止程序“跑飞” //实例 12:用自增运算控制 P0 口 8 位 LED 流水花样 #include ******************************************************/ voiddelay(void) { unsignedinti; for(i=0;i<20000;i++) ; } /****************************************************** 函数功能 :主函数 ******************************************************/ voidmain(void) { unsignedchar i; for(i=0;i<255;i++) //注意 i 的值不能超过 255 { P0=i; //将 i 的值送 P0 口 delay();//调用延时函数 } } //实例 13:用 P0 口显示逻辑\"与\"运算结果 #include P0=(4>0)&&(9>0xab);//将逻辑运算结果送 P0 口 while(1) ; //设置无限循环,防止程序“跑飞” } 110/ 192 . . // 14 P0 //实例 14:用 P0 口显示条件运算结果 #include P0=(8>4)?8:4;//将条件运算结果送 P0 口,P0=8=00001000B while(1) ; //设置无限循环,防止程序“跑飞” } //实例 15:用 P0 口显示按位\"异或\"运算结果 #include P0=0xa2^0x3c;//将条件运算结果送 P0 口,P0=8=00001000B while(1) ; //设置无限循环,防止程序“跑飞” } // 16 P0 //实例 16:用 P0 显示左移运算结果 #include P0=0x3b<<2;//将左移运算结果送 P0 口,P0=11101100B=0xec while(1) ; //无限循环,防止程序“跑飞” } //实例 17:\"万能逻辑电路\"实验 #include . . 1 1 1 / 1 9 2 . . sbitX=P1^5; //将 X 位定义为 P1.5 sbitY=P1^6; //将 Y 位定义为 P1.6 sbitZ=P1^7; //将 Z 位定义为 P1.7 voidmain(void) { while(1) { F=((~X)&Y)|Z; //将逻辑运算结果赋给 F ; } } //实例 18:用右移运算流水点亮 P1 口 8 位 LED #include *****************************/ voiddelay(void) { unsignedintn; for(n=0;n<30000;n++) ; } /***************************** 函数功能:主函数 *****************************/ voidmain(void) { unsignedchar i; 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 *****************************/ 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 *****************************/ voiddelay(void) { unsignedintn; for(n=0;n<10000;n++) ; } /***************************** 函数功能:主函数 *****************************/ voidmain(void) { unsignedchar i; 113/ 192 . . i=0; //将 i 初始化为 0 while(1) { if(S1==0) //如果 S1 键按下 { delay(); //延时一段时间 if(S1==0)//如果再次检测到 S1 键按下 i++; //i 自增 1 if(i==9) //如果 i=9,重新将其置为 1 i=1; } switch(i ) { //使用多分支选择语句 case 1:P0=0xfe; //第一个 LED 亮 break; case 2:P0=0xfd; //第二个 LED 亮 break; case 3:P0=0xfb; //第三个 LED 亮 break; case 4:P0=0xf7; //第四个 LED 亮 break; case 5:P0=0xef; //第五个 LED 亮 break; case 6:P0=0xdf; //第六个 LED 亮 break; case 7:P0=0xbf; //第七个 LED 亮 break; case 8:P0=0x7f; //第八个 LED 亮 break; default: //缺省值,关闭所有 LED P0=0xff; } } } // 21 for //实例 21:用 for 语句控制蜂鸣器鸣笛次数 #include 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(); } } } 11 / 192 5 . . //实例 22:用 whille 语句控制 LED #include 函数功能:延时约 60ms (3*100*200=60000μ s) ****************************************/ voiddelay60ms(void) { unsignedcharm,n; for(m=0;m<100;m++) for(n=0;n<200;n++) ; } /**************************************** 函数功能:主函数 ****************************************/ voidmain(void) { unsignedchar i; 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 函数功能:延时约 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 函数功能:延时约 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) { unsignedchar i; unsignedchar code Tab[]={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 函数功能:延时约 150ms (3*200*250=150 000μ s=150ms *************************************************/ voiddelay150ms(void) { unsignedcharm,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; } /************************************************* 函数功能:主函数 *************************************************/ voidmain(void) { unsignedcharstr[]={\"Now,Temperature is:\ //将字符串赋给字符型全部元素 赋值 unsignedchar i; 118/ 192 . . } while(1) { i=0; //将 i 初始化为 0,从第一个元素开始显示 while(str[i]!='\\0') //只要没有显示到结束标志'\\0' { P0=str[i]; //将第 i 个字符送到 P0 口显示 delay150ms(); //调用 150ms 延时函数 i++; //指向下一个待显字符 } } //实例 26:用 P0 口显示指针运算结果 #include unsignedchar*p1,*p2; //定义无符号字符型指针变量 p1,p2 unsignedchar i,j; //定义无符号字符型数据 i=25; //给 i 赋初值 25 j=15; p1=&i //使指针变量指向 i ,对指针初始化 ; //使指针变量指向 j ,对指针初始化 p2=&j ; P0=*p1+*p2; //*p1+*p2 相当于 i+j,所以 P0=25+15=40=0x28 //则 P0=0010 1000B,结果 P0.3、P0.5 引脚 LED 熄灭,其余点亮 while(1) ; //无限循环,防止程序“跑飞” } // 27 P0 8 LED //实例 27:用指针数组控制 P0 口 8 位 LED 流水点亮 #include /************************************************* 函数功能:延时约 150ms (3*200*250=150 000μ s=150ms *************************************************/ voiddelay150ms(void) { unsignedcharm,n; for(m=0;m<200;m++) . . 119/ 192 . . for(n=0;n<250;n++) ; } /************************************************* 函数功能:主函数 *************************************************/ voidmain(void) { unsignedchar code Tab[]={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]}; unsignedchar i; //定义无符号字符型数据 while(1) { for(i=0;i<8;i++) { P0=*p[i]; delay150ms(); } } } // 28 P0 8 LED //实例 28:用数组的指针控制 P0 口 8 位 LED 流水点亮 #include /************************************************* 函数功能:延时约 150ms (3*200*250=150 000μ s=150ms *************************************************/ voiddelay150ms(void) { unsignedcharm,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; } /************************************************* 函数功能:主函数 *************************************************/ voidmain(void) { . 220/ 192 . unsignedchar i; 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 、P1 口显示整型函数返回值 #include /************************************************* 函数功能:计算两个无符号整数的和 *************************************************/ unsignedintsum(inta,int b) { 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 /************************************************* 函数功能:延时一段时间 *************************************************/ voiddelay(unsigned charx) { unsignedcharm,n; for(m=0;m ; } /************************************************* 函数功能:主函数 *************************************************/ voidmain(void) { unsignedchar i; 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=60 000μ s) } //慢速流水点亮 LED for(i=0;i<8;i++) //共 8 个流水灯控制码 { P0=Tab[i]; delay(250); //延时约 150ms,(3*250*200=150000μ s) } } } 22 / 192 2 . . // 31 //实例 31:用数组作函数参数控制流水花样 #include /************************************************* 函数功能:延时约 150ms *************************************************/ voiddelay(void) { unsignedcharm,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; } /************************************************* 函数功能:流水点亮 P0 口 8 位 LED *************************************************/ voidled_flow(unsigned char a[8]) { unsignedchar i; 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 . . 223/ 192 . . /************************************************* 函数功能:延时约 150ms *************************************************/ voiddelay(void) { unsignedcharm,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; } /************************************************* 函数功能:流水点亮 P0 口 8 位 LED *************************************************/ voidled_flow(unsigned char *p) //形参为无符号字符型指针 { unsignedchar i; 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 unsignedchar code Tab[]={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) { unsignedchar i; 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 unsignedchar code str1[ ]=\"Temperature is testedbyDS18B20\";//C 语言中,字符串 是作为字符数组来处理的 unsignedchar code str2[ ]=\"Nowtemperatureis:\"; //所以,字符串的名字就是 字符串的首地址 unsignedchar code str3[ ]=\"The Systerm is designedbyZhangSan\"; unsignedchar code str4[ ]=\"The dateis2008-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[]) //形参必须为指针数组 { unsignedchar i,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) { unsignedchar i; while(1) { for(i=0;i<4;i++) led_display(p);//将指针数组名作实际参数传递 } } //实例 35:字符函数 ctype.h 应用举例 #include while(1) { P3=isalpha('_')?0xf0:0x0f;//条件运算,若'_'是英文字母,P3=0xf0 } } //实例 36:内部函数 intrins..h 应用举例 #include *************************************************/ 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 *************************************************/ voiddelay(void) { unsignedcharm,n; for(m=0;m<200;m++) for(n=0;n<250;n++) ; } /************************************************* 函数功能:主函数 *************************************************/ voidmain(void) { unsignedchar i; while(1) { for(i=0;i<10;i++) //产生 10 个随机数 { P3=rand()/160;//将产生的随机数缩小 160 倍后送 P3 显示 delay(); } } 228/ 192 . . } //实例 38:字符串函数 striing.h 应用举例 #include unsignedcharstr1[ ]=\"Now, The temperature is :\"; unsignedcharstr2[ ]=\"Now, The temperature is 36Centgrade:\"; unsignedchar i; i=strcmp(str1,str2); //比较两个字符串,并将结果存入 i if(i==0) //str1=str2 P3=0x00; else if(i<0) //str1 P3=0x0f; while(1) ; //防止程序“跑飞” } // 39 2 //实例 39:宏定义应用举例 2 #include unsignedchar i,j,k; i=40; j=30; k=20; P3=F(i,j+k); //i 和 j+k 分别为实参,宏展开时,实参将替代宏定义中的形 参 while(1) ; } 229/ 192 . . //实例 40:宏定义应用举例 2 #include 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 #defineMAX 100//将 MAX 宏定义为字符串 100 voidmain(void) { //如果字符串 100 大于 80 #if MAX>80 //P3 口低四位 LED 点亮 P3=0xf0; #else //否则,P3 口高四位 LED 点亮 P3=0x0f; //结束本次编译 #endif } 33 / . 0 . 192 . . /******************************************************** ******* **中断、定 时器********中 断、定时器************ *********中断、定时器*********中断、定时 器******** **** ********************************************************/ //实例 42:用定时器 T0 查询方式 P2 口 8 位控制 LED 闪烁 #include **************************************************************/ 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 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 /************************************************************** 函数功能:主函数 **************************************************************/ 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 P1=TL0; //计数器 TL0 加 1 后送 P1 口显示 } TF0=0; //计数器溢出后,将 TF0 清 0 } } //实例 45:用定时器 T0 的中断控制 1 位 LED 闪烁 #include /************************************************************** 函数功能:主函数 **************************************************************/ 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) interrupt 1using0//“interrupt”声明函数为中断服务函数 //其后的 1 为定时器 T0 的中断编号;0 表示使用第 0 组工作 寄存器 { D1=~D1; //按位取反操作,将 P2.0 引脚输出电平取反 TH0=(65536-46083)/256; //定时器 T0 的高 8 位重新赋初值 TL0=(65536-46083)%256; //定时器 T0 的高 8 位重新赋初值 } 33 / 192 3 . . // 46 T0 //实例 46:用定时器 T0 的中断实现长时间定时 #include 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) interrupt 1using0//“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 . 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) interrupt 3using0//“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 位重新赋初值 } 33 / 192 5 . . // 48 T1 1KHz //实例 48:用计数器 T1 的中断控制蜂鸣器发出 1KHz 音频 #include /************************************************************** 函数功能:主函数 **************************************************************/ 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) interrupt 3using0//“interrupt”声明函数为中断服务函数 { sound=~sound; TH1=(65536-921)/256; //定时器 T1 的高 8 位重新赋初值 TL1=(65536-921)%256; //定时器 T1 的高 8 位重新赋初值 } // 49 T0 \" \" //实例 49:用定时器 T0 的中断实现\"渴望\"主题曲的播放 #include . . 336/ 192 . . //以下是 C 调中音的音频宏定义 #definedao523 //将“dao”宏定义为中音“1”的频率 523Hz #definere 587 //将“re”宏定义为中音“2”的频率 587Hz #definemi659 //将“mi”宏定义为中音“3”的频率 659Hz #definefa698 //将“fa”宏定义为中音“4”的频率 698Hz #definesao784 //将“sao”宏定义为中音“5”的频率 784Hz #definela880 //将“la”宏定义为中音“6”的频率 880Hz #definexi 987 //将“xi”宏定义为中音“7”的频率 523H //以下是 C 调高音的音频宏定义 #defineh_dao1046 //将“h_dao”宏定义为高音“1”的频率 1046Hz #defineh_re1174 //将“h_re”宏定义为高音“2”的频率 1174Hz #defineh_mi1318 //将“h_mi”宏定义为高音“3”的频率 1318Hz #defineh_fa 1396 //将“h_fa”宏定义为高音“4”的频率 1396Hz #defineh_sao1567 //将“h_sao”宏定义为高音“5”的频率 1567Hz #defineh_la 1760 //将“h_la”宏定义为高音“6”的频率 1760Hz #defineh_xi1975 //将“h_xi”宏定义为高音“7”的频率 1975Hz /******************************************* 函数功能:1 个延时单位,延时 200ms ******************************************/ voiddelay() { unsignedchar i,j; for(i=0;i<250;i++) for(j=0;j<250;j++) ; } /******************************************* 函数功能:主函数 ******************************************/ voidmain(void) { unsignedchar i,j; //以下是《渴望》片头曲的一段简谱 unsigned intcode f[]={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 个延时单位 unsignedchar code JP[]={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 } } /*********************************************************** 函数功能:定时器 T0 的中断服务子程序,使 P3.7 引脚输出音频的方波 ************************************************************/ voidTime0(void ) interrupt 1using 1 { sound=!sound; //将 P3.7 引脚输出电平取反,形成方波 TH0=(8192-C)/32; //可证明这是 13 位计数器 TH0 高 8 位的赋初值方法 TL0=(8192-C)%32; //可证明这是 13 位计数器 TL0 低 5 位的赋初值方法 } // 50-1 50 //实例 50-1:输出 50 个矩形脉冲 #include sbitu=P1^4; //将 u 位定义为 P1.4 /************************************************* 函数功能:延时约 30ms (3*100*100=30 000μ s=30m *************************************************/ voiddelay30ms(void) { unsignedcharm,n; for(m=0;m<100;m++) for(n=0;n<100;n++) ; } /******************************************* 函数功能:主函数 ******************************************/ voidmain(void) { unsignedchar i; u=1; //初始化输出高电平 for(i=0;i<50;i++) //输出 50 个矩形脉冲 { . . 339/ 192 . . } u=1; delay30ms(); u=0; delay30ms(); while(1) ;//无限循环,防止程序“跑飞” } //实例 50-2:计数器 T0 统计外部脉冲数 #include ******************************************/ 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 sbitui=P3^2; //将 ui 位定义为 P3.0(INT0)引脚,表示输入电压 /******************************************* 函数功能:主函数 ******************************************/ voidmain(void) { TMOD=0x0a; //TMOD=00001010B,使用定时器 T0 的模式 2,GATE 置 1 EA=1; //开总中断 440/ 192 . . ET0=0; //不使用定时器 T0 的中断 TR0=1; //启动 T0 TH0=0; //计数器 T0 高 8 位赋初值 TL0=0; //计数器 T0 低 8 位赋初值 while(1) //无限循环,不停地将 TL0 计数结果送 P1 口 { while(ui== //INT0 为低电平,T0 不能启动 0) ; //INT0 为高电平,启动 T0 计时,所以将 TL0 清 0 TL0=0; while(ui==1) //在 INT0 高电平期间,等待,计时 ; P1=TL0; //将计时结果送 P1 口显示 } } // 52 T0 //实例 52:用定时器 T0 控制输出高低宽度不同的矩形波 #include 函数功能:延时约 30ms (3*100*100=30 000μ s=30ms) *************************************************/ voiddelay30ms(void) { unsignedcharm,n; for(m=0;m<100;m++) for(n=0;n<100;n++) ; } /******************************************* 函数功能:主函数 ******************************************/ voidmain(void) { unsignedchar i; EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 Countor=0; . . 441/ 192 . . for(i=0;i<100;i++) //输出 100 个负跳变 { u=1; delay30ms(); u=0; delay30ms(); } while(1) ;//无限循环, 防止程序跑飞 } /************************************************************** 函数功能:外中断 T0 的中断服务程序 **************************************************************/ voidint0(void)interrupt 0using0//外中断 0 的中断编号为 0 { Countor++; P1=Countor; } // 53 0 //实例 53:用外中断 0 的中断方式进行数据采集 #include ******************************************/ voidmain(void) { EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 P1=0xff; while(1) ;//无限循环, 防止程序跑飞 } /************************************************************** 函数功能:外中断 T0 的中断服务程序 **************************************************************/ voidint0(void)interrupt 0using0//外中断 0 的中断编号为 0 { 442/ 192 . . P1=~P1; //每产生一次中断请求,P1 取反一次。 } //实例 54-1:输出负脉宽为 200 微秒的方波 #include /******************************************* 函数功能:主函数 ******************************************/ 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) interrupt 1using0//\"interrupt\"声明函数为中断服务函数 { u=~u; //将 P1.4 引脚输出电平取反,产生方波 } // 54-2 //实例 54-2:测量负脉冲宽度 #include /******************************************* 函数功能:主函数 ******************************************/ 443/ 192 . . voidmain(void) { TMOD=0x02; //TMOD=00000010B,使用定时器 T0 的模式 2 EA=1; //开放总中断 EX0=1; //允许使用外中断 IT0=1; //选择负跳变来触发外中断 ET0=1; //允许定时器 T0 中断 TH0=0; //定时器 T0 赋初值 0 TL0=0; //定时器 T0 赋初值 0 TR0=0; //先关闭 T0 while(1) ;//无限循环, 不停检测输入负脉冲宽度 } /************************************************************** 函数功能:外中断 0 的中断服务程序 **************************************************************/ voidint0(void)interrupt 0using0//外中断 0 的中断编号为 0 { TR0=1; //外中断一到来,即启动 T0 计时 TL0=0; //从 0 开始计时 while(u==0) //低电平时,等待 T0 计时 ; P1=TL0; //将结果送 P1 口显示 TR0=0; //关闭 T0 } //实例 55:方式 0 控制流水灯循环点亮 #include unsignedchar code Tab[]={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(unsigned char dat) { 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) { unsignedchar i; SCON=0x00; //SCON=00000000B,使串行口工作于方式 0 while(1) { for(i=0;i<8;i++) { Send(Tab[i]); //发送数据 delay(); //延时 } } } //实例 56-1:数据发送程序 #include unsignedchar code Tab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯控制码,该数组被定义为全局变量 /***************************************************** 445/ 192 . . 函数功能:向 PC 发送一个字节数据 ***************************************************/ voidSend(unsigned char dat) { 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) { unsignedchar i; 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 发送一次检测数据 } } } 44 / 192 6 . . // 562 //实例 562 :数据接收程序 #include /***************************************************** 函数功能:接收一个字节数据 ***************************************************/ unsignedcharReceive(void) { unsignedchar dat; 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 口显示 } } // 571 //实例 571 :数据发送程序 #include sbitp=PSW^0; //包含单片机寄存器的头文件 unsignedchar code Tab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯控制码,该数组被定义为全局变量 . . /***************************************************** 447/ 192 . . 函数功能:向 PC 发送一个字节数据 ***************************************************/ voidSend(unsigned char dat) { 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) { unsignedchar i; 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 发送一次检测数据 } } } 44 / 192 8 . . // 572 //实例 572 :数据接收程序 #include sbitp=PSW^0; /***************************************************** 函数功能:接收一个字节数据 ***************************************************/ unsignedcharReceive(void) { unsignedchar dat; 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,允许接收(PCON=0x00; //PCON=00000000B,波特率 9600 TH1=0xfd; //根据规定给定时器 T1 赋初值 TL1=0xfd; //根据规定给定时器 T1 赋初值 TR1=1; //启动定时器 T1 REN=1; //允许接收 while(1) { P1=Receive();//将接收到的数据送 P1 口显示 } } . REN=1) . 44 / 192 9 . . // 58 PC //实例 58:单片机向 PC 发送数据 #include unsignedchar code Tab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯控制码,该数组被定义为全局变量 /***************************************************** 函数功能:向 PC 发送一个字节数据 ***************************************************/ voidSend(unsigned char dat) { 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) { unsignedchar i; 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 . . } } // 实例 5959 :单片机接收 PCPC // 发出的数据 #include ***************************************************/ unsignedcharReceive(void) { unsignedchar dat; 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,允许接收(PCON=0x00; //PCON=00000000B,波特率 9600 TH1=0xfd; //根据规定给定时器 T1 赋初值 TL1=0xfd; //根据规定给定时器 T1 赋初值 TR1=1; //启动定时器 T1 REN=1; //允许接收 while(1) { P1=Receive();//将接收到的数据送 P1 口显示 } } 55 / . REN=1)1 . 192 . . /******************************************************** *********数码管显示*****数码管显示******************** 数码管显示****************数码管显示 ***************************************************/ //实例 60:用 LED 数码显示数字 5 #include voidmain(void) { P2=0xfe; //P2.0 引脚输出低电平,数码显示器接通电源准备点亮 P0=0x92; //让 P0 口输出数字\"5\"的段码 92H } // 61 LED 0~9 //实例 61:用 LED 数码显示器循环显示数字 0~9 #include ***************************************************/ voiddelay(void) { unsignedchar i,j; for(i=0;i<255;i++) for(j=0;j<255;j++) ; } /************************************************** 函数功能:主函数 ***************************************************/ voidmain(void) { unsignedchar i; . . 55 / 192 2 . . unsignedchar code 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 unsignedchar i,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 unsignedchar i; for(i=0;i<200;i++) ; } // 包含 51 单片机寄存器定义的头文件 //延时函数,延时约 0.6 毫秒 voidmain(void) { while(1) { P2=0xfe; P0=0xf9; delay(); P2=0xfd; P0=0xa4; delay(); P2=0xfb; P0=0xb0; delay(); P2=0xf7; P0=0x99; delay(); P2=0xff; } } //无限循环 //P2.0 引脚输出低电平,DS0 点亮 //数字 1 的段码 //P2.1 引脚输出低电平,DS1 点亮 //数字 2 的段码 //P2.2 引脚输出低电平,DS2 点亮 //数字 3 的段码 //P2.3 引脚输出低电平,DS3 点亮 //数字 4 的段码 //实例 64:用数码管显示动态检测结果 #include // 包含 51 单片机寄存器定义的头文件 554/ 192 . . #include unsignedchar code Tab[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(unsigned intk) { 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)/25 6; 1.085 微秒=50000 微秒=50 毫秒 TL0=(65536-46083)%25 6; EA=1; ET0=1; TR0=1; //使用定时器 T0 //将定时器计时时间设定为 46083× //开启总中断 //定时器 T0 中断允许 //启动定时器 T0 开始运行 while(1) { display(x); } //调用检测结果的显示程序 } /******************************************************** 函数功能:定时器 T0 的中断服务程序 *******************************************************/ voidTime0(void) interrupt 1using1 { 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 //实例 65:数码秒表设计 #include . . 556 / 192 . . unsignedchar code Tab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数码管显示 0~9 的段码表 unsignedchar int_time; //记录中断次数 unsignedcharsecond; //储存秒 /******************************************************************** *** 函数功能:快速动态扫描延时,延时约 0.6 毫秒 ********************************************************************* ***/ voiddelay(void) { unsignedchar i; for(i=0;i<200;i++) ; } /******************************************************************** *** 函数功能:显示秒 入口参数:k 出口参数:无 ********************************************************************* ***/ voidDisplaySecond(unsigned chark) { P2=0xfb; P0=Tab[k/10]; delay(); //P2.6 引脚输出低电平, DS6 点亮 //显示十位 P2=0xf7; //P2.7 引脚输出低电平, DS7 点亮 P0=Tab[k%10]; //显示个位 delay(); P2=0xff; //关闭所有数码管 } voidmain(void) //主函数 { TMOD=0x01; //使用定时器 T0 TH0=(65536-46083)/25 //将定时器计时时间设定为 46083×1.085 微 6; 秒 //=50000 微秒=50 毫秒 TL0=(65536-46083)%256; 55 / 192 7 . . EA=1; //开启总中断 ET0=1; //定时器 T0 中断允许 TR0=1; //启动定时器 T0 开始运行 int_time=0; //中断次数初始化 second=0; //秒初始化 while(1) { DisplaySecond(second); // 调用秒的显示子程序 } } //******************************************************** //函数功能:定时器 T0 的中断服务程序 //******************************************************* voidinterserve(void )interrupt 1using1 { 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 } //实例 66:数码时钟设计 #include unsignedcharTab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //control shape unsignedchar port[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; unsignedchar int_time ;//中断次数计数变量 unsignedcharsecond; //秒计数变量 unsignedcharminute; //分钟计数变量 unsignedcharhour; //小时计数变量 ///////////////////////////////////////////////////// 558/ 192 . . voiddelay(void) //延时函数,延时约 0.6ms { unsignedchar j; for(j=0;j<200;j++) ; } /****************************************************************** 函数功能:显示秒的子程序 入口参数:s ********************************************************************/ voidDisplaySecond(unsigned chars) { P2=0xbf; //P2.6 引脚输出低电平, DS6 点亮 P0=Tab[s/10]; //显示十位 delay(); P2=0x7f; //P2.7 引脚输出低电平, DS7 点亮 P0=Tab[s%10]; //显示个位 delay(); P2=0xff; //关闭所有数码管 } /****************************************************************** 函数功能:显示分钟的子程序 入口参数:m ********************************************************************/ voidDisplayMinute(unsigned charm) { 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; //关闭所有数码管 55 / 192 9 . . } /****************************************************************** 函数功能:显示小时的子程序 入口参数:h ********************************************************************/ voidDisplayHour(unsigned charh) { P2=0xfe; P0=Tab[h/10]; delay(); //P2.0 引脚输出低电平, DS0 点亮 //显示十位 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 )interrupt 1using1 //using Time0 { 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; //定时器重新赋初值 } 66 / 192 1 . . // 67 LED T0 //实例 67:用 LED 数码管显示计数器 T0 的计数值 #include unsignedcharTab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //段 码表 unsignedcharx; /****************************************************************** 函数功能: 延时约 0.6ms ********************************************************************/ voiddelay(void) { unsignedchar j; for(j=0;j<200;j++) ; } /****************************************************************** 函数功能:显示计数次数的子程序 入口参数:x ********************************************************************/ voidDisplay(unsigned charx) { 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)interrupt 0using0//外中断 0 的中断编号为 0 { x++; if(x==100) x=0; } // 68 59 //实例 68:静态显示数字“59” #include /******************************************* 函数功能:主函数 ******************************************/ voidmain(void) { P0=0x92; //将数字 5 的段码送 P0 口 P1=0x90; //将数字 9 的段码送 P1 口 while(1) //无限循环,防止程序跑飞 ; } /******************************************************** ************ **键盘 控制*********键盘控制*************** ***************键盘控制**** *****键盘控制**** ********** ***** **** ****** *****************************************************/ . . 66 / 192 3 . . // 69 //实例 69:无软件消抖的独立式键盘输入实验 #include LED0=0; //P3.0 引脚输出低电平 while(1) { if(S1==0) //P1.4 引脚输出低电平,按键 S1 被按下 LED0=!LED0; //P3.0 引脚取反 } } //实例 70:软件消抖的独立式键盘输入实验 #include **************************************************/ voiddelay(void) { unsignedchar i,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 /************************************************* 函数功能:流水灯延时 **************************************************/ voidled_delay(void) { unsignedchar i,j; for(i=0;i<250;i++) for(j=0;j<250;j++) ; } /************************************************* 函数功能:软件消抖延时 **************************************************/ voiddelay30ms(void) { unsignedchar i,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) { case 1:forward(); break; case 2:backward(); break; case 3:stop(); break; case 4:flash(); break; } } } // 72 //实例 72:定时器中断控制的独立式键盘扫描实验 #include /************************************************* 函数功能:流水灯延时 **************************************************/ voidled_delay(void) { unsignedchar i,j; for(i=0;i<250;i++) for(j=0;j<250;j++) ; } /************************************************* 函数功能:软件消抖延时 **************************************************/ voiddelay20ms(void) { unsignedchar i,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 次(送一次中断请求 TL0=(65536-1000)%256; //定时器 T0 赋初值 keyval=0; //按键值初始化为 0,什么也不做 while(1) { switch(keyval) { case 1:forward(); 770/ 192 . 217 微秒)发 . break; case 2:backward(); break; case 3:stop(); break; case 4:flash(); break; } } } /************************************************* 函数功能:定时器 T0 的中断服务子程序 **************************************************/ voidTime0_serve(void) interrupt 1using1 { 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 // 包含 51 单片机寄存器定义的头文件 //储存流水灯的流动速度 //位定义 S1 为 P1.4 //位定义 S2 为 P1.5 //位定义 S3 为 P1.6 //位定义 S4 为 P1.7 771/ 192 . . /************************************************************** 函数功能:延时 20ms 的子程序 **************************************************************/ voiddelay20ms(void) //3*i*j+2*i=3*100*60+2*100=20000μs=20ms; { unsignedchar i,j; for(i=0;i<100;i++) for(j=0;j<60;j++) ; } /************************************************************** 函数功能:延时可调子程序 入口参数:x **************************************************************/ voiddelay(unsigned charx) { unsignedchark; for(k=0;k } /************************************************************** 函数功能:主函数 **************************************************************/ 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) interrupt 1using1 { 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 /************************************************************** 773/ 192 . . 函数功能:延时子程序 **************************************************************/ voiddelay(void) //因为仅对一个按键扫描,所以延时时间较长约 200ms { unsignedchar i,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) { case 0:P3=0xfe; break; case 1:P3=0xfd; break; case 2:P3=0xfb; break; case 3:P3=0xf7; break; } } } /************************************************************** 函数功能:定时器 T0 的中断服务子程序,进行键盘扫描 **************************************************************/ voidintersev(void) interrupt 1using1 { 774/ 192 . . TR0=0; //关闭定时器 T0 P1=0xff; if(S1== //如果是按键 S1 按下 0) { delay(); //延时 20ms,软件消抖 if(S1==0) //如果是按键 S1 按下 ID=ID+1; } if(ID==4) ID=0; TR0=1; //启动定时器 T0 } // 75 //实例 75:独立式键盘调时的数码时钟实验 #include unsignedchar code Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数字 0~9 的段码 unsignedchar int_time ;//中断次数计数变量 unsignedcharsecond; //秒计数变量 unsignedcharminute; //分钟计数变量 unsignedcharhour; //小时计数变量 sbitS1=P1^4; sbitS2=P1^5; sbitS3=P1^6; sbitS4=P1^7; //将 S1 位定义为 P1.4 //将 S2 位定义为 P1.5 //将 S3 位定义为 P1.6 //将 S4 位定义为 P1.7 /****************************************************************** 函数功能:数码管扫描延时 ********************************************************************/ voiddelay(void) { unsignedchar j; for(j=0;j<200;j++) ; } /****************************************************************** 函数功能:键盘扫描延时 . . 775/ 192 . . ********************************************************************/ voiddelay60ms(void) { unsignedchar i,j; for(i=0;i<200;i++) for(j=0;j<100;j++) ; } /****************************************************************** 函数功能:显示秒 入口参数:s ********************************************************************/ voidDisplaySecond(unsigned chars) { P2=0xbf; //P2.6 引脚输出低电平, DS6 点亮 P0=Tab[s/10]; //显示十位 delay(); P2=0x7f; //P2.7 引脚输出低电平, DS7 点亮 P0=Tab[s%10]; //显示个位 delay(); P2=0xff; //关闭所有数码管 } /****************************************************************** 函数功能:显示分钟 入口参数:m ********************************************************************/ voidDisplayMinute(unsigned charm) { 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(unsigned charh) { P2=0xfe; P0=Tab[h/10]; delay(); //P2.0 引脚输出低电平, DS0 点亮 //显示十位 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 )interrupt 1using1 //using Time0 { 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 . . } if(minute==60) //如果分钟计满 60 { minute=0; //如果分钟计满 60,将分钟计数变量清 0 hour++; //小时计数变量加 1 } if(hour==24) //如果小时计满 24 { hour=0; //如果小时计满 24,将小时计数变量清 0 } key_scan(); //执行键盘扫描 TH0=(65536-46083)/256; //定时器 T0 高四位赋值 TL0=(65536-46083)%256; //定时器 T0 低四位赋值 TR0=1; //启动定时器 T0 minute++ ; //分钟计数变量加1 } // 76 //实例 76:独立式键盘控制步进电机实验 #include /************************************************* 函数功能:软件消抖延时(约 50ms) **************************************************/ voiddelay(void) { unsignedchar i,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; //使用定时器 T0 的模式 1 EA=1; //开总中断 ET0=1; //定时器 T0 中断允许 TR0=1; //启动定时器 T0 TH0=(65536-500)/256; //定时器 T0 赋初值,每计数 200 次(217 微秒)发 送一次中断请求 TL0=(65536-500)%256; //定时器 T0 赋初值 keyval=0; //按键值初始化为 0,什么也不做 ID=0; while(1) { switch(keyval //根据按键值 keyval 选择待执行的功能 ) { case 1:forward(); //按键 S1 按下,正转 break; case 2:backward(); //按键 S2 按下 ,反转 break; case 3:stop(); //按键 S3 按下,停转 break; } } } /************************************************* 函数功能:定时器 T0 的中断服务子程序 **************************************************/ voidTime0_serve(void) interrupt 1using1 { 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 unsignedchar code Tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数字 0~9 的段码 unsignedcharkeyval; //定义变量储存按键值 /************************************************************** 函数功能:数码管动态扫描延时 **************************************************************/ voidled_delay(void) { unsignedchar j; for(j=0;j<200;j++) ; } /************************************************************** 函数功能:按键值的数码管显示子程序 **************************************************************/ voiddisplay(unsigned char k) { P2=0xbf; //点亮数码管 DS6 P0=Tab[k/10]; //显示十位 led_delay(); //动态扫描延时 P2=0x7f; //点亮数码管 DS7 P0=Tab[k%10]; //显示个位 led_delay(); //动态扫描延时 } /************************************************************** 函数功能:软件延时子程序 **************************************************************/ voiddelay20ms(void) { unsignedchar i,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) interrupt1using 1 //定时器 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 . . if(P17==0) “0” keyval=4; //如果检测到接 P1.7 引脚的列线为低电平 //可判断是 S4 键被按下 P1=0xfd; “0”) if(P14==0) keyval=5; if(P15==0) keyval=6; if(P16==0) keyval=7; if(P17==0) keyval=8; //第二行置为低电平“0”(P1.1 输出低电平 //如果检测到接 P1.4 引脚的列线为低电平“0” //可判断是 S5 键被按下 //如果检测到接 P1.5 引脚的列线为低电平 //可判断是 S6 键被按下 //如果检测到接 P1.6 引脚的列线为低电平 //可判断是 S7 键被按下 //如果检测到接 P1.7 引脚的列线为低电平 //可判断是 S8 键被按下 “0” “0” “0” P1=0xfb; “0”) if(P14==0) keyval=9; if(P15==0) keyval=10; if(P16==0) keyval=11; if(P17==0) keyval=12; //第三行置为低电平“0”(P1.2 输出低电平 //如果检测到接 P1.4 引脚的列线为低电平“0” //可判断是 S9 键被按下 //如果检测到接P1.5 引脚的列线为低电平“0” //可判断是 S10 键被按下 //如果检测到接 P1.6 引脚的列线为低电平“0” //可判断是 S11 键被按下 //如果检测到接 P1.7 引脚的列线为低电平“0” //可判断是 S12 键被按下 P1=0xf7; //第四行置为低电平“0”(P1.3 输出低电平 “0”) } if(P14==0) //如果检测到接 P1.4 引脚的列线为低电平“0” keyval=13; //可判断是 S13 键被按下 if(P15==0) //如果检测到接P1.5 引脚的列线为低电平“0” keyval=14; //可判断是 S14 键被按下 if(P16==0) //如果检测到接 P1.6 引脚的列线为低电平“0” keyval=15; //可判断是 S15 键被按下 if(P17==0) //如果检测到接 P1.7 引脚的列线为低电平“0” keyval=16; //可判断是 S16 键被按下 } TR0=1; //开启定时器 T0 TH0=(65536-500)/256; //定时器 T0 的高 8 位赋初值 TL0=(65536-500)%256; //定时器 T0 的高 8 位赋初值 884/ 192 . . //实例 78:矩阵式键盘按键音 #include /************************************************************** 函数功能:蜂鸣器发声延时约 120ms **************************************************************/ voiddelay_sound(void) { unsignedchar i; for(i=0;i<250;i++) ; } /************************************************************** 函数功能:软件延时子程序约 20ms **************************************************************/ voiddelay20ms(void) { unsignedchar i,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) interrupt1using 1 //定时器 T0 的中断编号为 1, 使用第一组寄存器 { unsignedchar i; 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 //实例 79:简易电子琴 #include sbitP14=P1^4; //将 P14 位定义为 P1.4 引脚 sbitP15=P1^5; //将 P15 位定义为 P1.5 引脚 sbitP16=P1^6; //将 P16 位定义为 P1.6 引脚 sbitP17=P1^7; //将 P17 位定义为 P1.7 引脚 unsignedcharkeyval; //定义变量储存按键值 sbitsound=P3^7; //将 sound 位定义为 P3.7 unsignedintC; //全局变量,储存定时器的定时常数 unsignedintf; //全局变量,储存音阶的频率 //以下是 C 调低音的音频宏定义 #definel_dao262 //将“l_dao”宏定义为低音“1”的频率 262Hz 886/ 192 . . #definel_re 286 #definel_mi 311 #definel_fa349 #definel_sao392 #definel_la440 #definel_xi 494 //将“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 #definere 587 //将“re”宏定义为中音“2”的频率 587Hz #definemi659 //将“mi”宏定义为中音“3”的频率 659Hz #definefa698 //将“fa”宏定义为中音“4”的频率 698Hz #definesao784 //将“sao”宏定义为中音“5”的频率 784Hz #definela880 //将“la”宏定义为中音“6”的频率 880Hz #definexi 987 //将“xi”宏定义为中音“7”的频率 53 //以下是 C 调高音的音频宏定义 #defineh_dao1046 //将“h_dao”宏定义为高音“1”的频率 1046Hz #defineh_re1174 //将“h_re”宏定义为高音“2”的频率 1174Hz #defineh_mi1318 //将“h_mi”宏定义为高音“3”的频率 1318Hz #defineh_fa 1396 //将“h_fa”宏定义为高音“4”的频率 1396Hz #defineh_sao1567 //将“h_sao”宏定义为高音“5”的频率 1567Hz #defineh_la 1760 //将“h_la”宏定义为高音“6”的频率 1760Hz #defineh_xi1975 //将“h_xi”宏定义为高音“7”的频率 1975Hz /************************************************************** 函数功能:软件延时子程序 **************************************************************/ voiddelay20ms(void) { unsignedchar i,j; for(i=0;i<100;i++) for(j=0;j<60;j++) ; } /******************************************* 函数功能:节拍的延时的基本单位,延时 200ms ******************************************/ voiddelay() { unsignedchar i,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) { case 1:f=dao; 中音 1 的频率赋给 f Output_Sound(); break; case 2:f=l_xi; 低音 7 的频率赋给 f Output_Sound(); break; //如果第 1 个键按下,将 //转去计算定时常数 //如果第 2 个键按下,将 //转去计算定时常数 88 / 192 8 . . case 3:f=l_la; 6 的频率赋给 f Output_Sound(); break; case 4:f=l_sao; //如果第 3 个键按下,将低音 //转去计算定时常数 //如果第 4 个键按下,将 //转去计算定时常数 低音 5 的频率赋给 f Output_Sound(); break; case 5:f=sao; //如果第 5 个键按下, 将中音 5 的频率赋给 f Output_Sound(); //转去计算定时常数 break; case 6:f=fa; //如果第 6 个键按下, 将中音 4 的频率赋给 f 音 3 的频率赋给 f Output_Sound(); //转去计算定时常数 break; case 7:f=mi; //如果第 7 个键按下,将中 Output_Sound(); break; case 8:f=re; Output_Sound(); break; case 9:f=h_re; Output_Sound(); break; case 10:f=h_dao; //转去计算定时常数 //如果第 8 个键按下,将 //转去计算定时常数 中音 2 的频率赋给 f //如果第 9 个键按下,将 //转去计算定时常数 高音 2 的频率赋给 f //如果第 10 个键按 下,将高音 1 的频率赋给 f Output_Sound(); //转去计算定时常数 break; case 11:f=xi; //如果第 11 个键按下,将中 音 7 的频率赋给 f Output_Sound(); break; case 12:f=la; Output_Sound(); break; case 13:f=h_la; Output_Sound(); break; //转去计算定时常数 //如果第 12 个键按下,将 //转去计算定时常数 中音 6 的频率赋给 f //如果第 13 个键按下, //转去计算定时常数 将高音 6 的频率赋给 f 889/ 192 . . case 14:f=h_sao; 将高音 5 的频率赋给 f //如果第 14 个键按下, Output_Sound(); //转去计算定时常数 break; case 15:f=h_fa; //如果第 15 个键按下,将高 音 4 的频率赋给 f Output_Sound(); break; case 16:f=h_mi; Output_Sound(); break; //转去计算定时常数 //如果第 16 个键按下, //转去计算定时常数 将高音 3 的频率赋给 f } } } /************************************************************** 函数功能:定时器 T0 的中断服务子程序,使 P3.7 引脚输出音频方波 **************************************************************/ voidTime0_serve(void )interrupt 1using1 { TH0=(8192-C)/32; 方法 TL0=(8192-C)%32; 法 sound=!sound; } //可证明这是 13 位计数器 TH0 高 8 位的赋初值 //可证明这是13 位计数器TL0 低5 位的赋初值方 //将 P3.7 引脚取反,输出音频方波 /************************************************************** 函数功能:定时器 T1 的中断服务子程序,进行键盘扫描,判断键位 **************************************************************/ voidtime1_serve(void) interrupt 3using2 //定时器 T1 的中断编号为 3,使用 第 2 组寄存器 { TR1=0; //关闭定时器 T0 P1=0xf0; //所有行线置为低电平“0”,所有列线置为高 电平“1” if((P1&0xf0)!=0xf0) //列线中有一位为低电平“0”,说明有键按下 { delay20ms(); //延时一段时间、软件消抖 if((P1&0xf0)!=0xf0) //确实有键按下 { 99 / 192 0 . 输出低电平“0”) 为低电平“0” 线为低电平“0” 线为低电平“0” 线为低电平“0” 输出低电平“0”) 低电平“0” 线为低电平“0” 线为低电平“0” 线为低电平“0” 输出低电平“0”) 电平“0” 为低电平“0” 为低电平“0” 为低电平“0” . . P1=0xfe; //第一行置为低电平“0”(P1.0 if(P14==0) //如果检测到接 P1.4 引脚的列线 keyval=1; //可判断是 S1 键被按下 if(P15==0) //如果检测到接 P1.5 引脚的列 keyval=2; //可判断是 S2 键被按下 if(P16==0) //如果检测到接 P1.6 引脚的列 keyval=3; //可判断是 S3 键被按下 if(P17==0) //如果检测到接 P1.7 引脚的列 keyval=4; //可判断是 S4 键被按下 P1=0xfd; //第二行置为低电平“0”(P1.1 if(P14==0) //如果检测到接P1.4 引脚的列线为 keyval=5; //可判断是 S5 键被按下 if(P15==0) //如果检测到接 P1.5 引脚的列 keyval=6; //可判断是 S6 键被按下 if(P16==0) //如果检测到接 P1.6 引脚的列 keyval=7; //可判断是 S7 键被按下 if(P17==0) //如果检测到接 P1.7 引脚的列 keyval=8; //可判断是 S8 键被按下 P1=0xfb; //第三行置为低电平“0”(P1.2 //如果检测到接 P1.4 引脚的列线为低 keyval=9; //可判断是 S9 键被按下 if(P15==0) //如果检测到接 P1.5 引脚的列线 keyval=1 //可判断是 S10 键被按下 0; if(P16==0)//如果检测到接 P1.6 引脚的列线 keyval=1//可判断是 S11 键被按下 //如果检测到接 1; P1.7 引脚的列线 if(P17==0) //可判断是 S12 键被按下 keyval=1 99 / 192 2; 1 if(P14==0) . P1=0xf7; 输出低电平“0”) 电平“0” 为低电平“0” 为低电平“0” 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 键被按下 为低电平“0” } } TR1=1; //开启定时器 T1 TH1=(65536-500)/256; //定时器 T1 的高 8 位赋初值 TL1=(65536-500)%256; //定时器 T1 的高 8 位赋初值 // 80 //实例 80:矩阵式键盘实现的电子密码锁 #include /************************************************************** 函数功能:延时输出音频 **************************************************************/ voiddelay(void) { unsignedchar i; for(i=0;i<200;i++) ; } 992/ 192 . . /************************************************************** 函数功能:软件延时子程序 **************************************************************/ voiddelay20ms(void) { unsignedchar i,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]) ; P3=0xfe; //第一位密码输入不正确,等待 //第二位密码输入不正确,等待 //第三位密码输入不正确,等待 //第四位密码输入不正确,等待 //第五位密码输入不正确,等待 //第六位密码输入不正确,等待 //没有输入“OK”,等待 //P3.0 引脚输出低电平,点亮 LED } /************************************************************** 函数功能:定时器 0 的中断服务子程序,进行键盘扫描,判断键位 993/ 192 . . **************************************************************/ voidtime0_interserve(void) interrupt1using 1 //定时器 T0 的中断编号为 1, 使用第一组寄存器 { unsignedchar i; TR0=0; P1=0xf0; 电平“1” if((P1&0xf0)!=0xf0) delay20ms(); if((P1&0xf0)!=0xf0) { P1=0xfe; “0” ) if(P14==0) keyval=1; if(P15==0) “0” keyval=2; if(P16==0) “0” keyval=3; if(P17==0) “0” keyval=4; P1=0xfd; “0” ) if(P14==0) keyval=5; if(P15==0) “0” keyval=6; if(P16==0) “0” keyval=7; if(P17==0) “0” keyval=8; P1=0xfb; “0” ) if(P14==0) keyval=9; . //关闭定时器 T0 //所有行线置为低电平“0”,所有列线置为高 //列线中有一位为低电平“0”,说明有键按下 //延时一段时间、软件消抖 //确实有键按下 //第一行置为低电平“0”(P1.0 输出低电平 //如果检测到接 P1.4 引脚的列线为低电平“0” //可判断是 S1 键被按下 //如果检测到接 P1.5 引脚的列线为低电平//可判断是 S2 键被按下 //如果检测到接 P1.6 引脚的列线为低电平//可判断是 S3 键被按下 //如果检测到接 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 键被按下 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”(P1.3 //如果检测到接 P1.4 引脚的列线为低 //可判断是 S13 键被按下 //如果检测到接 P1.5 引脚的列线 //可判断是 S14 键被按下 //如果检测到接 P1.6 引脚的列线 //可判断是 S15 键被按下 //如果检测到接 P1.7 引脚的列线 P1=0xf7; 输出低电平“0”) 电平“0” if(P14==0) keyval=13; if(P15==0) keyval=14; if(P16==0) keyval=15; if(P17==0) 为低电平“0” 为低电平“0” 为低电平“0” keyval=16; //可判断是 S16 键被按下 for(i=0;i<200;i++) //让 P3.7 引脚电平不断取反输出音频 { sound=0; delay(); sound=1; delay(); } } TR0=1; //开启定时器 T0 TH0=(65536-500)/256; //定时器 T0 的高 8 位赋初值 TL0=(65536-500)%256; //定时器 T0 的高 8 位赋初值 } /******************************************************** **************** ** 液 晶 显 示 LCDLCD********* LCD LCD*********液晶显示 ***** 液 晶 显 示 LCD ************* ******* 液 晶 显 示 LCD ************* ******* LCD*********液晶显示 LCD *****液晶显示 LCD**** ****** . . 995/ 192 . . ********************************************************* **/ //实例 81:用 LCD 显示字符''A' #include (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelay(unsigned charn) { unsignedchar i; for(i=0;i } /***************************************************** 函数功能:判断液晶模块的忙碌状态 返回值:result。result=1,忙碌;result=0,不忙 ***************************************************/ unsignedcharBusyTest(void) { bitresult; RS=0; //根据规定,RS 为低电平,RW 为高电平时,可以读状态 996/ 192 . . 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_(); //空操作四个机器周期,给硬件反应时间 E=0; //当 E 由高电平跳变成低电平时,液晶模块开始 执行命令 } /***************************************************** 函数功能:指定字符显示的实际地址 入口参数:x ***************************************************/ voidWriteAddress(unsigned charx) { 997/ 192 . . WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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(); //调用 LCD 初始化函数 WriteAddress(0x07); //将显示地址指定为第 1 行第 8 列 WriteData('A'); //将字符常量'A'写入液晶模块 //字符的字形点阵读出和显示由液晶模块自动完成 } //实例 82:用 LCD 循环右移显示\"Welcome to Chiina\" #include (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelay(unsigned charn) { unsignedchar i; for(i=0;i } 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(unsigned charx) { WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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) //主函数 { unsignedchar i; LcdInitiate(); //调用 LCD 初始化函数 delay(10); while(1) { 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 102 / 192 . . sbitRW=P2^1; //读写选择位,将 RW 位定义为 P2.1 引脚 sbitE=P2^2; //使能信号位,将 E 位定义为 P2.2 引脚 sbitBF=P0^7; //忙碌标志位,,将 BF 位定义为 P0.7 引脚 unsignedchar code digit[ ]={\"0123456789\ //定义字符数组显示数字 unsignedchar code string[]={\"TestResult\定义字符数组显示提示信息 /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelay(unsigned charn) { unsignedchar i; for(i=0;i } /***************************************************** 函数功能:判断液晶模块的忙碌状态 返回值: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(unsigned charx) { WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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) { unsignedchar i; //定义变量 i 指向字符串数组元素 unsignedintx; //定义变量,储存检测结果 105 / 192 . . unsignedcharD1,D2,D3,D4,D5; //分别储存采集的个位、十位、百位、千位和 万位数字 LcdInitiate(); //调用 LCD 初始化函数 delay(10); //延时 10ms,给硬件一点反应时间 WriteAddress(0x02); // 从第 1 行第 3 列开始显示 i= 0; //指向字符数组的第 1 个元素 while(string[i] != '\\0') { WriteData(string[i]); i++; //指向下字符数组一个元素 } while(1) //无限循环 { x=rand(); //模拟数据采集 D1=x%10; //计算个位数字 D2=(x%100)/10; //计算十位数字 D3=(x%1000)/100; //计算百位数字 D4=(x%10000)/1000; //计算千位数字 D5=x/10000; //计算万位数字 WriteAddress(0x45); // 从第 2 行第 6 列开始显示 WriteData(digit[D5]); //将万位数字的字符常量写入 LCD WriteData(digit[D4]); //将千位数字的字符常量写入 LCD WriteData(digit[D3]); //将百位数字的字符常量写入 LCD WriteData(digit[D2]); //将十位数字的字符常量写入 LCD WriteData('.'); //将小数点的字符常量写入 LCD WriteData(digit[D1]); //将个位数字的字符常量写入 LCD for(i=0;i<4;i++) //延时 1s(每 1s 采集一次数据) delay(250); //延时 250ms } } //实例 84:液晶时钟设计 #include unsignedchar code digit[ ]={\"0123456789\ //定义字符数组显示数字 106 / 192 . . unsignedchar code string[]={\"BeiJing Time\定义字符数组显示提示信息 unsignedchar count; //定义变量统计中断累计次数 unsignedchars,m,h; //定义变量储存秒、分钟和小时 /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelay(unsigned charn) { unsignedchar i; for(i=0;i } /***************************************************** 函数功能:判断液晶模块的忙碌状态 返回值: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(unsigned charx) { WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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() { unsignedchar i,j; i=h/10; //取整运算,求得十位数字 109 / 192 . . j=h%10; //取余运算,求得各位数字 WriteAddress(0x44); //写显示地址,将十位数字显示在第 2 行第 5 列 WriteData(digit[i]); //将十位数字的字符常量写入 LCD WriteData(digit[j]); //将个位数字的字符常量写入 LCD } /******************************************************************** ********** 函数功能:显示分钟 ********************************************************************* *********/ voidDisplayMinute() { unsignedchar i,j; i=m/10; //取整运算,求得十位数字 j=m%10; //取余运算,求得各位数字 WriteAddress(0x47); //写显示地址,将十位数字显示在第 2 行第 8 列 WriteData(digit[i]); //将十位数字的字符常量写入 LCD WriteData(digit[j]); //将个位数字的字符常量写入 LCD } /******************************************************************** ********** 函数功能:显示秒 ********************************************************************* *********/ voidDisplaySecond() { unsignedchar i,j; i=s/10; //取整运算,求得十位数字 j=s%10; //取余运算,求得各位数字 WriteAddress(0x4a); //写显示地址,将十位数字显示在第 2 行第 11 列 WriteData(digit[i]); //将十位数字的字符常量写入 LCD WriteData(digit[j]); //将个位数字的字符常量写入 LCD } /******************************************************************** * mainfunction ********************************************************************* **/ 110 / 192 . . voidmain(void) { unsignedchar i; LcdInitiate(); //调用 LCD 初始化函数 TMOD=0x01; TH0=(65536-46083)/25 6; TL0=(65536-46083)%25 6; EA=1; ET0=1; TR0=1; //使用定时器 T0 的模式 1 //定时器 T0 的高 8 位设置初值 //定时器 T0 的低 8 位设置初值 //开总中断 //定时器 T0 中断允许 //启动定时器 T0 count=0; s=0; m=0; h=0; //中断次数初始化为 0 //秒初始化为 0 //分钟初始化为 0 //小时初始化为 0 WriteAddress(0x03); //写地址,从第 1 行第 4 列开始显示 i=0; //从字符数组的第 1 个元素开始显示 while(string[i]!='\\0') //只要没有显示到字符串的结束标志'\\0',就继续 { WriteData(string[i]);//将第 i 个字符数组元素写入 LCD i++; //指向下一个数组元素 } WriteAddress(0x46); //写地址,将第二个分号显示在第 2 行第 7 列 WriteData(':'); //将分号的字符常量写入 LCD WriteAddress(0x49); //写地址,将第二个分号显示在第 2 行第 10 列 WriteData(':'); //将分号的字符常量写入 LCD while(1) //无限循环 { DisplayHour() //显示小时 ; //给硬件一点反应时间 delay(5); DisplayMinute(); //显示分钟 delay(5); //给硬件一点反应时间 DisplaySecond(); //显示秒 delay(5); //给硬件一点反应时间 } } /******************************************************* 函数功能:定时器 T0 的中断服务函数 ********************************************************/ voidTime0(void ) interrupt 1using 1//定时器 T0 的中断编号为 1,使用第 1 组工 作寄存器 { . . 111 / 192 . . } count++; //每产生 1 次中断,中断累计次数加 1 if(count==20) //如果中断次数计满 20 次 { count=0; //中断累计次数清 0 s++; //秒加 1 } if(s==60) //如果计满 60 秒 { s=0; //秒清 0 m++; //分钟加 1 } if(m==60) //如果计满 60 分 { m=0 //分钟清 0 ; //小时加 1 h++ ; //如果计满 24 小时 } if(h==24) //小时清 0 { h=0; } TH0=(65536-46083)/256; //定时器 T0 高 8 位重新赋初值 TL0=(65536-46083)%256; //定时器 T0 低 8 位重新赋初值 /******************************************************** ***********一些芯片的 使用*****24c02 DS18B20 红外遥控 X5045 ADC0832 DAC0832 DS1302 **********************************************/ // 85 \"0x0ff\" AT24C02 P1 //实例 85:将数据\"0x0ff\"写入 AT24C02 再读出送 P1 口显示 #include . . sbitSCL=P3^3; //将串行时钟总线 SDA 位定义在为 P3.3 引脚 112 / 192 . . /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /*************************************************** 函数功能:开始数据传送 ***************************************************/ 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 { unsignedchar i; 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(unsigned chary) 114 / 192 . . { 后 unsignedchar i; bitack_bit; //储存应答位 for(i =0;i < 8;i++) // 循环移入 8 个位 { SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到 S //因为传送时高位在前,低位在 _nop_(); SCL= 1; _nop_(); _nop_(); //等待一个机器周期 //在 SCL 的上升沿将数据写入 AT24Cxx //等待一个机器周期 //等待一个机器周期 SCL= 0; 据所需的8个脉冲 y<<= 1; } SDA = 1; 释放 SDA 线, //将 SCL 重新置为低电平,以在 SCL线形成传送数 //将 y 中的各二进位向左移一位 // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1) //以让 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(unsigned charadd,unsigned chardat) // 在指定地址 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(unsigned charset_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 (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /******************************************************************** *********** 以下是对液晶模块的操作程序 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(unsigned charx) { WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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); WriteInstruction(0x38); delaynms(5); WriteInstruction(0x0c); delaynms(5); WriteInstruction(0x06); delaynms(5); WriteInstruction(0x01); delaynms(5); //延时 5ms ,给硬件一点反应时间 //连续三次,确保初始化成功 //显示模式设置:显示开,无光标,光标不闪烁 //显示模式设置:光标右移,字符不移 //清屏幕指令,将以前的显示内容清除 } /*************************************************** 函数功能:显示小时 ***************************************************/ voidDisplay(unsigned charx) { unsignedchar i,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 { unsignedchar i; 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(unsigned chary) { unsignedchar i; bitack_bit; //储存应答位 for(i =0;i < 8;i++) // 循环移入 8 个位 { SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到 S //因为传送时高位在前,低位在 后 _nop_(); //等待一个机器周期 SCL= 1; //在 SCL 的上升沿将数据写入 AT24Cxx _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 SCL= 0; 据所需的8个脉冲 y<<= 1; } SDA = 1; 释放 SDA 线, //将 SCL 重新置为低电平,以在 SCL线形成传送数 //将 y 中的各二进位向左移一位 // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1) //以让 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(unsigned charadd,unsigned chardat) // 在指定地址 addr 处写入数据 WriteCurrent { start(); //开始数据传递 122 / 192 . . 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_add 出口参数:x ***************************************************/ unsignedcharReadSet(unsigned charset_add) // 在指定地址读取 { start(); //开始数据传递 WriteCurrent(OP_WRITE); //选择要操作的 AT24Cxx 芯片,并告知要对 其写入数据 WriteCurrent(set_add); //写入指定地址 return(ReadCurrent()); //从指定地址读出数据并返回 } /******************************************************************** * 函数功能:主函数 ********************************************************************* **/ voidmain(void) { unsignedcharsum; //储存计数值 unsignedcharx; //储存从 AT24C02 读出的值 123 / 192 . . LcdInitiate(); //调用 LCD 初始化函数 sum=0; //将计数值初始化为 0 while(1) //无限循环 { if(S==0) //如果该键被按下 { delaynms(80); //软件消抖,延时 80ms if(S==0) //确实该键被按下 sum++; //计件值加 1 if(sum==99) //如果计满 99 sum=0; //清 0,重新开始计数 } WriteSet(0x01,sum); //将计件值写入 AT24C02 中的指定地址\"0x01\" x=ReadSet(0x01); //从 AT24C02 中读出计件值 Display(x); //将计件值用 1602LCD 显示 } } // 87 I2C AT24C02 //实例 87:对 I2C 总线上挂接多个 AT24C02 的读写操作 #include #define OP_WRITE10xa0 // 器件 1 地址以及写入操作,0xa1 即为 10100000B #define OP_READ2 0xaf // 器件 2 地址以及读取操作,0xa1 即为 10101111B #define OP_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() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 124 / 192 . . 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /*************************************************** 函数功能:开始数据传送 ***************************************************/ 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 { unsignedchar i; 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(unsigned chary) { unsignedchar i; bitack_bit; //储存应答位 for(i =0;i < 8;i++) // 循环移入 8 个位 { SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到 S //因为传送时高位在前,低位在后 _nop_(); //等待一个机器周期 SCL= 1; //在 SCL 的上升沿将数据写入 AT24Cxx _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 SCL= 0; 数据所需的8个脉冲 y<<= 1; } //将 SCL 重新置为低电平,以在 SCL线形成传送 //将 y 中的各二进位向左移一位 126 / 192 . . SDA = 1; 释放 SDA 线, // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1) //以让 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(储存待写入的数据) ***************************************************/ voidWriteSet1(unsigned charadd,unsigned char dat) // 在指定地址 addr 处写入数据 WriteCurrent { start(); //开始数据传递 WriteCurrent(OP_WRITE1); //选择要操作的第一个 AT24Cxx 芯片,并告知要 对其写入数据 WriteCurrent(add); //写入指定地址 WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据 stop(); //停止数据传递 delaynms(4); //1 个字节的写入周期为 1ms, 最好延时 1ms 以 上 } /*************************************************** 函数功能:向第二个 AT24Cxx 中的指定地址写入数据 入口参数:add(储存指定的地址);dat(储存待写入的数据) ***************************************************/ voidWriteSet2(unsigned charadd,unsigned char dat) // 在指定地址 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(unsigned charset_addr) // 在指定地址读取 { start(); //开始数据传递 128 / 192 . . WriteCurrent(OP_WRITE1); //选择要操作的第一个 AT24Cxx 芯片,并 告知要对其写入数据 WriteCurrent(set_addr); //写入指定地址 return(ReadCurrent1()); //从第一个 AT24Cxx 芯片指定地址读出数据 并返回 } /*************************************************** 函数功能:从第二个 AT24Cxx 中的指定地址读取数据 入口参数:set_addr 出口参数:x ***************************************************/ unsignedcharReadSet2(unsigned charset_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 // 包含 51 单片机寄存器定义的头文件 . 129 / 192 . #include #define OP_WRITE0xa0 // 器件 1 地址以及写入操作,0xa1 即为 10100000B sbitSDA=P3^4; //将串行数据总线 SDA 位定义在为 P3.4 引脚 sbitSCL=P3^3; //将串行时钟总线 SDA 位定义在为 P3.3 引脚 sbitflag=P3^0; /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /*************************************************** 函数功能:开始数据传送 ***************************************************/ voidstart() // 开始位 { SDA = 1; //SDA 初始化为高电平“1” SCL= 1; //开始数据传送时,要求 SCL 为高电平“1” _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 SDA = 0; //SDA 的下降沿被认为是开始信号 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 130 / 192 . . SCL= 0; //SCL 为低电平时,SDA 上数据才允许变化(即允许以后的数据传 递) _nop_(); //等待一个机器周期 } /*************************************************** 函数功能:结束数据传送 ***************************************************/ 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 { unsignedchar i; 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(unsigned chary) { unsignedchar i; bitack_bit; //储存应答位 for(i =0;i < 8;i++) // 循环移入 8 个位 { SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到 S //因为传送时高位在前,低位在后 _nop_(); //等待一个机器周期 SCL= 1; //在 SCL 的上升沿将数据写入 AT24Cxx _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 SCL= 0; 数据所需的8个脉冲 y<<= 1; } SDA = 1; 释放 SDA 线, //将 SCL 重新置为低电平,以在 SCL线形成传送 //将 y 中的各二进位向左移一位 // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1) //以让 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(unsigned charset_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 #define OP_WRITE0xa0 // 器件 1 地址以及写入操作,0xa1 即为 10100000B sbitSDA=P3^4; //将串行数据总线 SDA 位定义在为 P3.4 引脚 sbitSCL=P3^3; //将串行时钟总线 SDA 位定义在为 P3.3 引脚 sbitflag=P3^0; /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /*************************************************** 函数功能:开始数据传送 ***************************************************/ voidstart() // 开始位 { SDA = 1; //SDA 初始化为高电平“1” SCL= 1; //开始数据传送时,要求 SCL 为高电平“1” _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 SDA = 0; //SDA 的下降沿被认为是开始信号 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 134 / 192 . . SCL= 0; //SCL 为低电平时,SDA 上数据才允许变化(即允许以后的数据传 递) _nop_(); //等待一个机器周期 } /*************************************************** 函数功能:结束数据传送 ***************************************************/ 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(unsigned chary) { unsignedchar i; 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; //将 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(unsigned charadd,unsigned chardat) // 在指定地址 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); //将数据\"0xf0\"写入第一个 AT24C02 的指定地址 \"0x36\" delaynms(50); //延时 50ms } while(flag==0) ; } } /*************************************************** 函数功能:定时器 T0 的中断函数,使 P3.0 引脚输出 100ms 方波 ***************************************************/ voidTime0(void) interrupt 1using1 { TH0=(65536-46083)/256; TL0=(65536-46083)%256; flag=!flag; } //实例 89:将\"渴望\"乐谱写入 AT24C02 并读出播放 #include //以下是 C 调低音的音频宏定义 #definel_dao262 //将“l_dao”宏定义为低音“1”的频率 262Hz #definel_re 286 //将“l_re”宏定义为低音“2”的频率 286Hz 137 / 192 . . #definel_mi 311 //将“l_mi”宏定义为低音“3”的频率 311Hz #definel_fa349 //将“l_fa”宏定义为低音“4”的频率 349Hz #definel_sao392 //将“l_sao”宏定义为低音“5”的频率 392Hz #definel_la440 //将“l_a”宏定义为低音“6”的频率 440Hz #definel_xi 494 //将“l_xi”宏定义为低音“7”的频率 494Hz //以下是 C 调中音的音频宏定义 #definedao523 //将“dao”宏定义为中音“1”的频率 523Hz #definere 587 //将“re”宏定义为中音“2”的频率 587Hz #definemi659 //将“mi”宏定义为中音“3”的频率 659Hz #definefa698 //将“fa”宏定义为中音“4”的频率 698Hz #definesao784 //将“sao”宏定义为中音“5”的频率 784Hz #definela880 //将“la”宏定义为中音“6”的频率 880Hz #definexi 987 //将“xi”宏定义为中音“7”的频率 523Hz //以下是 C 调高音的音频宏定义 #defineh_dao1046 //将“h_dao”宏定义为高音“1”的频率 1046Hz #defineh_re1174 //将“h_re”宏定义为高音“2”的频率 1174Hz #defineh_mi1318 //将“h_mi”宏定义为高音“3”的频率 1318Hz #defineh_fa 1396 //将“h_fa”宏定义为高音“4”的频率 1396Hz #defineh_sao1567 //将“h_sao”宏定义为高音“5”的频率 1567Hz #defineh_la 1760 //将“h_la”宏定义为高音“6”的频率 1760Hz #defineh_xi1975 //将“h_xi”宏定义为高音“7”的频率 1975Hz /******************************************* 函数功能:节拍的延时的基本单位,延时 200ms ******************************************/ voiddelay() { unsignedchar i,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() { unsignedchar i,j; 138 / 192 . . for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /*************************************************** 函数功能:开始数据传送 ***************************************************/ 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() { unsignedchar i; 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(unsigned chary) { unsignedchar i; 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; //根据上述规定,SCL 应为高电平 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 _nop_(); //等待一个机器周期 ack_bit=SDA;//接受设备(AT24Cxx)向 SDA 送低电平,表示已经接收到一个字 节 SCL= 0; 递) return ack_bit;// 返回 AT24Cxx 应答位 } /*************************************************** 函数功能:向 AT24Cxx 中的指定地址写入数据 入口参数:add(储存指定的地址);dat(储存待写入的数据) ***************************************************/ voidWriteSet(unsigned charadd,unsigned chardat) { 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 //若送高电平,表示没有接收到,传送异常 //SCL 为低电平时,SDA 上数据才允许变化(即允许以后的数据传 141 / 192 . . ***************************************************/ unsignedcharReadSet(unsigned charset_addr) { start(); //开始数据传递 WriteCurrent(OP_WRITE); //选择要操作的 AT24Cxx 芯片,并告知要对其写入数 据 WriteCurrent(set_addr); //写入指定地址 return(ReadCurrent()); //从指定地址读出数据并返回 } /*************************************************** 函数功能:主函数 ***************************************************/ main(void) { unsignedchar i,j; unsignedchartemp; //储存压缩后的音频 unsignedcharJi; //储存音符节拍 unsignedchar N; //储存音符的最大个数以在 AT24C02 中为音符和节拍分 配存储空间 unsignedintfr; //储存解压缩后的音频 //以下是《渴望》片头曲的一段简谱 unsigned intcode f[]={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 作为简谱的结束标 志 //以下是简谱中每个音符的节拍 unsignedchar code JP[]={4,1,1,4,1,1,2, 2,2,2,2,8, 142 / 192 . . 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 位计数器) SDA = 1; //SDA=1,SCL=1,使主从设备处于空闲状态 SCL= 1; while(1) //无限循环 { i=0; //从第 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 temp=ReadSet(0x00+i); //读出音频 143 / 192 . . 位的赋初值方法 位的赋初值方法 Ji=ReadSet(0x00+N+i) //读出节拍 ; //将音频解压 fr=8*temp; //定时常数的计算公式 C=460830/fr; //可证明这是 13 位计数器 TH0 高 8 TH0=(8192-C)/32; TL0=(8192-C)%32; //可证明这是 13 位计数器 TL0 低 5 TR0=1; for(j=0;j //启动定时器 T0 //控制节拍数 //延时 1 个节拍单位 //关闭定时器 T0 } sound=1; for(i=0;i<8;i++) 播放 } //播放完毕后,关闭蜂鸣器 //播放完毕后,停顿一段时间后继续 } delay(); ///////////////////////// /*********************************************************** 函数功能:定时器 T0 的中断服务子程序,使 P3.7 引脚输出音频的方波 ************************************************************/ voidTime0(void ) interrupt 1using 1 { TH0=(8192-C)/32; TL0=(8192-C)%32; sound=!sound; } //可证明这是 13 位计数器 TH0 高 8 位的赋初值方法 //可证明这是 13 位计数器 TL0 低 5 位的赋初值方法 //将 P3.7 引脚输出电平取反,形成方波 // 90 DS18B20 //实例 90:DS18B20 温度检测及其液晶显示 #include . . 144 / 192 . . unsignedchar code Error[]={\"Error!Check!\ //说明没有检测到 DS18B20 unsignedchar code Temp[]={\"Temp:\ //说明显示的是温度 unsignedchar code Cent[]={\"Cent\ //温度单位 /******************************************************************** *********** 以下是对液晶模块的操作程序 ********************************************************************* **********/ 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() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /***************************************************** 函数功能:判断液晶模块的忙碌状态 返回值: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; //将忙碌标志电平赋给 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_(); _nop_(); //空操作四个机器周期,给硬件反应时间 E=0; //当 E 由高电平跳变成低电平时,液晶模块开始 执行命令 } /***************************************************** 函数功能:指定字符显示的实际地址 入口参数:x ***************************************************/ voidWriteAddress(unsigned charx) { WriteInstruction(x|0x80);//显示位置的确定方法规定为\"80H+地址码 x\" } /***************************************************** 函数功能:将数据(字符的标准 ASCII 码)写入液晶模块 146 / 192 . . 入口参数:y(为字符常量) ***************************************************/ voidWriteData(unsigned chary) { 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) { unsignedchar i=0; unsignedchar dat; //储存读出的一个字节数据 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) { unsignedchar i=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) { unsignedchar i; WriteAddress(0x00); //写显示地址,将在第 1 行第 1 列开始显 示 i= 0; //从第一个字符开始显示 while(Error[i]!= '\\0') //只要没有写到结束标志,就继续写 { WriteData(Error[i]); //将字符常量写入 LCD i++; //指向下一个字符 delaynms(100); //延时 100ms 较长时间,以看清关于 显示的说明 } while(1) //进入死循环,等待查明原因 ; } /***************************************************** 函数功能:显示说明信息 ***************************************************/ voiddisplay_explain(void) { unsignedchar i; WriteAddress(0x00); //写显示地址,将在第 1 行第 1 列开始显 示 i= 0; //从第一个字符开始显示 while(Str[i]!= '\\0') //只要没有写到结束标志,就继续写 { WriteData(Str[i]); //将字符常量写入 LCD i++; //指向下一个字符 delaynms(100); //延时 100ms 较长时间,以看清关于 显示的说明 } } /***************************************************** 函数功能:显示温度符号 150 / 192 . . ***************************************************/ voiddisplay_symbol(void) { unsignedchar i; 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('.'); delaynms(50); //将小数点的字符常量写入 LCD //延时 1ms 给硬件一点反应时间 } /***************************************************** 函数功能:显示温度的单位(Cent) ***************************************************/ void display_cent(void) { unsignedchar i; WriteAddress(0x4c); //写显示地址,将在第 2 行第 13 列开 始显示 i= 0; //从第一个字符开始显示 while(Cent[i]!= '\\0') //只要没有写到结束标志,就继续写 { WriteData(Cent[i]); //将字符常量写入 LCD i++; //指向下一个字符 delaynms(50); //延时 1ms 给硬件一点反应时间 } } /***************************************************** 函数功能:显示温度的整数部分 入口参数:x 151 / 192 . . ***************************************************/ voiddisplay_temp1(unsigned charx) { unsignedchar j,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(unsigned charx) { 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; //储存温度的整数部分 unsigned char //储存温度的小数部分 TD; //将液晶初始化 LcdInitiate(); //延时 5ms 给硬件一点反应时间 delaynms(5); 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 #defineWREN 0x06 //包含单片机寄存器的头文件 //包含_nop_()函数定义的头文件 //将 SCK 位定义为 P3.4 引脚 //将 SI 位定义为 P3.5 引脚 //将 SO 位定义为 P3.6 引脚 //将 SCK 位定义为 P3.7 引脚 //写使能锁存器允许 153 / 192 . . #defineWRDI0x04 //写使能锁存器禁止 #defineWRSR0x01 //写状态寄存器 #defineREAD 0x03 //读出 #defineWRITE 0x02 //写入 /***************************************************** 函数功能:延时 1ms (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是 1 毫秒 ***************************************************/ voiddelay1ms() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i } /***************************************************** 函数功能:从 X5045 的当前地址读出数据 出口参数:x ***************************************************/ unsignedcharReadCurrent(void) { unsignedchar i; 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(unsigned chardat) { unsignedchar i; 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(unsigned char rs) { CS=0; //拉低 CS,选中 X5045 WriteCurrent(WREN); //写使能锁存器允许 CS=1; //拉高 CS CS=0; //重新拉低 CS,否则下面的写寄存器状态指令将被 丢弃 WriteCurrent(WRSR); //写状态寄存器 WriteCurrent(rs); //写入新设定的寄存器状态值 CS=1; //拉高 CS } /***************************************************** 函数功能:写数据到 X5045 的指定地址 入口参数:addr ***************************************************/ voidWriteSet(unsigned chardat,unsignedchar addr) { SCK=0; //将 SCK 置于已知状态 CS=0; //拉低 CS,选中 X5045 WriteCurrent(WREN); //写使能锁存器允许 155 / 192 . . CS=1; //拉高 CS CS=0; //重新拉低 CS,否则下面的写入指令将被丢弃 WriteCurrent(WRITE); //写入指令 WriteCurrent(addr); //写入指定地址 WriteCurrent(dat); //写入数据 CS=1; //拉高 CS SCK=0; //将 SCK 置于已知状态 } /***************************************************** 函数功能:从 X5045 的指定地址读出数据 入口参数:addr 出口参数:dat ***************************************************/ unsignedcharReadSet(unsigned charaddr) { unsignedchar dat; 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); //将数据“0xaa”写入指定地址“0x10” delaynms(10); //X5045 的写入周期约为 10ms P1=ReadSet(0x10); //将数据读出送 P1 口显示 WatchDog(); //复位看门狗 } } // 92 X5045 P1 //实例 92:将流水灯控制码写入 X5045 并读出送 P1 口显示 #include unsignedchar lamp[]={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() { unsignedchar i,j; for(i=0;i<10;i++) for(j=0;j<33;j++) ; } /***************************************************** 函数功能:延时若干毫秒 157 / 192 . . 入口参数:n ***************************************************/ voiddelaynms(unsigned charn) { unsignedchar i; for(i=0;i