国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何設(shè)定PendSV優(yōu)先級?

技術(shù)讓夢想更偉大 ? 來源:技術(shù)讓夢想更偉大 ? 作者:技術(shù)讓夢想更偉大 ? 2022-12-05 11:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

先了解下如何使用PendSV異常。(為何要使用PendSV而不是其他的異常,請參考《cortex-M3權(quán)威指南》)

1,如何設(shè)定PendSV優(yōu)先級?

37b73aaa-7432-11ed-8abf-dac502259ad0.png
NVIC_SYSPRI14EQU0xE000ED22
NVIC_PENDSV_PRIEQU0xFF
LDRR0,=NVIC_SYSPRI14LDRR1,=NVIC_PENDSV_PRI
STRBR1,[R0]

2,如何觸發(fā)PendSV異常?

37c38d64-7432-11ed-8abf-dac502259ad0.png

往ICSR第28位寫1,即可將PendSV異常掛起。若是當(dāng)前沒有高優(yōu)先級中斷產(chǎn)生,那么程序?qū)M(jìn)入PendSV handler

NVIC_INT_CTRLEQU0xE000ED04
NVIC_PENDSVSETEQU0x10000000

LDRR0,=NVIC_INT_CTRL
LDRR1,=NVIC_PENDSVSET
STRR1,[R0]

3,編寫PendSV異常handler

這里用PendSV_Handler來觸發(fā)LED點(diǎn)亮,以此證明PendSV異常觸發(fā)的設(shè)置是正確的。

#include"stm32f10x_conf.h"

#defineLED0*((volatileunsignedlong*)(0x422101a0))//PA8

unsignedcharflag=0;
voidLEDInit(void)
{
RCC->APB2ENR|=1<<2;
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;
GPIOA->ODR|=1<<8;
}

__asmvoidSetPendSVPro(void)
{
NVIC_SYSPRI14EQU0xE000ED22
NVIC_PENDSV_PRIEQU0xFF
LDRR1,=NVIC_PENDSV_PRI
LDRR0,=NVIC_SYSPRI14
STRBR1,[R0]
BXLR
}

__asmvoidTriggerPendSV(void)
{
NVIC_INT_CTRLEQU0xE000ED04
NVIC_PENDSVSETEQU0x10000000
LDRR0,=NVIC_INT_CTRL
LDRR1,=NVIC_PENDSVSET
STRR1,[R0]
BXLR
}

intmain(void)
{
SetPendSVPro();
LEDInit();
TriggerPendSV();
while(1);
}

voidPendSV_Handler(void)
{
LED0=0;
}

上述代碼可以正常點(diǎn)亮LED,說明PendSV異常是正常觸發(fā)了。

OK,是時候挑戰(zhàn)任務(wù)切換了。

如何實(shí)現(xiàn)任務(wù)切換?三個步驟:

步驟一:在進(jìn)入中斷前先設(shè)置PSP。

curr_task=0;

設(shè)置任務(wù)0為當(dāng)前任務(wù):

__set_PSP((PSP_array[curr_task]+16*4));

設(shè)置PSP指向task0堆棧的棧頂位置:

__set_CONTROL(0x3);

設(shè)置為用戶級,并使用PSP堆棧:

__ISB();

指令同步隔離。

步驟二:將當(dāng)前寄存器的內(nèi)容保存到當(dāng)前任務(wù)堆棧中。進(jìn)入ISR時,cortex-m3會自動保存八個寄存器到PSP中,剩下的幾個需要我們手動保存。

步驟三:在Handler中將下一個任務(wù)的堆棧中的內(nèi)容加載到寄存器中,并將PSP指向下一個任務(wù)的堆棧。這樣就完成了任務(wù)切換。

要在PendSV 的ISR中完成這兩個步驟,我們先需了解下在進(jìn)入PendSV ISR時,cortex-M3做了什么?

1,入棧。會有8個寄存器自動入棧。入棧內(nèi)容及順序如下:

37caed20-7432-11ed-8abf-dac502259ad0.pngimg

在步驟一中,我們已經(jīng)設(shè)置了PSP,那這8個寄存器就會自動入棧到PSP所指地址處。

2,取向量。找到PendSV ISR的入口地址,這樣就能跳到ISR了。,

3,更新寄存器內(nèi)容。

做完這三步后,程序就進(jìn)入ISR了。

進(jìn)入ISR前,我們已經(jīng)完成了步驟一,cortex-M3已經(jīng)幫我們完成了步驟二的一部分,剩下的需要我們手動完成。

在ISR中添加代碼如下:

MRSR0,PSP

保存PSP到R0。為什么是PSP而不是MSP。因?yàn)樵贠S啟動的時候,我們已經(jīng)把SP設(shè)置為PSP了。這樣使得用戶程序使用任務(wù)堆棧,OS使用主堆棧,不會互相干擾。不會因?yàn)橛脩舫绦驅(qū)е翺S崩潰。

STMDBR0!,{R4-R11}

保存R4-R11到PSP中。C語言表達(dá)是*(--R0)={R4-R11},R0中值先自減1,然后將R4-R11的值保存到該值所指向的地址中,即PSP中。

STMDB Rd!,{寄存器列表} 連續(xù)存儲多個字到Rd中的地址值所指地址處。每次存儲前,Rd先自減一次。

若是ISR是從從task0進(jìn)來,那么此時task0的堆棧中已經(jīng)保存了該任務(wù)的寄存器參數(shù)。保存完成后,當(dāng)前任務(wù)堆棧中的內(nèi)容如下(假設(shè)是task0)

37d21abe-7432-11ed-8abf-dac502259ad0.png

左邊表格是預(yù)期值,右邊是keil調(diào)試的實(shí)際值。可以看出,是一致的。在任務(wù)初始化時(步驟一),我們將PSP指向任務(wù)0的棧頂0x20000080。在進(jìn)入PendSV之前,cortex-M3自動入棧八個值,此時PSP指向了0x20000060。然后我們再保存R4-R11到0x20000040~0x2000005C。

這樣很容易看明白,如果需要下次再切換到task0,只需恢復(fù)R4~R11,再將PSP指向0x20000060即可。

所以切換到另一個任務(wù)的代碼:

LDRR1,=__cpp(&curr_task)
LDRR3,=__cpp(&PSP_array)
LDRR4,=__cpp(&next_task)
LDRR4,[R4]

獲取下一個任務(wù)的編號:

STRR4,[R1]
Curr_task=next_task
LDRR0,[R3,R4,LSL#2]

獲得任務(wù)堆棧地址,若是task0,那么R0=0x20000040( R0=R3+R4*4)

LDMIAR0!,{R4-R11}

恢復(fù)堆棧中的值到R4~R11。R4=*(R0++)。執(zhí)行完后,R0中值變?yōu)?x20000060

LDMIA Rd! {寄存器列表} 先將Rd中值所指地址處的值送出寄存器中,Rd再自增1.*

MSRPSP,R0
PSP=R0。
BXLR

中斷返回。

完整代碼

#include"stm32f10x.h"
#include"stm32f10x_usart.h"
#include"stm32f10x_gpio.h"
#include"stm32f10x_rcc.h"
#include"stdio.h"
#include"misc.h"

#defineHW32_REG(ADDRESS)(*((volatileunsignedlong*)(ADDRESS)))
#defineLED0*((volatileunsignedlong*)(0x422101a0))//PA8
voidUSART1_Init(void);
voidtask0(void);
unsignedcharflag=1;

uint32_tcurr_task=0;//當(dāng)前執(zhí)行任務(wù)
uint32_tnext_task=1;//下一個任務(wù)
uint32_ttask0_stack[17];
uint32_ttask1_stack[17];
uint32_tPSP_array[4];

u8task0_handle=1;
u8task1_handle=1;

voidtask0(void)
{
while(1)
{
if(task0_handle==1)
{
printf("task0
");
task0_handle=0;
task1_handle=1;
}
}
}

voidtask1(void)
{
while(1)
{
if(task1_handle==1)
{
printf("task1
");
task1_handle=0;
task0_handle=1;
}
}
}

voidLEDInit(void)
{
RCC->APB2ENR|=1<<2;
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;
GPIOA->ODR|=1<<8;
}

__asmvoidSetPendSVPro(void)
{
NVIC_SYSPRI14EQU0xE000ED22
NVIC_PENDSV_PRIEQU0xFF

LDRR1,=NVIC_PENDSV_PRI
LDRR0,=NVIC_SYSPRI14
STRBR1,[R0]
BXLR
}

__asmvoidTriggerPendSV(void)
{
NVIC_INT_CTRLEQU0xE000ED04
NVIC_PENDSVSETEQU0x10000000

LDRR0,=NVIC_INT_CTRL
LDRR1,=NVIC_PENDSVSET
STRR1,[R0]
BXLR
}

intmain(void)
{
USART1_Init();

SetPendSVPro();
LEDInit();

printf("OStest
");

PSP_array[0]=((unsignedint)task0_stack)+(sizeoftask0_stack)-16*4;
//PSP_array中存儲的為task0_stack數(shù)組的尾地址-16*4,即task0_stack[1023-16]地址
HW32_REG((PSP_array[0]+(14<<2)))=(unsignedlong)task0;/*PC*/
//task0的PC存儲在task0_stack[1023-16]地址+14<<2中,即task0_stack[1022]中
HW32_REG((PSP_array[0]+(15<<2)))=0x01000000;/*xPSR*/

PSP_array[1]=((unsignedint)task1_stack)+(sizeoftask1_stack)-16*4;
HW32_REG((PSP_array[1]+(14<<2)))=(unsignedlong)task1;/*PC*/
HW32_REG((PSP_array[1]+(15<<2)))=0x01000000;/*xPSR*/

/*任務(wù)0先執(zhí)行*/
curr_task=0;

/*設(shè)置PSP指向任務(wù)0堆棧的棧頂*/
__set_PSP((PSP_array[curr_task]+16*4));

SysTick_Config(9000000);
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//72/8=9MHZ
/*使用堆棧指針,非特權(quán)級狀態(tài)*/
__set_CONTROL(0x3);

/*改變CONTROL后執(zhí)行ISB(architecturalrecommendation)*/
__ISB();

/*啟動任務(wù)0*/
task0();
//LED0=0;
while(1);
}

__asmvoidPendSV_Handler(void)
{
//保存當(dāng)前任務(wù)的寄存器內(nèi)容
MRSR0,PSP//得到PSPR0=PSP
//xPSR,PC,LR,R12,R0-R3已自動保存
STMDBR0!,{R4-R11}//保存R4-R11共8個寄存器得到當(dāng)前任務(wù)堆棧

//加載下一個任務(wù)的內(nèi)容
LDRR1,=__cpp(&curr_task)
LDRR3,=__cpp(&PSP_array)
LDRR4,=__cpp(&next_task)
LDRR4,[R4]//得到下一個任務(wù)的ID
STRR4,[R1]//設(shè)置curr_task=next_task
LDRR0,[R3,R4,LSL#2]//從PSP_array中獲取PSP的值
LDMIAR0!,{R4-R11}//將任務(wù)堆棧中的數(shù)值加載到R4-R11中
//ADDSR0,R0,#0x20
MSRPSP,R0//設(shè)置PSP指向此任務(wù)
//ORRLR,LR,#0x04
BXLR//返回
//xPSR,PC,LR,R12,R0-R3會自動的恢復(fù)
ALIGN4
}

voidSysTick_Handler(void)
{
flag=~flag;
LED0=flag;
if(curr_task==0)
next_task=1;
else
next_task=0;
TriggerPendSV();
}

voidUSART1_Init(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
USART_InitTypeDefUSART_InitStructure;

/*configUSART1clock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);

/*USART1GPIOconfig*/
/*ConfigureUSART1Tx(PA.09)asalternatefunctionpush-pull*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
/*ConfigureUSART1Rx(PA.10)asinputfloating*/
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);

/*USART1modeconfig*/
USART_InitStructure.USART_BaudRate=9600;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}

intfputc(intch,FILE*f)
{
USART_SendData(USART1,(unsignedchar)ch);
while(!(USART1->SR&USART_FLAG_TXE));

return(ch);
}

測試后結(jié)果如圖:

37e621e4-7432-11ed-8abf-dac502259ad0.png

可以看出,兩個任務(wù)可以切換了。

上述代碼參考《cortex-M3權(quán)威指南》和《安富萊_STM32-V5開發(fā)板_μCOS-III教程》得來。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • led
    led
    +關(guān)注

    關(guān)注

    243

    文章

    24596

    瀏覽量

    690877
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3846

    瀏覽量

    85243

原文標(biāo)題:例說OS前的任務(wù)切換(附代碼)

文章出處:【微信號:技術(shù)讓夢想更偉大,微信公眾號:技術(shù)讓夢想更偉大】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    LTC4420:雙輸入微功耗電源路徑優(yōu)先級器的全方位解析

    LTC4420:雙輸入微功耗電源路徑優(yōu)先級器的全方位解析 在電子設(shè)備的電源管理領(lǐng)域,確保在各種電源狀況下為關(guān)鍵電路提供穩(wěn)定的電力供應(yīng)至關(guān)重要。LTC4420 作為一款雙輸入單片式 PowerPath
    的頭像 發(fā)表于 02-09 10:20 ?98次閱讀

    CS32L010系列能否支持串口的發(fā)送和接收中斷單獨(dú)配置?不同中斷的中斷優(yōu)先級如何設(shè)置?

    1、串口能否配置成阻塞式發(fā)送和中斷式接收。 2、不同中斷的中斷優(yōu)先級如何設(shè)置?我在開啟中斷函數(shù)代碼中看到說中斷優(yōu)先級配置需要先調(diào)用NVIC_PriorityGroupConfig()函數(shù),但此函數(shù)無定義,全局搜索不到。
    發(fā)表于 12-10 18:46

    搶占優(yōu)先級和子優(yōu)先級

    關(guān)于搶占優(yōu)先級和子優(yōu)先級: 1)具有高搶占式優(yōu)先級的中斷可以在具有低搶占式優(yōu)先級的中斷服務(wù)程序執(zhí)行過程中被響應(yīng),即中斷嵌套,或者說高搶占式優(yōu)先級
    發(fā)表于 12-03 07:11

    電能質(zhì)量在線監(jiān)測裝置的暫態(tài)數(shù)據(jù)補(bǔ)傳的優(yōu)先級如何在實(shí)際應(yīng)用中進(jìn)行動態(tài)調(diào)整?

    電能質(zhì)量在線監(jiān)測裝置的暫態(tài)數(shù)據(jù)補(bǔ)傳優(yōu)先級在實(shí)際應(yīng)用中通過 事件驅(qū)動、主站指令、資源狀態(tài)感知和動態(tài)策略調(diào)整 等多層機(jī)制實(shí)現(xiàn)靈活調(diào)控,確保關(guān)鍵數(shù)據(jù)的實(shí)時性與可靠性。以下是具體實(shí)現(xiàn)方式和典型場景的動態(tài)調(diào)整
    的頭像 發(fā)表于 11-06 14:10 ?271次閱讀

    電能質(zhì)量在線監(jiān)測裝置的暫態(tài)數(shù)據(jù)補(bǔ)傳的優(yōu)先級是怎樣的?

    電能質(zhì)量在線監(jiān)測裝置的暫態(tài)數(shù)據(jù)補(bǔ)傳優(yōu)先級設(shè)計(jì)遵循 事件驅(qū)動、主站指令優(yōu)先、資源動態(tài)分配 的原則,結(jié)合行業(yè)標(biāo)準(zhǔn)和設(shè)備機(jī)制,形成以下多層級優(yōu)先級體系: 一、最高優(yōu)先級:緊急事件驅(qū)動補(bǔ)傳 1
    的頭像 發(fā)表于 11-06 14:02 ?302次閱讀

    FreeRTOS任務(wù)調(diào)度及優(yōu)先級問題

    都有容錯,但是心里沒底,想向大家了解一下實(shí)際工作中有沒有遇到到類似的問題,如果有又是怎么解決的呢? 另外有前輩可以分享一下任務(wù)的優(yōu)先級在實(shí)際項(xiàng)目中該基于什么原則來劃分呢?
    發(fā)表于 11-06 02:18

    優(yōu)先級線程無法調(diào)度怎么解決?

    1,設(shè)置了3,5,6,8幾個優(yōu)先級,設(shè)備在現(xiàn)場正常運(yùn)行了一年多后,顯示、前端、后端這3個低優(yōu)先級線程異常了,表現(xiàn)為屏幕不動,前端采集數(shù)據(jù)沒有變化等,其他高優(yōu)先級的線程如通訊,按鍵都能正常運(yùn)行,通訊有喂狗操作,停止通訊,會看門狗復(fù)
    發(fā)表于 09-25 07:33

    什么是RTOS中的優(yōu)先級反轉(zhuǎn)

    當(dāng)一個高優(yōu)先級任務(wù)正在等待一個資源,但一個低優(yōu)先級任務(wù)正在持有它,一個中等優(yōu)先級任務(wù)繼續(xù)在中間運(yùn)行時,就會發(fā)生優(yōu)先級反轉(zhuǎn)——阻止低優(yōu)先級任務(wù)
    的頭像 發(fā)表于 09-09 14:50 ?1004次閱讀

    求助,關(guān)于MS51設(shè)置中斷優(yōu)先級問題求解

    我確實(shí)發(fā)現(xiàn)在庫代碼和 TRM 之間設(shè)置中斷優(yōu)先級有一些差異,如下圖所示。 Could you check what's wrong with me?
    發(fā)表于 08-25 07:01

    揭秘!基于RT-Thread探究“優(yōu)先級反轉(zhuǎn)”下的任務(wù)調(diào)度究竟是什么樣的?| 技術(shù)集結(jié)

    本文將基于RT-Thread,結(jié)合RT-Trace調(diào)試器細(xì)化到實(shí)際任務(wù)調(diào)度的粒度,來調(diào)試并逐步講解“優(yōu)先級反轉(zhuǎn)”的調(diào)度和運(yùn)行邏輯。如果對RT-Trace感興趣的可以看這篇文章:國產(chǎn)嵌入式調(diào)試器之光
    的頭像 發(fā)表于 08-17 10:07 ?3268次閱讀
    揭秘!基于RT-Thread探究“<b class='flag-5'>優(yōu)先級</b>反轉(zhuǎn)”下的任務(wù)調(diào)度究竟是什么樣的?| 技術(shù)集結(jié)

    請問STM32的內(nèi)部Flash操作是不是優(yōu)先級最高?

    STM32的內(nèi)部Flash操作是不是優(yōu)先級最高?目前在內(nèi)部Flash的單獨(dú)一頁存儲了數(shù)據(jù),發(fā)現(xiàn)在進(jìn)行頁擦除的時候正常工作的定時器中斷無法進(jìn)入了
    發(fā)表于 08-13 07:03

    TLe9893怎么調(diào)整外設(shè)的中斷優(yōu)先級?

    你好林工,我該怎么調(diào)整外設(shè)的中斷優(yōu)先級?是否可以通過工具調(diào)整?默認(rèn)設(shè)置下,是不是Brdv的在中斷優(yōu)先級高于T20和can?
    發(fā)表于 08-01 06:20

    請問C0系列單片機(jī)中斷優(yōu)先級只有4嗎?

    C0系列單片機(jī)中斷優(yōu)先級只有4?C071在配置的時候只能配置0-3
    發(fā)表于 07-23 08:00

    ADL5308可以通過軟件和硬件配置的參數(shù),配置的優(yōu)先級是什么?

    你好,麻煩問一下ADL5308可以通過軟件和硬件配置的參數(shù),配置的優(yōu)先級是什么?有沒有更詳細(xì)的寄存器配置手冊,截距配置的步進(jìn)是多少?
    發(fā)表于 06-10 06:39

    CyU3PDebugPrint的最高優(yōu)先級和最低優(yōu)先級是什么?

    [i]CyU3PDebugPrint的最高優(yōu)先級和最低優(yōu)先級是什么?
    發(fā)表于 05-13 08:22