51单片机程序运行过程
(完整版)51单片机流水灯程序
1.第一个发光管以间隔200ms 闪烁。
2.8 个发光管由上至下间隔1s 流动,其中每个管亮500ms, 灭500ms 。
3.8 个发光管来回流动,第个管亮100ms 。
4.用8 个发光管演示出8 位二进制数累加过程。
5.8 个发光管间隔200ms 由上至下,再由下至上,再重复一次,然后全部熄灭再以300ms 间隔全部闪烁 5 次。
重复此过程。
6.间隔300ms 第一次一个管亮流动一次,第二次两个管亮流动,依次到8 个管亮,然后重复整个过程。
7.间隔300ms 先奇数亮再偶数亮,循环三次;一个灯上下循环三次;两个分别从两边往中间流动三次;再从中间往两边流动三次;8 个全部闪烁 3 次;关闭发光管,程序停止。
1#include<reg52.h>#define uint unsigned intsbit led 仁P"0;void delay();void main(){while(1){led1=0;delay();led1=1;delay();}}void delay(){uint x,y;for(x=200;x>0;x--) for(y=100;y>0;y--);}#include<reg52.h> #include<intrins.h> #define uint unsigned int #define uchar unsigned char sbit p P1A0; uchar a;void delay(); void main() {a=0xfe;P1=a;while(1){ a=_crol_(a,1); delay();P1=a; delay();}}void delay(){uint b; for(b=55000;b>0;b--);}3#include<reg52.h>#include <intrins.h>#define uint unsigned int #define uchar unsigned char void delay() {uint x,y; for(x=100;x>0;x--) for(y=110;y>0;y--);}void main() {uchar a,i;while(1)a=0xfe; for(i=0;i<8;i++){P1=a; delay(100); a=_crol_(a,1);}a=0x7f; for(i=0;i<8;i++){P1=a; delay(100); a=_cror_(a,1);4#include<reg52.h>#include <intrins.h> #define uint unsigned int #define uchar unsigned char void delay(uint a) { uint x,y; for(x=a;x>0;x--) for(y=110;y>0;y--);}void main() {uchar b;while(1){b++;P1=~b; delay(200);5#include<reg52.h>#include <intrins.h> #define uint unsigned int #define uchar unsigned char void main() { uchar a,i,j;while(1){ for(j=0;j<2;j++){a=0xfe; for(i=0;i<8;i++){P1=a;delay(200); a=_crol_(a,1);}a=0x7f; for(i=0;i<8;i++){P1=a; delay(200); a=_cror_(a,1);}}P1=0xff; for(j=0;j<10;j++) {delay(300);P1=~P1;}}}void delay(){uint x,y; for(x=200;x>0;x--) for(y=110;y>0;y--); 6 #include<reg52.h> #include <intrins.h> #define uint unsigned int #define uchar unsigned char void delay(){uint x,y; for(x=300;x>0;x--) for(y=110;y>0;y--);} void main(){uchar a,i,j; while(1) {a=0xfe; for(j=0;j<8;j++) { for(i=0;i<8-j;i++) {P1=a; delay(200); a=_crol_(a,1);} a=_crol_(a,j); P1=0xff; a=a<<1;}} }7#include<reg52.h> #include <intrins.h> #define uint unsigned int #define uchar unsigned char void delay(uint z){uint x,y; for(x=z;x>0;x--)for(y=110;y>0;y--);}void main(){uchar a,i,j;for(j=0;j<3;j++){P1=0x55;delay(300);P1=0xaa; delay(300);}for(j=0;j<3;j++){a=0xfe;for(i=0;i<8;i++){P1=a;delay(300); a=_crol_(a,1);}}P1=0xff; for(j=0;j<3;j++){P1=0x7e;delay(300);P1=0xbd; delay(300);P1=0xdb; delay(300);P1=0xe7; delay(300);}P1=0xff;for(j=0;j<3;j++){P1=0xe7;delay(300);P1=0xdb;delay(300);P1=0xbd;delay(300);P1=0x7e;delay(300);}P1=0xff; for(j=0;j<6;j++) {P1=~P1; delay(300);}P1=0xff;while(1);}。
51单片机lcd1602全过程C语言编程显示大全
背光,黑色字体)
1602 液晶的正面(绿色
光,黑色字体)
“study up”程序中没有用到忙检测,而是用的是延时函数来替代忙检测
#include<reg52.h> //包含头文件,这个嘛,就不用多说了~~
#define uint unsigned int //预定义一下
#define uchar unsigned char sbit rs=P3^5; //1602 的数据/指令选择控制线
3.进入模式设置指令
功能:设定每次定入 1 位数据后光标的移位方向,并且设定每次写入的一个字符是否移动。 参数设定的情况如下数据后光标左移 1=写入新数据后光标右移 0=写入新数据后显示屏不移动 1=写入新数据后显示屏整体右移 1 个字
4.显示开关控制指令
功能:控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情况如下:
位名
设置
D
0=显示功能关
1=显示功能开
C
0=无光标
1=有光标
B
0=光标闪烁
1=光标不闪烁
5.设定显示屏或光标移动方向指令
功能:使光标移位或使整个显示屏幕移位。参数设定的情况如下:
S/C
R/L
设定情况
0
0
光标左移 1 格,且 AC 值减 1
0
1
光标右移 1 格,且 AC 值加 1
1
0
显示器上字符全部左移一格,但光标不动
51单片机位操作
C51单片机位操作方法C51对位的操控能力是非常强大的。
从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点。
这也是在各个领域中都可以看到C的重要原因。
在这一节中将详细讲解C51中的位操作及其应用。
1、位运算符C51提供了几种位操作符,如下表所示:1)“按位与”运算符(&)参加运算的两个数据,按二进位进行“与”运算。
原则是全1为1,有0为0,即:0&0=0; 0&1=0; 1&0=0; 1&1=1;如下例:a=5&3; //a=(0b 0101) & (0b 0011) =0b 0001 =1那么如果参加运算的两个数为负数,又该如何算呢?会以其补码形式表示的二进制数来进行与运算。
a=-5&-3; //a=(0b 1011) & (0b1101) =0b 1001 =-7在实际的应用中与操作经常被用于实现特定的功能:1.清零“按位与”通常被用来使变量中的某一位清零。
如下例:a=0xfe; //a=0ba=a&0x55;//使变量a的第1位、第3位、第5位、第7位清零a= 0b2.检测位要知道一个变量中某一位是‘1’还是‘0’,可以使用与操作来实现。
a=0xf5; //a=0bresult=a&0x08; //检测a的第三位,result=03.保留变量的某一位要屏蔽某一个变量的其它位,而保留某些位,也可以使用与操作来实现。
a=0x55; //a=0ba=a&0x0f; //将高四位清零,而保留低四位a=0x052)“按位或”运算符(|)参与或操作的两个位,只要有一个为‘1’,则结果为‘1’。
即有‘1’为‘1’,全‘0’为‘0’。
0|0=0; 0|1=1; 1|0=1; 1|1=1;例如:a=0x30|0x0f; //a=(0b)|(0b)=(0b)=0x3f“按位或”运算最普遍的应用就是对一个变量的某些位置‘1’。
关于51单片机启动程序和头文件的深入学习
总的作用:STARTUP.A51//启动文件. 清理RAM.设置堆栈等.即执行完start.a51后跳转到.c文件的main 函数<reg51.h> //特殊寄存器的字节地址和位地址,sfr定义字节变量、sbit定义位变量,用通俗名作为变量名,并赋地址值,从而用名称来使用这些特殊寄存器。
<intrins.h> //定义了一些外部函数,在C51单片机编程中,头文件INTRINS.H的函数使用起来,就会让你像在用汇编时一样简便.特别需要注意的概念:地址与地址值:“地址是存放值的内存空间对应的门牌号码。
地址值是门牌号对应内存空间里存放内容。
通俗讲,一栋楼房, 101号房间什么都没只有1个人。
这个人是值。
101是地址。
房间是内存空间。
”启动程序详细解释;STARTUP.A51:用户上电初始化程序;------------------------------------------------------------------------------;; 用户定义需上电初始化的内存空间;; 使用以下EQU命令可定义在CPU复位时需用0进行初始化的内存空间;; ;IDATA 存储器的空间的绝对起始地址总是0.IDATALENEQU 80H ; 需用0进行初始化的IDATA存储器空间的字节数;XDATASTARTEQU 0H ; XDATA存储器空间的绝对起始地址XDATALENEQU 0H ; 需用0进行初始化的XDATA存储器的空间字节数.;PDATASTARTEQU 0H ; PDATA存储器的空间的绝对起始地址PDATALENEQU 0H ; 需用0进行初始化的PDATA存储器的空间字节数.;; 注意: IDATA 存储器的空间在物理上包括了8051单片机的DATA和BIT存储器空间.; 听说至少要保证与C51编译器运行库有关的存储器的空间进行0初始化不知是否;------------------------------------------------------------------------------;; 再入函数模拟初始化;; 以下用EQU指令定义了再入函数模拟堆栈指针的初始化;; 使用SMALL存储器模式时再入函数的堆栈空间.IBPSTACKEQU 0 ; 使用SMALL存储器模式再入函数时将其设置成1. IBPSTACKTOPEQU 0FFH+1 ; 将堆栈顶设置为最高地址+1.;; 使用LARGE存储器模式时再入函数的堆栈空间.XBPSTACKEQU 0 ; 使用LARGE存储器模式再入函数时将其设置成1. XBPSTACKTOPEQU 0FFFFH+1; 将堆栈顶设置为最高地址+1.;; 使用COMPACT存储器模式时再入函数的堆栈空间.PBPSTACKEQU 0 ; 使用COMPACT存储器模式再入函数时将其设置成1. PBPSTACKTOPEQU 0FFFFH+1; 将堆栈顶设置为最高地址+1.;;------------------------------------------------------------------------------;; 使用COMPACT存储器模式时64K字节XDATA存储器空间的分页定义;; 以下用EQU指令定义PDATA类型变量在XDATA存储器空间的页地址; 使用EQU指令定义PFAGE时必须与L51连接定位器PDATA指令的控制参数一致;PPAGEENABLEEQU 0 ; 使用PDATA类型变量时将其设置成1.PPAGEEQU 0 ; 定义页号.;;------------------------------------------------------------------------------NAME?C_STARTUP ; 模块名为?C_STAUTUP?C_C51STARTUPSEGMENT CODE ; 代码?STACKSEGMENT IDATA ; 堆栈RSEG?STACK ; 堆栈DS 1EXTRNCODE (?C_START) ; 程序开始地址PUBLIC?C_STARTUPCSEGAT 0x8000 ; 定义用户程序的起始地址,用MON51仿真器时可能有用?C_STARTUP:LJMP STARTUP1RSEG?C_C51STARTUPSTARTUP1:;; 初始化串口MOVSCON,#40HMOVTMOD,#20HMOVTH1,#0fdHSETBTR1CLRTI; 单片机上电IDATA内存清零如果不需要上电清零IDATA可以注销IF到IFEDN之间的话句; 或者修改IDTALEN的长度为了具有掉电保护功能不知IDTALEN多长为好IFIDATALEN <> 0MOVR0,#IDATALEN - 1CLR AIDATALOOP:MOV @R0,ADJNZR0,IDATALOOPENDIF;; 单片机上电XDATA内存清零如果不需要上电清零XDATA可以注销IF到IFEDN之间的话句; 或者修改XDATALEN的长度IFXDATALEN <> 0MOVDPTR,#XDATASTARTMOVR7,#LOW (XDATALEN)IF(LOW (XDATALEN)) <> 0MOVR6,#(HIGH (XDATALEN)) +1ELSEMOVR6,#HIGH (XDATALEN)ENDIFCLR AXDATALOOP:MOVX @DPTR,AINCDPTRDJNZR7,XDATALOOPDJNZR6,XDATALOOPENDIF;; 送PDATA存储器页面高位地址IFPPAGEENABLE <> 0MOVP2,#PPAGEENDIF;; 单片机上电PDATA内存清零如果不需要上电清零XDATA可以注销IF到IFEDN之间的话句; 或者修改PDATALEN的长度IFPDATALEN <> 0MOVR0,#PDATASTARTMOVR7,#LOW (PDATALEN)CLR APDATALOOP:MOVX @R0,AINCR0DJNZR7,PDATALOOPENDIF;; 设置使用SMALL存储器模式时再入函数的堆栈空间.IFIBPSTACK <> 0EXTRNDATA (?C_IBP)MOV?C_IBP,#LOW IBPSTACKTOPENDIF;; 设置使用LARGE存储器模式时再入函数的堆栈空间.IFXBPSTACK <> 0EXTRNDATA (?C_XBP)MOV?C_XBP,#HIGH XBPSTACKTOPMOV?C_XBP+1,#LOW XBPSTACKTOPENDIF;; 设置使用COMPACT存储器模式时再入函数的堆栈空间.IFPBPSTACK <> 0EXTRNDATA (?C_PBP)MOV?C_PBP,#LOW PBPSTACKTOPENDIF;; 设置堆栈的起始地址MOVSP,#?STACK-1 ; 例如MOV SP,#4FH;;This code is required if you use L51_BANK.A51 with Banking Mode 4; 如果你的程序使用了Mode 4 程序分组技术请启动下面的程序,不会吧你的程序超过64K 利害;EXTRN CODE (?B_SWITCH0);CALL ?B_SWITCH0 ; init bank mechanism to code bank 0; 程序从第一组bank 0 块开始执行; 跳转到用户程序MAIN函数LJMP?C_STARTEND总之,在KEIL中,汇编是从ORG 000H开始启动,那么它在C51中是如何启动MAIN()函数的呢?实际上是C51中有一个启启动程序STARTUP.A51,它总是和C程序一起编译和链接的.启动文件STARTUP.A51中包含目标板启动代码,可在每个project中加入这个文件,只要复位,则该文件立即执行,其功能包括:z 定义内部RAM大小、外部RAM大小、可重入堆栈位置z 清除内部、外部或者以此页为单元的外部存储器z 按存储模式初使化重入堆栈及堆栈指针z 初始化8051硬件堆栈指针z 向main( )函数交权头文件详解/*--------------------------------------------------------------------------REG51.HHeader file for generic 80C51 and 80C31 microcontroller.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc.All rights reserved.--------------------------------------------------------------------------*/#ifndef __REG51_H__#define __REG51_H__/* BYTE Register */ 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;/* BIT Register */ /* PSW */sbit CY = 0xD7; sbit AC = 0xD6; sbit F0 = 0xD5; sbit RS1 = 0xD4; sbit RS0 = 0xD3; sbit OV = 0xD2; sbit P = 0xD0;/* TCON */sbit TF1 = 0x8F; sbit TR1 = 0x8E; sbit TF0 = 0x8D; sbit TR0 = 0x8C; sbit IE1 = 0x8B; sbit IT1 = 0x8A; sbit IE0 = 0x89; sbit IT0 = 0x88;/* IE */sbit EA = 0xAF;sbit ES = 0xAC;sbit ET1 = 0xAB;sbit EX1 = 0xAA;sbit ET0 = 0xA9;sbit EX0 = 0xA8;/* IP */sbit PS = 0xBC;sbit PT1 = 0xBB;sbit PX1 = 0xBA;sbit PT0 = 0xB9;sbit PX0 = 0xB8;/* P3 */sbit RD = 0xB7;sbit WR = 0xB6;sbit T1 = 0xB5;sbit T0 = 0xB4;sbit INT1 = 0xB3;sbit INT0 = 0xB2;sbit TXD = 0xB1;sbit RXD = 0xB0;/* SCON */sbit SM0 = 0x9F;sbit SM1 = 0x9E;sbit SM2 = 0x9D;sbit REN = 0x9C;sbit TB8 = 0x9B;sbit RB8 = 0x9A;sbit TI = 0x99;sbit RI = 0x98;#endif/*-------------------------------------------------------------------------- INTRINS.HIntrinsic functions for C51.Copyright (c) 1988-2002 Keil Elektronik GmbH and Keil Software, Inc. All rights reserved.--------------------------------------------------------------------------*/#ifndef __INTRINS_H__#define __INTRINS_H__extern void _nop_ (void);extern bit _testbit_ (bit);extern unsigned char _cror_ (unsigned char, unsigned char);extern unsigned int _iror_ (unsigned int, unsigned char);extern unsigned long _lror_ (unsigned long, unsigned char);extern unsigned char _crol_ (unsigned char, unsigned char);extern unsigned int _irol_ (unsigned int, unsigned char);extern unsigned long _lrol_ (unsigned long, unsigned char);extern unsigned char _chkfloat_(float);#endif关于sfr、sbit://如同int、char...sfr 似乎不是标准C 语言的关键字,而是Keil 为能直接访问80C51 中的SFR 而提供了一个新的关键词,其用法是:sfrt 变量名=地址值。
51单片机烧写方法
51单片机烧写方法一、引言51单片机是一种常用的单片机,广泛应用于各种电子设备中。
烧写是将程序代码写入51单片机的过程,是使用单片机的基础操作。
本文将介绍51单片机的烧写方法,帮助读者了解如何正确地进行烧写操作。
二、烧写工具准备进行51单片机的烧写操作,首先需要准备以下工具:1. 51单片机烧写器:一种专门用于将程序代码写入51单片机的设备,常见的有USB转串口烧写器和ISP烧写器两种;2. 电脑:用于连接烧写器,并通过烧写软件进行烧写操作;3. 烧写软件:根据烧写器的型号选择相应的烧写软件,常见的有STC-ISP、Flash Magic等。
三、烧写步骤1. 连接烧写器:将烧写器通过USB或串口连接到电脑上,并确保连接正常;2. 打开烧写软件:根据烧写器的型号选择相应的烧写软件,并打开软件;3. 设置烧写参数:在烧写软件中选择正确的单片机型号,并设置好烧写参数,如烧写速度、烧写模式等;4. 导入程序代码:将需要烧写的程序代码导入烧写软件中,通常是通过选择文件或拖拽文件的方式导入;5. 连接单片机:将51单片机通过编程接口连接到烧写器上,确保连接正常;6. 擦除单片机:在烧写软件中选择擦除操作,将单片机中原有的程序代码擦除,以便写入新的程序代码;7. 烧写程序代码:点击烧写软件中的烧写按钮,开始将程序代码写入单片机中;8. 等待烧写完成:等待烧写软件提示烧写完成,此时烧写操作已经完成;9. 断开连接:断开51单片机与烧写器之间的连接,完成烧写过程。
四、烧写注意事项1. 确认单片机型号:在烧写操作之前,要确认所使用的单片机型号,选择正确的烧写软件和参数设置;2. 确保连接正常:在进行烧写操作之前,要检查烧写器与电脑、单片机之间的连接是否正常,避免烧写失败;3. 备份程序代码:在擦除单片机之前,建议先备份原有的程序代码,以便需要时恢复;4. 不要中断烧写过程:在烧写过程中,不要随意中断电源或断开连接,以免造成单片机损坏;5. 验证烧写结果:在烧写完成后,可以通过读取单片机中的程序代码,与原始代码进行比对,以验证烧写结果的准确性。
51单片机秒表程序设计
51单片机秒表程序设计1. 简介秒表是一种用于测量时间间隔的计时器,常见于体育比赛、实验室实验等场合。
本文将介绍如何使用51单片机设计一个简单的秒表程序。
2. 硬件准备•51单片机开发板•LCD液晶显示屏•按键开关•连接线3. 程序流程3.1 初始化设置1.设置LCD液晶显示屏为8位数据总线模式。
2.初始化LCD液晶显示屏。
3.设置按键开关为输入模式。
3.2 主程序循环1.显示初始界面,包括“00:00:00”表示计时器初始值。
2.等待用户按下开始/暂停按钮。
3.如果用户按下开始按钮,则开始计时,进入计时状态。
4.如果用户按下暂停按钮,则暂停计时,进入暂停状态。
5.在计时状态下,每隔1毫秒更新计时器的数值,并在LCD液晶显示屏上显示出来。
6.在暂停状态下,不更新计时器的数值,并保持显示当前数值。
3.3 计时器控制1.定义一个变量time用于存储当前的计时器数值,单位为毫秒。
2.定义一个变量running用于标记计时器的状态,0表示暂停,1表示运行。
3.定义一个变量start_time用于存储计时器开始的时间点。
4.定义一个变量pause_time用于存储计时器暂停的时间点。
5.在计时状态下,每隔1毫秒更新time的值为当前时间与start_time的差值,并将其转换为小时、分钟、秒的表示形式。
6.在暂停状态下,保持time的值不变。
3.4 按键检测1.检测按键开关是否被按下。
2.如果按键被按下,判断是开始/暂停按钮还是复位按钮。
3.如果是开始/暂停按钮,并且当前处于计时状态,则将计时状态设置为暂停状态,并记录暂停时间点为pause_time;如果当前处于暂停状态,则将计时状态设置为运行状态,并记录开始时间点为当前时间减去暂停时间的差值。
4.如果是复位按钮,则将计时器数值重置为0,并将计时状态设置为暂停。
4. 程序代码示例#include <reg51.h>// 定义LCD控制端口和数据端口sbit LCD_RS = P1^0;sbit LCD_RW = P1^1;sbit LCD_EN = P1^2;sbit LCD_D4 = P1^3;sbit LCD_D5 = P1^4;sbit LCD_D6 = P1^5;sbit LCD_D7 = P1^6;// 定义按键开关端口sbit START_PAUSE_BTN = P2^0;sbit RESET_BTN = P2^1;// 定义全局变量unsigned int time = 0; // 计时器数值,单位为毫秒bit running = 0; // 计时器状态,0表示暂停,1表示运行unsigned long start_time = 0; // 开始时间点unsigned long pause_time = 0; // 暂停时间点// 函数声明void delay(unsigned int ms);void lcd_init();void lcd_command(unsigned char cmd);void lcd_data(unsigned char dat);void lcd_string(unsigned char *str);void lcd_clear();void lcd_gotoxy(unsigned char x, unsigned char y);// 主函数void main() {// 初始化设置lcd_init();while (1) {// 显示初始界面lcd_clear();lcd_gotoxy(0, 0);lcd_string("00:00:00");// 等待用户按下开始/暂停按钮while (!START_PAUSE_BTN && !RESET_BTN);// 判断按钮类型并处理计时器状态if (START_PAUSE_BTN) {if (running) { // 当前处于计时状态,按下按钮将进入暂停状态 running = 0;pause_time = time;} else { // 当前处于暂停状态,按下按钮将进入计时状态running = 1;start_time = get_current_time() - pause_time;}} else if (RESET_BTN) { // 复位按钮按下,重置计时器time = 0;running = 0;}}}// 毫秒级延时函数void delay(unsigned int ms) {unsigned int i, j;for (i = ms; i > 0; i--) {for (j = 110; j > 0; j--);}}// LCD初始化函数void lcd_init() {lcd_command(0x38); // 设置8位数据总线模式lcd_command(0x0C); // 显示开,光标关闭lcd_command(0x06); // 光标右移,不移动显示器lcd_command(0x01); // 清屏}// 向LCD发送指令函数void lcd_command(unsigned char cmd) {LCD_RS = 0;LCD_RW = 0;LCD_EN = 1;LCD_D4 = cmd >> 4 & 1;LCD_D5 = cmd >> 5 & 1;LCD_D6 = cmd >> 6 & 1;LCD_D7 = cmd >> 7 & 1;delay(1);LCD_EN = 0;LCD_D4 = cmd >> 0 & 1;LCD_D5 = cmd >> 1 & 1;LCD_D6 = cmd >> 2 & 1;LCD_D7 = cmd >> 3 & 1;delay(1);LCD_EN = 0;}// 向LCD发送数据函数void lcd_data(unsigned char dat) { LCD_RS = 1;LCD_RW = 0;LCD_EN = 1;LCD_D4 = dat >> 4 & 1;LCD_D5 = dat >> 5 & 1;LCD_D6 = dat >> 6 & 1;LCD_D7 = dat >> 7 & 1;delay(1);LCD_EN = 0;LCD_D4 = dat >> 0 & 1;LCD_D5 = dat >> 1 & 1;LCD_D6 = dat >> 2 & 1;LCD_D7 = dat >> 3 & 1;delay(1);LCD_EN = 0;}// 向LCD发送字符串函数void lcd_string(unsigned char *str) {while (*str) {lcd_data(*str++);delay(5);}}// 清屏函数void lcd_clear() {lcd_command(0x01);}// 设置光标位置函数void lcd_gotoxy(unsigned char x, unsigned char y) {unsigned char addr;if (y == 0)addr = x | (0x80 + y);else if (y == 1)addr = x | (0xC0 + y);lcd_command(addr);}5. 总结本文介绍了使用51单片机设计一个简单的秒表程序。
No.5C51程序设计
– 指定存储区的指针
• 指定存储区的指针在指针的声明中经常包含一个 存储类型标识符指向一个确定的存储区。 • 例如: char data *str; int xdata *ptr; long code *tab;
• 指定存储区指针存放时不再像通用指针那样需 要保存存储类型,指向idata、data 、bdata 和pdata存储区的指针只需要一个字节存放, 而code和xdata指针也才需要两字节。从而减 少了指针长度,节省了存储空间。
– 如:sfr16 TL0=0x8A;
– 特殊功能寄存器中特定位的定义
• 在C51中可以利用关键字sbit定义可独立寻址访问 的位变量
• 对一般位变量的定义
– 当位变量位于内部RAM的可位寻址区(20H~2FH 单元)时,可以利用C51编译器提供的bdata存储器 类型进行访问 – 带有bdata类型的变量可以进行字节或位寻址,用 sbit指定bdata变量的相应位后就可以进行位寻址。
– 考虑存储器结构 – 正确使用片内外RAM、特殊功能寄存器 – 正确处理接口芯片收发数据 – 不需要具体组织和分配存储器资源 – 结构模块化,思路与思维相同 – 但要与单片机结构相关联,否则不能正确映射
• C程序:
• C51:
– – – –
自动完成存储单元分配(内定义) 可编制常见接口芯片通用驱动函数 可采用模块化设计应用程序 加快开发速度
var=XBYTE[0x8000]; 头文件内定义的函数 XBYTE[0x8000]=0x21;
P71
– 例如:unchared xdta xram[0x8000]_at_0x1000; //在外部RAM1000H开始定义了一个一维数组
51系列单片机指令系统
MOV DPTR,#1000H MOVX A,@DPTR INC DPTR, MOVX @DPTR,A 7、程序存储器向累加器A传送指令 MOVC A,@A+DPTR MOV DPTR,#100H MOV A,R0 MOVC A,@A+DPTR ORG 0100H. DB 0,1,4,9,16,25 8、堆栈操作指令 PUSH direct POP direct 第一条指令称之为入栈指令,就是将direct中的内容 送入堆栈中,第二条指令称之为弹出指令,就是将堆栈 中的内容送回到direct中。
位寻址时,操作数是二进制数的某一位,其位地 址出现在指令中,例如指令 • SETB bit ;(bit) ← l • 51系列单片机可用于位寻址的空间是内部RAM的可 位寻址区和SFR区中的字节地址可以被8整除(即地址以 “0”或“8”结尾)的寄存器所占空间,寻址方式如表 2-2所示。
表2-2 寻址方式一览表
寻 址 方 式
寻 址 范 围
R0-R7 ,DPTR ACC,B,C(CY位)
内部RAM 00H-7FH 特殊功能寄存器 80H-FFH 内部RAM位寻址区 (20H-2FH): 位地址00H-7FH 可寻址的特殊功能寄存器: 位地址 80H-F7H 以数据指针表示操作数 内部RAM 00H-7FH 外部RAM或I/O端口 00H-FFH / 0000H-FFFFH
图2-3 寄存器间接寻址
图2-4 立即寻址
4、立即寻址
•
立即寻址时,指令中直接给出操作数。例如指令 MOV A,#76H ;数据76H送累加器 A。 • 立即数寻址过程如图2-4所示。
5、变址寻址
•
变址寻址时,指定的变址寄存器的内容与指令中 给出的偏移量相加,所得的结果作为操作数的地址。 例如指令MOVC A, @A+DPTR ;((A)+(DPTR))送 A。变址寻址过程如图2-5所示。 不论用DPTR或PC作为基址指针,变址寻址方式都 只适用于51系列单片机的程序存储器,通常用于读取 数据表也就是将程序存储器中的数送入A中。因此也称 为查表指令,常用此指令来查一个已做好在程序存储 器中的表格,这条指令采用变址寻址。
《单片机原理与接口技术》第2章 MCS-51单片机的基本结构
大连理工大学出版社
第2章
MCS-51单片机的基本结构 MCS-51单片机的基本结构
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 单片机内部组成及引脚功能 中央处理器 MCS-51单片机的存储结构 MCS-51单片机的存储结构 输入/ 输入/输出端口 时钟电路与时序 单片机工作过程 MCSMCS-51 单片机工作方式 MCSMCS-51 单片机的最小应用系统
8051/8751 都共有64KB程序存储器空间,片内 ROM/EPROM的容量为 4KB,地址为0000H~0FFFH; 片外最多可扩展至64KB的ROM/EPROM,地址 为1000H~FFFFH,片内外是统一编址的。 当引脚EA接高电平时,8051的PC在0000H~0FFFH范围内执行片内ROM 中的程序; 当指令超过0FFFH时,就自动转向片外ROM取指令。 当EA接低电平时,8051片内ROM不起作用,CPU只能从片外ROM/EPROM 中取指令。对于8031芯片,因其片内无ROM,故应使EA接低电平,这样才 能直接从外部扩展的EPROM中取指令。 3.程序运行的入口地址 3.程序运行的入口地址 实际应用时,程序存储器的容量由用户根据需要扩展,而程序地址 空间原则上也可由用户任意安排,但程序最初运行的入口地址是固定的, 用户不能更改。
MCS-51系列单片机的内部结构 图2-1 MCS-51系列单片机的内部结构
MSC-51系列单片机内部结构简化框图 图2-2 MSC-51系列单片机内部结为21个)特殊功能寄存器SFR (5)4个8位并行输入输出I/O接口 (6)1个串行I/O接口,完成单片机与其他微机之间的串行通信。 (7)2个(MCS-52子系列为3个)16位定时器/计数器T0、T1。
简单的51单片机时钟程序
简单的51单片机时钟程序,可以通过按键来设置时间,按键可以自己更改。
#include<reg52.h>#define uint unsigned int#define uchar unsigned char#define tt 46080 //设置时间间隔,对应11.0592MHZ的晶振uchar code table[]="Happy every day!";uchar code table1[]="00:00:00";uchar num,hh,mm,ss,t,s1num=0;sbit en=P3^4;sbit rs=P3^5;sbit rw=P3^6;sbit s1=P3^0;sbit s2=P3^1;sbit s3=P3^2;//按键所用的端口sbit s4=P3^3;void delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--); //大约是1ms,因为单片机的时钟周期为11.0592mhz。
}void write_com(uchar com){rs=0; //指令P0=com; //写指令函数delay(1);en=1;delay(1);en=0;}void write_data(uchar dat){rs=1; //数据P0=dat; //写指令函数delay(1);en=1;delay(1);en=0;}void init(){en=0; //初始时使能为0rw=0;write_com(0x38); //显示屏模式设置为1602方案write_com(0x0c);write_com(0x06); //显示开关/光标设置write_com(0x01); //清屏write_com(0x80); //指针置零for(num=0;num<16;num++)write_data(table[num]);write_com(0xc3);for(num=0;num<8;num++)write_data(table1[num]);}void dingshi(){TMOD=0x01; //确定定时器工作模式(定时模式)TH0=(65536-tt)/256; //赋初值为tt微秒TL0=(65536-tt)%256; //不赋值时默认其值是0EA=1; //开总中断ET0=1; //开定时器0中断// IE=0x82; //总线写法TR0=1; //启动定时器0 总线TCON=0x10;}void shuanxin(uchar add,uchar date){uchar shi,ge;write_com(0xc3+add); //指针指向shi=date/10;ge=date%10;write_data(0x30+shi);write_data(0x30+ge); //指针自动后移,故不必再写指针位置}/***************借助蜂鸣器接地起作用***************/ void keyscan(){if(s1==0){delay(5);if(s1==0){s1num++;while(!s1);if(s1num==1){TR0=0; //时钟停止运行write_com(0xca); //指针指向sswrite_com(0x0f); //光标闪烁}if(s1num==2){write_com(0xc7); //指针指向mmwrite_com(0x0f);}if(s1num==3){write_com(0xc4); //指针指向hhwrite_com(0x0f);}if(s1num==4){s1num=0;TR0=1; //时钟运行write_com(0x0c); //取消闪烁}}}/***************调节时间****************/if(s1num!=0) //目的是使s1按下的前提才起作用{if(s2==0){delay(5);if(s2==0){while(!s2); //松手检测,松手后方可向下执行if(s1num==1){ss++;if(ss==60)ss=0;shuanxin(6,ss);write_com(0xca);}if(s1num==2){mm++;if(mm==60)mm=0;shuanxin(3,mm);write_com(0xc7);}{hh++;if(hh==24)hh=0;shuanxin(0,hh);write_com(0xc4);}}}}if(s1num!=0) //s1按下的前提才起作用{if(s3==0){delay(5);if(s3==0){while(!s3);if(s1num==1){ss--;ss=59;shuanxin(6,ss);write_com(0xca);}if(s1num==2){mm--;if(mm==-1)mm=59;shuanxin(3,mm);write_com(0xc7);}if(s1num==3){hh--;if(hh==-1)hh=23;shuanxin(0,hh);write_com(0xc4);}}}}if(s1num!=0) //s1按下的前提才起作用{if(s4==0){delay(5);if(s4==0){while(!s4);if(s1num==1){ss=0;shuanxin(6,ss);write_com(0xca);}if(s1num==2){mm=0;shuanxin(3,mm);write_com(0xc7);}if(s1num==3){hh=0;shuanxin(0,hh);write_com(0xc4);}}}}}void main(){init();dingshi();while(1){keyscan();if(t==20){P1=P1-1;t=0;ss++;if(ss==60){ss=0;mm++;if(mm==60){mm=0;hh++;if(hh==24){hh=0;}shuanxin(0,hh);}shuanxin(3,mm);}shuanxin(6,ss);}}}void time0() interrupt 1{TH0=(65536-tt)/256; //不赋值时默认其值是0 TL0=(65536-tt)%256;t++;}。
51单片机程序烧录教程
目录•引言•51单片机基础知识•程序烧录工具及准备•程序烧录步骤详解•程序烧录常见问题及解决方法•实例演示与操作实践引言目的和背景介绍51单片机的程序烧录方法和步骤提供详细的教程和指导,帮助读者更好地掌握51单片机的程序烧录技能教程内容概述0151单片机简介和基础知识02程序烧录前的准备工作03程序烧录步骤和注意事项04常见问题和解决方法51单片机基础知识51单片机简介•51单片机是对所有兼容Intel 8051指令系统的单片机的统称。
该系列单片机的始祖是Intel的8051单片机,后来随着Flashrom技术的发展,8051单片机取得了长足的进展,成为应用最广泛的8位单片机之一,其代表型号是ATMEL公司的AT89系列,它广泛应用于工业测控系统之中。
很多公司都有51系列的兼容机型推出,今后很长的一段时间内将占有大量市场。
0102 03中央处理器(CPU)由运算和控制逻辑组成,同时还包括中断系统和部分外部特殊功能寄存器;RAM用以存放可以读写的数据,如运算的中间结果、最终结果以及欲显示的数据;ROM用以存放程序、一些原始数据和表格;1 2 3四个8位并行I/O口,既可用作输入,也可用作输出;I/O口两个16位定时器/计数器,可对机器周期计数,也可对外部输入脉冲计数;定时器/计数器(ROM)可响应三个内部中断源和两个外部中断源的中断请求;中断系统串行口一个全双工串行通信口,用于实现单片机和其他设备之间的串行数据传送;特殊功能寄存器(SFR)21个特殊功能寄存器,用于存放相应功能部件的控制/状态字,以实现对单片机的各功能部件进行管理、控制、监视。
主电源引脚(2根)VCC(Pin40):电源输入,接+5V电源。
GND(Pin20):接地线。
XTAL1(Pin19)和XTAL2(Pin20)。
外接一个振荡器(包括外部晶振),形成振荡电路。
RST/VPD(Pin9):复位引脚。
ALE/PROG(Pin30):地址锁存允许信号。
51单片机循迹小车程序
/*功能:寻迹小车使用芯片:AT89S52 或者STC89C52 或AT89S51 STC89C51晶振:12MHZ编译环境:Keil作者:MH~*/#include <reg51.h> // 引用标准库的头文件#include <intrins.h>#define uchar unsigned char#define uint unsigned int//=================电机驱动=====================sbit dianji_r = P3^0; //右边电机控制口,低电平转?sbit dianji_l = P3^7; //左边电机控制口,低电平转//=============循迹感应接口======================sbit xjmk_r = P3^2;// 右边寻迹模块检测口INT0sbit xjmk_l = P3^3;// 左边寻迹模块检测口INT1void check_righet();//右边时候检测到黑线测试程序void check_left();//左边时候检测到黑线测试程序void delay_50us(uint t);void delayms(uint Ms);uchar r_count;//右边传感器检测到的次数计数单元uchar l_count;uint time;//***********************主程序****************************** main(){time=50;dianji_r=0;//上电时右侧电机运行dianji_l=0;//上电时左侧电机运行EA=1;EX1=1;EX0=1;IT1=0;IT0=0;xjmk_r=1;//置IO为1,准备读取数据xjmk_l=1;_nop_();r_count=0;l_count=0;while(1){_nop_();// check_righet();//调用右边寻迹检测传感器// check_left();//if(r_count>=1){delayms(time);dianji_r=0;dianji_l=0;r_count=0;_nop_();}if(l_count>=1){delayms(time);dianji_r=0;dianji_l=0;l_count=0;_nop_();}}}void init0int() interrupt 2{l_count=5;dianji_l=1;dianji_r=0;if(r_count>0){ EX0=0;delayms(20);if(time>=20)time-=19;EX0=0;}return;}void init1int() interrupt 0{r_count=5;dianji_r=1;dianji_l=0;if(l_count>0){ EX1=0;delayms(20);if(time>=20)time-=19;EX1=1;}return;}//***************************************************************************** **//函数名称://功能:左边边时候检测到黑线测试程序void check_left(){if(xjmk_l==0)//检测右边的传感器是否感应到黑线{delay_50us(1);//延时,去除机械振动_nop_();if(xjmk_l==0)//再次检测{delay_50us(1);//延时,去除机械振动if(xjmk_l==0){l_count++;xjmk_l=1;}}}}//***************************************************************************** **//函数名称://功能:右边时候检测到黑线测试程序void check_righet(){if(xjmk_r==0)//检测右边的传感器是否感应到黑线{delay_50us(1);//延时,去除机械振动if(xjmk_r==0)//再次检测{delay_50us(1);//延时,去除机械振动if(xjmk_r==0){r_count++;xjmk_r=1;}}}}//***************************************************************************** **//函数名称:void delay_50US(unsigned int t)//功能:延时50*t(us)void delay_50us(uint t){uchar j;for(;t>0;t--){for(j=19;j>0;j--);}}/*====================================================================设定延时时间:x*1ms====================================================================*/ void delayms(uint Ms){uint i,TempCyc;for(i=0;i<Ms;i++){TempCyc =70;while(TempCyc--);}}。
51单片机内部定时器和中断系统以及编写第一个简单的定时器实验程序
51单片机内部定时器和中断系统以及编写第一个简单的定时器实验程序上讲通过讲述用单片机控制一个外部的LED闪烁实验来向读者介绍了单片机的工作原理与开发流程。
这一讲将介绍单片机内部非常重要的两个资源——定时/ 计数器和中断系统。
通过该讲,读者可以掌握定时器的工作原理和单片机的中断系统。
从而设计定时器计数程序和中断服务程序。
一、原理简介首先让我们举闹钟为例,将它定时在一分钟后闹铃,这就需要秒针走一圈(60 次)。
即一分钟时间转化为秒针走的次数,也就是计数的次数,计数到了60 次然后闹铃,而每一次计数的时间是1 秒。
单片机内部的定时/ 计数器跟闹钟类似,可以通过编程来设定要定时的时间、定时时间到了进行相应的操作。
那么在单片机内部计数一次的时间是多少呢,51 单片机输入的时钟脉冲是由晶体振荡器的输出经12 分频后得到的,所以定时器也可看作是对计算机机器周期的计数器。
因为每个机器周期包含12 个振荡周期,故每一个机器周期定时器加1,可以把输入的时钟脉冲看成机器周期信号。
故其频率为晶振频率的1/12。
如果晶振频率为12MHz,则定时器每接收一个输入脉冲的时间刚好为1μs。
在本实验套件中采用的是11.0592M 的晶振,故每接收一个输入脉冲的时间约为1.085μs。
实现精确定时在实际项目应用中非常重要,因为往往需要用到精确定时一段时间,然后定时时间到的时刻做相应的任务。
那如何编程实现定时时间呢?首先先简单介绍下本实验板上单片机(STC89C52)内的定时器资源。
STC89C52 内有三个定时/ 计数器,分别为T0、T1 和T2。
其中T0、T1 工作方式一样,一并介绍。
T2 的工作方式稍有区别,这里不做介绍,实验套件光盘中有实际应用程序。
同时,单片机中的定时器和计数器是复用的,计数器是记录外部脉冲的个数,而定时器则是由单片机内部时钟提供的一个非常稳定的计数源。
本讲中,以T0、T1 作为定时器来进行实例介绍使用。
常见51单片机指令及详解
常见51单片机指令及详解数据传递类指令(1)以累加器为目的操作数的指令MOV A,RnMOV A,directMOV A,@RiMOV A,#data第一条指令中,Rn代表的是R0-R7。
第二条指令中,direct就是指的直接地址,而第三条指令中,就是我们刚才讲过的。
第四条指令是将立即数data送到A中。
下面我们通过一些例子加以说明:MOV A,R1 ;将工作寄存器R1中的值送入A,R1中的值保持不变。
MOV A,30H ;将内存30H单元中的值送入A,30H单元中的值保持不变。
MOV A,@R1 ;先看R1中是什么值,把这个值作为地址,并将这个地址单元中的值送入A中。
如执行命令前R1中的值为20H,则是将20H单元中的值送入A中。
MOV A,#34H ;将立即数34H送入A中,执行完本条指令后,A中的值是34H。
(2)以寄存器Rn为目的操作的指令MOV Rn,AMOV Rn,directMOV Rn,#data这组指令功能是把源地址单元中的内容送入工作寄存器,源操作数不变。
(3)以直接地址为目的操作数的指令MOV direct,A 例: MOV 20H,AMOV direct,Rn MOV 20H,R1MOV direct1,direct2 MOV 20H,30HMOV direct,@Ri MOV 20H,@R1MOV direct,#data MOV 20H,#34H(4)以间接地址为目的操作数的指令MOV @Ri,A 例:MOV @R0,AMOV @Ri,direct MOV @R1,20HMOV @Ri,#data MOV @R0,#34H(5)十六位数的传递指令MOV DPTR,#data168051是一种8位机,这是唯一的一条16位立即数传递指令,其功能是将一个16位的立即数送入DPTR中去。
其中高8位送入DPH,低8位送入DPL。
例:MOV DPTR,#1234H,则执行完了之后DPH中的值为12H,DPL中的值为34H。
51单片机的工作原理
51单片机的工作原理
首先,我们来介绍51单片机的内部结构。
51单片机包括CPU、存储器、输入输出端口、定时器/计数器、串行通信接口等部分。
其中,CPU是单片机的核心部分,负责执行指令和控制整个系统的运行。
存储器用于存储程序和数据,输入输出端口用于与外部设备进行数据交换,定时器/计数器用于定时和计数,串行通信接口用于与其他设备进行数据通信。
这些部分共同组成了51单片机的内部结构,实现了对外部设备的控制和数据处理。
其次,我们来介绍51单片机的工作过程。
在51单片机工作时,首先需要加载程序到存储器中,然后CPU按照程序的指令逐步执行,控制各个部分的工作。
当需要与外部设备进行数据交换时,CPU通过输入输出端口与外部设备进行通信,实现数据的输入和输出。
同时,定时器/计数器可以提供精确的定时和计数功能,串行通信接口可以实现与其他设备的数据通信。
通过这些部分的协同工作,51单片机可以实现对外部设备的精确控制和数据处理。
最后,我们来介绍51单片机的应用场景。
由于其小巧、低功耗、功能强大等特点,51单片机被广泛应用于各种电子设备中,如家电控制、工业自动化、汽车电子、通信设备等领域。
在这些应用场景中,51单片机可以实现对各种外部设备的精确控制和数据处理,发挥着重要的作用。
综上所述,51单片机是一种常见的微控制器,其工作原理是通过内部的逻辑电路和控制器实现对外部设备的控制和数据处理。
通过对其内部结构、工作过程和应用场景的介绍,我们可以更加深入地了解51单片机的工作原理,为其在实际应用中的使用提供更多的参考和指导。
51单片机PID算法程序
51单片机PID算法程序(二)位置式PID控制算法由51单片机组成的数字控制系统控制中,PID控制器是通过PID控制算法实现的。
51单片机通过AD对信号进行采集,变成数字信号,再在单片机中通过算法实现PID运算,再通过DA把控制量反馈回控制源。
从而实现对系统的伺服控制。
位置式PID控制算法位置式PID控制算法的简化示意图? 上图的传递函数为:(2-1)?? 在时域的传递函数表达式(2-2)?? 对上式中的微分和积分进行近似(2-3)?? 式中n是离散点的个数。
?? 于是传递函数可以简化为:(2-4)其中u(n)——第k个采样时刻的控制;K P? ——比例放大系数;???K i?? ——积分放大系数;K d?? ——微分放大系数;T?? ——采样周期。
如果采样周期足够小,则(2-4)的近似计算可以获得足够精确的结果,离散控制过程与连续过程十分接近。
(2-4)表示的控制算法直接按(2-1)所给出的PID控制规律定义进行计算的,所以它给出了全部控制量的大小,因此被称为全量式或位置式PID控制算法。
缺点:1)??????????? 由于全量输出,所以每次输出均与过去状态有关,计算时要对e(k)(k=0,1,…n)进行累加,工作量大。
2)??????????? 因为计算机输出的u(n)对应的是执行机构的实际位置,如果计算机出现故障,输出u(n)将大幅度变化,会引起执行机构的大幅度变化,有可能因此造成严重的生产事故,这在实际生产中是不允许的。
位置式PID控制算法C51程序具体的PID参数必须由具体对象通过实验确定。
由于单片机的处理速度和ram资源的限制,一般不采用浮点数运算,而将所有参数全部用整数,运算到最后再除以一个2的N次方数据(相当于移位),作类似定点数运算,可大大提高运算速度,根据控制精度的不同要求,当精度要求很高时,注意保留移位引起的“余数”,做好余数补偿。
这个程序只是一般常用pid算法的基本架构,没有包含输入输出处理部分。
51单片机实验程序
用查表方式编写y=x13+x23+x33。
(x为0~9的整数)#include<reg51。
h>void main(){int code a[10]={0,1,8,27,64,125,216,343,512,729};//将0~9对应的每位数字的三次方的值存入code中,code为程序存储器,当所存的值在0~255或-128~+127之间的话就用char,而现在的值明显超过这个范围,用int较合适.int的范围是0~65535或-32768~32767。
int y,x1,x2,x3;//此处定义根据习惯,也可写成char x1,x2,x3但是变量y一定要用int 来定义。
x1=2;x2=4;x3=9;//x1,x2,x3三个的值是自定的,只要是0~9当中的数值皆可,也可重复.y=a[x1]+a[x2]+a[x3];while(1);//单片机的程序不能停,这步就相当于无限循环的指令,循环的内容为空白。
}//结果的查询在Keilvision软件内部,在仿真界面点击右下角(一般初始位置是右下角)的watch的框架内双击“double-click or F2 to add”文字输入y后按回车,右侧会显示其16进制数值如0x34,鼠标右键该十六进制,选择第一行的decimal,可查看对应的10进制数。
1、有10个8位二进制数据,要求对这些数据进行奇偶校验,凡是满足偶校验的数据(1的个数为偶数)都要存到内RAM50H开始的数据区中。
试编写有关程序。
#include〈reg51。
h>void main(){int a[10]={0,1,5,20,24,54,64,88,101,105};//将所要处理的值存入RAM中,这些可以根据个人随意设定,但建议不要超过0~255的范围.char i; //定义一个变量char *q=0x50;//定义一个指针*q指向内部0x50这个地址。
for(i=9;i〉=0;i--)//9~0循环,共十次,也可以用for(i=0;i〈10;i++){ACC=a[i];//将a[i]的值赋给累加器ACCif (P==0)//PSW0位上的奇偶校验位,如果累加器ACC内数值1的个数为偶数那么P为0,若为奇数,P为1。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 程序计数器的内容(这时是0000H)送到地址寄存器;
2 程序计数器的内容自动加1(变为0001H);
3 地址寄存器的内容(0000H)通过内部地址总线送到存储器,以存储器中地址译码电跟,使地址为0000H的单元被选中;
4 CPU使读控制线有效; 5 在读命令控制下被选中存储器单元的内容(此时应为74H)送到内部数据总线上,因为是取指阶段,所以该内容通过
程一直重复下去,直至收到暂停指令或循环等待指令暂停。CPU就是这样一条一条地执行指令,完成所有规定的功能。
过程实际上就是取出指令(取 出存储器中事先存放的指令阶段)和执行指令(分析和执行指令)的循环过程。 例如执行指令:MOV A,#0E0H,
其机器码为“74H E0H”,001H单元中已存放E0H。当单片机开始运行时,
单片机程序执行的过程 很遗憾,学习单片机这么长时间,才第一次认真看过单片机程序执行的过程。
下面是一段51单片机程序的执行过程:
51单片机程序执行的过程
单片机执行程序的过程,实际上就是执行我们所编制程序的过程。即逐条指令的过程。计算机每执行一条指令都可分为三个阶段进行。即取指
令-----分析指令-----执行指令。
部设备把程序和数据通过输入接口电路和数据总线送入到存储器,然后逐条取出执行。但单片机中的程序一般事先我们都已通过写入器固化在
片内或片外程序存储器中。因而一开机即可执行指令。
下面我们将举个实例来说明指令的执行过程: 开机时,程序计算器PC变为0000H。然后单片机在时序电路作用下自动进入执行程序过程。执行
CPU,即还要在存储器中取第二个字节。其过程与取指阶段很相似,只是此时PC已为0001H。指令译码器结合时序部件,产生74H操作码的微操作
系列,使数字E0H从0001H单元取出。因为指令是要求把取得的数送到A累加器,所以取出的数字经内部数据总线进入A累加器,而不是进入指令
寄存器。至此,一条指令的执行完毕。单片机中PC=0002H,PC在CPU每次向存储器取指或取数时自动加1,单片机又进入下一取指阶段。这一过
取指令的任务是:根据程序计数器PC中的值从程序存储器读出现行指令,送到指令寄存器。
分析指令阶段的任务是:将指令寄存器中的指令操作码取出后进行译码,分析其指令性质。如指令要求操作数,则寻找操作数地址。
计算机执行程序的过程实际上就是逐条指令地重复上述操作过程,直至遇到停机指令可循环等待指令。 一般计算机进行工作时,首先要通过外
数据总线被送到指令寄存器。
至此,取指阶段完成,进入译码分析和执行指令阶段。 由于本次进入指令寄存器中的内容是74H(操作码),以译码器译码后单片机就会
知道该指令是要将一个数送到A累加器,而该数是在这个代码的下一个存储单元。所以,执行该指令还必须把数据(E0H)从存储器中取出送到