標題:
基于stm32f103rct6的PID算法控制四驅車程序—基于HAL庫的
[打印本頁]
作者:
ly172762
時間:
2019-7-30 20:41
標題:
基于stm32f103rct6的PID算法控制四驅車程序—基于HAL庫的
STM32F103RCT6PID算法控制四個電機,基于HAL,希望可以給各位一些幫助,僅供參考,請勿他用
單片機源程序如下:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include "Motr_conter.h"
#include "pid.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* 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 */
uint8_t Left_Front_or_Right_rear; //用于保存電機行駛方向的變量
uint8_t RX_buff[100],Start_Flag=0; //接收緩沖區(qū),和電機運行開始的標志位
int16_t pwm_duth_A=0,pwm_duth_B=0,pwm_duth_C=0,pwm_duth_D=0;//四個電機的pwm變量
uint16_t save_Ecoder_A=0,save_Ecoder_B=0,save_Ecoder_C=0,save_Ecoder_D=0; //保存四個電機的編碼值
extern PID sPID; //PID結構體變量,用于改變目標值
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t TX_buff[500]={"今天是個好日子,天氣有點涼快!!\n"};
/* 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(); //GPIO的初始化
MX_DMA_Init(); //DMA的初始化
MX_TIM2_Init(); //定時器2的初始化
MX_USART1_UART_Init(); //串口1的初始化
MX_TIM1_Init(); //定時器1的初始化
MX_TIM6_Init(); //定時器6的初始化
MX_USART2_UART_Init(); //串口2的初始化
MX_TIM3_Init(); //定時器3的初始化
MX_TIM4_Init(); //定時器4的初始化
MX_TIM5_Init(); //定時器5的初始化
MX_TIM8_Init(); //定時器8的初始化
/* USER CODE BEGIN 2 */
Motor_Stop; //電機初始化狀態(tài)位停止的
HAL_TIM_Base_Start_IT(&htim6); //啟動定時器
HAL_UART_Transmit(&huart2,TX_buff,strlen((char*)TX_buff),1000); //串口2發(fā)送一串數(shù)據(jù),表示串口2工作正常
HAL_UART_Transmit(&huart1,TX_buff,strlen((char*)TX_buff),100); //串口發(fā)送數(shù)據(jù)測試 ,表示串口1工作正常
printf("電機編碼器測試,測試通過\n"); //發(fā)送實驗測試名稱
IncPIDInit(); //pPID參數(shù)初始化
HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //開始電機D編碼器接口計數(shù)
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL); //開啟電機C的編碼器接口計數(shù)
HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL); //開啟電機B的編碼器接口計數(shù)
HAL_TIM_Encoder_Start(&htim5,TIM_CHANNEL_ALL); //開啟電機C的編碼器接口計數(shù)
HAL_UART_Receive_DMA(&huart2,RX_buff,5); //開啟串口2的DMA接收數(shù)據(jù)
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(RX_buff[0]==0x31)
{
if(RX_buff[1]==0x31&&RX_buff[2]==0x31&&RX_buff[3]==0x31) Derection_Control(1,3,1,3); //左前行駛
}
if(RX_buff[0]==0x32)
{
if(RX_buff[1]==0x32&&RX_buff[2]==0x32&&RX_buff[3]==0x32) Derection_Control(1,1,1,1); //向前行駛
}
if(RX_buff[0]==0x33)
{
if(RX_buff[1]==0x33&&RX_buff[2]==0x33&&RX_buff[3]==0x33) Derection_Control(3,1,3,1); //右前行駛
}
if(RX_buff[0]==0x34)
{
if(RX_buff[1]==0x34&&RX_buff[2]==0x34&&RX_buff[3]==0x34) Derection_Control(1,2,1,2); //向左平行行駛
}
if(RX_buff[0]==0x35)
{
if(RX_buff[1]==0x35&&RX_buff[2]==0x35&&RX_buff[3]==0x35) Derection_Control(1,2,2,1); //順時針旋轉
}
if(RX_buff[0]==0x36)
{
if(RX_buff[1]==0x36&&RX_buff[2]==0x36&&RX_buff[3]==0x36) Derection_Control(2,1,2,1); //向右平行行駛
}
if(RX_buff[0]==0x37)
{
if(RX_buff[1]==0x37&&RX_buff[2]==0x37&&RX_buff[3]==0x37) Derection_Control(3,2,3,2); //左后行駛
}
if(RX_buff[0]==0x38)
{
if(RX_buff[1]==0x38&&RX_buff[2]==0x38&&RX_buff[3]==0x38) Derection_Control(2,2,2,2); //向后行駛
}
if(RX_buff[0]==0x39)
{
if(RX_buff[1]==0x39&&RX_buff[2]==0x39&&RX_buff[3]==0x39) Derection_Control(2,3,2,3); //右后行駛
}
if(RX_buff[0]==0x30)
{
if(RX_buff[1]==0x30&&RX_buff[2]==0x30&&RX_buff[3]==0x30) Derection_Control(2,1,1,2); //逆時針旋轉
}
if(RX_buff[0]==0x2E)
{
if(RX_buff[1]==0x31&&RX_buff[2]==0x32&&RX_buff[3]==0x33) {Derection_Control(3,3,3,3); } //停止
}
if(RX_buff[0]==0x2B)
{
sPID.SetPoint_A=sPID.SetPoint_B=sPID.SetPoint_C=sPID.SetPoint_D=(RX_buff[1]-0x30)*1000+(RX_buff[2]-0x30)*100+(RX_buff[3]-0x30)*10+(RX_buff[4]-0x30); //設置行駛的速度
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {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_MUL9;
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_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Enables the Clock Security System
*/
HAL_RCC_EnableCSS();
}
/* USER CODE BEGIN 4 */
uint8_t direction_A,direction_B,direction_C,direction_D; //保存四個電機方向的變量
uint32_t Code_val_A=0,Code_val_B=0,Code_val_C=0,Code_val_D=0; //保存四個編碼器計數(shù)器的的值
uint16_t last_Code_val_A=0,last_Code_val_B=0,last_Code_val_C=0,last_Code_val_D=0;//保存上一秒計數(shù)器的值,與下一秒的相比較到底計數(shù)了多少次
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6) //判斷是不是定時器6達到更新事件
{
if(Start_Flag==1) //判斷電機的行駛標志位
{
direction_A=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim5);//獲取電機A轉動的方向
direction_B=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim4);//獲取電機B 的旋轉方向
direction_C=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);//獲取電機C 的旋轉方向
direction_D=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2);//獲取電機D的旋轉方向
Code_val_A=__HAL_TIM_GET_COUNTER(&htim5); //讀取電機A的計數(shù)器的值
Code_val_B=__HAL_TIM_GET_COUNTER(&htim4); //讀取電機B的計數(shù)器的值
Code_val_C=__HAL_TIM_GET_COUNTER(&htim3); //讀取電機C的計數(shù)器的值
Code_val_D=__HAL_TIM_GET_COUNTER(&htim2); //讀取電機D的計數(shù)器的值
if(direction_A==0) save_Ecoder_A=(Code_val_A>=last_Code_val_A?Code_val_A-last_Code_val_A:Code_val_A+65535-last_Code_val_A); //方向為正定時器向上計數(shù)
if(direction_A==1) save_Ecoder_A=(Code_val_A>last_Code_val_A?last_Code_val_A+65535-Code_val_A:last_Code_val_A-Code_val_A); //方向為反轉代表計數(shù)器是向下計數(shù)
if(direction_B==0) save_Ecoder_B=(Code_val_B>=last_Code_val_B?Code_val_B-last_Code_val_B:Code_val_B+65535-last_Code_val_B); //方向為正定時器向上計數(shù)
if(direction_B==1) save_Ecoder_B=(Code_val_B>last_Code_val_B?last_Code_val_B+65535-Code_val_B:last_Code_val_B-Code_val_B); //方向為反轉代表計數(shù)器是向下計數(shù)
if(direction_C==0) save_Ecoder_C=(Code_val_C>=last_Code_val_C?Code_val_C-last_Code_val_C:Code_val_C+65535-last_Code_val_C); //方向為正定時器向上計數(shù)
if(direction_C==1) save_Ecoder_C=(Code_val_C>last_Code_val_C?last_Code_val_C+65535-Code_val_C:last_Code_val_C-Code_val_C); //方向為反轉代表計數(shù)器是向下計數(shù)
if(direction_D==0) save_Ecoder_D=(Code_val_D>=last_Code_val_D?Code_val_D-last_Code_val_D:Code_val_D+65535-last_Code_val_D); //方向為正定時器向上計數(shù)
if(direction_D==1) save_Ecoder_D=(Code_val_D>last_Code_val_D?last_Code_val_D+65535-Code_val_D:last_Code_val_D-Code_val_D); //方向為反轉代表計數(shù)器是向下計數(shù)
if(Left_Front_or_Right_rear==0) //如果小車是按照前后左右的某一個方向行駛,將ABCD四個電機進行PID控制
{
pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A)); //電機A的PID算法值返回
pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B)); //電機B的PID算法值返回
pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C)); //電機C的PID算法值返回
pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D)); //電機D的PID算法值返回
}
if(Left_Front_or_Right_rear==1) //電機向左前或者右后行駛
{
pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A)); //就只進行電機AC的PID算法,不進行電機BD的算法
pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C)); //就只進行電機AC的PID算法,不進行電機BD的算法
}
if(Left_Front_or_Right_rear==2) //電機向右前或者左后行駛
{
pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B)); //就只進行電機BD的PID算法,不進行電機AC的PID算法
pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D)); //就只進行電機BD的PID算法,不進行電機AC的PID算法
}
if(pwm_duth_A<0) pwm_duth_A=-pwm_duth_A; //處理電機A,當PWM值為負時變?yōu)檎?br />
if(pwm_duth_B<0) pwm_duth_B=-pwm_duth_B; //處理電機B,當PWM值為負時變?yōu)檎?br />
if(pwm_duth_C<0) pwm_duth_C=-pwm_duth_C; //處理電機C,當PWM值為負時變?yōu)檎?nbsp;
if(pwm_duth_D<0) pwm_duth_D=-pwm_duth_D; //處理電機D,當PWM值為負時變?yōu)檎?br />
if(pwm_duth_A>=7199) pwm_duth_A=7200*4/6; //限制電機A的速度為最大占空比的百分之六十六
if(pwm_duth_B>=7199) pwm_duth_B=7200*4/6; //限制電機B的速度為最大占空比的百分之六十六
if(pwm_duth_C>=7199) pwm_duth_C=7200*4/6; //限制電機C的速度為最大占空比的百分之六十六
if(pwm_duth_D>=7199) pwm_duth_D=7200*4/6; //限制電機D的速度為最大占空比的百分之六十六
Set_compare(motor_A,pwm_duth_A); //將電機A經(jīng)過PID算法之后得到的PWM賦給電機,讓電機真正的按照目標運行起來
Set_compare(motor_B,pwm_duth_B); //將電機B經(jīng)過PID算法之后得到的PWM賦給電機,讓電機真正的按照目標運行起來
Set_compare(motor_C,pwm_duth_C); //將電機C經(jīng)過PID算法之后得到的PWM賦給電機,讓電機真正的按照目標運行起來
Set_compare(motor_D,pwm_duth_D); //將電機D經(jīng)過PID算法之后得到的PWM賦給電機,讓電機真正的按照目標運行起來
last_Code_val_A=Code_val_A; //保存電機A的編碼值,便于進行脈沖值的計算
last_Code_val_B=Code_val_B; //保存電機B的編碼值,便于進行脈沖值的計算
last_Code_val_C=Code_val_C; //保存電機C的編碼值,便于進行脈沖值的計算
last_Code_val_D=Code_val_D; //保存電機D的編碼值,便于進行脈沖值的計算
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1) //判斷是不是串口1接收完成
{
// HAL_UART_Receive_IT(&huart1,RX_buff,8);
}
if(huart->Instance==USART2) //判斷是否是串口2接收完成
{
HAL_UART_Transmit_DMA(&huart2,RX_buff,5); //DMA發(fā)送數(shù)據(jù)
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) //發(fā)送完成回調函數(shù)
{
if(huart->Instance==USART2)
{
HAL_UART_Receive_DMA(&huart2,RX_buff,5); //使能DMA接收數(shù)據(jù)
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
復制代碼
所有資料51hei提供下載:
藍牙+PID控制的小車.7z
(264.82 KB, 下載次數(shù): 91)
2019-7-30 23:27 上傳
點擊文件名下載附件
基于HAL庫的
下載積分: 黑幣 -5
作者:
admin
時間:
2019-7-30 23:28
本帖需要重新編輯補全電路原理圖,源碼,詳細說明與圖片即可獲得100+黑幣(帖子下方有編輯按鈕)
作者:
小閆同學
時間:
2019-8-17 14:45
膜拜大佬
作者:
dqzhao
時間:
2019-9-28 20:37
資料注釋很詳細!贊!
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1