51单片机定时器初值计算可以同时开两种定时器模式吗 比如 TMOD=0x01; TMOD=0x20;

当前位置: >>
郭天祥新概念51单片机C语言教程例题
郭天祥-1-目录例 2.2.1编写程序,点亮第一个发光二极管(part2_1.cP27 ) .............. - 4 -例 2.5.1 利用 for 语句延时特性,编写第一个发光二极管以间隔 1S 亮灭闪动的程序(part2_3.c P42) ......................................................................................... - 5 -例 2.6.1 编写程序使第一个发光二极管以间隔 500ms 亮灭闪动。(part2_4.cP48) ........................................................................................................................ - 5 -例 2.7.1 例 2.8.3编写程序使第一个二极管以亮 200ms 、灭 800ms 的方式闪动。(part2_5.c P49) ....................................................................................................... - 6 利用 C51 自带库_crol_(),以间隔 500ms,实现流水灯程序(part2_6.cP53) ........................................................................................................................ - 6 -例 3.2.1 编写程序使第一个数码管显示 8(part2.1_.1cP59)..................... - 8 -例 3.2.2让实验板上 6 个数码管同时点亮,依次显示 0 到 F,时间间隔为0.5ms,循环下去。(part2.1_2.c P61) ............................................................. - 8 -例 3.3.1 第一个数码管显示 1,时间为 0.5s,然后关闭它,立即让第二个数码管显示 2,时间为 0.5s,在关闭它??一直到最后一个数码管显示 6,时间同样为 0.5s ,关闭它之后再回来显示第一个数码管,一直循环下去。( part2.1_3.c P62) ........................................................................................................................ - 9 -例 3.5.1 例 3.5.2利用定时器 0 工作方式 1,在实验板上实现第一个发光管以 1s 亮灭闪烁。(part2.1.4.c P74) ................................................................................. - 11 用定时器 0 的方式 1 实现个第一发光二极管以 200ms 间隔闪烁,用定时器 1 的方式 1 实现数码管前两位 59s 循环计时。(part2.1_5.c P75) . - 12 -例 4.1.1 用数码管前两位显示一个十进制数,变化范围为 00~59,开始时显示 00,每按下 S2 键一次,数值加 1;每按下 S3 键一次,数值减 1;每按下 S4 键一次,数值归零;按下 S5 键一次,利用定时器功能使数值开始自动每秒加 1,再次按下 S5 键,数值停止加 1,保持显示原数。(part2.2_1.c P82) . - 14 -例 4.2.1 实验班上电时,数码管不显示,顺序按下矩阵键盘后,数码管上依次显示 0~F,六个数码管同时静态显示即可。(part2.2_2.c P87) ............. - 17 -例 5.3.1 用单片机控制 ADC0804 进行数模转换,当拧动实验板上 A/D 旁边的电位时,在数码管的前三位以十进制方式显示出 A/D 转换后的数字量(8 位 郭天祥-2-A/D 转换后数值在 0~255 变化)。(part2.3_1.c P107) .............................. - 21 -例 5.5.1 用单片机控制 DAC0832 芯片输出电流,让发光二级管 D12 由灭均匀变到最亮,再由最亮均匀熄灭。在最亮和最暗时使用蜂鸣器分别警报一声,完 成整个周期时间控制在 5S 左右,循环变化。(part2.3_2.c P121) ............ - 24 -例 6.5.1在上位机上用串口调试助手发送一个字符 X,单片机收到字符后返回给上位机“I get X”,串口波特率设为 9600bps。(part2.4_1.c P137) . - 26 -例 6.6.1 单片机上电后等待从上位机串口发来的命令,同时在数码管的前三位以十进制方式显示 A/D 采集的数值,在未收到上位机发送来的启动 A/D 转换 命令之前数码管始终显示 000。当收到上位机以十六进制发送来的 01 后,向上 位机发送字符串“Turn on ad!”同时间隔 1s 读取一次 A/D 的值,然后把 A/D 采 集回来的 8 位二进制转换成十进制表示的实际电压浮点数,并且从串口发送给 上位机,形式如“The voltage is 3.398438V”,发送周期也是一秒一次,同时在 数码管上也要每秒刷新现实的数值。当收到上位机以十六进制发送过来的 02 后,向上位机发送字符串“Turn off ad!”,然后停止发送电压值,数码管上显 示上次结束时保持的值。当收到上位机发来的其他任何数时,向上位机发送字 符串“Error!”。 ................................................................................................... - 27 -例 7.2.1实现 1602 液晶的第一行显示“I LOVE MCU!”,在第二行显示。 ........................................................................................ - 31 -例 7.2.2 实现 1602 第一行从左侧移入“Hello everyone!”同时第二行从右侧移入“Welcome to here!”,移入速度自定,然后停留在屏幕上。( part2.5_2.c P154) .................................................................................................................... - 33 例 7.3.1 实现 12232 液晶的第一行显示“I LOVE MCU!”,第二行显示“我爱单 片机”。(part2.5_3.c P160) .......................................................................... - 34 -例 7.3.2实现 12232 液晶第一行从右侧移入“Hello everyone!”,同时第二行从右侧移入“欢迎大家来学习!”移入速度自定,最后停留在屏幕上。 (part2.5_4.c P163) .......................................................................................... - 37 例 7.4.1 实现在 12864 液晶上第一行显示“”,并且让每一位数字随机 变化,第二行显示“
”,第三行显示“天祥电子”,第四行对 应第三行显示出下划线。(part2.5_5.c P173) .............................................. - 40 知识点:生成随机数(part2.5_512232suiji.c P176) ........................................ - 44 -例 8.3.1利用定时器产生一个 0~99 秒变化的秒表,并且显示在数码管上,每过一秒将这个变化的数写入板上 AT24C02 内部。当关闭实验板电源,并再次 打开实验板电源时,单片机先从 AT24C02 中将原来写入的数读取出来,接着此 数继续变化并显示在数码管上。(part2.6_1.c P188) .................................. - 48 -例 10.1.1利用定时器 0 工作方式 0,在实验板上实现第一个发光管以 1s 亮 P203) ........................................................................... - 53 灭闪烁。(part3.1.1.c 郭天祥-3-例 10.2.1利用定时器 0 工作方式 2,在实验板上实现第一个发光管以 1s 亮 P204) ........................................................................... - 54 -灭闪烁。(part3.1.2.c例 10.3.1利用定时器工作方式 3,在实验板上实现:用 TL0 计数器对应的 8 位定时器实现第一个发光管以 1s 亮灭闪烁,用 TH0 计数器对应的 8 位定时 器实现第二个发光管以 0.5s 亮灭闪烁。(part3.1.3.c P206) ....................... - 55 -例 10.5.1 利用计数器 0 工作方式 1,在实验板上实现:用一根导线一端连接GND 引脚,另一端去接触 T0(P3.4)引脚,每接触一下,计数器计一次数,将所 计 的 数 值 实时 显 示 在数 码 管 的 前两 位 , 计满 100 时 清 0 , 再从 头 计 起 。 (part3.1.4.c P214) ........................................................................................... - 56 -例 11.1.1 设置单片机串行口的工作模式 0,间隔循环发送十六进制数 0xAA,然后用双路示波器观察 P3.0 和 P3.1 口波形。( .............................................. - 58 -例 11.3.1 用交叉串口线连接两块实验板,或直接用短线交叉线连接连个单片机的 P3.0 和 P3.1 口(共地)。在一块板上编写矩阵键盘扫描程序,当扫描到有 键按下时,将键值通过串口发送出去,另一块板上单片机收到串口发送来的键 值后,将对应键值以 0~F 方式显示在数码管上。 ............................................ - 60 -例 11.4.1程序分为主机程序和从机程序,约定一次传送的数据为 16B,以02H 地址的从机为例。(图 11.4.2 为多机通信主机程序流程图) ...................... - 65 图 11.4.3 为多机通信从机程序流程图。 ............................................................. - 68 从机程序代码:(part3.2.6.c P234) ............................................................... - 68 -例 12.8.1 指针使用例程:(point.cP264) ................................................ - 72 -例 13.1.1编写程序实现:开启两个外部中断,设置低电平触发中断,用定时器计数并且显示在数码管的前两位,当计数到 5 时,使单片机进入空闲(休 眠)模式,同时关闭定时器,当单片机响应外部中断后,从空闲(休眠)模式返 回,同时开启定时器。(..................................................................................... - 72 -例 13.2.1实验板上实现如下描述:程序启动后设定看门狗溢出时间为 2s,然后点亮第一个发光二极管,稍延时一会,然后熄灭发光二极管,使程序进入 等待死循环状态,并且在死循环中大约每隔 1s 喂狗一次,看程序运行是否正 常。......................................................................................................................... - 74 -例 13.6.1.在实验板上实现:操作 STC 单片机自带的 E2PROM,存储一组按秒递增的两位数据,并且将数据实时显示在数码管上,数据每变化一次就往 E2PROM 中写入一次,当关闭实验板电源并再次开启电源时,从 E2PROM 中读 取先前存储的数据,接着递增显示。................................................................. - 77 -例 13.7.1STC89LE516AD/X2 系列单片机的 A/D 转换功能。时钟 11.0592MHz, 郭天祥-4-转换结果以 16 进制形式输出到串行口,可以用串行口调试程序,观察输出结果 (本代码摘自宏晶科技芯片手册,经作者调试可正常运行)。..................... - 80 -例 13.8.1 给出一个 STC12C5412AD 应用的参考程序。(part3.4.6.cP287)................................................................................................................................. - 82 -程序 14.3.1 利用 51 单片机的定时器设计一个时钟。 ............................ - 90 程序 15.5.1 使用 DS12C887 时钟芯片设计高精度时钟。 .......................... - 98 -程序 16.3.1使用 TX-1C 实验板上的 DS18B20 温度传感器设计温控系统 C语言源代码(part4.3 P349) .............................................................................. - 108 -程序 17.3.1 太阳能充/放电控制器 C 语言源代码................................... - 114 ISD400x 系列语音芯片 C 语言参考程序: ...................................................... - 135 -例 21.1.1使用 TX-1C 实验板上两个独立按键调节直流电机的转速,同时在实验板的数码管上象征性的显示相应的转速值。通过控制单片机输出不同占空 比的 PWM 信号来控制直流电机的转速(感性认识)。(part5.3 P434) - 139 -例 21.2.1 步进电机应用 C 语言程序设计(part3.2P444) ..................... - 143 -例 21.3.1舵机应用 C 语言程序设计实例:开机时舵机角度自动转为 0 度,通过实验板上的独立按键调节舵机的角度转动,并且在实验板数码管上显示相 应的角度。本例仅演示 5 个角度的控制,若想实现任意角度控制请大家自行编 程实验。程序代码如下:(part5.3 P453) ...................................................... - 146 //调节舵机使之转动 5 个角度 0 45 90 135 180 PWM 信号周期为 20ms, ... - 146 //控制高电平的持续时间即可控制舵机停止制动的角度,0.5ms-0 度 1-45 1.5-90 2-135 2.5-180 ........................................................................................................ - 146 //程序流程是:开机时舵机角度自动转为 0 度,按下 P3.7 则转到 45 度,以后就 根据两个按键的按下而转动......................................................错误!未定义书签。例 2.2.1 编写程序,点亮第一个发光二极管(part2_1.c P27 )#include &reg52.h& //52 系列单片机头文件 sbit led1=P1^0; //声明单片机 P1 口的第一位 void main() //主函数 { led1=0; /*点亮第一个发光二极管*/ 郭天祥-5-} 例 2.2.2 编写程序,点亮 P1 口的若干二极管(part2_2.c #include &reg52.h& //52 系列单片机头文件 void main() //主函数 { P1=0 //while(1); } P39 )例 2.5.1 利用 for 语句延时特性,编写第一个发光二极管以 间隔 1S 亮灭闪动的程序(part2_3.c#include &reg52.h& //52 系列单片机头文件 #define uint unsigned int //宏定义 sbit led1=P1^0; //声明单片机 P1 口的第一位 uint i,j; void main() //主函数 { while(1) //大循环 { led1=0; /*点亮第一个发光二极管*/ for(i=1;i&0;i--) //延时 for(j=110;j&0;j--); led1=1; /*关闭第一个发光二极管*/ for(i=1000;i&0;i--) //延时 for(j=110;j&0;j--); } }P42)例 2.6.1 编写程序使第一个发光二极管以间隔 500ms 亮灭闪 动。 (part2_4.c#include &reg52.h& #define uint unsigned int sbit led1=P1^0; void delay1s(); void main()P48)//52 系列单片机头文件 //宏定义 //声明单片机 P1 口的第一位 //声明子函数 //主函数 郭天祥-6-{ while(1) { led1=0; delay1s(); led1=1; delay1s(); } } void delay1s() { uint i,j; for(i=500;i&0;i--) for(j=110;j&0;j--); } //大循环 /*点亮第一个发光二极管*/ //调用延时子函数 /*关闭第一个发光二极管*/ //调用延时子函数//子函数体例 2.7.1 编写程序使第一个二极管以亮 200ms、灭 800ms 的方式闪动。(part2_5.c#include &reg52.h& #define uint unsigned int sbit led1=P1^0; void delayms(uint); void main() { while(1) { led1=0; delayms(200); led1=1; delayms(800); } } void delayms(uint xms) { uint i,j; for(i=i&0;i--) for(j=110;j&0;j--); }P49)//52 系列单片机头文件 //宏定义 //声明单片机 P1 口的第一位 //声明子函数 //主函数 //大循环 /*点亮第一个发光二极管*/ //延时 200 毫秒 /*关闭第一个发光二极管*/ //延时 800 毫秒//i=xms 即延时约 xms 毫秒例 2.8.3 利用 C51 自带库_crol_(),以间隔 500ms,实现流水 郭天祥-7-灯程序(part2_6.cP53)#include &reg52.h& //52 系列单片机头文件 #include &intrins.h& #define uint unsigned int //宏定义 #define uchar unsigned char void delayms(uint); //声明子函数 void main() //主函数 { aa=0 //赋初值
while(1) //大循环 { P1= delayms(500); //延时 500 毫秒 aa=_crol_(aa,1); //将 aa 循环左移 1 位后再赋给 aa } } void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } 郭天祥-8-例 3.2.1 编写程序使第一个数码管显示 8(part2.1_.1c P59)#include &reg52.h& sbit dula=P2^6; sbit wela=P2^7; void main() { wela=1; P0=0xFE; wela=0; dula=1; P0=0x7F; dula=0; while(1); } //52 系列单片机头文件 //申明 U1 锁存器的锁存端 //申明 U2 锁存器的锁存端//打开 U2 锁存器 //送入位选信号 //关闭 U2 锁存器 //打开 U1 锁存器 //送入段选信号 //关闭 U2 锁存器 //程序停止到这里例 3.2.2 让实验板上 6 个数码管同时点亮, 依次显示 0 到 F, 时间间隔为 0.5ms,循环下去。 (part2.1_2.c#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 unchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void main() { wela=1; //打开 U2 锁存端 P0=0 //送入位选信号 wela=0; //关闭 U2 锁存端 while(1)P61) 郭天祥-9-{ for(num=0;num&16;num++) //16 个数循环显示 { dula=1; //打开 U1 锁存端 P0=table[num]; //送入段选信号 dula=0; //关闭 U1 锁存端 delay(500); //延时 0.5 秒 } } } void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); }例 3.3.1 第一个数码管显示 1,时间为 0.5s,然后关闭它, 立即让第二个数码管显示 2, 时间为 0.5s,在关闭它??一直 到最后一个数码管显示 6,时间同样为 0.5s,关闭它之后再 回来显示第一个数码管, 一直循环下去。 (part2.1_3.c#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 unchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void main() { while(1) { dula=1;P62) 郭天祥- 10 -P0=table[1]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(500); //延时 dula=1; P0=table[2]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(500); //延时 dula=1; P0=table[3]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(500); //延时 dula=1; P0=table[4]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0xf7; //送位选数据 wela=0; delayms(500); //延时 dula=1; P0=table[5]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(500); //延时 郭天祥- 11 -dula=1; P0=table[6]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(500); //延时 } } void delayms(uint xms) { uinti,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); }例 3.5.1 利用定时器 0 工作方式 1,在实验板上实现第一个 发光管以 1s 亮灭闪烁。 (part2.1.4.c P74)#include&reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; void main() { TMOD=0x01; //设置定时器 0 为工作方式 1(M1M0 为 01) TH0=()/256; //装初值 11.0592M 晶振定时 50ms 数为 45872 TL0=()%256; EA=1; //开总中断 ET0=1; //开定时器 0 中断 TR0=1; // 启动定时器 0 while(1); //程序停止在这里等待中断中断发生 } void T0_time() interrupt 1 { TH0=()/256; //重装初值 TL0=()%256; num++; //num 每加 1 次判断一次是否到 20 次 郭天祥- 12 -if(num==20) //如果到了 20 次,说明 1 秒时间到 { num=0; //然后把 num 清 0 重新再计 20 次 led1=~led1; //让发光管状态取反 } }3.5.2 用定时器 0 的方式 1 实现第一个发光二极管以 200ms 间隔闪烁, 用定时器 1 的方式 1 实现数码管前两位 59s 循环 计时。 (part2.1_5.c P75)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 sbit led1=P1^0; unchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void display(uchar,uchar); uchar num,num1,num2,shi, void main() { TMOD=0x11; //设置定时器 0 为工作方式 1(M1M0 为 11) TH0=()/256; //装初值 11.0592M 晶振定时 50ms 数为 45872 TL0=()%256; TH1=()/256; //装初值 11.0592M 晶振定时 50ms 数为 45872 TL1=()%256; EA=1; //开总中断 ET0=1; //开定时器 0 中断 ET1=1; //开定时器 1 中断 TR0=1; // 启动定时器 0 TR1=1; // 启动定时器 1 while(1); //程序停止在这里等待中断中断发生 { display(shi,ge); } 郭天祥- 13 -} void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge];//送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 } void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void T0_time() interrupt 1 { TH0=()/256; //重装初值 TL0=()%256; num++; if(num1==4) //如果到了 4 次,说明 200ms 时间到 { num1=0; //然后把 num1 清 0 重新再计 4 次 led1=~led1; //让发光管状态取反 } } void T1_time() interrupt 3 { 郭天祥- 14 -TH1=()/256; //重装初值 TL1=()%256; num2++; if(num2==20) //如果到了 20 次,说明 1 秒刷新时间到 { num2=0; //然后把 num2 清 0 重新再计 4 次 num++; if(num==60) //这个数用来送数码管显示,到 60 后归 0 num=0; shi=num/10; //把一个 2 位数分离后分别送数码管显示 ge=num%10; //十位和个位 } }例 4.1.1 用数码管前两位显示一个十进制数,变化范围为 00~59,开始时显示 00,每按下 S1 键一次,数值加 1;每 按下 S2 键一次,数值减 1;每按下 S3 键一次,数值归零; 按下 S4 键一次,利用定时器功能使数值开始自动每秒加 1, 再次按下 S4 键, 数值停止加 1, 保持显示原数。 (part2.2_1.c P82)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit key1=P3^4; sbit key2=P3^5; sbit key3=P3^6; sbit key4=P3^7; 郭天祥- 15 -sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); uchar numt0, void display(uchar numdis) //显示子函数 { uchar shi, //分离两个分别要显示的数 shi=numdis/10; ge=numdis%10; dula=1; P0=table[shi]; //送十位段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge]; dula=0; P0=0 wela=1; P0=0 wela=0; delayms(5);//送个位段选数据} void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void init() //初始化函数 { TMOD=0x01;//设置定时器 0 为工作方式 1() TH0=()/256;//装初值 50ms 一次中断 TL0=()%256; 郭天祥- 16 -EA=1; //开总中断 ET0=1; //开定时器 0 中断 } void keyscan() { if(key1==0) { delayms(10); if(key1==0) { num++; if(num==60)//当到 60 时重新归 0 num=0; while(!key1);//等待按键释放 } } if(key2==0) { delayms(10); if(key2==0) { if(num==0)//当到 0 时重新归 60 num=60; num--; while(!key2); } } if(key3==0) { delayms(10); if(key3==0) { num=0; //清 0 while(!key3); } } if(key4==0) { delayms(10); if(key4==0) { while(!key4); TR0=~TR0;//启动或停止定时器 0 } 郭天祥- 17 -} } void main() { init();//初始化函数 while(1) { keyscan(); display(num); } } void T0_time() interrupt 1 { TH0=()/256;//重装初值 TL0=()%256; numt0++; if(numt0==20) //如果到了 20 次,说明 1 秒时间到 { numt0=0; //然后把 num 清 0 重新再计 20 次 num++; if(num==60) num=0; } }例 4.2.1 实验班上电时,数码管不显示,顺序按下矩阵键盘 后, 数码管上依次显示 0~F, 六个数码管同时静态显示即可。 (part2.2_2.c P87)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint xms) { 郭天祥- 18 -uint i,j; for(i=i&0;i--) for(j=110;j&0;j--);//i=xms 即延时约 xms 毫秒} void display(uchar num) { P0=table[num]; //显示函数只送段选数据 dula=1; dula=0; } void matrixkeyscan() { uchar temp, P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xee: key=0; case 0xde: key=1; case 0xbe: key=2; case 0x7e: key=3; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } 郭天祥- 19 -display(key); } } P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xed: key=4; case 0xdd: key=5; case 0xbd: key=6; case 0x7d: key=7; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } display(key); } } P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; 郭天祥- 20 -temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xeb: key=8; case 0xdb: key=9; case 0xbb: key=10; case 0x7b: key=11; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } display(key); } } P3=0xf7; temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xe7: key=12; case 0xd7: 郭天祥- 21 -key=13; case 0xb7: key=14; case 0x77: key=15; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } display(key); } } } void main() { P0=0; //关闭所有数码管段选 dula=1; dula=0; P0=0xc0;//位选中所有数码管 wela=1; wela=0; while(1) { matrixkeyscan();//不停调用键盘扫描程序 } }例 5.3.1 用单片机控制 ADC0804 进行数模转换,当拧动实 验板上 A/D 旁边的电位时, 在数码管的前三位以十进制方式 显示出 A/D 转换后的数字量 (8 位 A/D 转换后数值在 0~255 郭天祥- 22 -变化) 。 (part2.3_1.cP107)#include &reg52.h& //52 系列单片机头文件 #include &intrins.h& #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 sbit adwr=P3^6; //定义 AD 的 WR 端口 sbit adrd=P3^7; //定义 AD 的 RD 端口 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void display(uchar bai,uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[bai]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0x7e; //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[shi]; dula=0; P0=0 wela=1; P0=0x7d; wela=0; delayms(5); dula=1; P0=table[ge]; 郭天祥- 23 -dula=0; P0=0 wela=1; P0=0x7b; wela=0; delayms(5); }void main() {//主程序uchar a,A1,A2,A3, wela=1; P0=0x7f; //置 CSAD 为 0,选通 ADCS 以后不必再管 ADCS wela=0; while(1) { adwr=1; _nop_(); adwr=0; //启动 AD 转换 _nop_(); adwr=1; for(a=10;a&0;a--) //TX-1C 实验板 AD 工作频率较低, 所以启动转 换后要多留点时间用来转换 { // 这里把显示部分放这里的原因也是为了延 长转换时间 display(A1,A2,A3); } P1=0 //读取 P1 口之前先给其写全 1 adrd=1; //选通 ADR _nop_(); adrd=0; //AD 读使能 _nop_(); adval=P1; //AD 数据读取赋给 P1 口 adrd=1; A1=adval/100; //分出百,十,和个位 A2=adval%100/10; A3=adval%10; } } 郭天祥- 24 -例 5.5.1 用单片机控制 DAC0832 芯片输出电流,让发光二 级管 D12 由灭均匀变到最亮,再由最亮均匀熄灭。在最亮 和最暗时使用蜂鸣器分别警报一声,完成整个周期时间控制 在 5S 左右,循环变化。 (part2.3_2.c P121)#include &reg52.h& #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 sbit dawr=P3^6; //定义 DA 的 WR 端口 sbit dacs=P3^2; //定义 DA 的 CS 端口 sbit beep=P2^3; //定义蜂鸣器端口 void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void main() { uchar val, dula=0; wela=0; dacs=0; dawr=0; P0=0; while(1) { if(flag==0) { val+=5; P0= //通过 P0 口给 DA 数据口赋值 if(val==255) { flag=1; beep=0; delayms(100); beep=1; } 郭天祥- 25 -delayms(50); } else { val-=5; P0= //通过 P0 口给 DA 数据口赋值 if(val==0) { flag=0; beep=0; delayms(100); beep=1; } delayms(50); } } } 郭天祥- 26 -例 6.5.1 在上位机上用串口调试助手发送一个字符 X,单片 机收到字符后返回给上位机“I get X” ,串口波特率设为 9600bps。 (part2.4_1.c#include &reg52.h& #define uchar unsigned char #define uint unsigned int unsigned char flag,a,i; uchar code table[]=&I get &; //uchar code table[]={'I',' ','g','e','t',' '}; void init() { TMOD=0x20; TH1=0 TL1=0 TR1=1; REN=1; SM0=0; SM1=1; EA=1; ES=1; } void main() { init(); while(1) { if(flag==1) { ES=0; for(i=0;i&6;i++) { SBUF=table[i]; while(!TI); TI=0; }P137) 郭天祥- 27 -SBUF=a; while(!TI); TI=0; ES=1; flag=0; } } } void ser() interrupt 4 { RI=0; a=SBUF; flag=1; }例 6.6.1 单片机上电后等待从上位机串口发来的命令,同时 在数码管的前三位以十进制方式显示 A/D 采集的数值, 在未 收到上位机发送来的启动 A/D 转换命令之前数码管始终显 示 000。当收到上位机以十六进制发送来的 01 后,向上位 机发送字符串“Turn on ad!”同时间隔 1s 读取一次 A/D 的 值,然后把 A/D 采集回来的 8 位二进制转换成十进制表示 的实际电压浮点数, 并且从串口发送给上位机, 形式如 “The voltage is 3.398438V” ,发送周期也是一秒一次,同时在数 码管上也要每秒刷新现实的数值。当收到上位机以十六进制 发送过来的 02 后,向上位机发送字符串“Turn off ad!” , 然后停止发送电压值,数码管上显示上次结束时保持的值。 当收到上位机发来的其他任何数时,向上位机发送字符串 “Error!” 。(part2.4_2.c P140) 郭天祥- 28 -#include &reg52.h& #include &intrins.h& #include &stdio.h& #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 sbit adwr=P3^6; //定义 AD 的 WR 端口 sbit adrd=P3^7; //定义 AD 的 RD 端口 uchar flag,a; unsigned char flag_uart,flag_time,flag_on,a,i,t0_num,ad_ float ad_ uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void init() { TMOD=0x21; // SCON=0x50; TH0=()/256; TL0=()%256; TH1=0 TL1=0 TR1=1; ET0=1; SM0=0; SM1=1; REN=1; EA=1; ES=1; } void display(uchar value) //显示子函数 { uchar bai,shi, bai=value/100; //分出百,十,和个位 郭天祥- 29 -shi=value%100/10; ge=value%10; dula=1; P0=table[bai]; //送段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0x7e; //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[shi]; dula=0; P0=0 wela=1; P0=0x7d; wela=0; delayms(5); dula=1; P0=table[ge]; dula=0; P0=0 wela=1; P0=0x7b; wela=0; delayms(5); } uchar get_ad() { adwr=1; _nop_(); adwr=0; _nop_(); adwr=1; P1=0 adrd=1; _nop_(); adrd=0; _nop_(); adval=P1; adrd=1; }//启动 AD 转换//读取 P1 口之前先给其写全 1//AD 读使能 //AD 数据读取 郭天祥- 30 -void main() { init(); wela=1; P0=0x7f; //置 CSAD 为 0,选通 ADCS 以后不必再管 ADCS wela=0; while(1) { if(flag_uart==1) { flag_uart=0; ES=0; TI=1; switch(flag_on) { case 0: puts(&Turn on ad!\n&); TR0=1; case 1: printf(&Turn off ad!\n&); TR0=0; case 2: puts(&Error!\n&); } while(!TI);//必须要加 TI=0; ES=1; } if(flag_time==1) { flag_time=0; ad_val=get_ad(); ad_vo=(float)ad_val*5.0/256.0; ES=0; TI=1; printf(&The voltage is %fV\n&,ad_vo); while(!TI); TI=0; ES=1; } display(ad_val); } } void timer0() interrupt 1 郭天祥- 31 -{ TH0=()/256; TL0=()%256; t0_num++; if(t0_num==20) { t0_num=0; flag_time=1; } } void ser() interrupt 4 { RI=0; a=SBUF; flag_uart=1; if(a==1) flag_on=0; else if(a==2) flag_on=1; else flag_on=2; }例 7.2.1 实现 1602 液晶的第一行显示“I LOVE MCU! ” ,在 第二行显示 。(part2.5_1.c P152) #include&reg52.h& #define uchar unsigned char #define uint unsigned int uchar code table[]=&I LOVE MCU!&; uchar code table1[]=&&; sbit lcden=P3^4; //液晶使能端 sbit lcdrs=P3^5; //液晶数据命令选择端 sbit dula=P2^6; //申明 U1 锁存器的锁存端 郭天祥- 32 -sbit wela=P2^7; //申明 U2 锁存器的锁存端 void delay(uint z) { uint x,y; for(x=z;x&0;x--) for(y=110;y&0;y--); } void write_com(uchar com) { lcdrs=0; P0= delay(5); lcden=1; delay(5); lcden=0; } void write_data(uchar date) { lcdrs=1; P0= delay(5); lcden=1; delay(5); lcden=0; } void init() { dula=0; wela=0; lcden=0; write_com(0x38);//设置 16X2 显示,5X7 点阵,8 位数据接口 write_com(0x0c);//设置开显示,不显示光标 write_com(0x06);//写一个字符后地址指针加 1 write_com(0x01);//显示清零,数据指针清零 } void main() { init(); write_com(0x80); for(num=0;num&11;num++) { write_data(table[num]); delay(5); 郭天祥- 33 -} write_com(0x80+0x40); for(num=0;num&13;num++) { write_data(table1[num]); delay(5); } while(1); }例 7.2.2 实现 1602 第一行从左侧移入“Hello everyone!” 同时第二行从右侧移入 “Welcome to here!” , 移入速度自定, 然后停留在屏幕上。 (part2.5_2.c#include&reg52.h& #define uchar unsigned char #define uint unsigned int uchar code table[]=&Hello everyone!&; uchar code table1[]=&Welcome to here!&; sbit lcden=P3^4; //液晶使能端 sbit lcdrs=P3^5; //液晶数据命令选择端 sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 void delay(uint z) { uint x,y; for(x=z;x&0;x--) for(y=110;y&0;y--); } void write_com(uchar com) { lcdrs=0; P0= delay(5); lcden=1; delay(5); lcden=0; } void write_data(uchar date)P154) 郭天祥- 34 -{ lcdrs=1; P0= delay(5); lcden=1; delay(5); lcden=0; } void init() { dula=0; wela=0; lcden=0; write_com(0x38);//设置 16X2 显示,5X7 点阵,8 位数据接口 write_com(0x0c);//设置开显示,不显示光标 write_com(0x06);//写一个字符后地址指针加 1 write_com(0x01);//显示清零,数据指针清零 } void main() { init(); write_com(0x80+0x10); for(num=0;num&15;num++) { write_data(table[num]); delay(5); } write_com(0x80+0x50); for(num=0;num&16;num++) { write_data(table1[num]); delay(5); } for(num=0;num&16;num++) { write_com(0x18); delay(200); } while(1); }例 7.3.1 实现 12232 液晶的第一行显示 “I LOVE MCU!” , 第 郭天祥- 35 -二行显示“我爱单片机” 。 (part2.5_3.c#include &REG52.h& #define uint unsigned int #define uchar unsigned char sbit CS=P1^2; sbit SID=P1^1; sbit SCLK=P1^0; uchar code disps[]={&I LOVE MCU!&}; uchar code dispx[]={&我爱单片机!&}; void delay_1ms(uint x) { uint i,j; for(j=0;j&x;j++) for(i=0;i&110;i++); } void send_command(uchar command_data) { uchar i_ i_data=0xf8; CS=1; SCLK=0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) {P160) 郭天祥- 36 -SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } CS=0; delay_1ms(10); } void send_data(uchar command_data) { uchar i_ i_data=0 CS=1; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } CS=0; delay_1ms(10); } void lcd_init() { 郭天祥- 37 -delay_1ms(100); send_command(0x30); /*设置 8 位数据接口,基本指令模式。*/ send_command(0x02); /*清 DDRAM*/ send_command(0x06); /*游标及显示右移一位*/ send_command(0x0c); /*整体显示开,游标关,反白关*/ send_command(0x01); /*写入空格清屏幕*/ send_command(0x80); /*设定首次显示位置*/ } void display_s() { send_command(0x80); for(a=0;a&11;a++) { send_data(disps[a]); } } void display_x() { send_command(0x92); for(a=0;a&11;a++) { send_data(dispx[a]); } } main() { lcd_init(); display_s(); display_x(); while(1); }例 7.3.2 实现 12232 液晶第一行从右侧移入“Hello everyone!” ,同时第二行从右侧移入“欢迎大家来学习! ” 移入速度自定,最后停留在屏幕上。 (part2.5_4.c#include &REG52.h& #define uint unsigned intP163) 郭天祥- 38 -#define uchar unsigned char sbit CS=P1^2; sbit SID=P1^1; sbit SCLK=P1^0; uchar code disps[]={&Hello everyone!&}; uchar code dispx[]={&欢迎大家来学习!&}; void delay_1ms(uint x) { uint i,j; for(j=0;j&x;j++) for(i=0;i&110;i++); } void send_command(uchar command_data) { uchar i_ i_data=0xf8; CS=1; SCLK=0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; 郭天祥- 39 -} CS=0; delay_1ms(1); } void send_data(uchar command_data) { uchar i_ i_data=0 CS=1; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } CS=0; delay_1ms(1); } void lcd_init() { delay_1ms(100); send_command(0x30); /*设置 8 位数据接口,基本指令模式。*/ send_command(0x02); /*清 DDRAM*/ send_command(0x06); /*游标及显示右移一位*/ 郭天祥- 40 -send_command(0x0c); /*整体显示开,游标关,反白关*/ send_command(0x01); /*写入空格清屏幕*/ send_command(0x80); /*设定首次显示位置*/ } void display_s(uchar num) { send_command(0x88-num); for(a=0;a&15;a++) { send_data(disps[a]); } } void display_x(uchar num) { send_command(0x98-num); for(a=0;a&15;a++) { send_data(dispx[a]); } } main() { lcd_init(); for(aa=0;aa&9;aa++) { display_s(aa); display_x(aa); delay_1ms(300); } while(1); }例 7.4.1 实现在 12864 液晶上第一行显示 “” , 并且让每一位数字随机变化,第二行显示 “” ,第三行显示“天祥电子” ,第四行对 应第三行显示出下划线。 (part2.5_5.cP173) 郭天祥- 41 -#include &reg51.h& #include &intrins.h& #include &stdlib.h& #define uchar unsigned char #define uint unsigned int /* 端口定义*/ #define LCD_data P0 //数据口 sbit LCD_RS = P3^5; //寄存器选择输入 sbit LCD_RW = P3^6; //液晶读/写控制 sbit LCD_EN = P3^4; //液晶使能控制 sbit LCD_PSB = P3^7; //串/并方式控制 sbit wela = P2^6; sbit dula = P2^7; uchar dis1[10]; uchar code dis2[] = {&&}; uchar code dis3[] = {&天祥电子&}; uchar code dis4[] = {&--------&}; void delay_1ms(uint x) { uint i,j; for(j=0;j&x;j++) for(i=0;i&110;i++); } /*******************************************************************/ /* */ /* 写 指 令 数 据 到 LCD */ /*RS=L, RW=L, E=高脉冲, D0-D7=指令码。 */ /* */ /*******************************************************************/ void write_cmd(uchar cmd) { LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; P0 = delay_1ms(5); LCD_EN = 1; delay_1ms(5); LCD_EN = 0; } /*******************************************************************/ /* */ /* 写 显 示 数 据 到 LCD 郭天祥- 42 -*/ /*RS=H, RW=L, E=高脉冲, D0-D7=数据。 */ /* */ /*******************************************************************/ void write_dat(uchar dat) { LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P0 = delay_1ms(5); LCD_EN = 1; delay_1ms(5); LCD_EN = 0; } /*********************************************************/ /* */ /* 设定显示位置 */ /* */ /*********************************************************/ void lcd_pos(uchar X,uchar Y) { if (X==0) {X=0x80;} else if (X==1) {X=0x90;} else if (X==2) {X=0x88;} else if (X==3) {X=0x98;} pos = X+Y ; write_cmd(pos); //显示地址 } void makerand() { ran=rand(); dis1[0]=ran/; dis1[1]=ran%+0x30; dis1[2]=ran%x30; dis1[3]=ran%100/10+0x30; dis1[4]=ran%10+0x30; ran=rand(); 郭天祥- 43 -dis1[5]=ran/; dis1[6]=ran%+0x30; dis1[7]=ran%x30; dis1[8]=ran%100/10+0x30; dis1[9]=ran%10+0x30; } /*******************************************************************/ /* */ /* LCD 初 始 化 设 定 */ /* */ /*******************************************************************/ void lcd_init() { LCD_PSB = 1; //并口方式 write_cmd(0x30); //基本指令操作 delay_1ms(5); write_cmd(0x0C); //显示开,关光标 delay_1ms(5); write_cmd(0x01); //清除 LCD 的显示内容 delay_1ms(5); } /*********************************************************/ /* */ /* 主程序 */ /* */ /*********************************************************/ main() { wela=0; dula=0; delay_1ms(10); //延时 lcd_init(); //初始化 LCD lcd_pos(1,0); //设置显示位置为第二行的第 1 个字符 i = 0; while(dis2[i] != '\0') { write_dat(dis2[i]); //显示字符 i++; } lcd_pos(2,0); //设置显示位置为第三行的第 1 个字符 i = 0; 郭天祥- 44 -while(dis3[i] != '\0') { write_dat(dis3[i]); //显示字符 i++; } lcd_pos(3,0); //设置显示位置为第四行的第 1 个字符 i = 0; while(dis4[i] != '\0') { write_dat(dis4[i]); //显示字符 i++; } while(1) { lcd_pos(0,0); //设置显示位置为第一行的第 1 个字符 makerand(); for(i=0;i&10;i++) { write_dat(dis1[i]); } } }知识点:生成随机数(part2.5_512232suiji.c P176)#include &reg52.h& #include &stdlib.h& #define uint unsigned int #define uchar unsigned char sbit CS=P1^2; sbit SID=P1^1; sbit SCLK=P1^0; uchar disps[10]; uchar code dispx[]={&我爱单片机!&}; void delay_1ms(uint x) { uint i,j; for(j=0;j&x;j++) for(i=0;i&110;i++); } void send_command(uchar command_data) { 郭天祥- 45 - uchar i_ i_data=0xf8; CS=1; SCLK=0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } CS=0; delay_1ms(10); } void send_data(uchar command_data) { uchar i_ i_data=0 CS=1; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; 郭天祥- 46 -i_data=i_data&&1; } i_data=command_ i_data&=0xf0; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } i_data=command_ i_data&&=4; for(i=0;i&8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data&&1; } CS=0; delay_1ms(10); } void lcd_init() { delay_1ms(100); send_command(0x30); /*设置 8 位数据接口,基本指令模式。*/ send_command(0x02); /*清 DDRAM*/ send_command(0x06); /*游标及显示右移一位*/ send_command(0x0c); /*整体显示开,游标关,反白关*/ send_command(0x01); /*写入空格清屏幕*/ send_command(0x80); /*设定首次显示位置*/ } void display_s() { send_command(0x80); for(a=0;a&10;a++) { send_data(disps[a]); } } void display_x() 郭天祥- 47 -{ send_command(0x92); for(a=0;a&11;a++) { send_data(dispx[a]); } } void makerand() { ran=rand(); disps[0]=ran/; disps[1]=ran%+0x30; disps[2]=ran%x30; disps[3]=ran%100/10+0x30; disps[4]=ran%10+0x30; ran=rand(); disps[5]=ran/; disps[6]=ran%+0x30; disps[7]=ran%x30; disps[8]=ran%100/10+0x30; disps[9]=ran%10+0x30; } main() { lcd_init(); display_x(); while(1) { makerand(); display_s(); delay_1ms(100); } while(1); } 郭天祥- 48 -例 8.3.1 利用定时器产生一个 0~99 秒变化的秒表,并且显 示在数码管上, 每过一秒将这个变化的数写入板上 AT24C02 内部。当关闭实验板电源,并再次打开实验板电源时,单片 机先从 AT24C02 中将原来写入的数读取出来,接着此数继 续变化并显示在数码管上。 (part2.6_1.c#include&reg52.h& #define uchar unsigned char #define uint unsigned int bit write=0; //写 24C02 的标志; sbit sda=P2^0; sbit scl=P2^1; sbit dula=P2^6; sbit wela=P2^7; uchar sec, uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delay() { ;; } void delay1ms(uint z) { uint x,y; for(x=z;x&0;x--)P188) 郭天祥- 49 -for(y=110;y&0;y--); } void start() //开始信号 { sda=1; delay(); scl=1; delay(); sda=0; delay(); } void stop() //停止 { sda=0; delay(); scl=1; delay(); sda=1; delay(); } void respons() //应答 { scl=1; delay(); while((sda==1)&&(i&250))i++; scl=0; delay(); } void init() { sda=1; delay(); scl=1; delay(); } void write_byte(uchar date) { uchar i, temp= for(i=0;i&8;i++) { temp=temp&&1; scl=0; 郭天祥- 50 -delay(); sda=CY; delay(); scl=1; delay(); } scl=0; delay(); sda=1; delay(); } uchar read_byte() { uchar i,k; scl=0; delay(); sda=1; delay(); for(i=0;i&8;i++) { scl=1; delay(); k=(k&&1)| scl=0; delay(); } } void write_add(uchar address,uchar date) { start(); write_byte(0xa0); respons(); write_byte(address); respons(); write_byte(date); respons(); stop(); } uchar read_add(uchar address) { start(); write_byte(0xa0); 郭天祥- 51 -respons(); write_byte(address); respons(); start(); write_byte(0xa1); respons(); date=read_byte(); stop(); } void display(uchar bai_c,uchar sh_c) //显示程序 { dula=0; P0=table[bai_c]; //显示第一位 dula=1; dula=0; wela=0; P0=0x7e; wela=1; wela=0; delay1ms(5); dula=0; P0=table[sh_c]; //显示第二位 dula=1; dula=0; wela=0; P0=0x7d; wela=1; wela=0; delay1ms(5); } void main() { init(); sec=read_add(2); //读出保存的数据赋于 sec if(sec&100) //防止首次读取出错误数据 sec=0; TMOD=0x01; //定时器工作在方式 1 ET0=1; EA=1; TH0=()/256; //对 TH0 TL0 赋值 TL0=()%256; //使定时器 0.05 秒中断一次 TR0=1; //开始计时 while(1) 郭天祥- 52 -{ display(sec/10,sec%10); if(write==1) { write=0; write_add(2,sec); } } } void t0() interrupt 1 //定时中断服务函数 { TH0=()/256; //对 TH0 TL0 赋值 TL0=()%256; //重装计数初值 tcnt++; //每过 50ms tcnt 加一 if(tcnt==20) //计满 20 次(1 秒)时 { tcnt=0; //重新再计 sec++; write=1; //1 秒写一次 24C02 if(sec==100) //定时 100 秒,再从零开始计时 sec=0; } } //判断计时器是否计时一秒 //清零 //在 24c02 的地址 2 中写入数据 sec 郭天祥- 53 -例 10.1.1 利用定时器 0 工作方式 0, 在实验板上实现第一个 发光管以 1s 亮灭闪烁。 (part3.1.1.c P203)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; void main() { TMOD=0x00;//设置定时器 0 为工作方式 0() TH0=()/32;//装初值 TL0=()%32; EA=1; //开总中断 ET0=1; //开定时器 0 中断 TR0=1; //启动定时器 0 while(1) //程序停止在这里等待中断发生 { if(num==200) //如果到了 200 次,说明 1 秒时间到 { num=0; //然后把 num 清 0 重新再计 200 次 led1=~led1; //让发光管状态取反 郭天祥- 54 -} } } void T0_time() interrupt 1 { TH0=()/32;//重装初值 TL0=()%32; num++; }例 10.2.1 利用定时器 0 工作方式 2, 在实验板上实现第一个 发光管以 1s 亮灭闪烁。 (part3.1.2.c P204)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; void main() { TMOD=0x02;//设置定时器 0 为工作方式 2() TH0=6; //装初值 TL0=6; EA=1; //开总中断 ET0=1; //开定时器 0 中断 TR0=1; //启动定时器 0 while(1) //程序停止在这里等待中断发生 { if(num==3686) //如果到了 3686 次,说明 1 秒时间到 { num=0; //然后把 num 清 0 重新再计 3686 次 led1=~led1; //让发光管状态取反 } } } void T0_time() interrupt 1 { num++; } 郭天祥- 55 -例 10.3.1 利用定时器工作方式 3,在实验板上实现:用 TL0 计数器对应的 8 位定时器实现第一个发光管以 1s 亮灭闪烁, 用 TH0 计数器对应的 8 位定时器实现第二个发光管以 0.5s 亮灭闪烁。 (part3.1.3.c P206)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit led1=P1^0; sbit led2=P1^1; uint num1,num2; void main() { TMOD=0x03;//设置定时器 0 为工作方式 3() TH0=6; //装初值 TL0=6; EA=1; //开总中断 ET0=1; //开定时器 0 中断 ET1=1; //开定时器 1 中断 TR0=1; //启动定时器 0 TR1=1; //启动定时器 0 的高 8 位计数器 while(1) //程序停止在这里等待中断发生 { if(num1&=3686) //如果到了 3686 次,说明 1 秒时间到 { num1=0; //然后把 num1 清 0 重新再计 3686 次 led1=~led1; //让发光管状态取反 } if(num2&=1843) //如果到了 1843 次,说明半秒时间到 { num2=0; //然后把 num2 清 0 重新再计 1843 次 led2=~led2; //让发光管状态取反 } } } void TL0_time() interrupt 1 { TL0=6; //重装初值 num1++; }void TH0_time() interrupt 3 { 郭天祥- 56 -TH0=6; num2++; }//重装初值例 10.5.1 利用计数器 0 工作方式 1,在实验板上实现:用一 根导线一端连接 GND 引脚,另一端去接触 T0(P3.4)引脚, 每接触一下,计数器计一次数,将所计的数值实时显示在数 码管的前两位, 计满 100 时清 0, 再从头计起。 (part3.1.4.c P214)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送十位段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge]; //送个位段选数据 dula=0; P0=0 wela=1; P0=0 wela=0; delayms(5); 郭天祥- 57 -} void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } uint read() { uchar tl,th1,th2; while(1) { th1=TH0; tl=TL0; th2=TH0; if(th1==th2) } val=th1*256+ } void main() { uchar a,b; TMOD=0x05; //设置计数器 0 为工作方式 1() TH0=0; //将计数器寄存器初值清零 TL0=0; TR0=1; while(1) { num=read(); if(num&=100) { num=0; TH0=0; //将计数器寄存器值清零 TL0=0; } a=num/10; b=num%10; display(a,b); } } 郭天祥- 58 -例 11.1.1 设置单片机串行口的工作模式 0, 间隔循环发送十 六进制数 0xAA,然后用双路示波器观察 P3.0 和 P3.1 口波形。 (part3.2.1.cP218) 郭天祥- 59 -#include&reg52.h& #define uchar unsigned char #define uint unsigned int void delayms(uint xms) { uint i,j; for(i=i&0;i--) for(j=110;j&0;j--); } void main() { SCON=0; EA=1; ES=1; TI=0; while(1) { SBUF=0 delayms(1); } } void ser0() interrupt 4 { TI=0; }//i=xms 即延时约 xms 毫秒例 11.2.1 设置单片机串行口工作模式 2,间隔循环发送 16 进制数 0xAA,然后用 示波器观察单片机 P3.1 口波形。 (part3.2.2.c P220) #include&reg52.h& #define uchar unsigned char #define uint unsigned int void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void main() { SM0=1; SM1=0; TB8=1; EA=1; 郭天祥- 60 -ES=1; TI=0; while(1) { SBUF=0 delayms(1); } } void ser0() interrupt 4 { TI=0; }例 11.3.1 用交叉串口线连接两块实验板, 或直接用短线交叉 线连接连个单片机的 P3.0 和 P3.1 口(共地) 。在一块板上 编写矩阵键盘扫描程序,当扫描到有键按下时,将键值通过 串口发送出去,另一块板上单片机收到串口发送来的键值 后,将对应键值以 0~F 方式显示在数码管上。发送方单片机程序代码(part3.2.3.c P225) #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void send(uchar key_num) { SBUF=key_ while(!TI); TI=0; } void matrixkeyscan() { uchar temp, 郭天祥- 61 -P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xee: key=0; case 0xde: key=1; case 0xbe: key=2; case 0x7e: key=3; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } send(key); } } P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { 郭天祥- 62 -temp=P3; switch(temp) { case 0xed: key=4; case 0xdd: key=5; case 0xbd: key=6; case 0x7d: key=7; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } send(key); } } P3=0 temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xeb: key=8; case 0xdb: key=9; case 0xbb: 郭天祥- 63 -key=10; case 0x7b: key=11; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; } send(key); } } P3=0xf7; temp=P3; temp=temp&0xf0; if(temp!=0xf0) { delayms(10); temp=P3; temp=temp&0xf0; if(temp!=0xf0) { temp=P3; switch(temp) { case 0xe7: key=12; case 0xd7: key=13; case 0xb7: key=14; case 0x77: key=15; } while(temp!=0xf0) { temp=P3; temp=temp&0xf0; 郭天祥- 64 -} send(key); } } } void main() { TMOD=0x20; TH1=0 TL1=0 TR1=1; SM0=0; SM1=1; EA=1; ES=1; while(1) { matrixkeyscan();//不停调用键盘扫描程序 } } 接收方单片机程序代码 part3.2.4.c 如下: #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void display(uchar num) { P0=table[num]; //显示函数只送段选数据 dula=1; dula=0; } void main() { TMOD=0x20; TH1=0 TL1=0 TR1=1; REN=1; 郭天祥- 65 -SM0=0; SM1=1; EA=1; ES=1; P0=0xc0;//位选中所有数码管 wela=1; wela=0; while(1);//等待串口中断产生,然后更新显示 } void ser() interrupt 4 { RI=0; a=SBUF; display(a); }例 11.4.1 程序分为主机程序和从机程序, 约定一次传送的数 据为 16B,以 02H 地址的从机为例。(图 11.4.2 为多机通信 主机程序流程图)主机程序代码:(part3.2.5.c P232) #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int #define SLAVE 0x02 /*从机地址*/ #define BN 16 uchar rbuf[16]; uchar code tbuf[16]={&master transmit&}; void err(void) { SBUF=0 while(TI!=1); TI=0; } uchar master(uchar addr,uchar command) { uchar aa,i,p; while(1) { SBUF=SLAVE; /* 发呼叫地址 */ 郭天祥- 66 -while(TI!=1); TI=0; while(RI!=1); RI=0; /* 等待从机回答 */ if(SBUF!=addr) err(); /* 若地址错,发复位信号 */ else { /* 地址相符 */ TB8=0; /* 清地址标志 */ SBUF= /* 发命令 */ while(TI!=1); TI=0; while(RI!=1); RI=0; aa=SBUF; /* 接收状态 */ if((aa&0x08)==0x08) /* 若命令未被接收,发复位信号 */ { TB8=1; err(); } else { if(command==0x01) /* 是发送命令 */ { if((aa&0x01)==0x01) /* 从机准备好接收 */ { do { p=0; /* 清校验和 */ for(i=0;i&BN;i++) { SBUF=tbuf[i]; /* 发送一数据 */ p+=tbuf[i]; while(TI!=1); TI=0; } SBUF=p; /* 发送校验和 */ while(TI!=1); TI=0; while(RI!=1); RI=0; }while(SBUF!=0); /* 接收不正确,重新发送 */ TB8=1; /* 置地址标志 */ return(0); 郭天祥- 67 -} else { if((aa&0x02)==0x02) */ { while(1) { p=0; for(i=0;i&BN;i++) { while(RI!=1); RI=0; rbuf[i]=SBUF; p+=rbuf[i]; } while(RI!=1); RI=0; if(SBUF==p) { SBUF=0X00; /* while(TI!=1); TI=0; } else { SBUF=0 /* 新接收 */ while(TI!=1); TI=0; } } TB8=1; return(0); } } } } } } } void main() {/* 是接收命令,从机准备好发送/* 清校验和 *//* 接收一数据 */校验和相同发&00& */校验和不同发&0FF&,重/* 置地址标志 */ 郭天祥- 68 -TMOD=0x20; TL1=0 TH1=0 PCON=0x00; TR1=1; SCON=0xf0; master(SLAVE,0x01); master(SLAVE,0x02); while(1);/* T/C1 定义为方式 2 */ /* 置初值 *//* 串行口为方式 3 */} ********************************************************************* **********图 11.4.3 为多机通信从机程序流程图。 从机程序代码: (part3.2.6.c#include &reg52.h& #define uchar unsigned char #define SLAVE 0x02 #define BN 16 uchar trbuf[16]; uchar rebuf[16]; void str(void); void sre(void); void main(void) { TMOD=0x20; /*T/C1 定义为方式 2*/ TL1=0 /*置初值*/ TH1=0 PCON=0x00; TR1=1; SCON=0xf0; /*串行口为方式 3*/ ES=1; EA=1; /*开串行口中断*/ while(1) { tready=1; rready=1; } /*假定准备好发送和接收*/ } void ssio(void) interrupt 4P234) 郭天祥- 69 -{ RI=0; ES=0; /*关串行口中断*/ if(SBUF!=SLAVE) { ES=1; } /*非本机地址,继续监听*/ SM2=0; /* 取消监听状态 */ SBUF=SLAVE; /* 从本地址发回 */ while(TI!=1); TI=0; while(RI!=1); RI =0; if(RB8==1) { SM2=1; ES=1; }/* 是复位信号,恢复监听 */ a=SBUF; /* 接收命令 */ if(a==0x01)/* 从主机接收的数据 */ { if(rready==1) SBUF=0x01;/* 接收准备好发状态 */ else SBUF=0x00; while(TI!=1); TI=0; while(RI!=1); RI=0; if(RB8==1) { SM2=1; ES=1; } sre(); /* 接收数据 */ } else { if(a==0x02) /* 从机向主机发送数据*/ { 郭天祥- 70 -if(tready==1) SBUF=0x02; /* 发送准备好发状态 */ else SBUF=0x00; while(TI!=1); TI=0; while(RI!=1); RI=0; if(RB8==1) { SM2=1; ES=1; } str();/* 发送数据 */ } else { SBUF=0x80; /* 命令非法 ,发状态 */ while(TI!=1); TI=0; SM2=1; ES=1; /* 恢复监听 */ } } reti:; } void str(void) /* 发数据块 */ { uchar p,i; tready=0 ; do { p=0;/* 清校验和 */ for(i=0;i&BN;i++) { SBUF=trbuf[i]; /* 发送一数据 */ p+=trbuf[i]; while(TI!=1); TI=0; } SBUF=p; /* 发送校验和 */ while(TI!=1); TI=0; 郭天祥- 71 -while(RI!=1); RI=0; }while(SBUF!=0);/* 主机接收不正确,重新发送 */ SM2=1; ES=1; } void sre(void) /* 接收数据块 */ { uchar p,i; rready=0 ; while(1) { p=0; /* 清校验和 */ for(i=0;i&BN;i++) { while(RI!=1); RI=0; rebuf[i]=SBUF; p+=rebuf[i]; } while(RI!=1); RI=0; if(SBUF==p) { SBUF=0x00; } /* 校验和相同发&00&*/ else { SBUF=0 while(TI==0); TI=0; } } SM2=1; ES=1; }/* 接收数据 *//* 校验和不同发&0FF&,重新接收 */ 郭天祥- 72 -例 12.8.1 指针使用例程: (point.cP264)#include &reg52.h& void main(void) { //定义一些随机数据,数据存放在片内 CODE 区中 unsigned char code date[]={ 0xFF,0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF, 0x7F,0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, 0xFE,0xFF,0xFF,0xFE,0xFC,0xF8,0xF0,0xE0, 0xC0,0x80,0x0,0xE7,0xDB,0xBD,0x7E,0xFF}; //定义循环用的变量 unsigned char code * //定义基于 CODE 区的指针 do { finger = &date[0]; //取得数组第一个单元的地址 for (b=0;b&32;b++) { for(a=0; a&30000; a++); //延时一段时间 P1 = * //从指针指向的地址取数据到 P1 口 finger++; //指针加一, } } while(1); }例 13.1.1 编写程序实现: 开启两个外部中断, 设置低电平触 发中断,用定时器计数并且显示在数码管的前两位,当计数 到 5 时,使单片机进入空闲(休眠)模式,同时关闭定时器, 郭天祥- 73 -当单片机响应外部中断后,从空闲(休眠)模式返回,同时 开启定时器。 (part3.4.1.cP266)#include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint); void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送十位段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge]; //送个位段选数据 dula=0; P0=0 wela=1; P0=0 wela=0; delayms(5); } void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void main() { uchar a,b,num1; 郭天祥- 74 -TMOD=0x01; //设置定时器 0 为工作方式 1() TH0=()/256; TL0=()%256; EA=1; ET0=1; EX0=1; EX1=1; TR0=1; while(1) { if(num&=20) { num=0; num1++; if(num1==6) { ET0=0; PCON=0x03; } a=num1/10; b=num1%10; } display(a,b); } } void timer0() interrupt 1 { TH0=()/256; TL0=()%256; num++; } void ex_int0() interrupt 0 { PCON=0; ET0=1; } void ex_int1() interrupt 2 { PCON=0; ET0=1; }例 13.2.1 实验板上实现如下描述: 程序启动后设定看门狗溢 郭天祥- 75 -出时间为 2s,然后点亮第一个发光二极管,稍延时一会,然 后熄灭发光二极管,使程序进入等待死循环状态,并且在死 循 环 中 大 约 每 隔 1s 喂 狗 一 次 , 看 程 序 运 行 是 否 正 常 。(part3.4.2.c P270) #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sfr WDT_CONTR=0xe1; sbit led1=P1^0; void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void main() { WDT_CONTR=0x35; led1=0; delayms(500); led1=1; while(1) { delayms(1000); WDT_CONTR=0x35; } } 例 13.1.1 实验板上实现:在数码管前两位显示以秒递增的数,增加到 10 时,利 用 STC 单片机的软件复位功能让单片机复位。 (part3.4.3.c P273) #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int sfr ISP_CONTR=0xe7; sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; 郭天祥- 76 - void delayms(uint); void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送十位段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge]; //送个位段选数据 dula=0; P0=0 wela=1; P0=0 wela=0; delayms(5); } void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void main() { uchar a,b,num1; TMOD=0x01; //设置定时器 0 为工作方式 1() TH0=()/256; TL0=()%256; EA=1; ET0=1; TR0=1; while(1) { if(num&=20) { num=0; num1++; if(num1==10) { 郭天祥- 77 -ISP_CONTR=0x20; } a=num1/10; b=num1%10; } display(a,b); } } void timer0() interrupt 1 { TH0=()/256; TL0=()%256; num++; }例 13.6.1.在实验板上实现: 操作 STC 单片机自带的 E2PROM, 存储一组按秒递增的两位数据,并且将数据实时显示在数码 管上,数据每变化一次就往 E2PROM 中写入一次,当关闭 实验板电源并再次开启电源时,从 E2PROM 中读取先前存 储的数据,接着递增显示。 (part3.4.3.cP279) #include &intrins.h& #include &reg52.h& //52 系列单片机头文件 #define uchar unsigned char #define uint unsigned int #define RdCommand 0x01 //定义 ISP 的操作命令 #define PrgCommand 0x02 #define EraseCommand 0x03 #define Error 1 #define Ok 0 #define WaitTime 0x01 //定义 CPU 的等待时间 sfr ISP_DATA=0xe2; //寄存器申明 sfr ISP_ADDRH=0xe3; sfr ISP_ADDRL=0xe4; sfr ISP_CMD=0xe5; sfr ISP_TRIG=0xe6; sfr ISP_CONTR=0xe7; sbit dula=P2^6; //申明 U1 锁存器的锁存端 sbit wela=P2^7; //申明 U2 锁存器的锁存端 uchar code table[]={ 郭天祥- 78 -0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; void delayms(uint xms) { uint i,j; for(i=i&0;i--) //i=xms 即延时约 xms 毫秒 for(j=110;j&0;j--); } void display(uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[shi]; //送十位段选数据 dula=0; P0=0 //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0 //送位选数据 wela=0; delayms(5); //延时 dula=1; P0=table[ge]; //送个位段选数据 dula=0; P0=0 wela=1; P0=0 wela=0; delayms(5); } /* ================ 打开 ISP,IAP 功能 ================= */ void ISP_IAP_enable(void) { EA = 0; /* 关中断 */ ISP_CONTR = ISP_CONTR & 0x18; /*
*/ ISP_CONTR = ISP_CONTR | WaitT /* 写入硬件延时 */ ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */ } /* =============== 关闭 ISP,IAP 功能 ================== */ void ISP_IAP_disable(void) { ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */ ISP_TRIG = 0x00; EA = 1; /* 开中断 */ 郭天祥- 79 -} /* ================ 公用的触发代码 ==================== */ void ISPgoon(void) { ISP_IAP_enable(); /* 打开 ISP,IAP 功能 */ ISP_TRIG = 0x46; /* 触发 ISP_IAP 命令字节 1 */ ISP_TRIG = 0xb9; /* 触发 ISP_IAP 命令字节 2 */ _nop_(); } /* ==================== 字节读 ======================== */ unsigned char byte_read(unsigned int byte_addr) { ISP_ADDRH = (unsigned char)(byte_addr && 8);/* 地址赋值 */ ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff); ISP_CMD = ISP_CMD & 0xf8; /* 清除低 3 位 */ ISP_CMD = ISP_CMD | RdC /* 写入读命令 */ ISPgoon(); /* 触发执行 */ ISP_IAP_disable(); /* 关闭 ISP,IAP 功能 */ return (ISP_DATA); /* 返回读到的数据 */ } /* ================== 扇区擦除 ======================== */ void SectorErase(unsigned int sector_addr) { unsigned int iSectorA iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */ ISP_ADDRH = (unsigned char)(iSectorAddr && 8); ISP_ADDRL = 0x00; ISP_CMD = ISP_CMD & 0xf8; /* 清空低 3 位 */ ISP_CMD = ISP_CMD | EraseC /* 擦除命令 3 */ ISPgoon(); /* 触发执行 */ ISP_IAP_disable(); /* 关闭 ISP,IAP 功能 */ } /* ==================== 字节写 ======================== */ void byte_write(unsigned int byte_addr, unsigned char original_data) { ISP_ADDRH = (unsigned char)(byte_addr && 8); /* 取地址 */ ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff); ISP_CMD = ISP_CMD & 0xf8; /* 清低 3 位 */ ISP_CMD = ISP_CMD | PrgC /* 写命令 2 */ ISP_DATA = original_ /* 写入数据准备 */ ISPgoon(); /* 触发执行 */ ISP_IAP_disable(); /* 关闭 IAP 功能 */ } void main() 郭天祥- 80 -{ uchar a,b,num1; TMOD=0x01; //设置定时器 0 为工作方式 1() TH0=()/256; TL0=()%256; EA=1; ET0=1; TR0=1; num1=byte_read(0x2000);//程序开始时读取 EEPROM 中数据 if(num1&=60) //防止首次上电时读取出错 num1=0; while(1) { if(num&=20) { num=0; num1++; SectorErase(0x2000);//擦除扇区 byte_write(0x2000,num1);//重新写入数据 if(num1==60) { num1=0; } a=num1/10; b=num1%10; } display(a,b); } } void timer0() interrupt 1 { TH0=()/256; TL0=()%256; num++; }例 13.7.1STC89LE516AD/X2 系列单片机的 A/D 转换功能。 时钟 11.0592MHz,转换结果以 16 进制形式输出到串行口, 可以用串行口调试程序,观察输出结果(本代码摘自宏晶科 技芯片手册,经作者调试可正常运行) 。 (part3.4.5.cP283) 郭天祥- 81 -#include &reg52.H& #include &intrins.H& // 定义与 ADC 有关的特殊功能寄存器 sfr P1_ADC_EN = 0x97; //A/D 转换功能允许寄存器 sfr ADC_CONTR = 0xC5; //A/D 转换控制寄存器 sfr ADC_DATA = 0xC6; //A/D 转换结果寄存器 typedef unsigned char INT8U; typedef unsigned int INT16U; void delay(INT8U delay_time) // 延时函数 { INT8U INT16U for (n=0;n&delay_n++) { for(m=0;m&10000;m++); } } void initiate_RS232(void) //串口初始化 { ES = 0; // 禁止串口中断 SCON = 0x50; //
位数据位, 无奇偶校验 T2CON = 0x34; // , 由 T2 作为波特率发生器 RCAP2H = 0xFF; // 时钟 11.0592MHz, 9600 波特率 RCAP2L = 0xDB; ES = 1; // 允许串口中断 } void Send_Byte(INT8U one_byte) // 发送一个字节 { TI = 0; // 清零串口发送中断标志 SBUF = one_ while (TI == 0); TI = 0; // 清零串口发送中断标志 } INT8U get_AD_result(INT8U channel) { INT8U AD_finished = 0; // 存储 A/D 转换标志 ADC_DATA = 0; ADC_CONTR = // 选择 A/D 当前通道 delay(1); //使输入电压达到稳定 ADC_CONTR |= 0x08; // 令 ADC_START = 1, 启动 A/D 转换 AD_finished = 0; while ( AD_finished == 0 ) // 等待 A/D 转换结束 { AD_finished = (ADC_CONTR & 0x10); //, ADC_FLAG ==1 测 郭天祥- 82 -试 A/D 转换结束否 } ADC_CONTR &= 0xF7; // 令 ADC_START = 0, 关闭 A/D 转换, return (ADC_DATA); // 返回 A/D 转换结果 } void main() { initiate_RS232(); P1 = P1 | 0x63; // ,要设置为 A/D 转换的 P1.x 口,先设为高 P1_ADC_EN = 0x63; //, P1 的 P1.0,P1.1,P1.5,P1.6 设置为 A/D 转 换输入脚 // 断开 P1.0,P1.1,P1.5,P1.6 内部上拉电阻 while(1) { Send_Byte(get_AD_result(0)); //P1.0 为 A/D 当前通道, 测量并发送结果 delay(0x200); Send_Byte(get_AD_result(1)); //P1.1 为 A/D 当前通道, 测量并发送结果 delay(0x200); Send_Byte(get_AD_result(5)); //P1.5 为 A/D 当前通道, 测量并发送结果 delay(0x200); Send_Byte(get_AD_result(6)); //P1.6 为 A/D 当前通道, 测量并发送结果 delay(0x200); Send_Byte(0); // 连续发送 4 个 00H, 便于观察输出显示 Send_Byte(0); Send_Byte(0); Send_Byte(0); delay(0x200); // 延时 delay(0x200); delay(0x200); delay(0x200); delay(0x200); delay(0x200); } }例 13.8.1 给出一个 STC12C5412AD 应用的参考程序。 (part3.4.6.c#include&STC12C5410AD.H& #define uchar unsigned char #define uint unsigned int void delayms(uint xms)P287)//STC12C54 系列单片机头文件 郭天祥- 83 -{ uint i,j; for(i=i&0;i--) for(j=110;j&0;j--); //i=xms 即延时约 xms 毫秒} void AD_Init() { P1M0=0x0f;// 设置 P1 口低 4 位为开漏模式,用来 AD 采集 P1M1=0x0f;// ADC_CONTR=0xe0;// 开启 AD 转换器电源,设置最高转换速度 delayms(100); } int GetAD(unsigned char channel) //channel 为要取的通道号(0~7) { unsigned char AD_finished=0; ADC_CONTR|= //选择 AD 通道号 ADC_CONTR|=0x08; //启动 AD 转换 while(AD_finished==0) //等待 AD 转换结束 { AD_finished=(ADC_CONTR&0x10);//查询 ADC_FLAG 位是否置 1 } result=ADC_DATA*4+ADC_LOW2;//读走 AD 转换结果,由于 ADC_DATA 中存储 12 位中的 //高 8 位,当要转换成 10 进制时,需将 ADC_DATA 中的数左移 2 位,即相 当于*4 ADC_CONTR&=0xf7; //清除转换结束标志 return (result); //返回结果给函数 } float Ad_Av(uchar channel) //求 100 次采集电压的平均值 { float Val_Av=0; for(num=100;num&0;num--) { Val_Av+=GetAD(channel);//100 次采集求和 } Val_Av/=100.0; //求平均值 Val_Av=Val_Av*5.0/1024; //单片机电源为 5V,求的真实电压值 return (Val_Av); //返回给函数 } void main() { float ad1,ad2,ad3,ad4; 郭天祥- 84 -AD_Init(); ad1=Ad_Av(1); ad2=Ad_Av(2); ad3=Ad_Av(3); ad4=Ad_Av(4); while(1); } ********************************************************************* ********** 以下为 STC12C5410AD.H 中除去原 51 单片机寄存器地址定义部分的内容: ********************************************************************* ********** /* After is STC additional SFR or change */ /* sfr AUXR = 0x8e; */ /* sfr IPH = 0xb7; */ /* Watchdog Timer Register */ sfr WDT_CONTR = 0xe1; /* ISP_IAP_EEPROM Register */ sfr ISP_DATA = 0xe2; sfr ISP_ADDRH = 0xe3; sfr ISP_ADDRL = 0xe4; sfr ISP_CMD = 0xe5; sfr ISP_TRIG = 0xe6; sfr ISP_CONTR = 0xe7; /* System Clock Divider */ sfr CLK_DIV = 0xc7; /* I_O Port Mode Set Register */ sfr P0M0 = 0x93; sfr P0M1 = 0x94; sfr P1M0 = 0x91; sfr P1M1 = 0x92; sfr P2M0 = 0x95; sfr P2M1 = 0x96; sfr P3M0 = 0xb1; sfr P3M1 = 0xb2; /* SPI Register */ sfr SPSTAT = 0x84; sfr SPCTL = 0x85; 郭天祥- 85 -sfr SPDAT= 0x86;/* ADC Register */ sfr ADC_CONTR = 0xc5; sfr ADC_DATA = 0xc6; sfr ADC_LOW2 = 0 /* PCA SFR */ sfr CCON = 0xD8; sfr CMOD = 0xD9; sfr CCAPM0 = 0xDA; sfr CCAPM1 = 0xDB; sfr CCAPM2 = 0xDC; sfr CCAPM3 = 0xDD; sfr CCAPM4 = 0xDE; sfr CCAPM5 = 0xDF; sfr CL = 0xE9; sfr CCAP0L = 0xEA; sfr CCAP1L = 0xEB; sfr CCAP2L = 0xEC; sfr CCAP3L = 0xED; sfr CCAP4L = 0xEE; sfr CCAP5L = 0xEF; sfr CH = 0xF9; sfr CCAP0H = 0xFA; sfr CCAP1H = 0xFB; sfr CCAP2H = 0xFC; sfr CCAP3H = 0xFD; sfr CCAP4H = 0xFE; sfr CCAP5H = 0xFF; sfr PCA_PWM0 = 0xF2; sfr PCA_PWM1 = 0xF3; sfr PCA_PWM2 = 0xF4; sfr PCA_PWM3 = 0xF5; sfr PCA_PWM4 = 0xF6; sfr PCA_PWM5 = 0xF7; /* CCON sbit CF sbit CR sbit CCF5 */ = CCON^7; = CCON^6; = CCON^5; 郭天祥- 86 -sbit CCF4 sbit CCF3 sbit CCF2 sbit CCF1 sbit CCF0= CCON^4; = CCON^3; = CCON^2; = CCON^1; = CCON^0;********************************************************************* ********** /* Above is STC additional SFR or change */ /*-------------------------------------------------------------------------REG51F.H Header file for 8xC31/51, 80C51Fx, 80C51Rx+ Copyright (c)
Keil Elektronik GmbH and Keil Software, Inc. All rights reserved. Modification according to DataSheet from April 1999 - SFR's AUXR and AUXR1 added for 80C51Rx+ derivatives --------------------------------------------------------------------------*/ /* BYTE Registers */ sfr P0 = 0x80; sfr P1 = 0x90; sfr P2 = 0xA0; sfr P3 = 0xB0; sfr PSW = 0xD0; sfr ACC = 0xE0; sfr B = 0xF0; sfr SP = 0x81; sfr DPL = 0x82; sfr DPH = 0x83; sfr PCON = 0x87; sfr TCON = 0x88; sfr TMOD = 0x89; sfr TL0 = 0x8A; sfr TL1 = 0x8B; sfr TH0 = 0x8C; sfr TH1 = 0x8D; sfr IE = 0xA8; sfr IP = 0xB8; sfr SCON = 0x98; sfr SBUF = 0x99; /* 80C51Fx/Rx Extensions */ 郭天祥- 87 -sfr AUXR = 0x8E; /* sfr AUXR1 = 0xA2; */ sfr SADDR = 0xA9; sfr IPH = 0xB7; sfr SADEN = 0xB9; sfr T2CON = 0xC8; sfr T2MOD = 0xC9; sfr RCAP2L = 0xCA; sfr RCAP2H = 0xCB; sfr TL2 = 0xCC; sfr TH2 = 0xCD; /* BIT Registers */ /* PSW */ sbit CY = PSW^7; sbit AC = PSW^6; sbit F0 = PSW^5; sbit RS1 = PSW^4; sbit RS0 = PSW^3; sbit OV = PSW^2; sbit P = PSW^0; /* TCON */ sbit TF1 = TCON^7; sbit TR1 = TCON^6; sbit TF0 = TCON^5; sbit TR0 = TCON^4; sbit IE1 = TCON^3; sbit IT1 = TCON^2; sbit IE0 = TCON^1; sbit IT0 = TCON^0; /* P3 */ sbit RD = P3^7; sbit WR = P3^6; sbit T1 = P3^5; sbit T0 = P3^4; sbit INT1 = P3^3; sbit INT0 = P3^2; sbit TXD = P3^1; sbit RXD = P3^0; /* SCON */ sbit SM0 = SCON^7; // alternatively &FE& 郭天祥- 88 -sbit FE sbit SM1 sbit SM2 sbit REN sbit TB8 sbit RB8 sbit}

我要回帖

更多关于 单片机定时器计算公式 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信