標題: STC單片機uCOS-II移植教程 [打印本頁]
作者: MrWu 時間: 2020-2-12 12:44
標題: STC單片機uCOS-II移植教程
前言
其實關于uCOS-II的51單片機移植教程和例子網上已經有很多了,但是大部分都是基于Proteus仿真外擴內存的,下載之后也不能直接在硬件上使用,也沒有具體的移植教程。這對于一個想學習操作系統而又無從下手小白的來說簡直就是噩夢。
由于51內核的特殊性和keil編譯器原因(51的系統堆棧指針和Keil編譯后仿真堆棧指針增長的方向是相反的)帶來移植的困難。網上的例程處理堆棧的方式有兩種(至于不太懂的同學可以移步看看這篇帖子)
https://blog.csdn.net/s111sw/article/details/6012720,一種是用小模式Small,另外一種是大模式Large。Small模式是把系統堆棧數據和仿真堆棧數據一起復制到用戶堆棧XDATA區,這種方式編譯代碼小但是任務切換速度慢。而Large模式在編譯的時候Keil默認是把仿真堆棧數據設置在XDATA區,所以在任務切換的時候只需要把系統堆棧和仿真堆棧的當前地址保存到用戶堆棧就行,這樣的方式編譯代碼大但任務切換速度快(現在都是用這種方式,STC12C5A60S2在22.1184MHz晶振下任務切換時間37us)。可是,前面已經說了51的系統堆棧指針是向上增長的,而Keil編譯的仿真指針是向下增長的,這就導致了一個 問題---uCOS操作系統的堆棧檢測函數OSTaskStkChk沒辦法使用。上面鏈接帖子里面用的方法是修改uCOS的內核函數實現堆棧檢測功能的。正是因為我不想修改內核函數的原因所以才有了我現在移植的uCOS的版本。
1.png (41.08 KB, 下載次數: 123)
下載附件
2020-2-12 13:07 上傳
圖1
雖然51的系統堆棧指針只能向上增長,但是在代碼里面我們可以人為的把里面的數據按照自己的意愿存放到用戶堆棧里。下面是我移植的堆棧結構,把系統堆棧增長方向和仿真堆棧統一起來就可以實現堆棧連續存放數據了。
2.png (46.89 KB, 下載次數: 110)
下載附件
2020-2-12 13:08 上傳
圖2
開始移植
準備工具
1、 電腦一臺(廢話!)
2、 Keil4
3、 下載配套的代碼一份,我移植的是比較經典的版本uCOS-II 2.52
下載的代碼已經是移植好STC12C5A60S2的例程
功能就是兩個任務用堆棧檢測函數OSTaskStkChk檢測當前自己堆棧使用情況,然后串口發出
波特率115200
下面開始講解怎么把uCOS移植到不同型號51單片機
打開工程\51_uCOS-IIV2.52\Project\ uCOS.uvproj
第1步:把keil配置為大模式,就是讓Keil把默認變量定義到XDATA,下圖3
3.png (93.9 KB, 下載次數: 115)
下載附件
2020-2-12 13:08 上傳
圖3
第2步:打開STARTUP .A51啟動文件修改一些啟動參數來對應單片機資源
根據單片機內部資源作調整,因為STC12C5A60S2有1280字節的SRAM,包括內部0-0xFF 256字節和外部0-0x3FF 1024字節
圖4把IDATALEN改成100H(內部256),XDATALEN改成0x03FF(外部內存根據不同型號芯片的大小配置,最大是0xFFFF),這樣單片機初始化的時候就會把相應的RAM清0。
4.png (54.97 KB, 下載次數: 106)
下載附件
2020-2-12 13:08 上傳
圖4
接著把圖5的XBPSTACK設置為1使能圖6的仿真堆棧初始化代碼,XBPSTACKTOP設置成 0x03FF,就是單片機外部RAM的末尾地址。
5.png (5.76 KB, 下載次數: 111)
下載附件
2020-2-12 13:08 上傳
圖5
6.png (2.38 KB, 下載次數: 127)
下載附件
2020-2-12 13:08 上傳
圖6
這樣就配置好啟動文件了。
第3 步:配置uCOS文件
uCOS系統需要一個時鐘節拍,節拍頻率10Hz-1000Hz。我用的是T0定時器每10ms中斷一次。打開OS_CPU_C.C文件找到void InitHardware(void) T0定時器初始化函數,配置成想要的中斷時間,然后修改中斷函數void OSTickISR(void) interrupt 1里面TL0和TL1的初值,如果是有 自動重裝功能的定時器就可以注釋掉這兩句,最后配置OS_CFG.H文件里最下面的宏定義#define OS_TICKS_PER_SEC,這個就是1秒鐘的節拍數,例如10ms中斷一次就是100,20ms中斷一次就是50。
#define OS_TICKS_PER_SEC100 /* Set the number of ticks in one second */
----------------------------------移植完畢---------------------------------------
堆棧結構解釋
7.png (50.56 KB, 下載次數: 114)
下載附件
2020-2-12 13:09 上傳
圖7
任務創建之后堆棧指針一直指向用戶棧頂,圖7左是堆棧初始化之后里面的數據結構,用戶堆棧的最高3個字節一直固定保存“系統堆棧長度”和“?C_XBP(仿真堆棧指針)”因為任務初始化的時候仿真堆棧還沒有使用,所以?C_XBP指向的堆棧下一個地址就是空閑堆棧,緊跟著就是系統堆棧數據。
在啟動任務調度置后仿真堆棧被使用之后變成圖7右的結構,任務切換時從?C_XBP指向的下一個地址開始保存系統堆棧數據,保存的數據長度由“系統堆棧長度” 決定 ,這樣就實現了堆棧向下連續增長而不需要修改uCOS的堆棧檢測函數。
//堆棧初始化函數
OS_STK *OSTaskStkInit(void (*task)(void *pd) reentrant, void *p_arg, OS_STK *ptos, INT16U opt)reentrant
{
OS_STK *stk;
p_arg =p_arg;
opt = opt; //opt沒被用到,保留此語句防止告警產生
stk =ptos; //用戶堆棧最低有效地址
*stk-- =15; //系統堆棧長度
*stk-- =(INT16U)(ptos-3) >> 8; //?C_XBP 仿真堆棧指針高8位
*stk-- = (INT16U)(ptos-3) &0xFF; //?C_XBP 仿真堆棧指針低8位 最高3個字節一直被占
//用所以減3
*stk-- =0x07; //R7
*stk-- =0x06; //R6
*stk-- =0x05; //R5
*stk-- =0x04; //R4
*stk-- =0x01; //R3
*stk-- =0x02; //R2
*stk-- =0x01; //R1
*stk-- =0x00; //R0
*stk-- =0x00; //PSW
*stk-- =0x00; //DPL
*stk-- =0x00; //DPH
*stk-- =0x0B; //B
*stk-- =0x0A; //ACC
*stk-- =(INT16U)task >> 8; //任務地址高8位
*stk-- =(INT16U)task & 0xFF; //任務地址低8位
stk = ptos;//堆棧指針一直指向棧頂
return stk;
}
;*****************************************************************************************
;* uC/OS-II
;* 實時內核
;*
;* (c) Copyright1992-1998, Jean J. Labrosse, Plantation, FL
;* 版權所有
;*
;* MCU-51 專用代碼
;* KEIL C51大模式編譯
;*
;* 文件名 : OS_CPU_A.ASM
;* 作者 : Jean J. Labrosse
;*****************************************************************************************
;聲明:本代碼僅供學習研究uCOS-II使用,如用作其他用途出現問題本人概不負責。
;偽指令詳細用法請查A51.PDF文件
;程序結構詳見《uC/OS-II》193-198頁
;不用此語句!!! $CASE ;標號和變量名區分大小寫
$NOMOD51
EA BIT 0A8H.7
SP DATA 081H
B DATA 0F0H
ACC DATA 0E0H
DPH DATA 083H
DPL DATA 082H
PSW DATA 0D0H
TR0 BIT 088H.4
TH0 DATA 08CH
TL0 DATA 08AH
NAMEOS_CPU_A ;模塊名
;定義重定位段
?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE
?PR?OSCtxSw?OS_CPU_A SEGMENT CODE
?PR?OSIntCtxSw?OS_CPU_A SEGMENT CODE
;?PR?OSTickISR?OS_CPU_A SEGMENT CODE
;?PR?_?serial?OS_CPU_A SEGMENT CODE
;聲明引用全局變量和外部子程序
EXTRNDATA (?C_XBP) ;仿真堆棧指針用于重入局部變量保存,為V2.51能被C使用定義在本模塊中
EXTRNIDATA (OSTCBCur)
EXTRNIDATA (OSTCBHighRdy)
EXTRNIDATA (OSRunning)
EXTRNIDATA (OSPrioCur)
EXTRN IDATA (OSPrioHighRdy)
EXTRNDATA (EA_Nesting)
; EXTRNCODE (OSTaskSwHook)
EXTRNCODE (OSIntEnter)
EXTRNCODE (OSIntExit)
EXTRNCODE (OSTimeTick)
;對外聲明4個不可重入函數
PUBLICOSStartHighRdy
PUBLICOSCtxSw
PUBLICOSIntCtxSw
; PUBLICOSTickISR
; PUBLICSerialISR
;分配堆棧空間,?STACK和STARTUP.A51中同名,編譯器會將兩個?STACK段合并,堆棧大小在STARTUP.A51中定義
?STACK SEGMENT IDATA
RSEG ?STACK
;-------------------------------------------------------------------------------
PUSHALL MACRO ;定義壓棧出棧宏
PUSH ACC
PUSH B
PUSH DPH
PUSH DPL
PUSH PSW
MOV PSW,#0x00
PUSH0x00 ;R0-R7入棧
PUSH 0x01
PUSH 0x02
PUSH 0x03
PUSH 0x04
PUSH 0x05
PUSH 0x06
PUSH 0x07
ENDM
POPALL MACRO
POP 0x07 ;R0-R7出棧
POP 0x06
POP 0x05
POP 0x04
POP 0x03
POP 0x02
POP 0x01
POP 0x00
POP PSW
POP DPL
POP DPH
POP B
POP ACC
ENDM
;-------------------------------------------------------------------------
; 啟動任務------切換堆棧指針,恢復堆棧數據
;-------------------------------------------------------------------------
RSEG?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
USING0 ;
; LCALL OSTaskSwHook
CtxSw:
;OSTCBCur ===> DPTR 獲得當前TCB指針,詳見C51.PDF第178頁
MOV R0,#LOW (OSTCBCur) ;獲得OSTCBCur指針低地址,
INC R0 ;指針占3字節。+0類型+1高8位數據+2低8位數據
MOV DPH,@R0 ;全局變量OSTCBCur在IDATA中
INC R0
MOV DPL,@R0
;OSTCBCur->OSTCBStkPtr ===> DPTR 獲得用戶堆棧指針
INC DPTR ;指針占3字節。+0類型+1高8位數據+2低8位數據
MOVXA,@DPTR ;取用戶棧頂指針OSTCBStkPtr
MOV R0,A
INC DPTR
MOVXA,@DPTR
ADD A,#0FEH ;DPTR-2指向保存?C_XBP低8位的地址
MOV DPL,A
MOV A,R0
ADDC A,#0FFH
MOV DPH,A
;恢復仿真堆棧指針
MOVX A,@DPTR
MOV ?C_XBP+1,A ;?C_XBP仿真堆棧指針低8位
INC DPTR
MOVX A,@DPTR
MOV ?C_XBP,A ;?C_XBP仿真堆棧指針高8位
INC DPTR
MOVXA,@DPTR ;恢復系統堆棧長度
MOV R5,A ;
;因為DPTR沒有自減1指令,所以只能計算出系統堆棧的末尾地址然后用INC DPTR復制數據提高效率
CLR C ;系統堆棧末尾地址 = 當前仿真堆棧地址-系統堆棧長度
MOV A,?C_XBP+1
SUBB A,R5
MOV DPL,A
MOV A,?C_XBP
SUBB A,#0
MOV DPH,A
MOV R0,#?STACK-1 ;獲取堆棧起址
RestoreStk: ;恢復現場堆棧內容
INC DPTR
INC R0
MOVXA,@DPTR
MOV @R0,A
DJNZR5,RestoreStk
MOV SP,R0 ;恢復堆棧指針SP
;OSRunning=TRUE
MOV R0,#LOW (OSRunning)
MOV @R0,#01
POPALL
MOVEA_Nesting,#0 ;切換任務清零EA嵌套
SETBEA ;開中斷
RETI
;-------------------------------------------------------------------------
; 任務級切換函數
;-------------------------------------------------------------------------
RSEG?PR?OSCtxSw?OS_CPU_A
OSCtxSw:
PUSHALL;任務堆棧進棧
IntCtxSw:
;OSTCBCur ===> DPTR 獲得當前TCB指針,詳見C51.PDF第178頁
MOV R0,#LOW (OSTCBCur) ;獲得OSTCBCur指針低地址,指針占3字節。+0類型+1高8位數據+2低8位數據
INC R0
MOV DPH,@R0 ;全局變量OSTCBCur在IDATA中
INC R0
MOV DPL,@R0
;OSTCBCur->OSTCBStkPtr ===> DPTR 獲得用戶堆棧指針
INC DPTR ;指針占3字節。+0類型+1高8位數據+2低8位數據
MOVXA,@DPTR ;取用戶棧頂指針OSTCBStkPtr
MOV R0,A
INC DPTR
MOVXA,@DPTR
ADD A,#0FEH ;DPTR-2指向保存?C_XBP低8位的地址
MOV DPL,A
MOV A,R0
ADDC A,#0FFH
MOV DPH,A
;保存仿真堆棧指針?C_XBP
MOV A,?C_XBP+1 ;?C_XBP 仿真堆棧指針低8位
MOVX @DPTR,A
INC DPTR
MOV A,?C_XBP ;?C_XBP 仿真堆棧指針高8位
MOVX @DPTR,A
MOV A,SP ;計算系統堆棧長度
CLR C
SUBBA,#?STACK-1
MOV R5,A
;保存系統堆棧長度
INC DPTR
MOVX @DPTR,A
;因為DPTR沒有自減1指令,所以只能計算出系統堆棧的末尾地址然后用INC DPTR復制數據提高效率
CLR C ;系統堆棧末尾地址 = 當前仿真堆棧地址-系統堆棧長度
MOV A,?C_XBP+1
SUBB A,R5
MOV DPL,A
MOV A,?C_XBP
SUBB A,#0
MOV DPH,A
MOV R0,#?STACK-1 ;獲取堆棧起址
SaveStk:
INC DPTR ;保存系統堆棧到任務堆棧
INC R0
MOV A,@R0
MOVX @DPTR,A
DJNZR5,SaveStk
; LCALL OSTaskSwHook ;調用用戶程序
;獲取新任務TCB指針
MOV R0,#OSTCBCur ;OSTCBCur= OSTCBHighRdy
MOV R1,#OSTCBHighRdy
MOV A,@R1
MOV @R0,A ;指針類型
INC R0
INC R1
MOV A,@R1
MOV @R0,A ;指針高8位
INC R0
INC R1
MOV A,@R1
MOV @R0,A ;指針低8位
;獲取新任務優先級
MOV R0,#OSPrioCur ;OSPrioCur =OSPrioHighRdy
MOV R1,#OSPrioHighRdy
MOV A,@R1
MOV @R0,A
LJMP CtxSw
;-------------------------------------------------------------------------
; 中斷級任務切換
;-------------------------------------------------------------------------
RSEG?PR?OSIntCtxSw?OS_CPU_A
OSIntCtxSw:
;調整SP指針去掉在調用OSIntExit(),OSIntCtxSw()過程中壓入堆棧的多余內容
;SP=SP-4
MOV A,SP
CLR C
SUBBA,#4
MOV SP,A
LJMPIntCtxSw
END
作者: jiayong612 時間: 2021-2-8 15:47
寫的不錯! 值得一試!

作者: datianmo 時間: 2021-2-9 10:20
哥太牛了,51能上系統
作者: jiayong612 時間: 2021-2-28 16:03
最近又測試了一下。非常好。發揮了STC的大XDATA. 值得一用!!!!!!!!
作者: wlyjack 時間: 2022-11-8 10:14
哪天吃多了沒事干的時候研究研究!!!
作者: youlinys 時間: 2022-11-9 21:25
太強大了。。。
歡迎光臨 (http://m.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
国产精品视频观看
|
日日网|
国产成人a亚洲精品
|
国产精品毛片
|
日本一区二区在线视频
|
久久国产精品视频
|
7777精品伊人久久精品影视
|
中文字幕av一区
|
91av在线免费
|
国产在线精品一区二区三区
|
九色网址|
国产男女猛烈无遮掩视频免费网站
|
欧美一区二区三区久久精品视
|
欧美日韩在线免费
|
一区二区视频在线
|
精品一区二区三区在线视频
|
亚洲精品一区av在线播放
|
91精品国产综合久久精品
|
av手机在线免费观看
|
日韩精品成人在线
|
亚洲综合视频
|
91精品国产91久久久久久丝袜
|
精品国产乱码久久久久久闺蜜
|
毛片一区二区三区
|
国产成人精品999在线观看
|
亚洲人成人一区二区在线观看
|
欧美美女爱爱视频
|
亚洲精品综合
|
日本精品视频一区二区
|
日本中文字幕在线观看
|
青青久久
|
欧美一区二区三区在线看
|
亚洲狠狠
|
91免费看片
|
亚洲一区影院
|
国产成人综合网
|
欧美成年网站
|
中文字幕乱码视频32
|
免费精品视频在线观看
|
www久久久|
午夜影院|