編輯個目錄,直接跳轉到總結。
作爲計算機專業的,數學不好,對數字相當不敏感。誒,悲催。
每次碰到個啥位操作,總是轉不過來,非得仔細地慢慢地看,好吧,寫在這裏。
在看ucos 源碼時,看到TCB 結構裏有四個變量,分別爲:
INT8U OSTCBX; /* Bit position in group corresponding to task
priority (0..7) */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT8U OSTCBBitY; /* Bit mask to access bit p osition in ready group*/
下面這段是在TCB 初始化裏,根據優先級對這幾個變量的給值。
ptcb->OSTCBY = prio >> 3; /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
另外有個OSMapTbl ,如下:
/*
*********************************************************************************************************
* MAPPING TABLE TO MAP BIT POSITION TO BIT MASK
*
* Note: Index into table is desired bit position, 0..7
* Indexed value corresponds to bit mask
*********************************************************************************************************
*/
INT8U const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/*
還有我搜到的一篇關於位掩碼的文:位掩碼
ucos ii 中任務優先級表是一個8x8 的表(8個UINT8),另設一個 8 位對應每一行,用以標識該行是否有 1 (即優先級是否用了)假設橫向是X,縱向是Y 。OSTCBY呢 是對應於Group , 縱向的。OSTCBX 是橫向的,根據(OSTCBX ,OSTCBY) 就可以很方便的找到 優先級對應的地方並且判斷 其 是 0 還是 1。
創建任務的時候,只是給了一個優先級,那麼,怎麼樣根據優先級來設置這橫座標和縱座標呢?
1. OSTCBY 的設置,右移三位,即 除 8,還好理解。儘管對數字不敏感,見了幾次還是知道意思的。
2. OSTCBX 的設置, &0x07 ,根據實驗結果, 即取後三位,64個優先級 用 6 位可以表示,那麼高三位就是表示 Y,低三位就是表示 X。(好吧,到這裏已經把前面的自己全部推翻了。標記爲紅色吧。)
3. 相應位掩碼的設置。位掩碼是幹啥用的?上面文裏的大神說:有這麼一種技術,叫做位掩碼技術,用來處理存在多個布爾值的情況。哦,理解了,記得看飛思卡爾 K60 的寄存器定義經常有這種MASK,一般說來,寄存器的某一位即可以看做一個開關,或者說裏面的值就代表將要使開關撥到何種狀態,那麼這種就是布爾型的。
如這一段:
//開啓各個GPIO口的轉換時鐘
SIM->SCGC5 = SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK;
/* SCGC5 Bit Fields */ #define SIM_SCGC5_LPTIMER_MASK 0x1u #define SIM_SCGC5_LPTIMER_SHIFT 0 #define SIM_SCGC5_REGFILE_MASK 0x2u #define SIM_SCGC5_REGFILE_SHIFT 1 #define SIM_SCGC5_TSI_MASK 0x20u #define SIM_SCGC5_TSI_SHIFT 5 #define SIM_SCGC5_PORTA_MASK 0x200u #define SIM_SCGC5_PORTA_SHIFT 9 #define SIM_SCGC5_PORTB_MASK 0x400u #define SIM_SCGC5_PORTB_SHIFT 10 #define SIM_SCGC5_PORTC_MASK 0x800u #define SIM_SCGC5_PORTC_SHIFT 11 #define SIM_SCGC5_PORTD_MASK 0x1000u #define SIM_SCGC5_PORTD_SHIFT 12 #define SIM_SCGC5_PORTE_MASK 0x2000u #define SIM_SCGC5_PORTE_SHIFT 13每一個對應一位開關,開了五個開關。(至於SHIFT是做什麼用的,就不知道了)
好吧,再回到ucos 中來,爲了在寫的時候 只需要寫一個 | , 設置下位掩碼,位掩碼指示多個開關中的某一位的開關狀態(0/1)。
20130528
那麼對這種位掩碼的操作我見到了的有三種形式
總結三種常見的位掩碼操作形式
1. 設置相應位
操作方法:“ |= ”。 如STM32中有關時鐘配置的一個函數 RCC->APB2ENR |= RCC_APB2Periph
2. 清除相應位
操作方法 :“ |= ” “~”
如 :RCC->APB2ENR &= ~RCC_APB2Periph
貼上整個函數:
/**
* @brief Enables or disables the High Speed APB (APB2) peripheral clock.
* @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
* This parameter can be any combination of the following values:
* @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
* RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
* RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
* RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
* RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
* RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
* RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11
* @param NewState: new state of the specified peripheral clock.
* This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB2ENR |= RCC_APB2Periph;
}
else
{
RCC->APB2ENR &= ~RCC_APB2Periph;
}
}
3. 檢查 位狀態
操作方法:“ & ” 後判斷
如: ucos 中掛起任務的一段,用來判斷任務就緒表的某一行中是否有其他就緒任務的一段。
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb ->OSTCBBitX) == 0x00) { // 如果該位的其他位沒有
就緒任務,就將 OSRdyGrp 的對應位(指示對應一行中是否有就緒任務)清除
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
ptcb ->OSTCBStat |= OS_STAT_SUSPEND;