找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 1036|回复: 2
打印 上一主题 下一主题
收起左侧

Keil汇编进阶指南(4) - 与C共舞

[复制链接]
跳转到指定楼层
楼主
与C共舞

我们在之前的内容学习了段的声明以及相关变量内存的声明,现在我们要开始最重要的一节课——汇编和C的混合编程
首先是在C中调用汇编
我们在汇编的学习中知道了汇编代码的跳转和调用都是依赖所谓的标记来进行,我们还是拿LCD1602的驱动举例

  1. <div class="blockcode"><blockquote>LCDWRCOM:
  2.                 CLR LCD_RS;写命令
  3.                 SJMP GOON
  4.         LCDWRDAT:
  5.                 SETB LCD_RS;写数据,这个没有jmp,应该更快一些
  6.         GOON:
  7.                 SETB LCD_EN;两段代码合一,这种技巧很常见,甚至编译器都这么优化
  8.                 MOV LCD_BUS,R7;注意,根据文档,单个char会直接传入R7,多看文档
  9.                 MOV R6,#10H;等待LCD
  10.                 DJNZ R6,$
  11.                 CLR LCD_EN
  12.                 CLR LCD_RS
  13.                 RET
复制代码


  1. LCDINIT:
  2.                 CLR LCD_RW
  3.                 CLR LCD_EN
  4.                 MOV R7,#38H
  5.                 CALL LCDWRCOM
  6.                 MOV R7,#0CH
  7.                 CALL LCDWRCOM
  8.                 MOV R7,#06H
  9.                 CALL LCDWRCOM
  10.                 MOV R7,#01H
  11.                 CALL LCDWRCOM;启动序列,别处抄的
  12.                
  13.                 MOV R7,#0FH
  14.         LCDFINWAIT:
  15.                 MOV R6,#0FFH
  16.                 DJNZ R6,$
  17.                 DJNZ R7,LCDFINWAIT;LCD需要一段时间准备
  18.                
  19.                 RET
复制代码




我们可以知道,上面有三个程序,一个是LCDWRCOM,一个是LCDWRDAT,以及LCDINIT,这三个都是程序的入口,我们要做的就是把入口声明告知C编译器,有这么个东西
我们以LCDINIT为例
首先,LCDINIT是一个没有输入输出的函数,所以一般来说它在C语言里的声明是这样的
  1. void lcdinit();
复制代码
其次,我们在C文件中调用的是别的文件中的函数,我们需要extern来表明,这个函数是从外部薅过来的(函数入口在别的文件)
最终,我们写在头文件里的声明函数是这样的
  1. extern void lcdinit();
复制代码

还记得我说过传到汇编编译器的名字不分大小写吗?这里就体现出来了,你只要名字对上就可以,它能找到认出来
光这样还不行,汇编语言的入口实际上是不符合C编译器的命名规则的,所以我们需要在汇编里做些操作,让汇编编译器知道,这个入口是可以被外界使用的,这里就要用到PUBLIC,具体用法是这样的
PUBLIC 标记名



所以最终的代码是这样的
  1. PUBLIC LCDINIT

  2. LCDINIT:
  3. CLR LCD_RW
  4. CLR LCD_EN
  5. MOV R7,#38H
  6. CALL LCDWRCOM
  7. MOV R7,#0CH
  8. CALL LCDWRCOM
  9. MOV R7,#06H
  10. CALL LCDWRCOM
  11. MOV R7,#01H
  12. CALL LCDWRCOM;启动序列,别处抄的

  13. MOV R7,#0FH
  14. LCDFINWAIT:
  15. MOV R6,#0FFH
  16. DJNZ R6,$
  17. DJNZ R7,LCDFINWAIT;LCD需要一段时间准备

  18. RET
复制代码

C语言中

  1. extern void lcdinit();
复制代码

这样,我们就完成了C语言调用汇编
但是对于有传入形参的函数,情况稍微复杂一些,C51传递参数有些不同,它是寄存器传参,参数放置在从R7开始的寄存器,然后才轮得到内存(可以关掉这个选项,但是内存能省则省),如果是一个char,那就R7,两个那就R7和R6,三个那就765,一个int就是R7和R6,以此类推,至于内存传参,你可以看看手册,一般来讲,超过四五个形参的我建议直接传指针进去
其次,汇编语言中的标记的前面必须带有一个下划线,比如ABC要变为_ABC
这里回收上一节埋下的伏笔,实际上内存段的标记也可以public


  1. ?DT?LCDMEM SEGMENT DATA
  2.                 PUBLIC LCDMEM
  3.                 RSEG ?DT?LCDMEM
  4.         LCDMEM:
  5.                 DS 32
复制代码
C语言中是这样的
  1. extern unsigned char LCDMEM[32];
复制代码


好了,C调用汇编已经学会了,我们现在要倒反天罡,让汇编也揩一下C语言的油
这一次,我们直接扒keil一开始给的StartUp.A51里面的例子
从116行开始
  1. ?C_C51STARTUP   SEGMENT   CODE
  2. ?STACK          SEGMENT   IDATA

  3.                 RSEG    ?STACK
  4.                 DS      1

  5.                 EXTRN CODE (?C_START)
  6.                 PUBLIC  ?C_STARTUP

  7.                 CSEG    AT      0
  8. ?C_STARTUP:     LJMP    STARTUP1

  9.                 RSEG    ?C_C51STARTUP
复制代码

好了,那个?C_START就是我们的目标,它就是我们调用C语言的方法(也是STARTUP以后跳转主函数的入口)
EXTRN CODE (函数名)
实际上还能用EXTERN,两者的区别就是EXTERN只能把PUBLIC过的标记薅过来用(顺便一提,变量也可以薅过来用,只需要把CODE改成DATA)
我们这次不写函数给汇编调用,我们在StartUp.A51上搞事情,众所周知,StartUp.A51先于主函数运行,所以它一定会跳转到主函数,我们使个坏把主函数改成mian(我不太确定是不是有副作用,就仅仅整活用吧)
所以我们需要改成
  1. EXTRN CODE (mian)
复制代码

好了,还有最后一步,我们可以在StartUp.A51的尾部看见这个
  1.                 LJMP    ?C_START

  2.                 END
复制代码

把它也改了,然后……
  1. StartUp.A51
  2. ……
  3. EXTRN CODE (mian)
  4. ……
  5. LJMP mian
  6. END

  7. main.c

  8. void mian(){
  9. ……
  10. }
复制代码
顺便一说,提示找不到?C_START也可以用这招

最后,汇编里面调用函数用CALL,这个应该不用多说


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶1 踩
回复

举报

沙发
ID:1138341 发表于 2024-12-2 18:52 | 只看该作者
好资料,51黑有你更精彩!!!
回复

举报

板凳
ID:624769 发表于 2024-12-3 23:33 | 只看该作者
你不要想当然啊……, 传参 3个 char 是 R7,R5,R3, 不是 R7R6R5, 算了,给你个表吧……


最多能通过通用寄存器 传3个参,再多就要用?DT? 声明了。
而这3个参有明确规定,比如 long 只能在 第一,第二位置传,传了long, 就只能再传 指针了。等等一系列的规定。
回复

举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表