[技术问答] 对单片机汇编和C混合编程的感悟

[复制链接]
1388|9
 楼主| Tennasi 发表于 2015-12-13 21:26 | 显示全部楼层 |阅读模式
如何在 KEIL C51(v6.21) 中调用汇编函数的一个示例 [ycong_kuang]

有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者
通过一个简单例子对这个过程进行描述,希望能对初学者有所帮助。几年来,在这个论坛里笔者得到很多热心人指导,因此也希望
藉此尽一点绵薄之力。

在这个例子里,阐述了编写c51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是
一个整型变量。例中,先用c51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所
要的汇编函数。该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。

step1. 按写普通c51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。

相关文件如下:
//main.c文件
  1. #include < reg51.h >

  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. extern uint AFUNC(uchar v_achr,bit v_bflag);

  5. void main()
  6. {
  7.      bit BFLAG;
  8.      uchar mav_chr;
  9.      uint     mvintrslt;

  10.      mav_chr=0xd4; BFLAG=1;
  11.      mvintrslt=AFUNC(mav_chr,BFLAG);
  12. }


 楼主| Tennasi 发表于 2015-12-13 21:27 | 显示全部楼层
//CFUNC.c文件
  1. #define uchar unsigned char
  2. #define uint unsigned int

  3. uint AFUNC(uchar v_achr,bit v_bflag)
  4. {
  5.      uchar tmp_vchr;
  6.      uint   tp_vint;

  7.      tmp_vchr=v_achr;
  8.      tp_vint=(uint)v_bflag;
  9.      return tmp_vchr+(tp_vint<<8);
  10. }
 楼主| Tennasi 发表于 2015-12-13 21:28 | 显示全部楼层
step2. 在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC
         File”和“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.c
  1. NAME CFUNC

  2. ?PR?_AFUNC?CFUNC      SEGMENT CODE
  3. ?BI?_AFUNC?CFUNC      SEGMENT BIT OVERLAYABLE
  4.      PUBLIC     ?_AFUNC?BIT
  5.      PUBLIC     _AFUNC

  6.      RSEG   ?BI?_AFUNC?CFUNC
  7. ?_AFUNC?BIT:
  8.      v_bflag?041:    DBIT    1
  9. ; #define uchar unsigned char
  10. ; #define uint unsigned int
  11. ;
  12. ; uint AFUNC(uchar v_achr,bit v_bflag)

  13.      RSEG   ?PR?_AFUNC?CFUNC
  14. _AFUNC:
  15.      USING     0
  16.              ; SOURCE LINE # 5
  17. ;---- Variable 'v_achr?040' assigned to Register 'R7' ----
  18. ; {
  19.              ; SOURCE LINE # 6
  20. ;      uchar tmp_vchr;
  21. ;      uint     tp_vint;
  22. ;
  23. ;      tmp_vchr=v_achr;
  24.              ; SOURCE LINE # 10
  25. ;---- Variable 'tmp_vchr?042' assigned to Register 'R5' ----
  26.      MOV       R5,AR7
  27. ;      tp_vint=(uint)v_bflag;
  28.              ; SOURCE LINE # 11
  29.      MOV       C,v_bflag?041
  30.      CLR       A
  31.      RLC       A
  32. ;---- Variable 'tp_vint?043' assigned to Register 'R6/R7' ----
  33. ;      return tmp_vchr+(tp_vint<<8);
  34.              ; SOURCE LINE # 12
  35.      MOV       R6,A
  36.      MOV       R4,#00H
  37.      CLR       A
  38.      ADD       A,R5
  39.      MOV       R7,A
  40.      MOV       A,R4
  41.      ADDC      A,R6
  42.      MOV       R6,A
  43. ; }
  44.              ; SOURCE LINE # 13
  45. ?C0001:
  46.      RET
  47. ; END OF _AFUNC

  48.      END
 楼主| Tennasi 发表于 2015-12-13 21:28 | 显示全部楼层
step5. 检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状
        态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。

参考文献:
   1.徐爱钧,彭秀华。单片机高级语言C51windows环境编程与应用,电子工业出版社
   2.   C51编程:关于在 KEIL C51 中直接嵌入汇编。。。帖子编号: 83838 发表用户:Youth
   .................................................................................................................
                                  keil中汇编函数调用c51函数 [ycong_kuang]

在keil的写法可参考89852帖子,具体如下:
与89852帖子相比,第一步在工程里多了一个被汇编调用的c51的函数文件(c51func.c),至于汇编函数还是先用c51编写出主体
(a51func.c),这样汇编程序接口和段都交给编译器处理,你只管在编译成汇编代码后按你的要求改写汇编代码就行了。

例程如下:
  1. //main.c
  2. #include < reg51.h >

  3. #define uchar unsigned char
  4. #define uint unsigned int

  5. extern uint AFUNC(uchar v_achr,bit v_bflag);

  6. void main()
  7. {
  8.      bit BFLAG;
  9.      uchar mav_chr;
  10.      uint     mvintrslt;

  11.      mav_chr=0xd4; BFLAG=1;
  12.      mvintrslt=AFUNC(mav_chr,BFLAG);
  13. }
 楼主| Tennasi 发表于 2015-12-13 21:30 | 显示全部楼层
  1. //a51FUNC.c

  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. extern uint CFUNC(uint);

  5. uint AFUNC(uchar v_achr,bit v_bflag)    //c51写的汇编函数,最终要变成汇编代码
  6. {
  7.      uchar tmp_vchr;
  8.      uint   tp_vint;

  9.      tmp_vchr=v_achr;
  10.      tp_vint=(uint)v_bflag;

  11.      return CFUNC(tp_vint);             //这里调用一个c51函数
  12. }

  13. //c51FUNC.c

  14. #define uchar unsigned char
  15. #define uint unsigned int

  16. uint CFUNC(uint v_int)                //被汇编函数调用c51函数
  17. {
  18.      return v_int<<2;
  19. }
 楼主| Tennasi 发表于 2015-12-13 21:31 | 显示全部楼层
第二步是按89852帖子的step2,3,4把用c51写的(汇编)函数变成a51文件(今天我试了一下step3可以不要)例程编译结果如
下:
  1. ; .\a51func.SRC generated from: a51func.c
  2. NAME     A51FUNC

  3. ?PR?_AFUNC?A51FUNC    SEGMENT CODE
  4. ?DT?_AFUNC?A51FUNC    SEGMENT DATA OVERLAYABLE
  5. ?BI?_AFUNC?A51FUNC    SEGMENT BIT OVERLAYABLE
  6.      EXTRN     CODE (_CFUNC)
  7.      PUBLIC     ?_AFUNC?BIT
  8.      PUBLIC     _AFUNC

  9.      RSEG   ?DT?_AFUNC?A51FUNC
  10. ?_AFUNC?BYTE:
  11.     tmp_vchr?042:    DS    1

  12.      RSEG   ?BI?_AFUNC?A51FUNC
  13. ?_AFUNC?BIT:
  14.      v_bflag?041:    DBIT    1
  15. ; //a51FUNC.c
  16. ;
  17. ; #define uchar unsigned char
  18. ; #define uint unsigned int
  19. ;
  20. ; extern uint CFUNC(uint);
  21. ;
  22. ; uint AFUNC(uchar v_achr,bit v_bflag)

  23.      RSEG   ?PR?_AFUNC?A51FUNC
  24. _AFUNC:        ;c51所写的函数产生的汇编代码从这里开始
  25.      USING     0
  26.              ; SOURCE LINE # 8
  27. ;---- Variable 'v_achr?040' assigned to Register 'R7' ----
  28. ; {
  29.              ; SOURCE LINE # 9
  30. ;      uchar tmp_vchr;
  31. ;      uint   tp_vint;
  32. ;
  33. ;      tmp_vchr=v_achr;
  34.              ; SOURCE LINE # 13
  35.      MOV       tmp_vchr?042,R7
  36. ;      tp_vint=(uint)v_bflag;
  37.              ; SOURCE LINE # 14
  38.      MOV       C,v_bflag?041
  39.      CLR       A
  40.      MOV       R6,A
  41.      RLC       A
  42.      MOV       R7,A
  43. ;---- Variable 'tp_vint?043' assigned to Register 'R6/R7' ----
  44. ;       这里说明R6,R7内容就是tp_vint
  45. ;      return CFUNC(tp_vint);
  46.              ; SOURCE LINE # 16
  47.      LCALL     _CFUNC    ;这里调用了用c51写的函数
  48. ; }
  49.              ; SOURCE LINE # 17
  50. ?C0001:
  51.      RET
  52. ; END OF _AFUNC

  53.      END
quray1985 发表于 2015-12-14 18:04 | 显示全部楼层
一般是加
春风的暖暖 发表于 2015-12-15 11:24 | 显示全部楼层
汇编里可以插入C语言吗?
玛尼玛尼哄 发表于 2015-12-15 21:04 | 显示全部楼层
第一步在工程里多了一个被汇编调用的c51的函数文件(c51func.c),至于汇编函数还是先用c51编写出主体(a51func.c),这样汇编程序接口和段都交给编译器处理,你只管在编译成汇编代码后按你的要求改写汇编代码就行了。
john_lee 发表于 2015-12-15 21:10 | 显示全部楼层
还在玩 51 啊,真执着,我没这个勇气。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

169

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部