c51嵌汇编.
- 格式:doc
- 大小:32.50 KB
- 文档页数:8
KEIL C51 中C语言加入汇编语言的使用方法
51单片机2008-06-03 18:20:42 阅读22 评论0字号:大中小
1.通过使用预处理指令#asm 和#endasm来使用汇编语言。
用户编写的汇编语言可以紧跟在#asm之后,而在#endasm之前结束。
如下所示:
#asm
/*汇编源程序*/
#endasm
在#asm和#endasm之间的语句将作为汇编语言的语句输出到由编译器产生的汇编语言文件中。
2.通过使用预处理指令# pragma asm和函数_asm()来使用汇编语言。
在程序的开头加上预处理指令#pragma asm,在该预处理指令之前只能有注释和其它预处理指令。
_asm()函数可按以下方式使用。
_asm(汇编语言字符串)
在汇编语言字符串中,可以通过回车和换行符把各个语句分开。
在C语言中使用汇编语言,可以操作C语言中的全局变量或完成用C语言难于完成的功能,但要注意以下几点:
①#asm不允许嵌套使用。
②当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件。
③ _asm只能用小写字母,如果写成大写,就作为普通变量。
④#asm#endasm和_asm只能用在函数内。
转载请注明出处谢谢
Keil C51中嵌入汇编
我们知道,用C语言实现精确延时是一件比较困难的事情,而用汇编写精确延时程序就简单多了,但是整个程序都用汇编,那就是件头疼的事情。
要是能在C里面嵌入汇编,那就爽了,本文介绍的就是如何在Keil C51里嵌入汇编。
1、在C 文件中以如下方式加入汇编代码:
#pragma ASM
; Assembler Code Here
#pragma ENDASM
例如:
//延时1ms程序晶振:11.0592MHZ
void delay_1ms(void)
{
#pragma asm
DELAY1MS: MOV R7,#50
DD: MOV R6,#10
D2: DJNZ R6,$
DJNZ R7,DD
#pragma endasm
}
2、在Project 窗口中包含汇编代码的C 文件上右键,选择“Options for ...”,点击右
边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色
(有
效)状态。
如图所示。
3、根据选择的编译模式,把相应的库文件(如Small 模式时,是Keil\C51\Lib\C51S.Lib)加入工程中, 该文件必须作为工程的最后文件。
4、编译,即可生成目标代码。
单片机c51汇编语言51单片机汇编语言单片机C51汇编语言单片机(C51)是指一种集成电路上只包含一个集中式控制器的微处理器,具有完整的CPU指令集、RAM、ROM、I/O接口等功能。
汇编语言是一种低级语言,是用于编写单片机指令的一种语言。
汇编语言能够直接操作单片机的寄存器和输入/输出端口,因此在嵌入式系统的开发中非常重要。
本文将介绍单片机C51的汇编语言编程。
一、了解单片机C51单片机C51是目前应用最广泛的一种单片机系列,广泛用于各种电子设备和嵌入式系统的开发。
C51指的是Intel公司推出的一种基于MCS-51架构的单片机。
该系列单片机具有较高的性能和低功耗的特点,可用于各种控制和通信应用。
二、汇编语言的基本概念汇编语言是一种低级语言,与机器语言紧密相关。
它使用助记符来代替机器指令的二进制表示,使程序的编写更加易读。
在单片机C51汇编语言中,每一条汇编指令都对应着特定的机器指令,可以直接在单片机上执行。
三、汇编语言的基本指令在单片机C51汇编语言中,有一些基本的指令用于控制程序的执行和操作寄存器。
以下是一些常用的指令:1. MOV指令:用于将数据从一个寄存器或内存单元复制到另一个寄存器或内存单元。
2. ADD指令:用于将两个操作数相加,并将结果存储到目的寄存器中。
3. SUB指令:用于将第一个操作数减去第二个操作数,并将结果存储到目的寄存器中。
4. JMP指令:用于无条件跳转到指定的地址。
5. JZ指令:用于在条件为零时跳转到指定的地址。
6. DJNZ指令:用于将指定寄存器的值减一,并根据结果进行跳转。
四、编写单片机C51汇编程序的步骤编写单片机C51汇编程序需要按照以下步骤进行:1. 确定程序的功能和目标。
2. 分析程序的控制流程和数据流程。
3. 设计算法和数据结构。
4. 编写汇编指令,实现程序的功能。
5. 调试程序,并进行测试。
六、实例演示以下是一个简单的单片机C51汇编程序的示例,用于实现两个数的相加,并将结果输出到LED灯上:org 0H ; 程序的起始地址为0mov a, 05H ; 将05H赋值给累加器mov b, 07H ; 将07H赋值给B寄存器add a, b ; 将A寄存器和B寄存器的值相加mov P1, a ; 将相加结果输出到P1口end ; 程序结束在这个例子中,首先将05H赋值给累加器A,然后将07H赋值给B寄存器,接着使用ADD指令将A和B的值相加,将结果存储到累加器A中,最后将累加器A的值输出到P1口。
第一个闪烁的灯:(P2口接LED,P2输出低时LED点亮)/**************************************************** /ORG 0000H ;ORG伪指令,定义程序起始地址AJMP START ;跳转到真正的程序起始地址ORG 0040H ;定义START地址START: SETB P2.0 ;设置P2口第一位为高,则LED灭(本开发板LED接低电平亮) LCALL DELAY;调用延时程序CLR P2.0 ;清除P20端口,则LED亮LCALL DELAY ;调用延时程序AJMP START ;返回开始处继续执行之前的步骤DELAY: MOV R7,#250 ;延时的外循环数放在R7D1: MOV R6,#250 ;内循环数放在R6内D2: DJNZ R6,D2 ;R6内数据自减,直至为0则继续执行下一行代码DJNZ R7,D1 ;R7内数据自减,直至为0则继续执行下一行代码RET ;返回指令END ;伪代码,告诉编译器程序到此结束/**********************************************************/#include <reg51.h> //包含51系列单片机标准头文件sbit P20=P2^0; //定义P20为一个bit寄存器(sbit定义一个位寄存器的关键字)void delay(int k); //声明delay函数,有形参int kvoid main() //主函数开始{while (1) //死循环,即程序一直运行这里面的命令{P20=1; //P20为高,LED灭=SETB P20delay(300); //延时P20=0; //P20为低,LED亮=CLR P20delay(300); //延时}}void delay(int k) //延时函数{unsigned char i; //定义i为无符号字符型,最大255for( ;k>0;k--) //外循环{for(i=250;i>0;i--); //内循环}}第一个简单的LED流水灯:(P2口接LED,P2输出低时LED点亮)************************************************************************** ORG 0000H ;ORG伪指令,定义程序起始地址AJMP START ;跳转到真正的程序起始地址ORG 0040H ;定义START地址START: MOV A,#0FEH ;将寄存器A赋值FEH,即1111 1110MOV P2,A ;将A赋值给P2端口,即P2=1111 1110,最低位LED亮LCALL DELAY ;延时LOOP: RL A ;将A循环左移,即A=1111 1101MOV P2,A ;再将A赋值给P2,则当前P2=1111 1101,第二个LED亮LCALL DELAY ;延时CJNE A,#7FH,LOOP ;A=7FH=0111 1111,则结束循环,否则跳转到LOOP处执行AJMP START ;如果A=7FH了,则跳转到START处重新开始执行DELAY: MOV R7,#250 ;延时的外循环数放在R7D1: MOV R6,#250 ;内循环数放在R6内D2: DJNZ R6,D2 ;R6内数据自减,直至为0则继续执行下一行代码DJNZ R7,D1 ;R7内数据自减,直至为0则继续执行下一行代码RET ;返回指令END ;伪代码,告诉编译器程序到此结束************************************************************************** #include <reg51.h> //包含头文件#define LED P2 //宏定义LED,即编译时程序出现LED处均用P2来代替void delay(int k); //声明delay函数,有形参int kchar code tab[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//定义tab为代码型数组void main(void) //主函数开始{ int a; //定义a为变量LED=0xfe; delay(300);//P2=0xfe=1111 1110,最低位LED亮while(1) //循环体{for(a=1;a<8;a++) //8次循环体{LED=tab[a]; delay(300);//将数组内数据赋值给P2=tab[1]=0xfd=1111 1101}//for结束for(a=6;a>=0;a--) //7次循环体,为什么a=6???{LED=tab[a]; delay(300);//同上一个循环} //for结束} //while结束} //main结束void delay(int k) //延时函数{unsigned char i; //定义i为无符号字符型,最大255for( ;k>0;k--) //外循环{for(i=250;i>0;i--); //内循环}}一个按键控制流水灯(P1口接8接独立按键,按键按下拉低;P2口接LED,P2输出低LED点亮)************************************************************************** ORG 0000HAJMP STARTORG 0030HSTART: MOV P1,#0FFH; ;将P1写入1JB P1.0,$ ;等待P10=0,即P10被按下接地,我们的P1接了上拉电阻LCALL DELAY ;如果被按下了,延时125*200us,去除抖动JB P1.0,START ;再次判断是否被按下,是则顺序执行,否则跳转到STARTMOV A,#0FEH ;将寄存器A赋值FEH,即1111 1110MOV P2,A ;将A赋值给P2端口,即P2=1111 1110,最低位LED亮LCALL DELAY ;延时LOOP: RL A ;将A循环左移,即A=1111 1101MOV P2,A ;再将A赋值给P2,则当前P2=1111 1101,第二个LED亮LCALL DELAY ;延时CJNE A,#7FH, LOOP;当A=7FH是,LED已经循环完成1次AJMP START ;跳转到起始位置,接着等待按键DELAY: MOV R7,#250D1: MOV R6,#250D2: DJNZ R6,D2DJNZ R7,D1RETEND**************************************************************************#include <reg51.h>char code tab[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};sbit P10=P1^0; sbit P11=P1^1;void delay(int k);void main(){ char a; P2=0xfe;while(1) //等待P10被按下,则执行流水等程序,详见上节{ P1=0xff;delay(2000); //延时20ms左右去除抖动if(P10==0) //按下P10执行流水灯{ for(a=0;a<8;a++){ P2=tab[a];delay(60000);}}if(P11==0) //按下P11执行反向流水灯{ for(a=7;a>=0;a--){ P2=tab[a];delay(60000);}} }}void delay(int k) //最简单的C延时程序{ while(k--); } //直至K减为0则跳出利用中断方式实现一个灯的闪烁(P2口接LED阴极,LED阳极经过400欧电阻接VCC)************************************************************************** ORG 0000hAJMP STARTORG 000BH ;T0中断入口地址AJMP TIME0 ;跳转到真正的中断程序处START: CLR P2.0 ;取反p20,点亮最低位LEDMOV 30H,#0 ;30H地址置数,用于计算中断次数MOV TMOD,#00000001B ;设置定时器0,使用方式1,定时20msMOV TH0,#0B1H ;计数器初始值高8位MOV TL0,#0E0H ;计数器初始值低8位SETB EA ;开总中断允许位SETB ET0 ;开启T0定时器SETB TR0 ;开启T0定时器中断允许位AJMP $ ;死循环,等待中断产生TIME0: PUSH ACC ;进入中断首先将ACC\PSW压栈PUSH PSW ;然后重装计数器初始值MOV TH0,#0B1H ;计数器初始值高8位MOV TL0,#0E0H ;计数器初始值低8位INC 30H ;将30H内数据加1MOV A,30H ;然后判断是否计数到25次(即0.5秒)?CJNE A,#25,TIME01 ;未到25次,则跳转到TIME01处执行出栈操作CPL P2.0 ;到了25次,则取反P20端口MOV 30H,#0 ;同时将30H单元内数据清零TIME01: POP PSW ;出栈POP ACC ;出栈RETI ;中断返回用RETIEND ;伪指令,结束程序********************************************************************#include<reg51.h>sbit P20=P2^0;volatile int i; //声明一个变量为可能意外变化的量(相对于const而言)用语中断程序void main(){ P20=0; //先将P20位的LED点亮TMOD=0x01; //设置定时器T0工作在模式1TH0=0xb1; TL0=0xe0; //装T0的计数初值,12MHz,20ms计时EA=1; //开启总中断允许位ET0=1; //开启T0定时器TR0=1; //开启T0定时器中断允许位while(1); //循环等待中断发生}void time0(void) interrupt 1 //中断程序写法{ TH0=0xb1; TL0=0xe0; //重装T0的计数初值i++; if(i==25) //计数到25次(即0.5秒)??{i=0; //i清零P20=~P20;//取反LED端口,}}一个数码管循环显示0—F(P2口接数码管段码,P00接数码管阴极)**************************************************************************ORG 0000HAJMP STARTORG 0030HSTART: MOV 30H,#00H ;要显示的内容,写入30H单元内MAIN: MOV R5,#50 ;设置显示次数,越大时间越长main1: MOV A,30H ;将显示的数据送入A寄存器MOV DPTR,#TAB ;将TAB的地址送入DPTR寻址MOVC A,@A+DPTR ;将TAB+A处地址内的数据读出来送入A寄存器SETB P0.0 ;关闭数码管公共端,关闭显示,是为了去除显示重影MOV P2,A ;将这个数据写入P2段码端口CLR P0.0 ;打开显示LCALL DELAY ;调用延时程序DJNZ R5,main1 ;一共显示R5次INC 30H ;将30H内数据加1MOV A,30H ;将30H内数据送入寄存器A,继续上面的步骤CJNE A,#10H,MAIN ;判断是否到达16,是则运行下一行程序,否则跳转到MAIN AJMP START ;TAB为数码管显示段码值TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71HDELAY: MOV R7,#50D1: MOV R6,#250D2: DJNZ R6,D2DJNZ R7,D1RETEND**************************************************************************#include <reg51.h>#define SEG P2sbit P00=P0^0; //Tab为数码管显示值,存入一个数组内unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};void delay(int k); //延时函数,每次都会用到void main(){ int i;while(1){ for(i=0;i<16;i++) //循环16次,显示0-9,A,B,C,D,E,F一共16个数{P00=1; //将LED公共端置高,关闭显示,目的是为了去除显示重影SEG=Tab[i]; //将段码送到P2口,输出到LED段码端P00=0; //打开显示delay(50000);delay(50000); //延时,使人能看清楚}}}void delay(int k) //最简单的C延时程序{ while(k--); } //直至K减为0则跳出两个数码管循环显示00—99(P2口接数码管段码,P00接数码管各位阴极,P01接十位)************************************************************************** ORG 0000HLJMP STARTORG 0040HSTART: MOV 30H,#00H ;30H单元内放低位数据MOV 31H,#00H ;31H单元内放高位数据MOV P2,#00H ;将P2初始化为0CLR P0.1 ;设置低位显示0CLR P0.0 ;设置高位显示0LCALL DELY1 ;调用延时程序MAIN: MOV R5,#50 ;设置重复显示次数,越大显示时间越长LCALL DISP ;调用显示程序INC 30H ;将30内数据加1,即个位加1MOV A,30H ;将30H单元内数据送给A寄存器CJNE A,#0AH,MAIN ;判断30H内数据是否计到了10?未达到则跳转到MAINMOV 30H,#00H ;30H内数计到了10,则清零INC 31H ;并将31H内数据加1MOV A,31HCJNE A,#0AH,MAIN ;同理判断31H内数据是否到了10MOV 31H,#00H ;到了10则清零LJMP MAIN ;并跳转到MAIN处循环上面的过程DISP: SETB P0.1 ;首先关闭十位显示SETB P0.0 ;再关闭个位显示MOV A,30H ;MOV DPTR,#TAB ;将显示代码TAB地址送入DPTRMOVC A,@A+DPTR ;查询30H内数据的显示代码送入AMOV P2,A ;将查询到的代码送入P2显示CLR P0.1 ;打开个位显示刚才的数据LCALL DELY1 ;调用小的演示程序(10ms以内),形成视觉效果SETB P0.1 ;关闭个位显示MOV A,31H ;现在要显示31H内数据了MOV DPTR,#TAB ;将显示代码TAB地址送入DPTRMOVC A,@A+DPTR ;查询31H内数据的显示代码送入AMOV P2,A ;将查询到的代码送入P2显示CLR P0.0 ;打开十位显示刚才的数据LCALL DELY1 ;调用小的演示程序(10ms以内),形成视觉效果SETB P0.0 ;关闭显示DJNZ R5,DISP ;R5自减,不为0则跳转到DISPRET ;子程序返回TAB: DB 3FH,06H,5BH,4FHDB 66H,6DH,7DH,07HDB 7FH,6FH,77H,7CHDB 39H,5EH,79H,71HDELY1: MOV R7,#10D10: MOV R6,#250D20: DJNZ R6,D20DJNZ R7,D10RETEND************************************************************************** #include<reg51.h>sbit P0_0=P0^0; //个位数字sbit P0_1=P0^1; //十位数字void delay(int k); //Tab为数码管显示值,存入一个数组内unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};unsigned char i,shi,ge,num,count; //num为被显示的数字void main(){P2=Tab[0];P0_0=0;P0_1=0;//显示00num=0; //被显示的数置0count=20;while(1){for(i=1;i<count;i++) //显示个位、十位count次后显示的数加1{shi=num/10; //取出十位数ge=num%10; //取出个位数P0_0=1;P0_1=1; //关闭显示P2=Tab[shi]; //P2口送出十位数据显示代码P0_0=0; //打开十位显示delay(10); //延时P0_0=1; //关闭显示P2=Tab[ge]; //P2口送出个位数据显示代码P0_1=0; //打开个位显示delay(10); //延时}if(++num==100) //num自加1,然后判断是否等于100,等于则置0 num=0;}}void delay(int k) //最简单的C延时程序{unsigned char i;while(k--) //直至K减为0则跳出{for(i=250;i>0;i--);}}按键控制加、减显示00-99(P10为加,P11为减,P2接A- -H,P0接DS1- -DS8)********************************************************************************** #include<reg51.h>sbit P0_0=P0^0; //个位数字sbit P0_1=P0^1; //十位数字void delay(int k); //Tab为数码管显示值,存入一个数组内void key_ccan(void); //声明按键扫描函数unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};unsigned char i,shi,ge,num,count=10; //num为被显示的数字void main(){P2=Tab[0];P0_0=0;P0_1=0;//显示00num=0; //被显示的数置0while(1){key_ccan(); //调用按键扫描程序for(i=0;i<count;i++) //显示个位、十位count次后显示的数加1{shi=num/10; //取出十位数ge=num%10; //取出个位数P0_0=1;P0_1=1; //关闭显示P2=Tab[shi]; //P2口送出十位数据显示代码P0_0=0; //打开十位显示delay(10); //延时P0_0=1; //关闭显示P2=Tab[ge]; //P2口送出个位数据显示代码P0_1=0; //打开个位显示delay(10); //延时P0_1=1; //关闭个位显示}}}void key_ccan(void){unsigned char ii;P1=0xff;ii=P1;if(ii!=0xff){P1=0xff;delay(50);ii=P1;if(ii!=0xff){switch(ii){case 0xfe: num++;if(num==100) num=0;break;case 0xfd: if(num==0) num=99;else num--;break;default: break;}}}}void delay(int k) //最简单的C延时程序{ unsigned char i;while(k--) //直至K减为0则跳出{for(i=100;i>0;i--);}}定时器计数00-59(P0接ds1-ds8,P2接A-H)*******************************************************************************************#include<reg51.h>sbit P0_0=P0^0; //个位数字sbit P0_1=P0^1; //十位数字void delay(int k); //Tab为数码管显示值,存入一个数组内unsigned char ge,shi,num,count;unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};void main(){TMOD=0x1; //T0,工作方式1TH0=0xb1; //20ms定时TL0=0xe0;TR0=1; //开启T0定时器ET0=1; //允许T0定时器中断EA=1; //开启总中断允许P2=Tab[0];P0_0=0;P0_1=0;//显示00num=0; //被显示的数置0while(1) //一直调用显示,等待T0中断修改显示数据{shi=num/10; //取出十位数ge=num%10; //取出个位数P0_0=1;P0_1=1; //关闭显示P2=Tab[shi]; //P2口送出十位数据显示代码P0_0=0; //打开十位显示delay(1000); //延时P0_0=1; //关闭显示P2=Tab[ge]; //P2口送出个位数据显示代码P0_1=0; //打开个位显示delay(1000); //延时P0_1=1; //关闭个位显示}}void time0(void) interrupt 1{TH0=0xb1;TL0=0xe0;count++; //计数值+1if(count==50) //加到50次即1秒{ count=0;num++; //显示数据+1if(num==60){ num=0; }}}void delay(int k){while(k--);}定时器计数秒表000.0-999.9(P0接ds1-ds8,P2接A-H)*******************************************************************************************#include<reg51.h>sbit P0_0=P0^0; //百位数字sbit P0_1=P0^1; //十位数字sbit P0_2=P0^2; //个位数sbit P0_3=P0^3; //小数位void delay(int k); //Tab为数码管显示值,存入一个数组内unsigned char ge,shi,bai,xiao,count;unsigned int num;unsigned char code Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};void main(){TMOD=0x1; //T0,工作方式1TH0= 0xd8; //10ms定时TL0=0xf0;TR0=1; //开启T0定时器ET0=1; //允许T0定时器中断EA=1; //开启总中断允许P2=Tab[0];P0_0=0;P0_1=0;//显示00num=0; //被显示的数置0while(1) //一直调用显示,等待T0中断修改显示数据{bai=num/1000; //取出十位数shi=num%1000/100; //取出个位数ge=num%100/10;//第一位小数xiao=num%10; //第二位小数P0_0=0xff; //关闭显示P2=Tab[bai]; //P2口送出十位数据显示代码P0_0=0; //打开十位显示delay(200); //延时P0_0=1; //关闭显示P2=Tab[shi]; //P2口送出个位数据显示代码,各位要加小数点,即最高位为1则显示小数点P0_1=0; //打开个位显示delay(200); //延时P0_1=1; //关闭个位显示P2=Tab[ge]+0x80; //P2口送出第一个小数据显示代码P0_2=0; //打开十位显示delay(200); //延时P0_2=1; //关闭显示P2=Tab[xiao]; //P2口送出第二个笑数据显示代码P0_3=0; //打开个位显示delay(200); //延时P0_3=1; //关闭个位显示}}void time0(void) interrupt 1{TH0= 0xd8; //10ms定时TL0=0xf0;count++; //显示数据+1if(count==10) //显示数据计数到9999次即99.99秒{ count=0;if(num++==10000) num=0;}}void delay(int k){while(k--);}11。
C51与汇编语言混合编程之一
1、函数内部混合编程若想在C 语言函数内部使用汇编语言,应使用以下Cx51 编译器控制命令:
#pragma asm
;;;Assembly code
#pragma endasm
功能作用:
asm 和endasm 命令用于将其标记的汇编程序合并到.SRC 文件中。
这个带有asm 和endasm 块标记的源程序可看作是在线嵌入式汇编程序。
从这点来说,此命令有些类似于#define 命令。
具体实现:
(1)编译器设置及SRC 文件的产生
.SRC 文件在命令行编译模式下是使用SRC 编译器控制命令产生的,在IDE 环境中可以为需要产生SRC 文件的C 源文件设置特定选项:
l 右键单击Project Workspace 下的文件标签
l 选择Options for file 项,打开Options – Properties 页。
l 选中Generate Assembler SRC file 项
l 选中Assembler SRC file 项
(2)添加库文件
根据选择的编译模式,把相应的库文件添加到工程下面,如在small 模式下,需将keil\c51\lib\c51s.lib 文件加入工程中。
在Keil 安装目录下的\C51\LIB\ 目录的LIB 文件如下:
C51S.LIB - 没有浮点运算的Small modelC51C.LIB - 没有浮点运算的。
C51汇编语言16进制书写规则1. 概述C51汇编语言是一种常用于嵌入式系统开发的低级语言,它通过对CPU 的指令进行底层控制,可以实现对硬件设备的高效操作。
在编写C51汇编程序时,经常会用到16进制数值,因此了解16进制数值的书写规则对于正确编写程序至关重要。
本文将对C51汇编语言16进制书写规则进行详细介绍。
2. 16进制数值的表示方式16进制数值由0-9和A-F共16个字符组成,分别对应10-15的十进制数值。
在C51汇编语言中,16进制数值可以使用0x或者#前缀进行表示,例如0x1A或者#1F表示16进制数值1A和1F。
3. 16进制数值的书写规则在C51汇编语言中,16进制数值的书写规则如下:3.1 小写字母表示在书写16进制数值时,C51汇编语言允许使用小写字母a-f来表示十六进制的A-F,也就是说,整个16进制数值可以使用小写字母来表示,例如:0x1a3b。
3.2 数值前缀在表示16进制数值时,一般会在数值前面加上0x或者#前缀,这样可以明确表示这是一个16进制数值而不是10进制数值。
3.3 数值范围在C51汇编语言中,16进制数值的范围通常是0x00到0xFF,表示的是一个字节范围内的数值。
4. 16进制数值的应用在C51汇编语言程序中,16进制数值经常用于表示寄存器的位置区域、控制寄存器的位操作、设置定时器的初值等。
使用16进制数值可以有效地减少程序的长度,提高程序的执行效率。
5. 总结了解C51汇编语言16进制数值的书写规则对于编写高质量、高效率的程序至关重要。
通过掌握16进制数值的表示方式和书写规则,开发人员可以更加灵活地利用C51汇编语言来实现对嵌入式系统的底层控制,从而更好地满足项目的需求。
在C51汇编语言程序中,16进制数值的合理使用可以提高程序的可读性和可维护性,减少程序的长度,提高程序的执行效率。
对C51汇编语言16进制数值的书写规则进行了解和掌握对于程序开发人员至关重要。
KEILC51中C语言加入汇编语言的使用方法一、为什么使用汇编语言?汇编语言是一种底层的编程语言,其主要目的是实现对硬件的直接控制,具有高度灵活性和效率。
在开发单片机程序时,通常使用高级语言来编写大部分的代码,但是在一些特定的情况下,使用汇编语言能够更好地满足需求,例如对一些硬件寄存器的操作、实现高速计算等。
二、C语言与汇编语言相结合的方法在KEILC51中,可以通过使用内联汇编或者使用汇编模块的方式将C 语言与汇编语言相结合。
1.内联汇编内联汇编是将汇编代码直接嵌入到C语言代码中。
使用内联汇编可以获得更高的性能和灵活性,但也增加了代码的可读性和可维护性。
在C语言中使用内联汇编需要使用__asm关键字,并在括号中编写要嵌入的汇编代码。
以下是一个示例:```void delay(unsigned int count)__asmMOVR1,loop:INCR1CJNE R1, count, loop}```在上述示例中,使用了__asm关键字将一段简单的汇编代码嵌入到了C函数delay中,以实现一个延时功能。
2.汇编模块另一种将C语言与汇编语言相结合的方法是使用汇编模块。
汇编模块是一个独立的文件,其中包含了汇编语言代码。
可以通过使用extern关键字将C语言代码与汇编模块连接起来。
首先,需要创建一个汇编模块的文件,例如delay.asm,其中包含了要实现的汇编代码:```; delay.asmPUBLIC delaydelay PROCMOVR1,loop:INCR1CJNE R1, R2, loopRETdelay ENDP```在上述示例中,创建了一个名为delay的汇编函数,该函数实现了一个简单的延时功能。
接下来,在C语言代码中使用extern关键字声明要调用的汇编函数:```// main.cextern void delay(unsigned int count);void maindelay(1000);```在上述示例中,使用extern关键字声明了一个名为delay的汇编函数。
我找到了一些资料希望对你有用下周就要做实验了,由于听老师说机房位子可能比较少,对我这种蹭课的学生来说也就不敢奢望同选这门课的同学一样能够正常的在机房调试程序了,因此,我决定提前先在自己的工作室里把实验内容给过一遍。
第一个实验是关于嵌入式编程的,这个实验目的一方面是为了让我们熟悉ARM下编程的编译环境ADS和调试器A TX,另一方面是让我们掌握如何将c 语言和汇编语言在实际编程中相互调用。
经过这两天靠自己不断的摸索,终于掌握了如何在编译环境中进行ARM编程,另外,还学会了在c中调用汇编程序的方法,以及如何通过linux 自带的gcc编译嵌有汇编的c程序,总之,收获还是蛮多的哦,下面就总结一下吧。
1、c嵌汇编首先说一下关于GCC编译嵌有汇编语言的c语言吧,GCC编译的汇编语言不是我们上课时学的Intel x86汇编,而是A T&T汇编,两者的区别可以查看《Gcc使用的内嵌汇编语法格式小教程》。
下面是内嵌汇编的几种格式:语法__asm__(“instruction. ……instruction”); //Linux gcc中支持(注意asm的下划线均为两个否则GCC将会无法编译)__asm{instruction…instruction}; //ADS中支持(注意asm的下划线均为两个否则GCC将会无法编译)asm(“instruction [; instruction]”); //ARM C++中使用例1是我在linux环境下,编的嵌有汇编程序的c语言,并通过了GCC的编译:例1:#includeint plus(int a,int b){__asm__(“add %1,%0\n\t”:”+r”(a):”r”(b));return (c);}int main(){int a,b,c;a=2;b=1;c=plus(a,b);printf(“c=%d\n”,c);}这个程序应该是很简单的,但关键是子函数中嵌入的那段汇编程序,具体的写法可以参看其他文章。
关于在 KEIL C51 中嵌入汇编(zz)如何在 KEIL C51(v6.21)中调用汇编函数的一个示例 [ycong_kuang]有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者通过一个简单例子对这个过程进行描述,希望能对初学者有所帮助。
几年来,在这个论坛里笔者得到很多热心人指导,因此也希望藉此尽一点绵薄之力。
在这个例子里,阐述了编写c51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是一个整型变量。
例中,先用c51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所要的汇编函数。
该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。
step1. 按写普通c51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。
相关文件如下://main.c文件#include < reg51.h >#define uchar unsigned char#define uint unsigned intextern uint AFUNC(uchar v_achr,bit v_bflag);void main(){bit BFLAG;uchar mav_chr;uint mvintrslt;mav_chr=0xd4; BFLAG=1;mvintrslt=AFUNC(mav_chr,BFLAG);}//CFUNC.c文件#define uchar unsigned char#define uint unsigned intuint AFUNC(uchar v_achr,bit v_bflag){uchar tmp_vchr;uint tp_vint;tmp_vchr=v_achr;tp_vint=(uint)v_bflag;return tmp_vchr+(tp_vint<<8);}step2. 在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRCFile”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;step3. 根据选择的编译模式,把相应的库文件(如 Small 模式时,是 Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工程的最后文件;step4. build这个工程后将会产生一个CFUNC.SRC的文件,将这个文件改名为CFUNC.A51(也可以通过编译选项直接产生CFUNC.A51文件),然后在工程里去掉库文件(如C51S.Lib)和CFUNC.c,而将CFUNC.A51添加到工程里。
//CFUNC.SRC文件如下.\CFUNC.SRC generated from: CFUNC.cNAME CFUNC?PR?_AFUNC?CFUNC SEGMENT CODE?BI?_AFUNC?CFUNC SEGMENT BIT OVERLAYABLEPUBLIC ?_AFUNC?BITPUBLIC _AFUNCRSEG ?BI?_AFUNC?CFUNC?_AFUNC?BIT:v_bflag?041: DBIT 1; #define uchar unsigned char; #define uint unsigned int;; uint AFUNC(uchar v_achr,bit v_bflag)RSEG ?PR?_AFUNC?CFUNC_AFUNC:USING 0; SOURCE LINE # 5 ;---- Variable 'v_achr?040' assigned to Register 'R7' ----; {; SOURCE LINE # 6; uchar tmp_vchr;; uint tp_vint;;; tmp_vchr=v_achr;; SOURCE LINE # 10;---- Variable 'tmp_vchr?042' assigned to Register 'R5' ----MOV R5,AR7; tp_vint=(uint)v_bflag;; SOURCE LINE # 11MOV C,v_bflag?041CLR ARLC A;---- Variable 'tp_vint?043' assigned to Register 'R6/R7' ---- ; return tmp_vchr+(tp_vint<<8);; SOURCE LINE # 12MOV R6,AMOV R4,#00HCLR AADD A,R5MOV R7,AMOV A,R4ADDC A,R6MOV R6,A; }; SOURCE LINE # 13?C0001:RET; END OF _AFUNCENDstep5. 检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。
参考文献:1.徐爱钧,彭秀华。
单片机高级语言C51windows环境编程与应用,电子工业出版社, C51编程:关于在 KEIL C51 中直接嵌入汇编。
帖子编号: 83838 发表用户:Youth.................................................................................................................keil中汇编函数调用c51函数 [ycong_kuang]在keil的写法可参考89852帖子,具体如下:与89852帖子相比,第一步在工程里多了一个被汇编调用的c51的函数文件(c51func.c),至于汇编函数还是先用c51编写出主体(a51func.c),这样汇编程序接口和段都交给编译器处理,你只管在编译成汇编代码后按你的要求改写汇编代码就行了。
例程如下://main.c#include < reg51.h >#define uchar unsigned char#define uint unsigned intextern uint AFUNC(uchar v_achr,bit v_bflag);void main(){bit BFLAG;uchar mav_chr;uint mvintrslt;mav_chr=0xd4; BFLAG=1;mvintrslt=AFUNC(mav_chr,BFLAG);}//a51FUNC.c#define uchar unsigned char#define uint unsigned intextern uint CFUNC(uint);uint AFUNC(uchar v_achr,bit v_bflag) //c51写的汇编函数,最终要变成汇编代码{uchar tmp_vchr;uint tp_vint;tmp_vchr=v_achr;tp_vint=(uint)v_bflag;return CFUNC(tp_vint); //这里调用一个c51函数}//c51FUNC.c#define uchar unsigned char#define uint unsigned intuint CFUNC(uint v_int) //被汇编函数调用c51函数{return v_int<<2;}第二步是按89852帖子的step2,3,4把用c51写的(汇编)函数变成a51文件(今天我试了一下step3可以不要)例程编译结果如下:; .\a51func.SRC generated from: a51func.cNAME A51FUNC?PR?_AFUNC?A51FUNC SEGMENT CODE?DT?_AFUNC?A51FUNC SEGMENT DATA OVERLAYABLE?BI?_AFUNC?A51FUNC SEGMENT BIT OVERLAYABLEEXTRN CODE (_CFUNC)PUBLIC ?_AFUNC?BITPUBLIC _AFUNCRSEG ?DT?_AFUNC?A51FUNC?_AFUNC?BYTE:tmp_vchr?042: DS 1RSEG ?BI?_AFUNC?A51FUNC?_AFUNC?BIT:v_bflag?041: DBIT 1; //a51FUNC.c;; #define uchar unsigned char; #define uint unsigned int;; extern uint CFUNC(uint);;; uint AFUNC(uchar v_achr,bit v_bflag)RSEG ?PR?_AFUNC?A51FUNC_AFUNC: ;c51所写的函数产生的汇编代码从这里开始USING 0; SOURCE LINE # 8;---- Variable 'v_achr?040' assigned to Register 'R7' ----; {; SOURCE LINE # 9; uchar tmp_vchr;; uint tp_vint;;; tmp_vchr=v_achr;; SOURCE LINE # 13MOV tmp_vchr?042,R7; tp_vint=(uint)v_bflag;; SOURCE LINE # 14MOV C,v_bflag?041CLR AMOV R6,ARLC AMOV R7,A;---- Variable 'tp_vint?043' assigned to Register 'R6/R7' ----; 这里说明R6,R7内容就是tp_vint; return CFUNC(tp_vint);; SOURCE LINE # 16LCALL _CFUNC ;这里调用了用c51写的函数; }; SOURCE LINE # 17?C0001:RET; END OF _AFUNCEND这个文件就是你的汇编函数所在文件,把函数里面的汇编代码修改成你所需的汇编函数就ok了。
建议参考徐爱钧,彭秀华所写的《单片机高级语言C51windows环境编程与应用》或马忠梅所写的《单片机的c语言应用程序设计》有关混合语言编程有关章节.................................................................................................................关于在 KEIL C51中直接嵌入汇编。