历史上的今天
返回首页

历史上的今天

今天是:2025年07月04日(星期五)

正在发生

2020年07月04日 | 用51汇编完整写一个函数

2020-07-04 来源:eefocus

本文将以查表法CRC为例,完整介绍如何用汇编写一个函数,以及如何传入函数参数、获得返回值、被其他函数调用。


最近用汇编写了一个查表法CRC16校验函数,其中遇到很多困难,走了很多弯路,特此记录,请大家共勉。请结合最后的附录代码看前面的解释,会好理解很多。汇编代码基本就是按照C代码一句一句翻译的。


1.汇编函数如何传入参数

需要改写的C函数如下:


u16 Crc16withTable(u8 *buf, u16 seeds, u16 len) 

首先想到的就是怎么传入参数,因为汇编不像C语言一样可以用括号表示形参,那么如何给汇编函数传入参数呢?这涉及到不同芯片架构的规定,C51规定如下:

大家可以在keil4软件中的Help->uVision Help->搜索中搜索Parameter Passing关键字,就会看到这段信息。翻译如下:


C51编译器在CPU寄存器中最多传递三个函数参数。这显著提高了系统性能,因为不需要将参数写入内存并从内存中读取参数。参数传递可以通过REGPARMS和NOREGPARMS控制指令进行控制。下表列出了用于不同参数和数据类型的寄存器。


如果没有寄存器可用来传递参数,或者涉及的参数太多,则为这些额外的参数使用固定的内存位置。


对上表进行解释:


首先,传递的参数不能超过3个,如果超过3个,需要使用外部ram的固定地址存放。

其次,从表中可以看出,传递的参数类型不同,允许传递的参数个数也将发生变化。

最后,不同参数类型对应的寄存器不同。

以本文的函数为例,传入的参数有3个,分别是指向u8的指针buf、2byte大小的seeds、2byte大小的len。

第1个参数对应表的第1行,buf是一个指针,在51中地址是16位,所以buf本质上是2byte 指针,所以寄存器R6和R7分别存放buf的高字节和低字节,可以参考汇编代码第60行和第63行,直接调用R6和R7就是调用buf的高字节和低字节;

第2个参数对应表的第2行,seed也是2byte,所以它占用R4和R5两个寄存器;

第3个参数对应表的第3行,len也是2byte,所以它占用R2和R3两个寄存器。

当你在调用这个函数时,给函数传入实参,然后程序就会跳转到汇编代码一行一行执行,这时候你传入的实参就已经在寄存器中了,至于各寄存器里面放哪个参数的值,上一段已经讲的很清楚了。


2.汇编函数如何返回结果

有的函数执行完后需要返回结果,这个结果可能是1byte,也可能是2byte,也可能是4byte。但是汇编不像C语言函数直接用return就可以,与第1章所述一样,汇编函数的返回值也是放在寄存器中的。如本文汇编函数最后4行,是将计算结果放在了R6和R7两个寄存器中。那么在执行完函数返回到C语言中时,芯片自动将R6和R7中的值取出,作为返回值返回。


这里只是知道2byte返回值放在R6和R7寄存器中,但是不知道1byte和4byte时应该放在哪个寄存器,也没有找到资料。大家实际用的时候可以试一下,看放在哪个寄存器里可以返回正确值。


3.汇编函数如何在C语言中被调用

我自己的方法是:


将需要用汇编写的函数单独新建一个.asm文件,然后在这个里面写汇编函数;

写汇编函数时需要特别注意:如果有参数,需要在函数名前加“_”,表示这个函数时带参数的,参考本文汇编代码第1行;

汇编函数最后一定加“END”,参考本文汇编代码最后1行;

在调用这个函数的地方,先用“extern”声明一下这个函数,声明就能直接用C语言函数的格式就行,如下:

extern u16 Crc16withTable(u8 *buf, u16 seeds, u16 len); 

最后将这个.asm文件添加到工程即可。

 

附录A:查表法crc校验C代码:

/*****************************************************************************

*function name:Crc16withTable

*function: 用查表法计算CRC

*input:  addr:字符串起始地址;len :字符串长度;crcHighTable,crcLowTable:用到的表格

*output:无

******************************************************************************/

u16 Crc16withTable(u8 *buf, u16 seeds, u16 len)  

{  

    u8 crcHi = 0x00;

    u8 crcLo = 0x00;

    u8 index;

    u16 crc;

    u16 i;

    for (i=0;i    {  

        index = crcLo ^ *(buf+i+1);//低8位异或,得到表格索引值

        crcLo = crcHi ^ crcHighTable[index];

        crcHi = crcLowTable[index];

 

        index = crcLo ^ *(buf+i);//低8位异或,得到表格索引值

        crcLo = crcHi ^ crcHighTable[index];

        crcHi = crcLowTable[index]; 

    }

    crc = (u16)(crcHi<<8 | crcLo);

    return crc;

}

 


附录B:查表法crc校验汇编代码:

PUBLIC _Crc16withTable ;函数名前加"_",表示此函数带参数

;u16 Crc16withTable(u8 *buf, u16 seeds, u16 len)

?PR?__Crc16withTable SEGMENT CODE

RSEG ?PR?_Crc16withTable

CRC16HighTable: DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H

DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H

CRC16LowTable: DB 00H,  0c0H,0c1H, 01H,0c3H, 03H, 02H,0c2H,0c6H, 06H, 07H,0c7H, 05H,0c5H,0c4H, 04H

DB 0ccH, 0cH, 0dH,0cdH, 0fH,0cfH,0ceH, 0eH, 0aH,0caH,0cbH, 0bH,0c9H, 09H, 08H,0c8H

DB 0d8H, 18H, 19H,0d9H, 1bH,0dbH,0daH, 1aH, 1eH,0deH,0dfH, 1fH,0ddH, 1dH, 1cH,0dcH

DB 14H,  0d4H,0d5H, 15H,0d7H, 17H, 16H,0d6H,0d2H, 12H, 13H,0d3H, 11H,0d1H,0d0H, 10H

DB 0f0H, 30H, 31H,0f1H, 33H,0f3H,0f2H, 32H, 36H,0f6H,0f7H, 37H,0f5H, 35H, 34H,0f4H

DB 3cH,  0fcH,0fdH, 3dH,0ffH, 3fH, 3eH,0feH,0faH, 3aH, 3bH,0fbH, 39H,0f9H,0f8H, 38H

DB 28H,  0e8H,0e9H, 29H,0ebH, 2bH, 2aH,0eaH,0eeH, 2eH, 2fH,0efH, 2dH,0edH,0ecH, 2cH

DB 0e4H, 24H, 25H,0e5H, 27H,0e7H,0e6H, 26H, 22H,0e2H,0e3H, 23H,0e1H, 21H, 20H,0e0H

DB 0a0H, 60H, 61H,0a1H, 63H,0a3H,0a2H, 62H, 66H,0a6H,0a7H, 67H,0a5H, 65H, 64H,0a4H

DB 6cH,  0acH,0adH, 6dH,0afH, 6fH, 6eH,0aeH,0aaH, 6aH, 6bH,0abH, 69H,0a9H,0a8H, 68H

DB 78H,  0b8H,0b9H, 79H,0bbH, 7bH, 7aH,0baH,0beH, 7eH, 7fH,0bfH, 7dH,0bdH,0bcH, 7cH

DB 0b4H, 74H, 75H,0b5H, 77H,0b7H,0b6H, 76H, 72H,0b2H,0b3H, 73H,0b1H, 71H, 70H,0b0H

DB 50H,  90H, 91H, 51H, 93H, 53H, 52H, 92H, 96H, 56H, 57H, 97H, 55H, 95H, 94H, 54H

DB 9cH,  5cH, 5dH, 9dH, 5fH, 9fH, 9eH, 5eH, 5aH, 9aH, 9bH, 5bH, 99H, 59H, 58H, 98H

DB 88H,  48H, 49H, 89H, 4bH, 8bH, 8aH, 4aH, 4eH, 8eH, 8fH, 4fH, 8dH, 4dH, 4cH, 8cH

DB 44H,  84H, 85H, 45H, 87H, 47H, 46H, 86H, 82H, 42H, 43H, 83H, 41H, 81H, 80H, 40H

_Crc16withTable:

;R6放addr高字节

;R7放addr低字节

;R4放seeds高字节,即crcHi

;R5放seeds低字节,即crcLo

;R2放len高字节

;R3放len低字节

 

MOV     R0,#0x00 ;R0放i高字节

MOV     R1,#0x00 ;R1放i低字节

BEGINLOOP:

CRL     C ;清除结借位(进位)标志位

MOV     A,R1

SUBB    A,R3

MOV     A,R0

SUBB    A,R2

JNC     ENDLOOP

;index=crcLo^*(buf+i+1)

MOV A,R7 ;buf低字节->A

ADD A,R1 ;buf低字节+i低字节

MOV DPL,A ;低字节之和->PDL

MOV A,R6 ;buf高字节->A

ADDC A,R0 ;buf高字节+i高字节

MOV DPH,A ;高字节之和->DPH

MOV A,#0x01

MOVC A,@A+DPTR ;*(buf+i+1)

XRL A,R5 ;A=index=*(buf+i+1)^crcLo

MOV B,A ;B=index

;crcLo=crcHi^CRCHighTable[index]

MOV DPTR,#CRC16HighTable;获取表的首地址

MOVC A,@A+DPTR ;CRCHighTable[index]

XRL A,R4 ;CRCHighTable[index]^crcHi

MOV R5,A ;crcLo=A,更新crcLo的值

;crcHi=CRC16LowTable[index]

MOV A,B ;index->A

MOV DPTR,#CRC16LowTable ;获取表的首地址

MOVC A,@A+DPTR ;A=CRC16LowTable[index]

MOV R4,A ;crcHi=A,更新crcHi的值

;第2次循环

;index=crcLo^*(buf+i)

MOV A,R7 ;buf低字节->A

CLR C

ADD A,R1 ;buf低字节+i低字节

MOV DPL,A ;低字节之和->PDL

MOV A,R6 ;buf高字节->A

ADDC A,R0 ;buf高字节+i高字节

MOV DPH,A ;高字节之和->DPH

CLR A

MOVC A,@A+DPTR ;*(buf+i)

XRL A,R5 ;A=index=*(buf+i)^crcLo

MOV B,A ;B=index

;crcLo=crcHi^CRCHighTable[index]

MOV DPTR,#CRC16HighTable;获取表的首地址

MOVC A,@A+DPTR ;CRCHighTable[index]

XRL A,R4 ;CRCHighTable[index]^crcHi

MOV R5,A ;crcLo=A,更新crcLo的值

;crcHi=CRC16LowTable[index]

MOV A,B ;index->A

MOV DPTR,#CRC16LowTable ;获取表的首地址

MOVC A,@A+DPTR ;A=CRC16LowTable[index]

MOV R4,A ;crcHi=A,更新crcHi的值

;i=i+2

MOV A,#0x02

CLR C

ADD A,R1

MOV R1,A ;更新i低字节

CLR A

ADDC A,R0 ;

MOV R0,A ;更新i高字节

LJMP BEGINLOOP ;无条件跳转至循环开始部分

ENDLOOP:

MOV A,R4 ;

MOV R6,A

MOV A,R5

MOV R7,A

RET

END

推荐阅读

史海拾趣

Bharat Electronics Ltd公司的发展小趣事

随着市场的不断变化和竞争的加剧,BEL并未满足于现状,而是积极寻求多元化发展。公司不仅拓展了原有的军事电子领域,还涉足电信、运算、公共运输和广播等多个行业。同时,BEL还积极拓展全球市场,将产品出口到多个国家和地区,实现了从区域性企业向全球性企业的跨越。

Aristo-Craft/ L M P Inc公司的发展小趣事

Aristo-Craft/L M P Inc公司最初由几位电子工程领域的专家创立,他们看到了电子行业的巨大潜力,并决定成立一家公司来开发和生产创新的电子产品。创业初期,公司面临着资金短缺、市场竞争激烈等挑战。然而,通过不懈的努力和精准的市场定位,公司成功推出了一款具有竞争力的产品,并逐渐在市场中获得了一席之地。

American Electric公司的发展小趣事

随着全球化进程的加速,American Electric公司开始实施国际化战略。公司积极拓展海外市场,与多个国家的电力企业建立合作关系,共同开展电力项目。同时,公司还在海外设立了多个分支机构,以便更好地服务当地客户。这些举措不仅提高了公司的国际影响力,还为公司的长期发展奠定了坚实的基础。

BH Electronics公司的发展小趣事

近年来,随着环保意识的提高,BH Electronics积极响应国家绿色发展的号召,开始了绿色转型之路。公司加大了对环保技术的研发和应用力度,推出了一系列绿色环保产品。同时,BH Electronics还优化了生产流程,减少了能源消耗和废物排放。这些举措不仅提升了公司的环保形象,也为公司的可持续发展注入了新的动力。

这五个故事只是BH Electronics发展历程中的一部分,但它们却生动地展现了这家公司在电子行业中的崛起之路。从初创时期的筚路蓝缕,到技术创新的突破;从国际化战略的拓展,到品质管理的提升;再到绿色发展的转型,BH Electronics始终保持着敏锐的市场洞察力和不懈的创新精神。正是这些因素的共同作用,使得BH Electronics能够在激烈的市场竞争中脱颖而出,成为电子行业中的佼佼者。

Eagle-Picher公司的发展小趣事

进入21世纪后,Eagle-Picher公司迎来了新的发展机遇。2017年,OMGroup斥资1.7亿美元收购了Eagle-Picher公司,这一举措为Eagle-Picher注入了新的资金和资源。在新的资本支持下,Eagle-Picher加大了在电池技术领域的研发投入,不断推出新的产品和解决方案。同时,公司也积极拓展国际市场,与全球多家知名企业建立了合作关系。这些新的发展机遇为Eagle-Picher的未来发展奠定了坚实的基础。

Connection One公司的发展小趣事

随着技术的不断成熟,Connection One公司开始寻求与其他企业的战略合作。通过与全球知名的电子设备制造商合作,公司的芯片产品得以广泛应用于各类电子设备中。这种合作不仅拓展了公司的市场份额,还提升了其品牌知名度。

问答坊 | AI 解惑

電解電容爆裂!

請教各位 電解電容爆裂,除了受高壓導致,還有其他什麽因素會導致? 另外電解電容得頂部有“人”或”+“的凹槽樣,是有什麽作用的? 謝謝…

查看全部问答>

WIFE不能记住登录过的网络和密码

我现在的WIFE登录后,重新开机发现不能记住上次我成功登录的网络,密码也不会记,用户使用起来很麻烦。 我也看到别人的机器上能够保存,我找了一下,好象是在PUBLIC下面的NETUI里面实现的,不知道哪位仁兄做过,赐教一下 或是微软有更新过这里, ...…

查看全部问答>

[在线讨论]wince下能否支持JavaScript?

如题,var myTextField=document.getElementById(\"myText\"); 这个没法实现。要是能实现该如何做? 看了yudong54的回帖(http://topic.eeworld.net/u/20091116/14/1b2cc357-3aea-4329-b527-ab7828142f8f.html?26416)说要打08年的补丁和09年一月 ...…

查看全部问答>

移植人脸识别程序到ARM处理器

本人有人脸识别的源代码,需要移植到ARM处理器,希望能够找到人脸识别方面的朋友共同讨论切磋技术问题。…

查看全部问答>

VxWorks下的打印机并口问题

大家好. 我碰到了一个vxworks中打印机方面的问题.我的目标机是pc486, TornadoV2.02, 24针老式打印机EPSON LQ-1600K,用telnet 进行连接调试.BUILD中包含了并口组件.现在我想要让打印机打出一些测试文字,然后我写了一小段代码 ******************** ...…

查看全部问答>

学习心得:PWM模块的学习和使用

最近在使用TI的stellaris的芯片,项目主要用来做系统的控制模块,M3的外设基本都用到了,后面一点点总结各个模块简单的用法,并附上之前搜集和学习的资料,方便大家学习特别适合新手的入门学习,共同进步吧,感觉自己也还属于菜鸟级的呢,同时也感 ...…

查看全部问答>

STM32接光纤模块构建以太网,官方参考电路板的PHY片子DP83848CVV可以接光纤模块吗?

我用的方案是STM32F107+DP83848CVV+OCM2521,DP83848是官方的电路图使用的PHY,但是官方的电路图接的是RJ45电口,我想用DP83848CVV接光纤模块,光纤模块用的是OCM2521多模光纤,但是现在一直无法连通,光纤链路的灯都不亮。 我阅读了DP83848CVV的 ...…

查看全部问答>

谁能给个链接先

小弟目前刚接触zigbee,在编程方面缺个freescale cyclone pro的仿真烧录器,想学学这个软件 望大家给力支持下 有下载地址的可以发我邮箱weiqifan2009@sina.com  不胜感激!!!…

查看全部问答>

我收到了文化衫是不是EEWORLD的缘故呀?

今天我父亲来的时候门卫给我父亲的,晕,昨天好像看到过我呀,也不知道快递什么时候送到学校的。大概也因为手机号码还是我的旧号码,这两天也忘了开了,我的论坛资料早就更新过新号码了呀(被移动公司一气,愤而改用联通的了,移动的号码由于为了贪 ...…

查看全部问答>