1. 程式人生 > >stm32f1系列微控制器實戰應用

stm32f1系列微控制器實戰應用

最近有一個小專案,測量運動自行車速度,上傳給上位機軟體,處理VR視訊播放。正好公司有現成的stm32f1系列微控制器開發板,所以我就想到了使用它來實現這個小功能。

1. 硬體配置:

1.1. 運動自行車;

 

1.2. 磁感應開關與專用磁鐵;    

      

1.3. 基於Stm32f103zet6晶片的開發板(七星蟲),如下圖;


1.4. 連線線若干;

1.5. miniusb線纜,用於給開發板供電及串列埠通訊。

 

2. 系統描述與框圖:

運動自行車車輪上安裝5只磁鐵,通過磁感應開關檢測磁鐵產生訊號,接入stm32開發板PE0引腳。測量出的速度值通過串列埠傳送給PC上位機軟體(mini usb線纜連線)。硬體框圖如下:

 

3. 軟體實現

3.1.設定開發板PE0引腳下降沿中斷,在引腳中斷服務函式裡累計中斷次數(即磁感應開關感應到磁鐵的次數),同時每累計10次LED2交換一次狀態。外部初始化程式碼及中斷服務函式如下:

void EXTIX_Init(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    //  引腳埠初始化 PE0
    GPIO_InitStructure.GPIO_Pin  = DEF_BIT_00;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOE, &GPIO_InitStructure);    
     // 啟 AFIO 時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    //GPIOE.0 中斷線以及中斷初始化配置,下降沿觸發
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource0);// 配置中斷線為0
    EXTI_InitStructure.EXTI_Line=EXTI_Line0;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿觸發
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure); // 初始化中斷線引數
    
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                //使能按鍵外部中斷通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;    //搶佔優先順序 2,
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;           //子優先順序 2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //使能外部中斷通道
    NVIC_Init(&NVIC_InitStructure);                                 // 初始化 NVIC
}
// 外部中斷0服務程式
long long lSpeedCnt = 0;
void EXTI0_IRQHandler(void)
{
    OSIntEnter();             // 告訴ucosii系統進入中斷
    
    if(GPIO_ReadInputDataBit(GPIOE, DEF_BIT_00)==0) // PE0檢測到下降沿
    {
        // 累計中斷次數,每隔10次改變led1狀態
        if(!((lSpeedCnt++)%10))
        {
            BSP_LED_Toggle(2);
        }
    }
    EXTI_ClearITPendingBit(EXTI_Line0); // 清除LINE0上的中斷標誌位
    
    OSIntExit             // 告訴ucosii系統退出中斷
}

3.2.在啟用一個定時器中斷,週期為1s,在定時器中斷服務函式裡計算自行車的速度。計算方式如下:v = p / μ * C,其中:v是速度:m/s,p是磁感應開關感應頻率, μ為車輪上安裝磁鐵個數:5,C為自行車車輪周長:1.38m。定時器中斷初始化程式碼及中斷服務函式如下:

/*******************************************************************************
* Function Name  : BSP_TIM2_Init
* Description    : Compute return latest speed measurement 
* Input          : None
* Output         : s16
* Return         : Return the speed in 0.1 Hz resolution.                    
*******************************************************************************/
static void BSP_TIM2_Init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef   bsp_tim2_init;    
    
    //使能TIM2時鐘
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    
    TIM_DeInit(TIM2);
    TIM_TimeBaseStructInit(&bsp_tim2_init);
    //TIM2初始化
    bsp_tim2_init.TIM_Prescaler = psc;                                          //時鐘預分頻   定時器每隔 (psc+1)/72 us計數一次
    bsp_tim2_init.TIM_CounterMode = TIM_CounterMode_Up;                         //向上計數
    bsp_tim2_init.TIM_Period = arr;                                             //計數滿(arr+1)次更新重灌載暫存器資料
    bsp_tim2_init.TIM_ClockDivision = TIM_CKD_DIV1;                             //時鐘不分頻
//    bsp_tim2_init.TIM_RepetitionCounter = ;                                   //高階定時器用,這裡不需設定
    TIM_TimeBaseInit(TIM2, &bsp_tim2_init);                                     //初始化定時器
    
    //設定定時器TIM2中斷
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                                  //設定定時器更新中斷
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                                 //清除中斷標誌,防止剛上電時進一次中斷
    
    //初始化中斷
    BSP_NVIC_Init(TIM2_IRQn, 3, 3); 
    
    //使能定時器TIM2
    TIM_Cmd(TIM2, ENABLE);
}
long long lvalCur;
long long lValPrev;
float fSpeedVal;
void TIM2_IRQHandler(void)
{
    OSIntEnter();             // 告訴ucosii系統進入中斷
    
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {      
      extern long long lSpeedCnt;
      
      lvalCur = lSpeedCnt;
      fSpeedVal = (float)lvalCur - (float)lValPrev;
      fSpeedVal /= 5.0;
      fSpeedVal *= 1.38;      
      lValPrev = lvalCur;
      TIM_ClearFlag(TIM2, TIM_IT_Update);
    }
    OSIntExit();             // 告訴ucosii系統退出中斷

}

3.3.系統共有兩個任務,其中一個任務每50ms傳送一次速度值給PC機,另一個控制LED1閃爍,週期100ms,用於指示系統正常執行。

第一個任務中執行程式碼如下:

 while(DEF_TRUE)
    {              
        extern float fSpeedVal;
        if((int)(fSpeedVal*100) > 9999)
        {
            printf("9999"); 
        }
        else if((int)(fSpeedVal*100) > 999)
        {
            printf("%d",(int)(fSpeedVal*100)); 
        }
        else if((int)(fSpeedVal*100) > 99)
        {
            printf("0%d",(int)(fSpeedVal*100)); 
        }
        else if((int)(fSpeedVal*100) > 9)
        {
            printf("00%d",(int)(fSpeedVal*100)); 
        }
        else
        {
            printf("000%d",(int)(fSpeedVal*100)); 
        }     
        
        OSTimeDlyHMSM(0, 0, 0, 80);
    }        

第二個任務中程式碼如下:

while (DEF_TRUE)
    {     
        BSP_LED_Toggle(1);  
        OSTimeDlyHMSM(0, 0, 0, 100);
    }
整體執行穩定,滿足專案需求。