C51 汇编和C语言编写从1加到100 | 您所在的位置:网站首页 › c51单片机sp是什么 › C51 汇编和C语言编写从1加到100 |
编写第一个程序
创建项目的方式:
创建一个项目:Project - New μVision Project... 以新建项目 创建项目文件夹:在目录下创建一个文件夹,它将容纳将来所有的项目 (注意:所有路径均不能包含中文字符,下同) 创建项目文件夹:为你的项目取一个名字,打开文件夹 创建项目解决方案:该文件名可以和外面的一样,然后点击保存。 为你的项目选择设备:如果你选择STM32F10x系列,就在software里找,如果是单片机,需要下拉列表找到Legacy Device Database[no RTE],然后搜索51,找到AT89C51芯片,点击ok。 然后会弹出选项框:问我们是否拷贝51单片机的启动文件到当前项目目录中并把它添加到项目里。这个文件是c语言的启动文件,帮助程序找到main函数并执行的。简而言之如下: 如果用汇编编写51程序,就不需要拷贝,点【否】 如果用C语言编写51程序,就需要拷贝,点【是】 【启动文件详解传送门】C51启动文件详解_wang0901的专栏-CSDN博客 点【是】则会发现多一个启动文件,打开是这个样子的: 创建代码文件:之后打开目录层次,我们右键source group 添加一个项,选择C文件或者asm文件(取决于你想用什么语言,因为刚才选了否,我们选择asm文件),然后起一个名字,点击Add。 然后就可以愉快地编写程序了! 编写1加到100的汇编程序首先分析,1+2+···+100结果是5050,大于255,因此8位不够,16位才够,需要进行16位加法add16子程序的编写:低位和低位半加,高位和高位全加。子程序需要确定传参方式,这里选择比较简单的寄存器传参;无论如何子程序调用和释放至少需要压入PC的值,是需要堆栈的设置SP为60H。 由于是第一个程序,我们对代码进行详细分析: (1)声明变量(也有说法说这不是变量,这里就当作起个名字) HB EQU 30H;代表和的高8位 LB EQU 31H;代表和的低8位 LP EQU 32H;代表加数,因为一直加到100,即64H,因此8位够表示 Q1:为什么从30H开始,30H有什么讲究吗? A1:因为30H以下不属于用户RAM区。C51片内数据存储器的组成如下: 30H~7FH 用户RAM区(堆栈、数据缓冲区) 20H~2FH 可位寻址区 00H~1FH 平均分配有4组工作寄存器区 Q2:为什么EQU没有运行? A2:EQU是汇编伪指令,不生成机器码。 (2)初始化操作 ORG 0;标记下一条指令在0000H JMP MAIN;由于上电复位后的程序入口地址0000H,因此执行指令,并跳转到Main ORG 30H;标记下一条指令在0030H,为了跳过中断向量表区域. MAIN: .................... Q1:ORG是不是执行不到?JMP MAIN都跳走了,还怎么执行? A1:ORG本来就是伪指令,是标记下一指令存在ROM中什么位置的,根本就不生成机器码,也不会被执行到。 Q2:为何在之前要标记为00H? A2:00H是上电复位后的程序入口地址,标记下一条为执行的第一条指令。(不写也不会报错,因为系统自动从0开始,属于是规范。) Q3:为何又标记为30H?这个30H和上面的30H是一个意思吗? A3:赋值30H是因为ROM中00H~30H有如下中断向量表,不应覆盖(不同于之前的RAM): 外部中断00003H定时器/计数器T0000BH外部中断10013H定时器/计数器T1001BH串行口0023H(3)子程序的书写 ORG 0060H ADD16: CLR C;先清除进位标志 MOV A,R4 ADD A,R6 MOV R6,A;低位加法,加完存在R6中 MOV A,R5 ADDC A,R7 MOV R7,A;高位加法,加完存在R7中 RET END 首先标记为60H的程序地址(这个应该是估测,实际主函数只写到了0x52)。先做低位加法,再做高位带进位加法。 (4)主程序的书写: ORG 30H;跳过中断向量表区域 MAIN: MOV A,#60H MOV SP,A;入栈操作后sp-2,出栈操作后sp+2。mov sp,#60H 的意思是设置堆栈的长度为60H byte CLR A MOV HB,A;给HB赋个0 INC A MOV LB,A;给LB赋个1 MOV LP,#2;给LP赋个2 LOOP: MOV R7,HB;加数高八位 MOV R6,LB;加数低八位 MOV R5,#0;由于16位加法,加和上限为100,故高八位为0 MOV R4,LP;加数,代表1,2,3,...,100 CALL ADD16;调用子程序 MOV HB,R7 MOV LB,R6;R6,R7写回内存 INC LP;加数加一 MOV R0,LP;将LP放入寄存器 CJNE R0,#101,LOOP;进行寄存器比较 JMP $;陷入死循环,启动中断服务程序,程序终止 设置栈顶位置为60H,这个是因为元素入栈操作后sp-2,出栈操作后sp+2,低地址存放着栈顶元素,而高地址存放着栈底元素造成的,60H即申请了一块比较大的堆栈空间。 中间给几个寄存器赋值没什么好说的,存入操作数。LOOP前4句是给寄存器赋值,相当于子程序的寄存器传参。 CALL是调用子程序的关键字,这个子程序无论写在该文件的哪里都能被访问到。 做完加法写回内存,将内存中LP(又是加数,又是自增的变量,相当于for循环中的i),与101立即数比较,CJNE,如果不为101则转LOOP(相当于80x86中的JNE) JMP $中,jump表示跳转,$表示当前程序指针的位置。跳转到当前程序指针的位置什么意思?该指令会反复执行JMP $,直到启动中断服务程序。因此也就结束了这个程序的运行。 综上所述,代码如下: ;00H~1FH依次排列4个工作寄存器区 ;20H~2FH存放着可位寻址区 ;用户RAM区从30H开始到7FH,因此从30H存数据。 HB EQU 30H;代表和的高8位 LB EQU 31H;代表和的低8位 LP EQU 32H;代表加数,因为一直加到100,即64H,因此8位够表示 ORG 0;上电复位后的程序入口地址0000H JMP MAIN;跳转到Main ORG 30H;跳过中断向量表区域 MAIN: MOV A,#60H MOV SP,A;入栈操作后sp-2,出栈操作后sp+2。mov sp,#60H 的意思是设置堆栈的长度为60H byte CLR A MOV HB,A;给HB赋个0 INC A MOV LB,A;给LB赋个1 MOV LP,#2;给LP赋个2 LOOP: MOV R7,HB;加数高八位 MOV R6,LB;加数低八位 MOV R5,#0;由于16位加法,加和上限为100,故高八位为0 MOV R4,LP;加数,代表1,2,3,...,100 CALL ADD16;调用子程序 MOV HB,R7 MOV LB,R6;R6,R7写回内存 INC LP;加数加一 MOV R0,LP;将LP放入寄存器 CJNE R0,#101,LOOP;进行寄存器比较 JMP $;陷入死循环,启动中断服务程序,程序终止 ORG 0060H ADD16: CLR C;先清除进位标志 MOV A,R4 ADD A,R6 MOV R6,A;低位加法,加完存在R6中 MOV A,R5 ADDC A,R7 MOV R7,A;高位加法,加完存在R7中 RET END 编写1加到100的C语言程序前面步骤差不多,除了拷贝51单片机的启动文件和创建C文件以外,没有什么区别。 #include #include #define OSC 11059200 #define BAUD 9600 void main(void){ int i; int result; SCON=0x50; TMOD=0x20; TH1=TL1=256-(OSC/12/16/BAUD); TR1=1; TI=1; for(i=0;i |
CopyRight 2018-2019 实验室设备网 版权所有 |