位掩码 及在 ucos ii 中一段位掩码

编辑个目录,直接跳转到总结。


作为计算机专业的,数学不好,对数字相当不敏感。诶,悲催。

每次碰到个啥位操作,总是转不过来,非得仔细地慢慢地看,好吧,写在这里。

在看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;  





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章