(1) 掌握基于 PROTEUS 和 KEIL 的仿真調試方法。 (2) 掌握 uCOS-II 的移植,并采用多任務編程、調試。 (3) 熟悉電機的工作原理和功能,并掌握電機的應用和驅動方法。 1.2 內容
(1) 基本功能:本任務通過輸出脈沖控制步進電機的停止、運動、方向。使用 兩個按鍵分別控制步進電機的正轉和反轉,再次按下這兩個按鍵,步進電機停止, 同時 LCD 顯示電機狀態信息。 (2) 擴展功能:加入一個轉速閾值設置功能,由電位器充當閾值設置器,可設 置目標轉速并使電機接近設置的轉速。
第 2 章 系統硬件設計
2.1 總體框架設計
51hei圖片編輯_20210906150340.jpg (24.4 KB, 下載次數: 109)
下載附件
2021-9-6 15:04 上傳
圖 2-1 硬件框架圖
本次任務實踐的硬件架構設計如圖 2-1 所示。按照設計任務的要求,本次設 計采用的主控芯片為 STM32F103,整體硬件設計以該芯片為中心,由按鍵輸入模 塊、LCD 顯示模塊、電機模塊等組成。 2.2 硬件電路設計
(1) 參考 LCD1602 液晶顯示屏的芯片資料,在 LCD 顯示屏的電路連接中,將 VDD 以及 VSS、VEE 接到電源以及地上。之后再將它的3 個信號控制引腳 RS、RW、 E 以及 8 個數據傳輸引腳 DO-D7 分別連接到 STM32 的相應引腳上。 (2) 按鍵輸入模塊采用兩個獨立按鍵,分別連接 STM32 的 PB6、PB7 引腳,公 共端接地。 (3) 電機模塊使用直流無刷電機,并采用 L293D 和 IRF540 MOS 管驅動。 (4) 用所謂“六步換向法”,根據轉子當前的位置,按照一定的順序給定子繞 組通電使 BLDC 電機轉動。如圖 2-2 所示。 永磁體 N-S 交替交換,使位置傳感器產生相位差 120°的 H3、H2、H1 方波, 從而產生有效的六狀態編碼信號:010、011、001、101、100、110,通過邏輯組 件處理產生 V6-V1 導通、V5-V6 導通、V4-V5 導通、V3-V4 導通、V2-V3 導通、V1-V2 導通,也就是說將直流母線電壓依次加在 U ->V、w ->V、W ->U、V->U、V->W、 U ->W 上,這樣轉子每轉過一對 N-S 極,V1、V2、V3、V4、V5、V6 各功率管即按 固定組合成六種狀態的依次導通。
圖 2-2 BLDC 控制框圖
圖 2-3 120°HAll 換相控制圖 對于典型的三相帶傳感器的 BLDC 電機,有 6 個不同的工作區間,每個區間 中有特定的兩相繞組通電。通過檢測霍爾傳感器,可以得到一個 3 位編碼,編碼 值的范圍從 1 到 6。每個編碼值代表轉子當前所處的區間。從而提供了需要對哪 些繞組通電的信息。因此程序可以使用簡單的查表操作來確定要對哪兩對特定的 繞組通電以使轉子轉動。注意狀態"0 和 7"對于霍爾效應傳感器而言是無效狀態。 軟件應該檢查出這些值并相應地禁止 PWM。 (5) Proteus 的無刷直流電機模型帶有 3 個霍爾傳感器,霍爾傳感器的輸出信 號兩相間相差 120 度。與此對應的是電機轉子每旋轉一周霍爾傳感器就能輸出 6 種編碼狀態,如圖 2-4 所示。 從圖可見,霍爾傳感器輸 出狀態變化一次,就 意味著電機轉子轉過了 60 度。 據此,可以根據單位時間 T 內捕獲的霍爾傳感 器輸出變化的個數 n 計算出電機的轉速 V=60n/T。 根據這一原理,通過控制器 的輸入捕獲功能 IC 獲取到其中 一相霍爾傳感器輸出信號的周期,就可以比較準 精確地測量到電機的轉速。
圖 2-4 霍爾位置傳感器輸出信號波形
圖 2-5 硬件原理圖
第 3 章 系統軟件設計

為了方便編程并使代碼美觀,需要創建一個開始任務。該任務可以用來創建 其他任務以及一些信號量、消息郵箱、事件標志組等。而根據設計要求,需要在 本地 LCD 顯示電機運轉狀態,因此需要一個信息顯示任務。該控制系統最終所實 現的功能是控制直流無刷電機,故還需要一個步進電機驅動任務。根據上述分析, 一共劃分為兩個任務。
圖 3-1 主函數流程圖 開始任務主要用來對一些驅動電機的寄存器進行初始化并啟動電機以及創 建后面所需要的任務以及一些信號量、事件標志組和消息郵箱,任務優先級設置 為 10。
圖 3-2 開始任務流程圖 速度任務主要將霍爾傳感器的數據進行讀取并將讀到的速度參數進行轉換, 之后顯示在顯示屏上,任務優先級設置為 1。
圖 3-3 速度讀取任務流程圖 速度讀取主要是在中斷服務函數里進行,通過對捕獲霍爾傳感器的上升沿以 及下降沿,讀的其信號周期,再將其轉換為頻率得到速度值。
圖 3-4 轉速讀取計算流程圖
 第 4 章 調試過程及結果
圖 4-1 仿真過程中 圖 4-2 反轉時的調速過程 仿真過程中可以看到定時器 PWM 輸出之間的切換以及脈寬的變化。
圖 4-3 接近穩定時
圖 4-4 穩定后增大轉速
STM32單片機源程序如下:
- include "main.h"
- #include "adc.h"
- #include "tim.h"
- #include "gpio.h"
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "includes.h"
- #include "lcd.h"
- /* USER CODE END Includes */
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
- /* USER CODE END PTD */
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
- #define HALL_GPIO GPIOA
- //START 任務
- //設置任務優先級
- #define START_TASK_PRIO 10 //開始任務的優先級設置為最低
- //設置任務堆棧大小
- #define START_STK_SIZE 64
- //任務堆棧
- OS_STK START_TASK_STK[START_STK_SIZE];
- //任務函數
- void start_task(void *pdata);
-
- //LED0任務
- //設置任務優先級
- #define LED0_TASK_PRIO 2
- //設置任務堆棧大小
- #define LED0_STK_SIZE 64
- //任務堆棧
- OS_STK LED0_TASK_STK[LED0_STK_SIZE];
- //任務函數
- void led0_task(void *pdata);
- //Speed_ADC 任務
- //設置任務優先級
- #define SPEED_ADC_TASK_PRIO 1
- //設置任務堆棧大小
- #define SPEED_ADC_STK_SIZE 64
- //任務堆棧
- OS_STK SPEED_ADC_TASK_STK[SPEED_ADC_STK_SIZE];
- //任務函數
- void speed_adc_task(void *pdata);
- /* USER CODE END PD */
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
- /* USER CODE END PM */
- /* Private variables ---------------------------------------------------------*/
- /* USER CODE BEGIN PV */
- //定時器2捕獲通道參數
- /* Private variables ---------------------------------------------------------*/
- uint16_t Channel1HighTime, Channel2HighTime, Channel3HighTime; //高電平時間
- uint16_t Channel1Period, Channel2Period, Channel3Period; //周期
- uint8_t Channel1Edge = 0, Channel2Edge = 0, Channel3Edge = 0; //上升沿
- uint16_t Channel1Percent, Channel2Percent, Channel3Percent; //占空比
- uint16_t Channel1PercentTemp[3] = {0, 0, 0};
- uint8_t Channel1TempCount = 0;
- uint16_t Channel1RisingTimeLast=0, Channel1RisingTimeNow, Channel1FallingTime;
- uint16_t Channel2RisingTimeLast=0, Channel2RisingTimeNow, Channel2FallingTime;
- uint16_t Channel3RisingTimeLast=0, Channel3RisingTimeNow, Channel3FallingTime;
- extern int motor_period;
- extern int motor_duty;
- extern int clock_wise;
- int current_speed = 0;
- int ADC_Speed = 500; //555 / 90% = 500
- int ADC_Value = 555; //
- BOOLEAN state = 0; // 0 關閉中 1 啟動中
- /* USER CODE END PV */
- /* Private function prototypes -----------------------------------------------*/
- void SystemClock_Config(void);
- /* USER CODE BEGIN PFP */
- /* USER CODE END PFP */
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
- /* USER CODE END 0 */
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);//設置中斷優先級分組為組2:2位搶占優先級,2位響應優先級
- OSInit();
- OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//創建起始任務
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
- /* USER CODE BEGIN Init */
- /* USER CODE END Init */
- /* Configure the system clock */
- SystemClock_Config();
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_TIM1_Init();
- MX_ADC1_Init();
- MX_TIM2_Init();
- /* USER CODE BEGIN 2 */
- OSStart();
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
- /**
- * @brief System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
- /** Initializes the CPU, AHB and APB busses clocks
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
- RCC_OscInitStruct.HSIState = RCC_HSI_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL2;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
- /** Initializes the CPU, AHB and APB busses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
- {
- Error_Handler();
- }
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
- PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
- {
- Error_Handler();
- }
- }
- /* USER CODE BEGIN 4 */
- //開始任務
- void start_task(void *pdata)
- {
- // //設置通道1的脈寬。 width = (1000 - 500) / 1000 = 50%
- __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, motor_duty);
- __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, motor_duty);
- __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, motor_duty);
-
- //打開定時器2通道 , 中斷使能
- HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
- HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
- HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_3);
- HAL_Delay(100);
- //開啟定時器1的通道1
- HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
- HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
- HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);
- //
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
-
- //
- uint16_t hall_read = (HALL_GPIO->IDR)&0x0007; // 獲取霍爾傳感器狀態 pin0 1 2__IO uint8_t uwStep = 0;
- BLDC_PHASE_CHANGE(hall_read); // 驅動換相
-
- //PID初始化
- Speed_PIDInit();
-
- OS_CPU_SR cpu_sr=0;
- OS_ENTER_CRITICAL(); //進入臨界區(無法被中斷打斷)
- OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);
- OSTaskCreate(speed_adc_task,(void *)0,(OS_STK*)&SPEED_ADC_TASK_STK[SPEED_ADC_STK_SIZE-1],SPEED_ADC_TASK_PRIO);
- OSTaskSuspend(START_TASK_PRIO); //掛起起始任務.
- OS_EXIT_CRITICAL(); //退出臨界區(可以被中斷打斷)
- }
- //LED0任務
- void speed_adc_task(void *pdata)
- {
- lcd_system_reset();
- unsigned char temp_table[16] ={"Cur_Speed:"};
- unsigned char temp_table1[16] ={"Tar_Speed:"};
- for(uint8_t i=0;i<10;i++)
- {
- lcd_char_write(i,0,temp_table[i]);
- lcd_char_write(i,1,temp_table1[i]);
- }
- HAL_ADC_Start(&hadc1);
- while(1)
- {
- HAL_ADC_PollForConversion(&hadc1,0); //等待轉換完成,第二個參數代表最長等待時間ms
- if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
- {
- ADC_Value = HAL_ADC_GetValue(&hadc1); // 讀取ADC數據 ,4096 -> 3.3V
- ADC_Speed = ADC_Value + 500; //轉換公式 0-4096 -> 500 - 4596
- // if(ADC_Speed > 100){
- // HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin);
- // }
- }
- //當前速度
- temp_table[10]=current_speed/1000+'0';
- temp_table[11]=current_speed/100%10+'0';
- temp_table[12]=current_speed/10%10+'0';
- temp_table[13]=current_speed%10+'0';
- //目標速度
- temp_table1[10]=ADC_Speed/1000+'0';
- temp_table1[11]=ADC_Speed/100%10+'0';
- temp_table1[12]=ADC_Speed/10%10+'0';
- temp_table1[13]=ADC_Speed%10+'0';
- for(uint8_t i=10;i<14;i++)
- {
- lcd_char_write(i,0,temp_table[i]);
- lcd_char_write(i,1,temp_table1[i]);
- }
- }
- }
- //speed adc 采樣函數
- void led0_task(void *pdata)
- {
- while(1)
- {
- HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);
- OSTimeDly(10);
- HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);
- OSTimeDly(10);
- }
- }
- //外部中斷服務函數
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- if(!state)
- {
- __IO uint8_t uwStep = 0;
- uint16_t hall_read=(HALL_GPIO->IDR)&0x0007; // 獲取霍爾傳感器狀態 pin0 1 2
- uwStep = hall_read;
- BLDC_PHASE_CHANGE(uwStep); // 驅動換相
-
- }
- uint16_t key_read =(Start_GPIO_Port->IDR)&0x00e0;
- if(key_read == 0x00c0)
- {
- // state = !state;
- // HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
- // HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
- // HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);
- //
- // //BLDC_PHASE_CHANGE(7);
- // HAL_TIM_Base_MspDeInit(&htim1);
- //
- // HAL_Delay(300);
- // HAL_TIM_Base_MspDeInit(&htim1);
- // HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
- // HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
- // HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
- // BLDC_PHASE_CHANGE(7);
- //HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin);
- }else if(key_read == 0x00a0)
- {
- clock_wise = 0;
- }else if(key_read == 0x0060)
- {
- clock_wise = 1;
- }
- }
- //定時器2中斷函數
- //溢出時間為1s
- //溢出值1000 每個點為1ms
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
- {
-
- if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) //捕獲中斷
- {
- /*
- 測速邏輯
- 1、中斷產生,先判斷是否為第一次上升沿
- 2、捕獲到上升沿后,將時間點存入變量,切換捕獲下降沿
- 3、捕獲到下降沿后,記下時間點,切換為捕獲上升沿
- 4、捕獲到上升沿后,記下時間點
- 5、計算周期和占空比
- 6、問題如果經過多個周期才有一次上升沿和下降沿怎么辦,需要記錄溢出次數
- 如果溢出的時候有上升沿標志位
-
- 問題:proteus三路輸入捕獲計算,測轉速時,如果第一個上升沿和第二個上升沿不在一個定時器計數周期,會計算失敗
- */
- if(Channel1Edge == 0)
- {
- //獲取通道1上升沿時間點
- Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
- Channel1Edge = 1;//捕獲上升沿置位
- Channel1RisingTimeLast = Channel1RisingTimeNow;
- }else if(Channel1Edge == 1)
- {
- Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
- if(Channel1RisingTimeNow > Channel1RisingTimeLast)
- {
- Channel1Period = Channel1RisingTimeNow - Channel1RisingTimeLast;
- }
- else
- {
- //Channel2Period = Channel2RisingTimeNow + 1000 - Channel2RisingTimeLast + 1;
- }
- Channel1Edge = 0;
- //pid計算
- // current_speed = 60*1000 / Channel1Period; //轉速計算
- // current_speed = current_speed * 5; //速度調整系數
- // motor_duty = Speed_PIDAdjust(current_speed);
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
51hei.png (3.38 KB, 下載次數: 79)
下載附件
2021-9-6 16:31 上傳
全部資料51hei下載地址:
代碼:
uCos_ii_Demo.7z
(5.21 MB, 下載次數: 297)
2021-9-6 15:01 上傳
點擊文件名下載附件
程序 下載積分: 黑幣 -5
仿真:
Proteus.zip
(102.55 KB, 下載次數: 310)
2021-9-6 15:00 上傳
點擊文件名下載附件
仿真 下載積分: 黑幣 -5
以上圖文:
電機轉速檢測系統設計與實現v2.0.pdf
(1.3 MB, 下載次數: 195)
2021-9-6 15:01 上傳
點擊文件名下載附件
報告 下載積分: 黑幣 -5
|