keil 函数调用时的参数问题

genelin22 2008-07-08 10:52:53
用keil开发51的程序
写了个函数:
INT16U halSetTimer1Period(INT32U p)
{
。。。。。
}
在调用的时候参数p不能正确的传递,可是我看R4 R5 R6 R7寄存器里面的值明明是传递的那个值。
而当把参数p的类型改成两个字节的INT16U 就能正确传递了,这是什么原因呢?

谢谢指教
...全文
750 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
shuiyan 2008-07-08
  • 打赏
  • 举报
回复
函数体里面引用p的部分都贴出来。
既然用了INT32U,那就传个32位的数看看。然后贴编译后的汇编代码
sherlock_lai 2008-07-08
  • 打赏
  • 举报
回复
不能正确传递是指什么? 比如你 halSetTimer1Period(32) 传进函数里的是什么? 难道不是32?
genelin22 2008-07-08
  • 打赏
  • 举报
回复
可是如果用small
原来的大程序就出错了
UCOS_II.C(27): error C249: 'DATA': SEGMENT TOO LARGE
......
shuiyan 2008-07-08
  • 打赏
  • 举报
回复
就在项目的option里面,有Compact Small Large,默认Compact,按你所说,small就可以了。
genelin22 2008-07-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 shuiyan 的回复:]
溢出了。还有堆栈设置怎么样的?
[/Quote]
恩 应该是你说的这个原因,我建工程的时候很多的都是默认设置(刚开始用keil)
不知堆栈在哪设置,估计就是堆栈设置有问题了
再次感谢
shuiyan 2008-07-08
  • 打赏
  • 举报
回复
溢出了。还有堆栈设置怎么样的?
fouryu 2008-07-08
  • 打赏
  • 举报
回复
Large模式下,默认的内存使用XData段、Small模式下默认的内存使用Data段。

从汇编语言上看你在Large模式下编译器优化产生了一个函数C?LSTXDATA: 用来处理XData参数传递的问题。使用XData的0x0000地址来保存实参。

进入Test函数首先通过C?LSTXDATA:函数将寄存器R4 R5 R6 R7的值拷贝到XData段0x0000开始的4个字节,然后开始计算p++。这个计算过程你看懂了要吐血——把刚才拷贝出去的内容再一个一个拷贝到R4 R5 R6 R7寄存器中,只是最后拷贝到R7之前先做一个加一,后面跟着做进位处理。所有的处理结束之后,再调用C?LSTXDATA:函数将寄存器R4 R5 R6 R7的值拷贝到XData段0x0000开始的4个字节。

整个流程是正确的。

你观察变量的值时要注意内存所处的段。C51是哈佛结构的CPU,这点和PC上的调试不太一样。
genelin22 2008-07-08
  • 打赏
  • 举报
回复
Disassembly里面的代码是这样的
发现p传递的居然是02003590(0x0000 - 0x0003里面的内容)为什么呢?
===================================================================
C:0x0000 020035 LJMP C:0035
4: void test(unsigned long p)
C:0x0003 900000 MOV DPTR,#0x0000
C:0x0006 120041 LCALL C?LSTXDATA(C:0041)
5: {
6: p++;
7:
8: }
9:
C:0x0009 900000 MOV DPTR,#0x0000
C:0x000C E0 MOVX A,@DPTR
C:0x000D FC MOV R4,A
C:0x000E A3 INC DPTR
C:0x000F E0 MOVX A,@DPTR
C:0x0010 FD MOV R5,A
C:0x0011 A3 INC DPTR
C:0x0012 E0 MOVX A,@DPTR
C:0x0013 FE MOV R6,A
C:0x0014 A3 INC DPTR
C:0x0015 E0 MOVX A,@DPTR
C:0x0016 2401 ADD A,#0x01
C:0x0018 FF MOV R7,A
C:0x0019 E4 CLR A
C:0x001A 3E ADDC A,R6
C:0x001B FE MOV R6,A
C:0x001C E4 CLR A
C:0x001D 3D ADDC A,R5
C:0x001E FD MOV R5,A
C:0x001F E4 CLR A
C:0x0020 3C ADDC A,R4
C:0x0021 FC MOV R4,A
C:0x0022 900000 MOV DPTR,#0x0000
C:0x0025 020041 LJMP C?LSTXDATA(C:0041)
10: void main(void)
11: {
12: test(0x1FFFFFFF);
C:0x0028 7FFF MOV R7,#0xFF
C:0x002A 7EFF MOV R6,#0xFF
C:0x002C 7DFF MOV R5,#0xFF
C:0x002E 7C1F MOV R4,#0x1F
C:0x0030 120003 LCALL test(C:0003)
13: while(1);
C:0x0033 80FE SJMP C:0033
C:0x0035 787F MOV R0,#0x7F
C:0x0037 E4 CLR A
C:0x0038 F6 MOV @R0,A
C:0x0039 D8FD DJNZ R0,C:0038
C:0x003B 758107 MOV SP(0x81),#0x07
C:0x003E 020028 LJMP main(C:0028)
C?LSTXDATA:
C:0x0041 EC MOV A,R4
C:0x0042 F0 MOVX @DPTR,A
C:0x0043 A3 INC DPTR
C:0x0044 ED MOV A,R5
C:0x0045 F0 MOVX @DPTR,A
C:0x0046 A3 INC DPTR
C:0x0047 EE MOV A,R6
C:0x0048 F0 MOVX @DPTR,A
C:0x0049 A3 INC DPTR
C:0x004A EF MOV A,R7
C:0x004B F0 MOVX @DPTR,A
C:0x004C 22 RET
genelin22 2008-07-08
  • 打赏
  • 举报
回复
写了个简单的试验程序
void test(unsigned long p)
{
p++;
}

void main(void)
{
test(0x1FFFFFFF);
while(1);
}
采用在线调试工具,memory model = large
结果进入test()中时,p的值不是1fffffff,而是一个很奇怪的的大数。

当改成模拟器调试时,该问题不存在
当改成memory model = small,时,该问题也不存在

以下是汇编代码
-----------------------------------------------------------------
; .\main.SRC generated from: main.c
; COMPILER INVOKED BY:
; C:\Keil\C51\BIN\C51.EXE main.c LARGE BROWSE DEBUG OBJECTEXTEND SRC(.\main.SRC)


NAME MAIN

?PR?_test?MAIN SEGMENT CODE
?XD?_test?MAIN SEGMENT XDATA OVERLAYABLE
?PR?main?MAIN SEGMENT CODE
EXTRN CODE (?C?LSTXDATA)
EXTRN CODE (?C_STARTUP)
PUBLIC main
PUBLIC _test

RSEG ?XD?_test?MAIN
?_test?BYTE:
p?040: DS 4
;
;
;
; void test(unsigned long p)

RSEG ?PR?_test?MAIN
_test:
USING 0
; SOURCE LINE # 4
MOV DPTR,#p?040
LCALL ?C?LSTXDATA
; {
; SOURCE LINE # 5
; p++;
; SOURCE LINE # 6
MOV DPTR,#p?040
MOVX A,@DPTR
MOV R4,A
INC DPTR
MOVX A,@DPTR
MOV R5,A
INC DPTR
MOVX A,@DPTR
MOV R6,A
INC DPTR
MOVX A,@DPTR
ADD A,#01H
MOV R7,A
CLR A
ADDC A,R6
MOV R6,A
CLR A
ADDC A,R5
MOV R5,A
CLR A
ADDC A,R4
MOV R4,A
MOV DPTR,#p?040
LJMP ?C?LSTXDATA
; END OF _test

;
; }
;
; void main(void)

RSEG ?PR?main?MAIN
main:
USING 0
; SOURCE LINE # 10
; {
; SOURCE LINE # 11
; test(0x1FFFFFFF);
; SOURCE LINE # 12
MOV R7,#0FFH
MOV R6,#0FFH
MOV R5,#0FFH
MOV R4,#01FH
LCALL _test
?C0002:
; while(1);
; SOURCE LINE # 13
SJMP ?C0002
; END OF main

END
谢谢指教 :)
1.1 课程内容嵌入式软件工程师的学习路线一般是:单片机、RTOS、Linux。当你掌握单片机开发后,如果要进一步提升编程水平,建议学习RTOS(Real Time Operating System,实操作系统)。有很多优秀的RTOS,比如FreeRTOS、RT-Thread、UCOS等等。FreeRTOS使用范围最广泛,RT-Thread生态丰富,UCOS是收费的并且很少使用了。对于初学者,建议先学习FreeRTOS。只要学会了任意一款RTOS,肯定就会使用其他RTOS了。我们在2022年已经推出了“FreeRTOS快速入门”课程。为何还要重新制作“FreeRTOS入门与工程实践”?“FreeRTOS快速入门”只是讲解FreeRTOS的各类API的理论、用法、示例,这些实验是基于Keil自带的STM32F103模拟器。没有使用更多的硬件模块、不能体现工作中的实际场景。在“FreeRTOS入门与工程实践”,将引入更多的硬件模块,并展示实际工程示例中的用法。另外,基于RTOS的程序一般都比较复杂,涉及的源文件非常多,在工作中一般都基于“面向对象”的思想来写程序。所以,本课程会涉及如下内容:讲解FreeRTOS的常用API:理论、用法选择合适的硬件模块,展示这些API的实例实现合适的小项目,展示工作中的编程方法1.2 讲课方式对于每一个实验,我们会精心设计:要解决什么问题;然后讲解FreeRTOS提供的解决方法。讲解FreeRTOS的API及内部原理(不深入讲解内部源码,只是进行原理性介绍)讲解实验过程使用的模块的接口函数(只讲使用,不讲内部实现,模块的源码实现单独开课讲解)讲解原理,配合着文档、现场画图进行讲解,跟学校老师写黑板一样最后现场从0编写程序并调试一切都是现场操作,绝对不会照着PPT念,绝对不会照着现成的代码讲解。只有现场从0操作,学员才能身临其境地学习,跟着教程:碰到问题、解决问题。1.3 硬件平台本课程基于DshanMCU-103开发套件进行开发,它由3部分组成:STM32F103C8T6的最小系统板、扩展底板、各类模块。如下图所示:  上述硬件再加一个ST-Link即可学完本课程所有内容。主板DshanMCU-103是基于STM32F103C8T6的最小系统板。之所以选择最小系统板,而不是把所有模块都放在一个整体的电路板上,目的如下:低成本尝试:嵌入式软件开发并不一定适合你,可以购买最小系统板进行体验、及放弃按需购买:用到再买,讲究一个性价比 

27,373

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧