51单片机excel查找相同单元格30-3F单元中的相同数个数

14:56 提问
关于AT89C51单片机数字时钟的设计C语言程序warning问题
本人新手,还希望各位大大帮忙看下怎么解决
Build target 'Target 1'
assembling STARTUP.A51...
linking...
*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL
STARTUP.obj (?C_STARTUP)
*** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL
STARTUP.obj (?C_STARTUP)
ADDRESS: 080AH
Program Size: data=9.0 xdata=0 code=15
"t" - 0 Error(s), 2 Warning(s).
源程序如下:
#define uint unsigned int
#define uchar unsigned char
sbit QB1=P1^0;
sbit QB2=P1^1;
//数码管段选
sbit QB3=P1^2;
sbit QB4=P1^3;
sbit QB5=P1^4;
sbit QB6=P1^5;
sbit fm=P1^6; //蜂鸣器
sbit s1=P2^4; //s5按键,切换显示
sbit s2=P2^3; //s2按键,设置调时
sbit s3=P2^2; //s3按键,加1
sbit s4=P2^1; //s4按键,减1
sbit led1=P0^0;
sbit led2=P0^1;
sbit led3=P0^2;
uchar sec,minu,hour,day,week,
uchar n_sec,n_minu,n_
uchar set_2=1,set_1=1;
uchar hs,hg,mis,mig,ss,
uchar nhs,nhg,nms,nmg,nss=0,nsg=0;
uchar ms,mg,ds,dg,w;
uchar code table[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,
0X90,0X88,0X83,0XC6,0XA1,0X8E,0X86,0xbf}; //0~F,-,共阳
//uchar code tableyi[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
//0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};//0-F,-,共阴
uchar code table_d[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,
0x87,0xff,0xef}; //0~9数组,带小数点
uchar table1[]={31,31,29,31,30,31,30,31,31,30,31,30,31}; //闰年
uchar table2[]={31,31,28,31,30,31,30,31,31,30,31,30,31}; //非闰年
void delay(uint); //延时函数
void timer0(); //走时中断函数
void jishi(); //计时函数
void key_change(); //切换显示按键函数
void key_set(); //设置时间按键函数
void disp(uchar,uchar,uchar,uchar,uchar,uchar); //显示函数
void zd_clock(); //整点报时函数
void nz_clock(); //闹钟函数
uchar incone(uchar); //加1函数
uchar decone(uchar); //减1函数
void set_time(); //设置时间函数
void set_clock(); //设置闹钟函数
void set_mdw(); //设置月日星期函数
void main() //主函数
TMOD=0x01;
TH0=0x4c; //50ms初值 晶振11.0592
hour=23;minu=59;sec=49; //赋初值:11点59分0秒
n_hour=12;n_minu=56;n_sec=0; //闹钟赋初值12点1分0秒
year=2008;mon=5;day=14;week=3;//年月日星期赋初值日星期天;祝天下所有母亲节日快乐
hs=hour/10; //时分秒HH.MM.SS
hg=hour%10;
mis=minu/10;
mig=minu%10;
ss=sec/10;
sg=sec%10;
ms=mon/10; //月日-星期MM.DD.-W
mg=mon%10;
ds=day/10;
dg=day%10;
nhs=n_hour/10; //闹钟定时HH.MM.SS
nhg=n_hour%10;
nms=n_minu/10;
nmg=n_minu%10;
nss=n_sec/10;
nsg=n_sec%10;
key_change(); //s4按键扫描
key_set(); //s2按键扫描
set_time(); //设置时间
set_mdw(); //设置月日星期
set_clock(); //设置闹钟
if(set_1==1) //正常走时显示
disp(hs,hg,mis,mig,ss,sg);
if(set_1==2) //设置时间,LED1闪亮
disp(hs,hg,mis,mig,ss,sg);
if(sec%2==0)
{led2=1;led3=1;led1=~led1;}
// {led1=1;}
if(set_1==3) //正常显示月日-星期
disp(ms,mg,ds,dg,16,w);
if(set_1==4) //设置月日-星期,LED2闪亮
disp(ms,mg,ds,dg,16,w);
if(sec%2==0)
{led1=1;led3=1;led2=~led2;}
// {led2=1;}
if(set_1==5) //正常显示定时
disp(nhs,nhg,nms,nmg,nss,nsg);
if(set_1==6) //设置闹钟定时,LED3闪亮
disp(nhs,nhg,nms,nmg,nss,nsg);
if(sec%2==0)
{led1=1;led2=1;led3=~led3;}
// {led3=1;}
zd_clock(); //整点报时
nz_clock(); //闹钟
void timer0() interrupt 1 //50ms中断函数
TMOD=0x01;
TH0=0x4c; //50ms初值 晶振11.0592
if(count==20)
jishi(); //调计时函数
void jishi() //计时函数
if(sec==60)
if(minu==60)
if(hour==24)
if(week==8)
if(year%4==0&&year%100!=0||year%400==0) //闰年
if(day==table1[mon]+1)
if(mon==13)
{mon=0;year++;}
else //非闰年
if(day==table2[mon]+1)
if(mon==13)
{mon=0;year++;}
void key_change() //s1按键扫描
delay(200);
while(!s1);
if(set_1==7)
{set_1=1;}
void key_set() //s2按键扫描
delay(10);
while(!s2);
if(set_2==4)
{set_2=1;}
void disp(uchar a1,uchar a2,uchar a3,uchar a4,uchar a5,uchar a6) //显示函数
P3=table[a1]; //段码送P0口
delay(10); //延时一小会
P3=table[a2]; //第2个数码管显示,带小数点
delay(10);
P3=table[a3]; //第3个数码管显示
delay(10);
P3=table[a4]; //第4个数码管显示,带小数点
delay(10);
//第5个数码管显示
P3=table[a5];
delay(10);
P3=table[a6]; //第6个数码管显示
delay(10);
void zd_clock() //整点报时函数
if(minu==59&&(sec==53||sec==55||sec==57))
if(minu==59&&sec==59)
void nz_clock() //闹钟函数
if(hour==n_hour&&minu==n_minu&&sec==n_sec)
//if((sec%2==0)&&sec&30)
void set_time() //设置时间函数
if(set_1==2)
if(set_2==1)
hour=incone(hour);
if(hour==24)
// if(hour&0)
// {hour=23;}
hour=decone(hour);
if(set_2==2)
minu=incone(minu);
if(minu==60)
// if(minu&0)
// {minu=59;}
minu=decone(minu);
void set_mdw() //设置月日星期函数
if(set_1==4)
if(set_2==1)
mon=incone(mon);
if(mon==13)
mon=decone(mon);
// if(mon==0)
// {mon=12;}
if(set_2==2)
day=incone(day);
if(day==32)
day=decone(day);
// if(day==0)
// {day=0;}
if(set_2==3)
week=incone(week);
if(week==8)
week=decone(week);
// if(week==0)
// {week=7;}
void set_clock() //设置闹钟函数
if(set_1==6)
if(set_2==1)
n_hour=incone(n_hour);
if(n_hour==24)
{n_hour=0;}
n_hour=decone(n_hour);
if(n_hour==0)
{n_hour=0;}
if(set_2==2)
n_minu=incone(n_minu);
if(n_minu==60)
{n_minu=0;}
n_minu=decone(n_minu);
if(n_minu==0)
{n_minu=0;}
uchar incone(uchar n) //加1函数
{ delay(200);
while(!s3);
return(n);
uchar decone(uchar m) //减1函数
delay(200);
while(!s4);
return(m);
void delay(uint k) //延时函数
for(i=k;i&0;i--)
for(j=80;j&0;j--);
按赞数排序
表示自己已经解决忘记添加到项目了。。。
----------------------同志你好,我是CSDN问答机器人小N,奉组织之命为你提供参考答案,编程尚未成功,同志仍需努力!
好厉害哦,我们刚学而已
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐【图文】51单片机硬件结构_百度文库
赠送免券下载特权
10W篇文档免费专享
部分付费文档8折起
每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
51单片机硬件结构
阅读已结束,下载本文到电脑
想免费下载本文?
登录百度文库,专享文档复制特权,积分每天免费拿!
你可能喜欢第一讲 单片机基础知识引言 商用 微机 工控 计算机 单片机 智能仪器仪表 集散控制 家用电器 C 语言 PASCAL FORTRAN高级语言 计算机语言 汇编语言(不同的 CPU,汇编语言不同)单片机1 位(几乎没有具体使用) 4 位(早期的产品) 8 位(当前应用最多,51 系列) 16 位(部分使用,与 8 位相比较少,80196) 32 位(未来趋势)所有计算机的三总线结构相同; 程序流程图相同。 学习计算机的基础知识是数字电子技术:触发器、计数器、移位寄存器、 译码器、编码器 1.1 MCS-51 单片机的特点单片机(MICROCONTROLLER,又称微控制器)是在一块硅片上集成了各种 部件的微型机算计,这些部件包括中央处理器 CPU、数据存贮器 RAM、程序存贮 器 ROM、定时器/计数器和多种 I/O 接口电路。 MCS-51 单片机的基本结构如图 1-1 所示。1 51 系列单片机结构特点: 8 位 CPU; 片内振荡器及时钟电路; 32 根 I/O 线; 外部存贮器寻址范围 ROM、RAM 各 64K; 3 个 l6 位的定时器/计数器; 5 个中断源,2 个中断优先级; 全双工串行口; 布尔处理器。1.2MCS-51 单片机的内部结构图 1-2 是 MCS-5l 单片机片内部结构的总框图,它可以划分为 CPU、存贮器、 并行口、串行口、定时器/计数器、中断逻辑几部分。2 图 1-2 MCS-51 的内部结构框图1.2.1 中央处理器 MCS-51 的中央处理器 CPU 由运算器和控制逻辑构成, 其中包括若干特殊功能 寄存器(SFR)。 ① CPU:8 位;ALU:算术、逻辑运算单元 ② 程序状态字 PSW:8 位宽度、F0、RS1 和 RS0 ③ 振荡周期、机器周期中处理器一、以 ALU 为中心的运算器 算术逻辑单元 ALU 能对数据进行加、减、乘、除等算术运算; “与” 、 “或” 、 “异或”等逻辑运算以及位操作运算。 PSW 的格式如图 1-3 所示,其各位的含义是: D7 D6 D5 D4 D3 D2 D1 D0 CY AC F0 RS1 RS0 OV P图 1-3 PSW 的格式 3 CY:进位标志。有进位/借位时 CY=1,否则 CY=0; AC:半进位标志。当 D3 位向 D4 位产生进位/借位时 AC=1,常用于十进制 调整运算中; F0:用户可设定的标志位,可置位/复位,也可供测试。 RS1、RS0: 四个通用寄存器组的选择位,该两位的四种组合状态用来选择 0~3 寄存器组。见表 1-2。表 l-2 RS1、RS0 与工作寄存器组的关系RS1 0 0 1 1RS0 0 1 0 1工作寄存器组 0 组(00-07) 1 组(08-0F) 2 组(10-17) 3 组(18-1F)OV: 溢出标志。 当带符号数运算结果超出-128~+127 范围时 OV=1, 否则 OV=0。 当无符号数乘法结果超过 255 时,或当无符号数除法的除数为 0 时,OV=1,否则 OV=0。 P: 奇偶校验标志。 每条指令执行完, 若 A 中 l 的个数为奇数时 P=1, 否则 P=0, 即奇偶校验方式。 二、控制器、时钟电路和基本时序周期 控制逻辑主要包括定时和控制逻辑、 指令寄存器、 译码器以及地址指针 DPTR 和程序计数器 PC 等。 1.MCS-51 的时钟 时钟是时序的基础,MCS-51 片内由一个反相放大器构成振荡器,可以由它产 生时钟。 XTAL1 XTAL2 外部时钟 XTAL1 XTAL2Vss(a) 图 l-4 时钟产生电路 (b)(1) 内部方式:图 1-4(a) (2) 外部方式:图 1-4(b) 2.MCS-51 的基本时序周期 一条指令译码产生的一系列微操作信号在时间上有严格的先后次序, 这种次序 就是计算机的时序。MCS-51 的主要时序将在存贮器扩展时讨论,这里先介绍它的4 基本时序周期。 振荡周期:指振荡源的周 期, 若为内部产生方式时, 为石英晶体的振荡周期。 机器周期:一个机器周期 含 6 个时钟周期(S 周期), 图 1-5 基本时序周期 12 个震荡周期。 指令周期:完成一条指令占用的全部时间。MCS-51 的指令周期含 l-4 个 机器周期,其中多数为单周期指令,还有 2 周期和 4 周期指令。 1.2.2 存贮器结构 计算机的存贮器的管理模式,大致可分为两类。第一类是将程序存贮器和数据 存贮器分开,并有各自的寻址机构和寻址方式,这种结构形式称为哈佛型结构。另 一类是存贮器逻辑空间统一管理,可随意安排 ROM 或 RAM,访问时用同一种指 令,这种结构形式称为普林斯顿型。MCS-51 单片机的存贮器结构属于前者,一般 微机属于后者。 程序:0000-0FFFFH 内部 00-7F:工作寄存区、通用数据区 数据: 存贮器结构 80-FF:特殊功能寄存器、通用数据区 程序:1000-FFFFH(或 0000-FFFF) 外部 数据:0000-FFFFH 存贮器组织结构:图 1-5 MCS-51 存贮器组织结构数据存贮器 RAM 也有 64KB 寻址区,在地址上是和 ROM 重叠的。MCS-51 通过不同的信号来选通 ROM 或 RAM: 当从外部 ROM 取指令时用选通信号 PSEN , 而从外部 RAM 读写数据时采用读写信号 RD 或 WR 来选通。因此不会因地址重叠而 出现混乱。5 第二讲MCS-51 单片机的内部结构1.2.3 片内并行接口 P0:常用功能(数据/低 8 位地址) 单片机 P1:常用并行端口 (8051) P2:常用于地址高 8 位(A8-A15) P3:常用第二功能(RXD、TXD、INT0、INT1、T0、T1、WR、RD) 1.2.4 MCS-51 的内部资源 串行口 内部资源 定时器/计数器 中断系统:5 个中断源(INT0、T0、INT1、T1 和串口) 1.2.5 MCS-51 的芯片引脚 ① XTAL1、XTAL1:晶体、电容; ② ALE(地锁存信号) :锁存P0 口的地址低 8 位,频率=fSOC/6; ③ PSEN(读指令信号) :接程序存贮器的允许输端子; ④ WR、RD:分别与外部数据存贮器的读、端子相连接 ⑤ EA:接高电平(或接低电平) 。图 1-8 MCS-51 引脚图 6 1.2.6 单片机的工作方式 单片机的工作方式包括:复位方式、程序执行方式、单步执行方式、低功耗操 作方式以及 EPROM 编程和校验方式。 1. 复位方式:经典的上电复位电路 2. 程序执行方式: (1)执行内部程序; (2)执行外部程序 3. 单步执行方式:用于调试程序和系统 4. 低功耗操作方式 5. 编程和校验第三讲定时器/计数器MCS-51 子系列单片机有 2 个定时器/计数器,即定时器/计数器 0 和 1,52 子 系列单片机()除了有上述 2 个定时器/计数器外,还有一个定时器/计数 器 2,后者的功能比前两者强。 1.3.1 定时器/计数器 0 和 1 在专用寄存器 TMOD(定时器方式)中,有一个控制位(C/T),分别用于控制定时 器/计数器 0 和 1 是工作在定时器方式还是计数器方式。 1. 输入信号基本要求:24 个振荡周期,即两个机器周期; 2. 作为定时器时,计数速率是 振荡频率/12; 3. 由定时器/计数器模式控制寄存器设置工作方式。 模式 0:13 位宽度,主要保持与 48 系列兼容; 工作 模式 1:16 位宽度,最大计数 65535; 模式 模式 2: 8 位自动重装载,用于周期性的作某件事; 模式 3:定时器/计数器 0 和 1 不同,适合于额外定时器。 1.3.2 定时器/计数器 2(自己阅读) 定时器/计数器 2 是一个具有 16 位自动重装载或捕获能力的定时器/计数器。 专用寄存器 T2CON 是它的控制寄存器。 可用作波特率发生器 定时/计数方式 1.3.3 定时器/计数器的控制和状态寄存器 专用寄存器 TMOD、 TCON 和 T2CON 用于控制和确定各定时器/计数器的功能和操 作模式。这些寄存器的内容靠软件设置。系统复位时,寄存器的所有位都被清零。 1. 模式控制寄存器 TMOD 8 位宽度,高四位和低四位分别控制定时器/计数器 1 和 0,参阅图 1-11、 图 1-12、图 1-13。7 定时器 1(MSB) D7 D6 D5 D4 D3 D2定时器 0(LSB) D1 D0GATEC/ TM1M0GATEC/ TM1M0图 1-16 定时器/计数器控制寄存器 TMOD例MOV MOV MOV SETB 表 1-5TOMD,#B TH1,#56 TL1,#56 TR1 操作模式控制位 操;定时器 1,8 位自动重装载 ;时间常数 ;时间常数 ;启动定时器开始工作M1 MO 0 0作模式模式 0。 TLx 中低 5 位与 THx 中 8 位构成 13 位计数器, TLx 相当一 个 5 位定标器(见图 1-11)。 模式 10 TLx 与了 Hx 构成全 16 位计数器,操作模式同上,但无定标 器。 模式 2。 8 位自动重装载的定时器/计数器, 每当计数露 TLx 溢出时, THx 中的内容重新装载到 TLx(见图 1-12)。 模式 3。对于定时器 0,分成 2 个 8 位计数器(见图 1-13)。对于定时 器 1,停止计数。0 1 11 0 12. 控制寄存器 TCON(MSB) D7 TF1 D6 TR1 D5 TF0 D4 TR0 D3 IE1 D2 IT1 D1 IE0 (LSB) D0 IT0图 1-17 定时器/计数器控制寄存器 TCONTF0、TR0:定时器/计数器 0 TF1、TR1:定时器/计数器 1 IE0、IT0:外部中断 0 IE1、IT1:外部中断 1 例如可用以下语句: SETB IT0 //外部中断 0 下降沿触发 CLR IT1 //外部中断 1 低电平触发8 3. 定时器/计数器 2 控制寄存器 T2CON (MSB)D7 D6 D5 D4 D3 D2 D1(LSB)D0TF2EXF2RCLKTCLKEXEN2TR2C/ T 2CP/ RL 2图 1-18 T2CON 定时器/计数器 2 控制寄存器作为波特率发生器: RCLK=TCLK=1(参考图 1-15) C/T2=0 TR2=1第四讲 串行口MCS-51 中的串行接口使它增色不少。此串行接口是一个全双工通信接口,即 能同时进行发送和接收。它可以作 UART(通用异步接收和发送器)用,也可以作同 步移位寄存器用。 1.4.1 数据缓冲寄存器 SBUF SBUF:输入、输出寄存器,可同时发送、接收。实际上,这两个寄存器共 用了物理地址。 1.4.2 串行口控制寄存器 SCON SCON 用于控制和监视串行口的工作状态。它的各位定义,见图 1-19,并说明 如下: (MSB) (LSB) D7 SM0 D6 SM1 D5 SM2 D4 REN D3 TB8 D2 RB8 D1 TI D0 RI图 1-19 串行控制寄存器 SCONSM0、SM1:工作模式,共 4 种; SM2:模式 2 和模式 3 方式时使用; REN:允许接收; TB8:发送数据的第 8 位; RB8:接收数据的第 8 位; TI: 发送完成(软件清除) ; RI: 接收数据就绪(软件清除) ;9 表 1-6串行口操作模式选择SM1 SM0 0 0 1 1 0 1 0 l模式 0 1 2 3功能波特率同步移位寄存器 8 位 UART 9 位 UART 9 位 UARTfosc/l2 可 变 fosc/ 64 或 fosc/32 可 变1.4.3 模式 0 在操作模式 0 下, 串行口作同步移位寄存器用, 其波特率是固定的, 为 fosc/12, 其中 fosc 是振荡器频率。 这时数据由 RXD(P3.0)端出入, 同步移位时钟由 TXD(P3.1) 端输出。发送或接收的是 8 位数据,低位在先(参见图 1-20) 。 汇编语言程序: ORG 8000H MOV SCON,#B MOV SBUF,#88H JNB TI,$ ;查询方式 CLR TI END C 语言程序: #include &reg52.h& //包含文件 #include &stdio.h& //包含文件 main() { SCON=0X10; //初始化串行控制寄存器 SBUF=0X88; //输出数据 while(!TI); //查询方式 TI=0; } 1.4.4 模式 1 串行口工作于模式 1 时,传输的是 10 位:1 位起始位(0),8 位宽度的数据(低 位在先),1 位停止位(1)。由 TXD 发送,由 RXD 接收。波特率是可变的,取决于定 时器 1 或 2 的溢出速率(参见图 1-22) 。 MOV SCON,#B ;通讯模式(11.0592MHz) MOV TMOD,#B ;定时模式(注意定时器 0) MOV TL1,#0E8H ;时间常数(RS232:1200) MOV TH1,#0E8H ;时间常数 SETB TR1 ;启动定时器10 (TH1) = 256 ?fosc 32 × 12 × 波特率TH1 40H A0H D0H E8H F4H FAH FDH,fosc=11.0592MHz,SMOD=0定时器 1 作为波特率发生器时,常用时间常数及误差对照表 波特率(Hz) 150 300 600 00 9600 误差 0% 0% 0% 0% 0% 0% 0%1.4.5 模式 2 和 3 操作模式 2 和 3 中,发送(通过 TXD)和接收(通过 RXD)的都是 11 位:1 位起始 位(0),8 位数据(低位在先),1 位可编程位(第 9 数据位)和 1 位停止位(1)。发送 时,可编程位(TB8 可赋予 0 或 1。接收时可编程位进入 SCON 中的 RB8。 模式 2 和模式 3 的工作原理类同,唯一的差别是:模式 2 的波特率为 fosc/32 或 fosc/64,而模式 3 的波特率是可变的,利用定时器 1 或定时器 2 作波特率发生 器(参见图 1-22 和图 1-23) 。 定时器 1 作为波特率发生器: 定时器 1 的计数速率=fosc/12 SMOD=0 时,n=32 波特率=定时器 1 的计数速率/n PCON 寄存器 SMOD=1 时,n=16 波特率=2 SMOD × (定时器 / 计数器1溢出速率) 32f osc 2 SMOD × = 32 12 × [256 ? (TH1)]定时器 2 作为波特率发生器: 波特率=fosc 2 × 16 × [65536 ? (RCAP2H, RCAP2L)]11 第五讲 中断系统MCS-51 系列中,有 5 个中断源(或 6 个中断源) ,可分为 2 个优先级,其中每 一个中断源的优先级都可以由程序排定(图 1-26)。 1.5.1 允许中断寄存器 IE(物理地址:A8,可按位寻址) 图 1-27 示出允许中断寄存器各位的定义。现说明如下: (MSB) (LSB) D7 EA D6 × D5 ET2 D4 ES图 1-27D3 ET1D2 EX1D1 ET0D0 EX0IE 允许中断寄存器1.5.2 中断优先级寄存器 IP(物理地址:D8,可按位寻址) MCS-51 的中断分为 2 个优先级。每个中断源的优先级都可以通过中断优先级 寄存器 IP 中的相应位来设定。图 1-28 示出 IP 的,各位定义,其中: (MSB) (LSB) D7 × D6 × D5 PT2图 1-28D4 PSD3 PT1D2 PX1D1 PT0D0 PX0IP 允许中断优先级寄存器例如 …… SETB PX0 ;外部中断 0 为高优先级 SETB ES ;串行中断 SETB EA ;开总中断 …… 1.5.3 优先级结构 靠 IP 寄存器把各中断源的优先级分为高低 2 级。 它们遵循这样 2 条基本规则: 1. 低优先级中断可被高优先级中断所中断,反之不能; 2. 一种中断(不管是什么优先级)―旦得到响应,与它同级的中断不能再中断 它。 中断源 同级内的优先权 外部中断 0 最高 定时器/计数器 0 溢出 外部中断 1 定时器/计数器 1 溢出 串行口 定时器/计数器 2 溢出 最低12 1.5.4 中断响应协议 当某中断源提出中断请求后,作为应答,CPU 首先使相应的“优先级激活”触 发器置位,以阻断同级和低级的中断。 硬件中断服务子程序调用时, 把当时程序计数器 PC 的内容压入堆栈(在 MCS-51 中,PC 是 16 位的,占用了 2 个字节,没有自动保存程序状态字 PSW 的内容),同 时还根据中断的来源,把相应的矢量单元地址装入 PC 中。这些矢量地址是: 中断源 矢量单元 外部中断 0 0003H 最高 定时器 0 溢出 000BH 外部中断 1 0013H 定时器 1 溢出 001BH 串行口 0023H 定时器 2 溢出或 T2EX 端出现负跳变 002BH 最低 注意:仿真器常常将中断入口地址映射到别的地址空间。 1.5.5 外部中断 外部中断的激活方式分为两种:―种是电平激活,另一种是边沿激活。这两种 方式可以靠 TCON 寄存器中的中断方式位 ITl 或 IT0 来控制。(MSB) D7 TF1 D6 TR1 D5 TF0 D4 TR0 D3 IE1 D2 IT1 D1 IE0 (LSB) D0 IT01.5.6 中断请求的撤除 CPU 响应某中断请求后,在中断返回(RETI)前,该中断请求应该撤除,否则会 引起另一次中断。 定时器/计数器 0 和 1:进入中断服务后自动清除中断申请标志位 TF0 或 TFl; 边沿激活:自动清除 IE0、IE1; 外部中断 0 和 1: 电平激活:采取措施,例如对信号进行整形等。 1.5.7 中断响应时间从外部中断请求有效到开始执行服务程序的第一条指令, 中间要隔 3 个机器周 期,这是最短的响应时间。当对 IE,IP 寄存器进行操作或执行 RETI 指令时,不会 立即相应中断源的申请。13 第六讲 MCS-51 单片机系统扩展在很多应用场合,MCS-51 自身的存贮器和 I/O 资源不能满足要求,这时就要 进行系统扩展。 1.6.1 外部总线的扩展 以 8051 单片机最小系统为例,介绍数据总线、地址总线和控制总线。 基本要求:熟练掌握最小系统的结构及三组总线。图 1-29 MCS-51 外部三总线示意图1.6.2 外部程序存贮器的扩展 介绍简明取指令时序; 在最小系统的基础上,以扩展 2764 为程序存贮器为例, 介绍扩展方法。 基本要求:熟练掌握程序存贮器的扩展 方法及取指时序。图 1-32 外部程序存贮器的简明操作时序图 l-33 外部程序存贮器的连接 14 1.6.3 外部数据存贮器的扩展 介绍简明数据存贮时序; 在最小系统的基础上,以扩 展 6264 为程序存贮器为例, 介绍扩展方法。 基本要求:熟练掌握数据存贮器 的扩展方法及读写时序。图 1-36 外部数据存贮器操作的简明时序图图 1-38 扩展 6264 静态 RAM第七讲 MCS-51 单片机的指令系统1.7.1 寻址方式 寻址方式就是根据指令中给出的地址寻找真实操作数地址的方式。MCS-51 单 片机的寻址方式有种:寄存器寻址、直接寻址、立即寻址、变址寻址、相对寻址、 间接寻址和位寻址。 寄存器寻址: MOV A,R0 ;A←(R0) 直接寻址: MOV A,4FH ;A4←(4FH) 立即寻址: MOV A,# 6FH ;A←6FH 间接寻址: MOV A,@R1 ;A←((R1)) 相对寻址: SJMP rel ;PC←(PC)+ 2+ rel 变址寻址: MOVC A,@A 十 DPTR ;A4←((A)十(DPTR)) 位寻址: SETB EA ;EA=1 1.7.2 指令说明 MCS-51 指令系统按其功能可分为:数据传送指令、转移指令、算术运算指令、 逻辑运算指令和十进制指令。15 1.7.3 伪指令 汇编语言必须通过汇编器的处理,才能转换为计算机能识别和执行的机器语 言。伪指令是汇编器用的指令。MCS-51 汇编器常用的伪指令有以下几种: 一、 ORG 伪指令(Origin) ORG 0000H 二、 DB 伪指令(Define Byte) DB 40H,56H,’A’ 三、 DW 伪指令(Define Word) DW ,0AF0H 四、 EQU 或=伪指令(Equal) COUNT=100 SPACE EQU 50H 五、 DATA 伪指令(Data) ERROR DATA 80H 六、 XDATA 伪指令(External Data) ADC XDATA 4000H 七、 BIT 伪指令 LED BIT 30H 八、 END 伪指令 1.7.4 汇编语言编程6400 ÷ 16 = ?ORG SJMP ORG MOV MOV MOV MOV MOV MOV MOV MOV LCALL MOV MOV 0000H MAIN 0040H DPTR,#H R3,#00H R4,DPH R5,DPL DPTR,#16 R6,DPH R7,DPL DIVD DPH,R3 DPL,R4 ;定义程序首地址 ;跳转到主程序 ;主程序地址 ;省去人工转换 ;被除数 ; ; ; ;除数 ; ; ;调用出除法子程序 ;商的高 8 位? ;商的低 8 位?16MAIN: NOP SJMP $ ;------------------------------------------------------------;标号: DIVD ;功能: 双字节二进制无符号数除法 ;入口条件:被除数在 R4 、 R5 中,除数在 R6 、 R7 中。 ;出口信息: OV=0 时,双字节商在 R2 、 R3 中, OV=1 时溢出。 ;影响资源: PSW 、 A 、 B 、 R1 ~ R7 ;堆栈需求: 2字节 ;------------------------------------------------------------DIVD: CLR C ;比较被除数和除数 MOV A, R3 SUBB A, R7 MOV A, R2 SUBB A, R6 JC DVD1 SETB OV ;溢出 RET DVD1: MOV B, #10H ;计算双字节商 DVD2: CLR C ;部分商和余数同时左移一位 MOV A, R5 RLC A MOV R5, A MOV A, R4 RLC A MOV R4, A MOV A, R3 RLC A MOV R3, A XCH A, R2 RLC A XCH A, R2 MOV F0, C ;保存溢出位 CLR C SUBB A, R7 ;计算( R2R3 - R6R7 ) MOV R1, A MOV A, R2 SUBB A, R617 DVD3:ANL JC MOV MOV MOV INC DJNZ MOV MOV MOV MOV CLR RET ENDC, /F0 DVD3 R2, A A, R1 R3, A R5 B, DVD2 A, R4 R2, A A, R5 R3, A OV;结果判断 ;够减,存放新的余数;商的低位置一 ;计算完十六位商( R4R5 ) ;将商移到 R2R3 中;设立成功标志1.7.4 C 语言编程 #include &reg52.h& #include &stdio.h& void main(void) { unsigned int y,z; x=6400; y=16; z=x/y; while(1){;} } //包含文件 //包含文件 //主函数 //长整型变量 //整型变量 //赋初值(被除数) //除数 //计算第八讲 keil 51 应用入门KEIL51 软件是众多单片机应用软件开发的优秀软件之一,它集编辑、编译、 仿真于一体,支持汇编、PLM 语言和 C 语言的程序设计;界面友好,易学易用。 2.1 KEIL51 的集成环境 2.2 简单的程调试 2.3 建立一个项目 2.4 项目中含有多个文件18 2.5 汇编语言 2.6 机器代码的效率比较 (在实验室进行)第九讲 keil 51 软件调试技巧这一章我们将简单地向读者介绍调试用户应用程序的调试技巧, 并给出相应的 程序清单,必要时还给出与之相应的操作方法及执行程序时的主要屏幕画面,以方 便读者的学习。 (在实验室进行) 3.1 P1 口作为输入端口 3.2 P1 口作为输出端口 3.3 外部中断 3.4 定时/计数器 0 作为定时器 3.5 定时/计数器 0 作为计数器 3.6 调试函数第十讲MCS-51 单片机系统扩展这一章将向读者介绍一些 MCS-51 单片机系统扩展的常用电路设计, 其中有并 行口、串并转换、静态数码管显示、动态数码管显示、A/D 转换、D/A 转换、时钟 日历、IC 卡等,举例中,均以 C 语言编程(为了兼顾初学者,部分地给出对应的 汇编程序) ,不熟悉的读者,可参阅本书的第五、六、七、八、九章。 4.1 扩展并行口 (1)用闲置不用的口线作为选通信号 此种方式连线简单,编程方便灵活。如 果使用 74LS573(74LS373)且不对 P1 口进行驱动处理,则最多可扩展四个同样类 型的并行输出端口,当然还需要与之对应 4 个选通信号。 ORG 8000H CLR P3.3 ;选通信号无效 MOV P1,#00H ;P1 口设定为输出口 MOV P1,#80H ;欲输出的数据为 80 SETB P3.3 ;选通信号有效 CLR P3.3 ;锁定数据,选通信号无效 END 下边是用 C 语言编写的同样功能的程序: #include &reg52.h& //包含文件 #include &stdio.h& //包含文件19 sbit CLK=P3^3;main() { CLK=0; //选通信号无效 P1=0X00; //P1 口设定为输出口 P1=0X80; //欲输出的数据为 80 CLK=1; //选通信号有效 CLK=0; //锁定数据,选通信号无效 } (2)部分地址译码法扩展并行输出端口 利用地址译码法扩展并行输出端口需要占用单片机的数据存贮器空间, 其优点 是可扩展的端口数几乎不受限制,编程并不比前一种方法复杂,缺点是需要一些组 合逻辑电路与之配合。图 4-2 就是基于这一种方法而实现的硬件电路。从图中可以 看到所扩展的并行输出端口地址是 0000H~1FFFH,下边分别给出操作该端口的汇 编语言和 C 语言源程序: ORG 0000H MOV DPTR,#0000H MOV A,#80H MOVX @DPTR,A END C 语言源程序如下: #include &reg52.h& #include &stdio.h& #include &absacc.h& #define our_port XBYTE[0x0000] main() { our_port=0x80; }图中 74HC138 使用了地址总线的高三位,即A15A14A13,把 64K地址空间分为 8 等份,其中新扩展的 8 位并行端口占用了 0000H~1FFFH地址空间,可见地址空 间的浪费还是比较严重的,但在大多数情况下还是可以接受的。如果需要充分利用 地址空间,可以使用全地址译码法。20 (3)全地址译码法扩展并行输出端口 这一种方法需要借助于数字电子学中的一些门电路来实现,此处我们不再详 述,而是采用大家已经比较熟悉的可编程逻辑器件来实现这一设计要求。首先设计 一个全译码器,如下是实现这一要求的 PLD 设计文件(图 4-3 原理图) : subdesign encoder ( A15,A14,A13,A12,A11,A10,A9,A8 :INPUT; A7,A6,A5,A4,A3,A2,A1,A0,WR :INPUT; ENABLE :OUTPUT; ) BEGIN ENABLE=A15 & A14 & A13 & A12 & A11 & A10 & A9 & A8 & A7 & A6 & A5 & A4 & A3 & A2 & A1 & A0 & !WR; END; 4.2 串并转换 在 8051 系列单片机系统中,如果串行口闲置不用,则利用它来扩展并行输出 或输入端口。这种扩展方法不占用外部数据存贮器的地址空间,而且也节省单片机 的硬件资源,但操作速度较慢,级连的越多,速度越慢。 (1)74HC164 扩展并行输出端口(图 4-4) 扩展方法如图 4-4 所示,下边分别给出汇编语言和 C 语言程序。 汇编语言程序: ORG 0000H MOV SCON,#B MOV SBUF,#88H END C 语言程序: #include &reg52.h& //包含文件 #include &stdio.h& //包含文件 main() { SCON=0X00; //初始化串行控制寄存器 SBUF=0X88; //输出数据 } (2)用 74HC165 扩展并行输入端口 扩展方法如图 4-5 所示,下边分别给出汇编语言和 C 语言程序。 汇编语言程序:21 ORG 0000H SETB P1.0 CLR P1.0 SETB P1.0 MOV SCON,#B JNB RI,$ MOV A,SBUF CLR RI END C 语言程序: #include &reg52.h& #include &stdio.h& sbit load = P1^0; main() { load=1; load=0; load=1; SCON=0X10; while(!RI); x=SBUF; RI=0; };数据锁入无效 ;锁入数据 ;数据锁入无效 ;模式 0 工作方式,启动一次接收过程 ;等待接收结束 ;读取已接收的数据 ;清除接收就绪标志//包含文件 //包含文件//并行数据锁入无效 //并行数据锁入使能 //并行数据锁入无效 //模式 0 工作方式,启动一次接收过程 //等待数据移入 //读取已接收的数据 //清除接收就绪标志第十一讲数码管显示4.3 静态数码管显示 数码管显示器,是各种仪器设备所不可缺少的重要组成部分,是仪器设备与人 对话的一种重要形式,它告诉人们机器的运行状态、数据的处理结果、提示操作人 员下一步要进行的操作等。 按照显示方法的不同, 可分为静态显示和动态显示两种, 这一节讨论静态数码管显示的设计方法。 汇编语言源程序: ORG 0000H MOV SCON,#00H ;初始化串行控制寄存器 CLR TI ;清除数据发送结束标志 MOV SBUF,#01H ;输出数据“8” JNB TI,$ ;等待数据发送结束22 CLR TI MOV SBUF,#9FH JNB TI,$ CLR TI END C 语言源程序: #include &reg52.h& #include &stdio.h&;清除数据发送结束标志 ;输出数据“1” ;等待数据发送结束 ;清除数据发送结束标志//包含文件 //包含文件main() { SCON=0X00; //初始化串行控制寄存器 TI=0; //清除数据发送结束标志 SBUF=0X01; //输出数据“8” while(!TI); //等待数据发送结束 TI=0; //清除数据发送结束标志 SBUF=0X9F; //输出数据“1” while(!TI); //等待数据发送结束 TI=0; //清除数据发送结束标志 } 对于图 4-6 来讲,编写程序相对比较简单,一旦将欲显示的数据发送出去,只 要当前显示的数据没有变化,就无须理睬数码管显示器,这就是静态数码管显示的 好处。但是,如果显示的位数比较多,硬件的开销、电源的功耗等问题,将变得更 加突出。 4.4 动态数码管显示 动态数码管显示,可以大幅度地降低硬件成本和电源的功耗,因为某一时刻只 有一个数码管工作, 也就是所谓的分时显示, 故显示所需要的硬件电路可分时复用。 图 4-7 基于这种思想的 8 位动态显示电路。 图中使用了两片 74LS373 作为 7 段码和 位码驱动锁存器,8 个数码管是共阴极数码管,一片 ULN2803 作为位增强驱动器。 ULN2803 是 8 反相驱动器,其最大驱动电流为 500mA,假如数码管的 8 个二 极管都点亮,则共有 80mA 电流从阴极流出,ULN2803 完全有能力 80mA 的灌入 电流。 若 S0 和 S1 选通信号的地址分别为 7F80H、7F90H,定时器 1 作为定时刷新定 时器,定时时间常数为 2.5mS,C 语言源程序如下: #include &at89x52.h& #include &stdio.h& #include &absacc.h&23 #define SEGMENT XBYTE[0x8000] #define BIT_LED XBYTE[0x8001] #define fosc 11.0592 #define time0 2500 unsigned char data display_bit,display_buffer[8]; unsigned char data time0_h,time0_l; unsigned int idata time0_ unsigned char get_code(unsigned char i); void display(void); main() { BIT_LED=0; TMOD=0x21; time0_times=65536-time0*fosc/12; time0_h =(time0_times/256 ); time0_l =(time0_times%256); TH0=time0_h;TL0=time0_l; TR0=1; EA=ET0=1; display_bit=0x01; display_buffer[7]=8; display_buffer[6]=7; display_buffer[5]=6; display_buffer[4]=5; display_buffer[3]=4; display_buffer[2]=3; display_buffer[1]=2; display_buffer[0]=1; while(1); } void time0_int(void) interrupt 1 { TH0=time0_h;TL0=time0_l;//段码寄存器地址 //位码寄存器地 //晶振频率 //定时 2500uS//定时器/计数器 0 定时方式 1//高 8 位和低 8 位时间常数 //启动定时器 0 //允许中断 //从第一个数码管开始显示//中断服务子程序24 display(); }//共需 40m 秒unsigned char get_code(unsigned char i) { switch (i){ case 0: p=0x3F; case 1: p=0x06; case 2: p=0x5B; case 3: p=0x4F; case 4: p=0x66; case 5: p=0x6D; case 6: p=0x7D; case 7: p=0x07; case 8: p=0x7F; case 9: p=0x67; case 10: p=0x77; case 11: p=0x7C; case 12: p=0x39; case 13: p=0x5E; case 14: p=0x79; case 15: p=0x71; default:} return (p); } void display(void) { switch (display_bit) { case 1: i=0; case 2: i=1; case 4: i=2; case 8: i=3; case 16: i=4; case 32: i=5;/*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/ /*A*/ /*B*/ /*C*/ /*D*/ /*E*/ /*F*/25 case 64: i=6; case 128: i=7; default : } { BIT_LED=0; SEGMENT=get_code(display_buffer[i]); BIT_LED=display_ if (display_bit&0x64) {display_bit=display_bit*2;} else display_bit=0x01; } }//关闭显示 //送段码 //送位码第十二讲 A/D 转换(ADC0809)ADC0809 是 8 通道 8 位逐次逼近型 A/D 转换器,典型时钟频率为 640KHz,每一通 道转换时间约为 100μS,即 64 个脉冲转换一次。 一、等待连接方式 电路如图 4-10 所示。图中,将 ALE 信号二分频作为时钟信号。如果单片机晶 振 6MHz,则 ALE 信号的频率为 1MHz,故分频后送给 ADC0809 的时钟信号为 500KHz。 IN0-IN7 接模拟信号,8 通道轮流采集一次数据,并存贮与内部 RAM 中。A/D 转唤 起的地址为 7FFFH。 此种方式编程简单,但单片机的有效利用率不高,常常在只有单一任务时使用 这一种方法。 #include &reg51.h& #include &absacc.h& #define IN0 XBYTE[0X7FFF] //通道 0 地址 typedef void void adc0809 (uchar idata *x); delay (void); //ADC0809 采样函数 //延时函数void main (void) { static uchar idata ad[8]; adc0809(ad); }//定义数据存储区26 void adc0809 (uchar idata *x) { uchar xdata *ad_ ad_adr=&IN0; for(i=0;i&8;i++) { *ad_adr=i; delay(); x[i]=*ad_ } } void delay(void) { for(j=0;j&20;j++) {;} }//8 个通道 //启动 AD 转换 //延时等待 //取转换值二、中断连接方式 将图 4-11 ADC0809 的 EOC 信号经过一反相器反相后接到 MCS-51 的外部中断输 入端则形成另一种接口电路――中断方式接口,即利用 EOC 信号产生中断,通知 MCS-51 转换结束。 用中断方式处理 A/D 转换问题,可以大幅度地提高单片机的事务处理能力,使 其可以更出色地执行多个任务。 #include &reg51.h& #include &absacc.h& #define IN0 XBYTE[0x7FFF] //通道 0 地址 typedef uchar i=0; uchar xdata *ad_ static uchar idata x[8]; void main (void) { IT1=0; EX1=1; EA=1; i=0; ad_adr=&IN0;27 *ad_adr=i; for(;;) {;} } void int_serv(void) interrupt 2 { x[i]=*ad_ i++; if (i&8) {*ad_adr=i;} }//启动转换//中断服务程序,读取转换值 //读取转换结果 //8 路转换完毕否? //未完,继续三、查询连接方式 在 8051 单片机的应用系统中,如果外部中断多于两个,而且将其分配给更重 要的事务时,常常使用查询方式处理 A/D 转换的问题。 将图 4-12 中 ADC08098 的 EOC 信号接到 MCS-51 的 I/O 线上(本程序为 EOC 与 P1.0 相连)则形成又一种接口电路――查询方式,8051 即通过循环查询 EOC 信号, 判断转换是否结束。 #include &reg51.h& #include &absacc.h& #define IN0 XBYTE[0X7FFF] //通道 0 地址 typedef sbit ad_busy=P1^0; void adc0809 (uchar idata *x); //ADC0809 采样函数 void main (void) {static uchar idata ad[8]; //定义数据存储区 adc0809(ad); } void adc0809 (uchar idata *x) { uchar xdata *ad_ ad_adr=&IN0; for(i=0;i&8;i++) //8 个通道 {*ad_adr=i; //启动 AD 转换 while (ad_busy==0){;} x[i]=*ad_ //取转换值 } }28 第十三讲 时钟日历(DS1302)在研制智能设备仪器仪表时,常常用到时钟和日历,能够实现这种功能的集成 电路有好几种,都有各自的优点,DS1302 就是其中的一种。DS1302 以其体积小, 功耗低,自带 31 字节 RAM,遇闰年自动修正,使用简单,且不存在“千年虫”问 题,赢得了人们的青睐。 一、DS1302 的时序 DS1302 的时序图如图 4-19 所示,寄存器地址分配如图 4-20 所示。 二、DS1302 的典型应用 图 4-21 是 DS1302 在单片机应用 系统中,最简单的应用方法之一。图 中仅使用了单片机的三条 I/O 线,便 可实现对 DS1302 所有功能的操作。 三、编程分析 图 4-21 DS1302 的简单应用 #include &reg52.h& #include &intrins.h& sbit SCL_DS1302 =P1^0; sbit IO_DS1302 =P1^1; sbit RST_DS1302 =P1^2; //时钟 //输入输出口 //复位引脚定义unsigned char data display_buffer[8]; unsigned char bdata data_ds1302; sbit bit_data0=data_ds1302^0; sbit bit_data7=data_ds1302^7; u sbit x0 =x^0; sbit x7 =x^7; void open_write_bit(); void initial_ds1302(); unsigned char read_ds1302(char command); void open_write_bit(); void close_write_bit(); void read_time(); void set_time();定义全局变量外部函数29 main() { initial_ds1302(); read_time(); display_buffer[0]=0X00; display_buffer[1]=0X08; display_buffer[4]=0X01; display_buffer[5]=0X00; display_buffer[6]=0X05; display_buffer[7]=0X08; set_time(); while(1); } void close_write_bit() { SCL_DS1302=0; _nop_(); RST_DS1302=1; _nop_();_nop_(); data_dse; for (i=1;i&=8;i++) {//上电启用,否则不走时 //读取当前时分秒,放在数组中//将 08 时 10 分 58 秒设置为当前时间 //将数组中的时间置入 DS1302//write control redister SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } //close write protect bitdata_ds; IO_DS1302=0; for (i=1;i&=8;i++) {SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } }void open_write_bit()30 { SCL_DS1302=0; _nop_(); RST_DS1302=1; _nop_();_nop_(); data_dse; for (i=1;i&=8;i++) {//write control redister SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1;} data_ds; IO_DS1302=0; for (i=1;i&=8;i++) { //open write protect bitSCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } } void initial_ds1302() { SCL_DS1302=0; _nop_(); RST_DS1302=1; _nop_();_nop_(); data_dse; for (i=1;i&=8;i++) {//write control redister SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1;} data_ds; IO_DS1302=0; for (i=1;i&=8;i++) { //close write protect bitSCL_DS1302=0;IO_DS1302=bit_data0;_nop_();31 SCL_DS1302=1;data_ds1302=data_ds1302&&1; } RST_DS1302=0; _nop_(); SCL_DS1302=0; SCL_DS1302=0; _nop_(); RST_DS1302=1; _nop_();_nop_(); data_ds; for (i=1;i&=8;i++) {//recharge register SCL_DS1302=0;IO_DS1302=bit_data0;_nop_(); SCL_DS1302=1;data_ds1302=data_ds1302&&1;} data_ds; for (i=1;i&=8;i++) { //no rechaarge for battery SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } RST_DS1302=0; _nop_(); SCL_DS1302=0; SCL_DS1302=0; _nop_(); RST_DS1302=1; _nop_();_nop_(); data_ds; for (i=1;i&=8;i++) { SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } data_ds; for (i=1;i&=8;i++) { SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1;32 } RST_DS1302=0; _nop_(); SCL_DS1302=0; } unsigned char read_ds1302(char command) { data_ds1302=(command&&1)|0x81; SCL_DS1302=0; _nop_(); RST_DS1302=1; for (i=1;i&=8;i++) { SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } SCL_DS1302=1; for (i=1;i&=8;i++) { data_ds1302=data_ds1302&&1; SCL_DS1302=0;_nop_(); bit_data7=IO_DS1302;SCL_DS1302=1; } RST_DS1302=0; _nop_(); SCL_DS1302=0; return(data_ds1302); } void write_ds1302(unsigned char address,unsigned char numb) //写入时分秒 { RST_DS1302=0; SCL_DS1302=0; RST_DS1302=0; RST_DS1302=1; data_ds|(address&&1);33 for (i=1;i&=8;i++) { SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } data_ds1302= for (i=1;i&=8;i++) { SCL_DS1302=0;IO_DS1302=bit_data0; _nop_();SCL_DS1302=1; data_ds1302=data_ds1302&&1; } RST_DS1302=0; SCL_DS1302=1; } void read_time() { unsigned char second,minute,hour,d; second=0; d=read_ds1302(second); display_buffer[7]=d&0x0f; display_buffer[6]=d&&4; minute=1; d=read_ds1302(minute); display_buffer[5]=d&0x0f; display_buffer[4]=(d&&4); hour=2; d=read_ds1302(hour); display_buffer[1]=d&0x0f; display_buffer[0]=(d&&4); } //读时分秒//read second address//read minute address//read hour addressvoid set_time() { uns unsigned char data hour_address,minute_address,second_ open_write_bit(); temp=(display_buffer[0]&&4)|display_buffer[1]; write_ds1302(hour_address,temp);34 temp=(display_buffer[4]&&4)|display_buffer[5]; write_ds1302(minute_address,temp); temp=(display_buffer[6]&&4)|display_buffer[7]; write_ds1302(second_address,temp); close_write_bit(); }第十四讲 IC 卡(24C01)在日常生活中,IC 卡的使用越来越广泛,而且还有进一步扩大的趋势。因此 有必要掌握这方面的知识,下面以 24C01 为例,简单地介绍一般使用方法。 #include &reg52.h& #include &intrins.h& sbit SCL_IC_CARD=P1^3; sbit SDA_IC_CARD=P1^4; sbit WP_IC_CARD =P1^7; bdata char com_ sbit mos_bit=com_data^7; sbit low_bit=com_data^0; unsigned char data display_buffer[8]; void delay(int n); unsigned char rd_24c01(char a); void wr_24c01(char a,char b); main() { WP_IC_CARD=1; for (i=0;i&=7;i++) {display_buffer[i]=rd_24c01(i);delay(250);} for (i=0;i&=7;i++) {wr_24c01(i,display_buffer[i]);delay(250);} while(1); } void start() { //启动读写时序 //图 4-22 (c)开始、结束脉冲时序35 图 4-24 简单应用 SDA_IC_CARD=1; SCL_IC_CARD=1; SDA_IC_CARD=0; SCL_IC_CARD=0; } void stop() { SDA_IC_CARD=0; SCL_IC_CARD=1; SDA_IC_CARD=1; } void ack() { SCL_IC_CARD=1; SCL_IC_CARD=0; } void shift8(char a) {
com_data=a; for(i=0;i&8;i++) { SDA_IC_CARD=mos_ SCL_IC_CARD=1; SCL_IC_CARD=0; com_data=com_data*2; } } unsigned char rd_24c01(char a) { data unsigned char i, SDA_IC_CARD=1; SCL_IC_CARD=0; start(); command=0XA0; shift8(command); ack(); shift8(a);//启动 start//停止操作 //图 4-22 (c)开始、结束脉冲时序//应答函数//8 位移位输出//读 IC 卡函数//启动 //160; //送出器件地址 //应答 //送出存储器地址第一步36 ack(); //应答 start(); //启动 command=0XA1 //161; shift8(command); //送出器件地址 ack(); //应答 SDA_IC_CARD=1; // for(i=0;i&8;i++) //循环 8 次读取一个字节 { com_data=com_data*2; SCL_IC_CARD=1; low_bit=SDA_IC_CARD; 读取数据 SCL_IC_CARD=0; } stop(); //停止操作 return(com_data); } void wr_24c01(char a,char b) { data u WP_IC_CARD=0; _nop_(); SDA_IC_CARD=1; SCL_IC_CARD=0; start(); command=0XA0; shift8(command); ack(); shift8(a); ack(); shift8(b); ack(); stop(); _nop_(); WP_IC_CARD=1; } void delay(int n) //写 IC 卡函数第二步//启动 //160; //送出器件地址 //应答 //送出存储器地址 //应答 //送出欲写入的数据 //应答 //停止操作写 IC 卡函数//延时函数37 { for (i=1;i&=n;i++){;} }第十五讲 温度转换(DS18B20)DS18B20 是单总线温度传感器。 1?功能特点 采用单总线技术,与单片机通讯只要一根 IO 线; 通过比较系列号可以在一根线上挂接多个 DS18B20; 低压供电,电源范围从 3V~5V,也可以直接从数据线上窃取电源; 测温范围-550~1250摄氏度,在-100~850摄 氏度范围内误差为±0.5 度; 数据位可编程 9~12 位, 转换 12 位温度时 间为 750ms(最大); 用户可自设定预警上下限温度; 报警搜索命令可识别和寻址那个器件的 温度至超出预定值。 2?与单片机接口如图 4-25 所示。 图 4-25 与 8051 系列单片机连接 3?程序分析 #include &reg51.h& typedef sbit TMDAT = P3^6; /********** FUNCTION **********/ void dmsec (unsigned int count) { // mSec Delay 11.0592 M // 1MS 延时 while (count--) { for (i=0;i&125;i++){} } } void tmreset (void) { TMDAT = 0; i = 103; while (i&0) i--; TMDAT = 1; i = 4; while (i&0) i--; // Reset TX// Approx 900 uS38 } void tmpre (void) { while (TMDAT); while (~TMDAT); i = 4; while (i&0) i--; } bit tmrbit (void) { TMDAT = 0; i++; TMDAT = 1; i++; i++; dat = TMDAT; i = 8; while (i&0) i--; return (dat); } unsigned char tmrbyte (void) { unsigned char i,j, dat = 0; for (i=1;i&=8;i++) { j = tmrbit (); dat = (j && 7) | (dat && 1); } return (dat); } void tmwbyte (unsigned char dat) { for (j=1;j&=8;j++) { testb = dat & 0x01; dat = dat && 1; if (testb) { TMDAT = 0; // Wait for Presence RX// read one bit// read one byte// write one byte// Write 139 i++; i++; TMDAT = 1; i = 8; while (i&0) i--; } else { TMDAT = 0; i = 8; while (i&0) i--; TMDAT = 1; i++; i++; } } } void tmstart (void) { tmreset (); tmpre (); dmsec (1); tmwbyte (0xcc); tmwbyte (0x44); } unsigned char tmrtemp (void) { unsigned char a,b,y1,y2,y3; tmreset (); tmpre (); dmsec (1); tmwbyte (0xcc); tmwbyte (0xbe); a = tmrbyte (); b = tmrbyte (); y1=a&&4; y2=b&&4; y3=y1 | y2; return(y3); } /********** MAIN **********/ void main (void)40// Write 0// ds1820 start convert// skip rom // convert// read temp// skip rom // convert // LSB // MSB { uchar lsb, dmsec(1); tmstart (); dmsec(1000); last=tmrtemp (); msb=last/0x0a+0x30; lsb=last%0x0a+0x30; while(1){} }// ds1820 start convert // read temperature第十六讲 键盘控制器7289A7289A是具有SPI 串行接口功能的可同时驱动8 位共阴式数码管或64 只独立 LED 的智能显示驱动芯片,该芯片同时还可连接多达64键的键盘矩阵,单片即可 完成LED显示p键盘接口的全部功能。7289A内部含有译码器,可直接接受BCD码 或16进制码,并同时具有两种译码方式。此外还具有多种控制指令如消隐p闪烁p 左移p右移p段寻址等。7289A具有片选信号,可方便地实现多于8位的显示或多 于64键的键盘接口。 一、键盘控制器7289A特点 1)串行接口无需外围元件可直接驱动LED; 2)各位独立控制译码/不译码及消隐和闪烁属性; 3)循环左移/循环右移指令; 4)具有段寻址指令方便控制独立LED; 5)64 键键盘控制器内含去抖动电路; 二、7289A 典型应用电路 如图 4-36 所示。 三、程序分析 #include &reg52.h& #define uchar unsigned char sbit sbit sbit sbit uchar CS=P1^0; CLK=P1^1; DIO=P1^2; KEY=P1^3; rebuf,41 bdata sbit sbit void {uchar com_ mos_bit=com_data^7; low_bit=com_data^0; delay_50us() for(i=0;i&6;i++){;} //延时50us} void delay_8us() { for(i=0;i&1;i++){;} } void delay_50ms() { uchar i,j; for(j=0;j&50;j++) for(i=0;i&125;i++){;} } void send(uchar sebuf) { com_data= CLK=0; CS=0; delay_50us(); for(i=0;i&8;i++) { delay_8us(); DIO=mos_ CLK=1; delay_8us(); com_data=com_data&&1; CLK=0; //延时8us//延时50ms//发送42 } DIO=0; } void receive() { CLK=1; delay_50us(); for(i=0;i&8;i++) { com_data=com_data&&1; low_bit=DIO; CLK=1; delay_8us(); CLK=0; delay_8us(); } rebuf=com_ DIO=1; CS=1; } void reset() { KEY=1; DIO=1; delay_50ms(); send(0xa4); CS=1; } //接收//复位清零main() { reset(); sebuf=0x84; send(0x83);//发送缓冲赋值0x84;43 delay_50us(); send(sebuf); CS=1; while(1) { while(KEY); send(0x15); delay_50us(); receive(); delay_50us(); switch(rebuf){//读取键值case 0x00: {send(0xA3);CS=1;} 循环左移 case 0x01: {send(0xA2);CS=1;} //循环右移 case 0x0b: { send(0x88); delay_50us(); send(0x00);CS=1; } //闪烁 case 0x03: { send(0x88); delay_50us(); send(0xff); CS=1; } //取消闪烁 default: } while(!KEY); KEY=1; } }//44 45}

我要回帖

更多关于 查找内容相同的单元格 的文章

更多推荐

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

点击添加站长微信