显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

信息 灵感 创新

III = Information,Inspiration,Innovation

 
 
 
 

日历

 
 
模块内容加载中...
 
 
 
 
 

天气

 
 
模块内容加载中...
 
 
 
 
 
 
 

湖北省 武汉市 天秤座

 发消息  写留言

 
we are 5. Mathematics, Computation, Programming, Engineering, and Making fun of life.
 
近期心愿make it happen, make it happy, make it harmony
博客等级加载中...
今日访问加载中...
总访问量加载中...
最后登录加载中...
 
 
 
 
 
 
 
 

C51生成汇编代码剖析(3)

2017-10-31 10:37:19 阅读42 评论0 312017/10 Oct31

关于指针(1)

测试如下程序生成的汇编代码:

从C代码可知这个程序申明了两个变量以及一个对应的指针,分别让指针指向这两个变量,并修改其值。

在反汇编代码中,可以看到c1的地址是0x08,c2的地址是0x09,看看指针初始化,指向变量的操作:

8:     ptr_c=&c1;

C:0x0009    7B00     MOV      R3,#0x00

C:0x000B    7A00     MOV      R2,#0x00

C:0x000D    7908     MOV      R1,#0x08

可见,使用到了R1、R2和R3共3个寄存器,其中R1中的内容就是c1的地址0x08,而R2和R3中为0。但是这两个地方的含义不大一样。重点在下面:

9:     *ptr_c=0xaa;

C:0x000F    74AA     MOV      A,#0xAA

C:0x0011    12001E   LCALL    C?CSTPTR(C:001E)

这两句是通过指针的方式为其指向的地址空间赋值,显然累加器A中存放了赋值的立即数,但是调用了一个C?CSTPTR的函数,并不是源代码中编写的,因此,肯定是在链接的时候加进去的,看看这段代码的内容(首地址在0x001E):

C?CSTPTR:

C:0x001E    BB0106   CJNE     R3,#0x01,C:0027

作者  | 2017-10-31 10:37:19 | 阅读(42) |评论(0) | 阅读全文>>

C51生成汇编代码剖析(2)

2017-10-28 11:05:32 阅读35 评论0 282017/10 Oct28

关于变量

分析C51编译之后的代码,会将变量存放在哪里。

首先需要说明,编译器如果检测到有申明,但未初始化的变量,会给出警告,并且在生成代码的时候会忽略这些未使用的变量。

例如:

unsigned char a;//仅申明,如果后面一直不使用,就不会有任何与之相关的代码生成

但是:

unsigned char a=12;//申明+初始化,会生成代码

右边可以看到,将12赋值给了存储器0x08中,检查存储器可以证实:

如果再跟一个char b,用负数为其初始化,则可以看到占据的存储器空间是紧跟在a之后,并采用补码的形式表示。

对于像int、long类型的,占据多个字节(int为2字节,long为4字节),摆放地址是高位在前,低位在后,测试如下:

float类型:

这段代码说明了2个问题:

1. 变量所占据的地址,是根据申明的顺序,不是根据初始化的顺序。

2.浮点数按IEEE754规范表示(见下图),并且也是高位在前,低位在后,但写入方式是先写入低位(0x11),最后写入高位(0x0E)。

3. 代码0x0006处,出现的0x80,被反汇编解释为#P0,显然是单片机中的P0扣地址(0x80)。

bit类型

通过测试,bit类型会依次放在存储器第一个可位寻址(20H)的第一位,第二位等。

例如对于两个bit型的变量:

C:0x000F  

作者  | 2017-10-28 11:05:32 | 阅读(35) |评论(0) | 阅读全文>>

C51生成汇编代码剖析(1)

2017-10-28 10:54:57 阅读38 评论0 282017/10 Oct28

研究C51编译生成的汇编代码,有助于学习汇编语言,以及C和汇编的混合编程。

1.最简单的程序

C51中最简单的程序肯定是这个:

看右边反汇编的结果,可以发现,在进入main函数之前,程序会做一些准备工作,例如

C:0x0003    787F     MOV      R0,#0x7F

C:0x0005    E4       CLR      A

C:0x0006    F6       MOV      @R0,A

这三行,相当于是将00写入存储器0x7F中。

C:0x0007    D8FD     DJNZ     R0,C:0006

这一句相当于是将存储器0x00-0x7F中的数据全部清零,即将存储器低128位全部清零,可以查看存储器:

C:0x0009    758107   MOV      SP(0x81),#0x07

则是设置堆栈。

这些工作做完之后,则是一个长跳转到了main函数的入口点0x000F,当然这里什么都没有,只有一个RET。

作者  | 2017-10-28 10:54:57 | 阅读(38) |评论(0) | 阅读全文>>

C程序:查找前n个质数

2017-10-15 16:04:35 阅读40 评论0 152017/10 Oct15

void ListNPrimes(unsigned int n) { unsigned long long *pPrimes=NULL; unsigned long long test; unsigned int cnt,i,primeFlag,sqrt_test; if(n<4) { printf("ListNPrimes:\"n\" should be no less than 4.\n"); return; } pPrimes=(unsigned long long*)calloc(n,sizeof(unsigned long long)); if(!pPrimes) { printf("ListNPrimes:Memory allocation failed.\n"); return; } *pPrimes=2UL; *(pPrimes+1)=3UL; *(pPrimes+2)=5ULL; cnt=3; test=5; while(cnt<n) { test+=2; if((test-1)%6!=0&&(test+1)%6!=0) continue; primeFlag=1; sqrt_test=(unsigned int)sqrt(test);

作者  | 2017-10-15 16:04:35 | 阅读(40) |评论(0) | 阅读全文>>

C51 外部中断扩展

2017-10-13 17:00:06 阅读37 评论0 132017/10 Oct13

只有两个外部中断的51单片机,很多时候是不能满足我们的使用需求的,这个时候可以考虑使用扩展,通过硬件触发中断,软件检索的方式确定最终的中断来源。对于低电平或者下降沿触发,可以使用与门,而对于高电平或者上升沿触发,可以使用与非门。

以低电平的输入为例,可以使用一个74LS21,这是一种双四路与门芯片。

代码:

#include <reg51.h> //0,1,2,3 unsigned char SEGCODE[]={0x3F,0x06,0x5B,0x4F}; sbit FL=P1^0; sbit FR=P1^1; sbit RL=P1^2; sbit RR=P1^3; void main() { EA=1; IT0=1; EX0=1; P2=0; while(1); } void INT_EX0() interrupt 0 { EX0=0; if(FL==0) { P2=SEGCODE[0]; EX0=1; return; } if(FR==0) { P2=SEGCODE[1]; EX0=1; return; } if(RL==0) { P2=SEGCODE[2]; EX0=1; return; } if(RR==0) { P2=SEGCODE[3];

作者  | 2017-10-13 17:00:06 | 阅读(37) |评论(0) | 阅读全文>>

查看所有日志>>

 
 
 
 
 
 
 
模块内容加载中...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017

注册 登录  
 加关注