找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9564|回復: 91
收起左側(cè)

請教各位大神一個匯編語言堆棧大小計算的問題

[復制鏈接]
ID:227818 發(fā)表于 2022-7-12 06:34 | 顯示全部樓層 |閱讀模式
我有一個主程序A(是51單片機的匯編),在STC 8H上跑,這個主程序A調(diào)用了子程序A1,A1又調(diào)用了A2,A2又調(diào)用了A3,即A->A1->A2->A3。中斷用了5個,可以定義成中斷B,C,D,E,F(xiàn)。其中中斷B,C是高級中斷,D,E,F(xiàn)是低級中斷。所有中斷中都是PUSH ACC,PUSH PSW,沒有再PUSH其他寄存器,出中斷時POP PSW ,POP ACC。中斷B中,調(diào)用了子程序B1,B1又調(diào)用了B2即B-B1->B2。C中斷中沒有調(diào)用其他子程序。D中斷中調(diào)用了子程序D1,D1又調(diào)用了D2,即D->D1-D2。E中斷中調(diào)用了子程序E1,E1又調(diào)用了E2,E2又調(diào)用了E3,即E->E1->E2-E3。所有子程序都是簡單的對單片機的端口進行操作,即置高或低,子程序沒有用堆棧傳遞參數(shù)。按照我的理解,考慮一個最復雜的情況,主程序在調(diào)用A3時,堆棧用了6個字節(jié),這時發(fā)生E中斷,E中斷在調(diào)用E3時,堆棧用了8個字節(jié),這是發(fā)生B中斷,在B中斷調(diào)用B2時,堆棧用了6個字節(jié),這樣堆棧最多用20個字節(jié)就可以了,但在實際情況中,單片機不時會死機.這個程序原先不是我寫的,我不過做了一點修改,即在中斷E中加了一個子程序E3。以前堆棧留的比較小,只有20個字節(jié),后來我又找了幾個加上了,但還是不大,F(xiàn)在我懷疑是堆棧溢出了,請問我堆棧大小的計算對嗎?衷心感謝
回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-12 12:03 | 顯示全部樓層
1.51的任何子程序都需要通過堆棧傳遞PC值,最少2字節(jié)。
2.51的中斷子程序通過堆棧傳遞PC、ACC、PSW ,最少4字節(jié)。
3.中斷內(nèi)部調(diào)用子程序算情形1,最少2字節(jié)。

你的代碼有2級中斷調(diào)用,情形1調(diào)用算6級,所以最少20字節(jié)(2*4+6*2)。
但上述是最理想的情況。我們一般按10級情形1算,但情形1算5字節(jié),預留50字節(jié)堆棧。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:401564 發(fā)表于 2022-7-12 12:26 | 顯示全部樓層
8051是軟件堆棧,如果不是刻意去填滿它,堆棧基本上是不會有問題的
卡死的問題不一定是堆棧的問題,可能是中斷太多,而且中斷觸發(fā)間隔時間太短
比如說:
1,ADC中你調(diào)用了某個子程序,ADC執(zhí)行的總時長是5mS,ADC中斷你又設(shè)定成最高優(yōu)先等級,而ADC中斷間隔是1mS
2,定時器中斷是2mS的
那么,這個程序就一直在ADC和定時器之間運行了,主程序基本是不會執(zhí)行的

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 14:21 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-12 12:03
1.51的任何子程序都需要通過堆棧傳遞PC值,最少2字節(jié)。
2.51的中斷子程序通過堆棧傳遞PC、ACC、PSW ,最少 ...

謝謝您的回復,我算的是最多需要20字節(jié),您算的最少需要20字節(jié)
我是這樣理解的同為高級的2個中斷B,C,同一時刻只能有一個中斷響應(yīng),C中斷響應(yīng),堆棧占用2個字節(jié),B中斷響應(yīng),最多占用6個字節(jié),所以按B中斷記,D,E,F三個低級中斷,它們?nèi)齻同一時刻只有1個被CPU響應(yīng),主貼中忘記說了,F(xiàn)中斷內(nèi)沒有子程序,按子程序調(diào)用最深的E中斷算,低級中斷最多需要8個字節(jié),主程序中子程序調(diào)用最多需要6個字節(jié),這樣需要20個字節(jié)就可以了。按照您的計算,我肯定是哪里理解錯了,錯在那里,麻煩您再說一下,我在這方面是半路出家,有些方面理解不透,謝謝。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 14:28 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-12 12:26
8051是軟件堆棧,如果不是刻意去填滿它,堆;旧鲜遣粫袉栴}的
卡死的問題不一定是堆棧的問題,可能是中 ...

謝謝您的回復,我明白了您的意思,您是說,中斷觸發(fā)間隔的時間短,而中斷本身執(zhí)行的時間長,結(jié)果就是CPU在中斷之間運行,一個中斷執(zhí)行完,馬上又去響應(yīng)另一個中斷,然后又去響應(yīng)前一個中斷,沒有時間去執(zhí)行主程序,我按您的思路拿示波器跟蹤下,看看每一個中斷需要多少時間。
回復

使用道具 舉報

ID:1006814 發(fā)表于 2022-7-12 15:00 | 顯示全部樓層
每次中斷,自動入棧一個PC寄存器,具體幾個字節(jié)我忘了,然后中斷返回的時候再自動出棧,樓主沒考慮這個,所以可能會亂。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 15:24 | 顯示全部樓層
hb_lhw 發(fā)表于 2022-7-12 15:00
每次中斷,自動入棧一個PC寄存器,具體幾個字節(jié)我忘了,然后中斷返回的時候再自動出棧,樓主沒考慮這個,所 ...

您說的應(yīng)該是程序寄存器,也就是PC寄存器,它是16位的,占用2個字節(jié),按說我已經(jīng)考慮到了。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 15:27 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-12 12:03
1.51的任何子程序都需要通過堆棧傳遞PC值,最少2字節(jié)。
2.51的中斷子程序通過堆棧傳遞PC、ACC、PSW ,最少 ...

我剛才又想到,是不是中斷嵌套時,堆棧需要消耗更多的字節(jié)?中斷嵌套時堆棧消耗的字節(jié)是怎樣計算的?
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 15:44 | 顯示全部樓層
本帖最后由 newlined 于 2022-7-12 15:47 編輯
Y_G_G 發(fā)表于 2022-7-12 12:26
8051是軟件堆棧,如果不是刻意去填滿它,堆;旧鲜遣粫袉栴}的
卡死的問題不一定是堆棧的問題,可能是中 ...

您好,我剛才拿示波器跟蹤了一下,一共5個中斷,2個中斷是1毫秒一次,一個外部中斷是20毫秒到100毫秒一次,這3個1個請問-中斷的時間在5微妙到10微妙之間,應(yīng)該沒有問題。還有一個是30毫秒1次,執(zhí)行時間是10微秒,也沒有問題,執(zhí)行時間比較長的是一個掉電中斷,是高級中斷,執(zhí)行時間10毫秒,這個中斷執(zhí)行完就不再執(zhí)行其他語句了,單片機就等著掉電了。按說也不影響主程序的運行
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-12 16:25 | 顯示全部樓層
是不是堆棧大小的問題, 用KEIL 編譯后,仿真一下,看一下 SP_max 就知道了。有什么好算得?

我現(xiàn)在好奇的是,你確定是堆棧問題? 你那么多中斷 你居然   都是只 PUSH ACC 和 PSW 的? 你不用 R0~R7 的? 不用 B 的?  不用 DPTR 的? 這些只要有一個,你該PUSH 的沒有PUSH 都會有可能造成發(fā)生過 中斷后,程序出現(xiàn)錯誤,最終跑飛。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:401564 發(fā)表于 2022-7-12 16:56 | 顯示全部樓層
newlined 發(fā)表于 2022-7-12 14:28
謝謝您的回復,我明白了您的意思,您是說,中斷觸發(fā)間隔的時間短,而中斷本身執(zhí)行的時間長,結(jié)果就是CPU ...

大概就是這么個意思了
也就是說程序是在中斷之間來回跑的
主程序幾乎沒有執(zhí)行的時間
為什么要在中斷中執(zhí)行那么多功能呢?能不能放在主程序執(zhí)行呢?
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 17:03 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-12 16:56
大概就是這么個意思了
也就是說程序是在中斷之間來回跑的
主程序幾乎沒有執(zhí)行的時間

這個程序是20年前別人編寫的,我現(xiàn)在接手維護,整個程序還沒有吃透。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 17:13 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-12 16:56
大概就是這么個意思了
也就是說程序是在中斷之間來回跑的
主程序幾乎沒有執(zhí)行的時間

大約1小時前回復過,不知道回帖為什么沒有了。今天下午我拿示波器跟蹤了各個中斷的執(zhí)行時間,有2個是1毫秒1次的中斷,執(zhí)行時間在10微妙左右,1個是30毫秒的中斷,執(zhí)行時間是10微妙多一點,一個外部中斷,20毫秒到100毫秒一次,執(zhí)行時間在8微妙左右,應(yīng)該都可以,不會引起主程序執(zhí)行時間的不足,一個掉電中斷,是高級中斷,執(zhí)行時間10毫秒,這個按說也不影響主程序的運行,因為這個中斷執(zhí)行完,就等著掉電了,不再執(zhí)行其他語句了。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-12 17:18 | 顯示全部樓層
188610329 發(fā)表于 2022-7-12 16:25
是不是堆棧大小的問題, 用KEIL 編譯后,仿真一下,看一下 SP_max 就知道了。有什么好算得?

我現(xiàn)在好奇 ...

這個程序是20年前別人寫的,我接手維護,小改下,不好動架構(gòu)。
回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-12 17:23 | 顯示全部樓層
newlined 發(fā)表于 2022-7-12 14:21
謝謝您的回復,我算的是最多需要20字節(jié),您算的最少需要20字節(jié)
我是這樣理解的同為高級的2個中斷B ...
考慮一個最復雜的情況,主程序在調(diào)用A3時,堆棧用了6個字節(jié),這時發(fā)生E中斷,E中斷在調(diào)用E3時,堆棧用了8個字節(jié),這是發(fā)生B中斷,在B中斷調(diào)用B2時,堆棧用了6個字節(jié),這樣堆棧最多用20個字節(jié)就可以了

A到A3,是函數(shù)調(diào)用3級,最少6字節(jié)。
E中斷,是中斷函數(shù)調(diào)用,最少4字節(jié)。
E到E3,是函數(shù)調(diào)用3級,最少6字節(jié)。
B中斷,是中斷函數(shù)調(diào)用,最少4字節(jié)。
B到B2,是函數(shù)調(diào)用2級,最少4字節(jié)。
最少24字節(jié)。

不需要按上述計算,堆棧就是按函數(shù)調(diào)用深度和中斷函數(shù)調(diào)用深度估算。
函數(shù)調(diào)用深度8級,最少占用16(2*8)字節(jié)。
中斷函數(shù)調(diào)用深度2級,最少占用8(4*2)字節(jié)。
我提到的3點原則只考慮了PCH PCL ACC PSW的保存、恢復,是最低要求的情形。有些應(yīng)用還要考慮DPTR、B、R0~R7的保存、恢復,所以堆棧需求會明顯大于24個字節(jié)。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-12 17:35 | 顯示全部樓層
C51中斷中使用函數(shù)是很不好的習慣。
你把中斷中的函數(shù)改成不是函數(shù),以代碼空間換時間和RAM。
應(yīng)該能解決問題。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:401564 發(fā)表于 2022-7-12 18:20 | 顯示全部樓層
newlined 發(fā)表于 2022-7-12 17:13
大約1小時前回復過,不知道回帖為什么沒有了。今天下午我拿示波器跟蹤了各個中斷的執(zhí)行時間,有2個是1毫 ...

所謂"死機"和中斷無法跳出,這不過是推測而已,說不定可能就是其它的小問題而已
匯編是很容易出問題的
如果說是以前的代碼是可以量產(chǎn)的,就說明以前的代碼是沒有問題的
重點看你的代碼會影響到哪些
如果不是什么商業(yè)機密,就把完整代碼上傳,大家一看就知道了
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-13 13:32 | 顯示全部樓層
188610329 發(fā)表于 2022-7-12 16:25
是不是堆棧大小的問題, 用KEIL 編譯后,仿真一下,看一下 SP_max 就知道了。有什么好算得?

我現(xiàn)在好奇 ...

您好,以前的程序就是沒有對DPTR保護。看了您的發(fā)言后,我看了下程序,里邊的確用了DPTR,不知道為什么程序還可以運行。工作寄存器的4個區(qū),有1個區(qū)是2個低級中斷公用的,這2個中斷不會同時響應(yīng),只用了R0和R1,每次用之前,都要先賦值,訪問間接尋址的空間,所以不會沖突。B寄存器也用了,不知道為什么沒有保護。這個程序大幾千行,沒有文字的介紹資料,注釋也很少,估計不止一人維護過.我還遠沒有吃透.
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-13 13:44 | 顯示全部樓層
newlined 發(fā)表于 2022-7-13 13:32
您好,以前的程序就是沒有對DPTR保護?戳四陌l(fā)言后,我看了下程序,里邊的確用了DPTR,不知道為什么程 ...

程序沒吃透的前提下, 最不變應(yīng)萬變的做法,就是中斷里用了了什么, 進入中斷前就 PUSH什么, 出中斷前 POP什么, 這是最笨,但也是最穩(wěn)妥的辦法。 等到吃透之后,可以選擇性的 PUSH 和 POP

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-13 13:47 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-12 17:35
C51中斷中使用函數(shù)是很不好的習慣。
你把中斷中的函數(shù)改成不是函數(shù),以代碼空間換時間和RAM。
應(yīng)該能解決 ...

您好,您這一說,我意識到一個問題,函數(shù)重入,這個程序編譯時曾經(jīng)出過這個警告,后來我把一個函數(shù)復制了一份,另起了一個名字,供不同的子程序還是中斷調(diào)用,現(xiàn)在是不是還有這個問題?在keil c中也不能這么用嗎?
回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-13 15:12 | 顯示全部樓層
newlined 發(fā)表于 2022-7-13 13:47
您好,您這一說,我意識到一個問題,函數(shù)重入,這個程序編譯時曾經(jīng)出過這個警告,后來我把一個函數(shù)復制了 ...

一般的C51函數(shù)是不支持再入的。
一個函數(shù)復制了一份,另起了一個名字

可以這樣解決(這個函數(shù)內(nèi)部不能有函數(shù)),但你必須確保業(yè)務(wù)邏輯不會有問題。

中斷調(diào)用的函數(shù)一般只被中斷調(diào)用,所以沒有必要寫成函數(shù)。

評分

參與人數(shù) 1黑幣 +15 收起 理由
newlined + 15

查看全部評分

回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-13 15:42 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-12 17:35
C51中斷中使用函數(shù)是很不好的習慣。
你把中斷中的函數(shù)改成不是函數(shù),以代碼空間換時間和RAM。
應(yīng)該能解決 ...

您說的對,開始我并沒有理解您的意思,剛才看中斷中的函數(shù),我想到,假設(shè)在中斷中,我使用了R0,然后調(diào)用函數(shù),在函數(shù)中我又使用了R0,從函數(shù)返回后,R0的值肯定變了.好在我用R0都是用來訪問間接尋址的地址,隨用隨賦值,要是用R0保存某個數(shù)據(jù)的話,調(diào)用函數(shù)前,可不可以PUSH到堆棧,調(diào)用函數(shù)后再POP?
回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-13 15:52 | 顯示全部樓層
newlined 發(fā)表于 2022-7-13 15:42
您說的對,開始我并沒有理解您的意思,剛才看中斷中的函數(shù),我想到,假設(shè)在中斷中,我使用了R0,然后調(diào)用 ...

當然可以。但這又會增加堆棧需求。
匯編代碼要自己考慮如何保護現(xiàn)場,恢復現(xiàn)場。

C51編譯器能根據(jù)上下文,自動做好保護現(xiàn)場,恢復現(xiàn)場。
好在我用R0都是用來訪問間接尋址的地址,隨用隨賦值

你這種做法沒有用。這個操作不是原子操作,中斷會發(fā)生在操作中間,發(fā)生中斷后,不能恢復現(xiàn)場。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-13 16:11 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-13 15:52
當然可以。但這又會增加堆棧需求。
匯編代碼要自己考慮如何保護現(xiàn)場,恢復現(xiàn)場。

您是說中斷自己不能恢復現(xiàn)場,需要人為的PUSH,POP來恢復現(xiàn)場?而函數(shù)調(diào)用,C51的編譯器可以調(diào)用函數(shù)時,用堆棧保存PC的值,調(diào)用完,函數(shù)執(zhí)行到RET,PC的值自動恢復,其他寄存器的值也自動恢復?
回復

使用道具 舉報

ID:887371 發(fā)表于 2022-7-13 17:12 | 顯示全部樓層
newlined 發(fā)表于 2022-7-13 16:11
您是說中斷自己不能恢復現(xiàn)場,需要人為的PUSH,POP來恢復現(xiàn)場?而函數(shù)調(diào)用,C51的編譯器可以調(diào)用函數(shù)時, ...

只有PC值能自動恢復,其它值得恢復要靠軟件操作。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-13 17:22 | 顯示全部樓層
是這樣,明天我仿真下,再仔細領(lǐng)會您的意思。
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-13 18:22 | 顯示全部樓層
newlined 發(fā)表于 2022-7-13 16:11
您是說中斷自己不能恢復現(xiàn)場,需要人為的PUSH,POP來恢復現(xiàn)場?而函數(shù)調(diào)用,C51的編譯器可以調(diào)用函數(shù)時, ...

你是不是理解 混了?
你如果寫匯編的話, 是不用C51 編譯器, 用A51 編譯器的。
C51 的話, 函數(shù)是可以做成重入函數(shù)的, (即便他編譯報了有重入風險)。
而 A51 的話,你只要用好了 PUSH POP 函數(shù)也可以做成  重入的。比如: 被調(diào)用函數(shù),用到 R0, 你只要函數(shù)入口 PUSH AR0, 出口 POP AR0  那么,這個函數(shù),你中斷調(diào)用了,一樣現(xiàn)場會被保護。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-14 08:26 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-12 18:20
所謂"死機"和中斷無法跳出,這不過是推測而已,說不定可能就是其它的小問題而已
匯編是很容易出問題的
如 ...

您好,這個可能不方便貼出,隨說是20年的程序,但老板交代過。
經(jīng) 188610329大神提醒,我DPTR沒有保護造成的,但這個寄存器以前就沒有保護,可能是我修改了程序,不保護不行了。匯編是很麻煩,要面面俱到。、z*cx您好,這個可能不方便貼出,隨說是20年的程序,但老板交代過。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-14 08:39 | 顯示全部樓層
您好,是這樣,程序是匯編的,擴展名是ASM,但是在KEIL C下編譯的,我注意到一個問題,在KEIL C下新建一個匯編工程,它的擴展名是A51,我懷疑這個程序最開始不是在KEIL C下編譯的,后來轉(zhuǎn)到KEIL C下,KEIL C內(nèi)部是不是有A51的編譯器?
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-14 08:45 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-12 18:20
所謂"死機"和中斷無法跳出,這不過是推測而已,說不定可能就是其它的小問題而已
匯編是很容易出問題的
如 ...

您好,剛才回復過,提交時不小心按錯了鍵,出現(xiàn)了亂碼,可能審核不通過。
這個程序,雖說是20年前的了,但老板有交代,不方便貼出。
經(jīng)188610329 大神提醒,我懷疑是DPTR沒有保護造成的,我補充了一些代碼,可能是不保護不行了。
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-14 09:57 | 顯示全部樓層
datouyuan 發(fā)表于 2022-7-13 17:12
只有PC值能自動恢復,其它值得恢復要靠軟件操作。

剛才仿真了下,只看的R0,在中斷下,給它賦一個值,比如說5,然后調(diào)用一個函數(shù),在函數(shù)中對R0修改為8,函數(shù)執(zhí)行完后,再返回調(diào)用它的那個中斷,發(fā)現(xiàn)R0的值還是8,看來在中斷中使用函數(shù)真不是一個好的習慣。
回復

使用道具 舉報

ID:883242 發(fā)表于 2022-7-14 19:44 | 顯示全部樓層
你的軟件用到了idata了嗎?
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-14 19:55 | 顯示全部樓層
newlined 發(fā)表于 2022-7-14 08:39
您好,是這樣,程序是匯編的,擴展名是ASM,但是在KEIL C下編譯的,我注意到一個問題,在KEIL C下新建一個 ...

KEIL 就是編譯器,
KEIL C51 是在KEIL 下的 51單片機 用的C語言
KEIL A51 是在KEIL 下的 51單片機 用的A語言
你既然是 用的匯編,后綴還是 ASM 就肯定是用的 A51 編譯,怎么可能用 C51編譯?
兩者編譯方式完全不一樣, KEIL中的提示也不一樣,一個是: compiling xxxxxxx.C...  一個是:assembling xxxxxxx.ASM...
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-14 20:06 | 顯示全部樓層
newlined 發(fā)表于 2022-7-14 09:57
剛才仿真了下,只看的R0,在中斷下,給它賦一個值,比如說5,然后調(diào)用一個函數(shù),在函數(shù)中對R0修改為8,函 ...

如果,你進入中斷,用的是不同的寄存器組, 那么,你對 R0 的操作,是不會影響 主程序的 R0的,因為,此 R0 不是 彼R0,  相對于這個問題,我反而覺得,你應(yīng)該是 對某些寄存器的 現(xiàn)場保護沒有做好。你新加的內(nèi)容才是關(guān)鍵。
而且,你說的部分內(nèi)容,我覺得非常困惑,“以前堆棧留的比較小,只有20個字節(jié),后來我又找了幾個加上了,但還是不大! 你這個  只有20字節(jié)是什么來的? 又找了幾個加上 是怎么加的? 正常情況下, 一般分配完內(nèi)存地址后, 我們就在  內(nèi)存末尾 打上 Stack,作為堆棧的起點,賦值給SP, 假定SP 為 80H, 那么 從80H 往后 到 0FFH 相當于都是 堆棧用的。 所以不存在原來 堆棧只有多少,然后你還“找了幾個”的情況存在。 所以,你描述的這個情況,到底是什么情況?
回復

使用道具 舉報

ID:401564 發(fā)表于 2022-7-14 20:43 | 顯示全部樓層
newlined 發(fā)表于 2022-7-14 08:26
您好,這個可能不方便貼出,隨說是20年的程序,但老板交代過。
經(jīng) 188610329大神提醒,我DPTR沒有保護造 ...

DPTR,R0,R1什么的,你在多個地方用到了,就進行保護,如果用不到就不用管
匯編子程序的原則是你在調(diào)用的時候,如果在其它地方你也用到某個地址的RAM.那就進行保護,每個子程序都要保護
常用的就是R0R1之類,比如DELAY:               
        PUSH R0        PUSH R1
        MOV R0,#100
        MOV R1,#100
NEXT:
        DJNZ R1,NEXT
        DJNZ R0,NEXT
        POP R1
        POP R0
        RET

這就是一個延時程序,這樣的話,你在其它的程序中包括中斷,再使用R0R1,也同樣的PUSH,POP,那么這個程序就不會出問題
假設(shè)你整個完整的程序中,只有這一個地方用到R0R1,那么,這個PUSH,POP就是多余的
還有R0-R7這幾個地址,默認的情況下,在整個程序地址是固定的,你在任何一個地方修改了R0-R7其中一個的值,它在其它地方的也是會改變的
假設(shè)你延時中用到了R0,中斷中也用到R0,那么當延時程序被中斷打斷之后,如果不用PUSH,POP保護R0的話,等到中斷中修改了R0之后
RETI返回之后,R0的值就是中斷中最后操作的值,那么,你這個延時程序就出錯了
你不要都是想著堆棧滿不滿的,基本不會的,完全可以先不管堆棧的大小問題
專注找你自己代碼的問題
回復

使用道具 舉報

ID:624769 發(fā)表于 2022-7-14 21:07 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-7-14 20:43
DPTR,R0,R1什么的,你在多個地方用到了,就進行保護,如果用不到就不用管
匯編子程序的原則是你在調(diào)用的時 ...

R0~R7 屬于 通用寄存器, 是不能PUSH的。
如果是完全自己寫的代碼,配合USING 可以用 PUSH AR0~AR7 方式來PUSH 但是,如果不是自己的代碼,而4組寄存器 一直輪換在用的話,非常不好處理。
所以,還是比較建議樓主多注重一下,改了部分的代碼,到底涉及到哪些東西,針對性的處理一下,而不是去動那些既存的,由來已久的代碼。
簡易樓主,全程序  查找一下, "MOV  PSW,#"   看看具體用了幾組 通用寄存器,為了影響最小化,假定,之前只用了 3組寄存器,建議樓主加的部分代碼全都用 第四組 通用寄存器,這樣,可以把影響降到最低。
回復

使用道具 舉報

ID:883242 發(fā)表于 2022-7-14 21:41 | 顯示全部樓層
函數(shù)的好處是可以復用,一處定義多處調(diào)用,節(jié)約程序空間。

但是對于大多數(shù)8位單片機編譯器,包括C51,沒有按照標準c語言的做法——在進入函數(shù)的時候在堆棧上臨時分配局部變量(具體做法可以看《數(shù)據(jù)結(jié)構(gòu)》關(guān)于遞歸的那一部分),因為8位機間接尋址指令和空間非常有限,按標準c語言的做法,最后生成的機器碼會非常龐大,占用的RAM空間也非常多,對本來就很少的資源造成巨大浪費。

C51的做法是對函數(shù)調(diào)用關(guān)系進行分析,然后靜態(tài)分配變量,以樓主的問題為例A->A1->A2->A3,那么A的局部變量可能是27H~29H,A1的局部變量占用2AH~2FH,A2的局部變量占用30H~35H,A3的局部變量占用36H以后空間。這種做法導致中斷調(diào)用的函數(shù)是無法復用的!比如中斷B調(diào)用了函數(shù)B1,B1的局部變量占用33H這個空間,那么如果主程序調(diào)用B1,局部變量在運算過程中發(fā)生了中斷,中斷B1修改了局部變量,那么中斷結(jié)束后,回到主程序,局部變量33H的內(nèi)容被修改了,那么主程序顯然就會執(zhí)行錯誤。同樣的原因,不僅主程序不能調(diào)用B1,其他中斷C、D也不能調(diào)用B1!。∵@個函數(shù)B1是中斷B專用的。

綜上所述,使用函數(shù),可以復用的優(yōu)點在中斷這里不存在!在中斷中調(diào)用函數(shù)只有各種各樣的缺點,一點好處都沒有,樓主為什么要這么做?
回復

使用道具 舉報

ID:401564 發(fā)表于 2022-7-14 22:01 | 顯示全部樓層
188610329 發(fā)表于 2022-7-14 21:07
R0~R7 屬于 通用寄存器, 是不能PUSH的。
如果是完全自己寫的代碼,配合USING 可以用 PUSH AR0~AR7 方式 ...

好久不用匯編了,忘記了
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-15 10:58 | 顯示全部樓層
Hephaestus 發(fā)表于 2022-7-14 19:44
你的軟件用到了idata了嗎?

您好,用到了
回復

使用道具 舉報

ID:227818 發(fā)表于 2022-7-15 11:08 | 顯示全部樓層
Hephaestus 發(fā)表于 2022-7-14 21:41
函數(shù)的好處是可以復用,一處定義多處調(diào)用,節(jié)約程序空間。

但是對于大多數(shù)8位單片機編譯器,包括C51,沒 ...

您好,在中斷中有十幾行語句,用了幾次,早先我不知道函數(shù)調(diào)用會產(chǎn)生一些列的問題,就把它們寫成了函數(shù).前邊datouyuan大神也已經(jīng)指出了.
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表