这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 基于stm32f103的蓝牙小车

共1条 1/1 1 跳转至

基于stm32f103的蓝牙小车

高工
2025-10-21 19:00:56   被打赏 25 分(兑奖)     打赏

【前言】

此篇的目的是制作一个用蓝牙远程控制的小车。

【硬件】

1、网购的一个小车底盘

image.png

2、STM32F103RC开发板

3、蓝牙模块:

image.png

原来的底盘是用51来做主控的,我这里修改为stm32f103来做主控。

【stm32控制设计】

1、小车底盘上面有两个直流有刷减速电机,由一块L293D进行驱动。其原理图如下:

image.png

因此我使用STM32F103的四个IO来控制方向即IN1-IN4,使用两路PWM来控制EN1与EN2,分别控制两个电机的速度。

使用stm32cubeMX配置PA4-PA7为普通GPIO输出。

image.png


配置两路PWM如下:

image.png

配置USART1为蓝牙串口接入,串口波特率为115200,使能串口空闲中断。

image.png

在串口初始化后,加入中断及空闲中断的开启代码:

  __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);  
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

修改串口1的中断函数如下:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) == SET)
	{

			__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
			
			{
					USART1_Head.RxBuf[USART1_Head.Rx_count++] = USART1->DR;
			}
	}

	if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) == SET)
	{
			__HAL_UART_CLEAR_IDLEFLAG(&huart1);
			
			USART1_Head.Rx_over = 1;  
	}

  /* USER CODE END USART1_IRQn 1 */
}

添加串口解析函数如下:

void Uart_Analysis(uint8_t Rx_over)
{
	  uint8_t ctrl ;
    uint8_t left_dir ;  // 左轮方向(bit7-bit6)
    uint8_t right_dir ;        // 右轮方向(bit1-bit0)
	  uint8_t left_speed ;    // 左轮速度(TIM2_CH4=PB11)
    uint8_t right_speed ;   // 右轮速度(TIM2_CH3=PB10)
  if(Rx_over == 1)
  {
		printf("rcv:%s",USART1_Head.RxBuf);
		if(strstr((char*)USART1_Head.RxBuf, "+CONNECTED") != NULL)
		{
			printf("max2 isreadey\r\n");
			return;
		}
    else if(USART1_Head.RxBuf[0] != FRAME_HEADER || USART1_Head.RxBuf[5] != FRAME_TAIL)
		{
			Rx_over = 0;
			UART_ClearArray(&USART1_Head);  
			return;
		}
		// 校验位验证(字节1 ^ 字节2 ^ 字节3 == 字节4)
    uint8_t check = USART1_Head.RxBuf[1] ^ USART1_Head.RxBuf[2] ^ USART1_Head.RxBuf[3];
    if (check != USART1_Head.RxBuf[4]) {
        Rx_over = 0;
				UART_ClearArray(&USART1_Head);  
        return;
    }
    
    // 解析控制位(字节1)
    ctrl = USART1_Head.RxBuf[1];
    left_dir = (ctrl >> 6) & 0x03;  // 左轮方向(bit7-bit6)
    right_dir = ctrl & 0x03;        // 右轮方向(bit1-bit0)
		 // 设置PWM速度(0x00~0xFF映射到0~99,因ARR=99)
    left_speed = USART1_Head.RxBuf[2];    // 左轮速度(TIM2_CH4=PB11)
    right_speed = USART1_Head.RxBuf[3];   // 右轮速度(TIM2_CH3=PB10)
		blue_car_tontrl(ctrl,left_dir,right_dir,left_speed ,right_speed) ;
		UART_ClearArray(&USART1_Head);  
  }			
		
}

具体的解析协议如下:

image.png

解析函数放入main的大循环中周期调用。

当解析数据就位后,执行控制函数:

void blue_car_tontrl(uint8_t ctrl, 
										uint8_t left_dir,
										uint8_t right_dir,
										uint8_t left_speed ,
										uint8_t right_speed) 
{

    // 控制左轮方向(IN1=PA4,IN2=PA5)
    switch (left_dir) {
        case 0x00:  // 停止(IN1=0,IN2=0)
            GPIOA->ODR &= ~(GPIO_ODR_ODR4 | GPIO_ODR_ODR5);
            break;
        case 0x01:  // 前进(IN1=1,IN2=0)
            GPIOA->ODR |= GPIO_ODR_ODR4;    // PA4=1
            GPIOA->ODR &= ~GPIO_ODR_ODR5;   // PA5=0
            break;
        case 0x02:  // 后退(IN1=0,IN2=1)
            GPIOA->ODR &= ~GPIO_ODR_ODR4;   // PA4=0
            GPIOA->ODR |= GPIO_ODR_ODR5;    // PA5=1
            break;
        case 0x03:  // 刹车(IN1=1,IN2=1)
            GPIOA->ODR |= GPIO_ODR_ODR4 | GPIO_ODR_ODR5;
            break;
    }
    
    // 控制右轮方向(IN3=PA6,IN4=PA7)
    switch (right_dir) {
        case 0x00:  // 停止(IN3=0,IN4=0)
            GPIOA->ODR &= ~(GPIO_ODR_ODR6 | GPIO_ODR_ODR7);
            break;
        case 0x01:  // 前进(IN3=1,IN4=0)
            GPIOA->ODR |= GPIO_ODR_ODR6;    // PA6=1
            GPIOA->ODR &= ~GPIO_ODR_ODR7;   // PA7=0
            break;
        case 0x02:  // 后退(IN3=0,IN4=1)
            GPIOA->ODR &= ~GPIO_ODR_ODR6;   // PA6=0
            GPIOA->ODR |= GPIO_ODR_ODR7;    // PA7=1
            break;
        case 0x03:  // 刹车(IN3=1,IN4=1)
            GPIOA->ODR |= GPIO_ODR_ODR6 | GPIO_ODR_ODR7;
            break;
    }
    
    // 设置PWM速度(0x00~0xFF映射到0~99,因ARR=99)

    TIM2->CCR4 = (left_speed * 100) / 255;  // 占空比 = (CCR / ARR) * 100%
    TIM2->CCR3 = (right_speed * 100) / 255;

}

最后在main中添加开启pwm两路输出的命令:

  /* USER CODE BEGIN 2 */
 
	TIM2->CR1 |= TIM_CR1_CEN;             // 启动定时器(CubeMX可能已启动,此处冗余)
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */


  while (1)
  {
    Uart_Analysis(USART1_Head.Rx_over);		
    HAL_Delay(1);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

到此代码编写结束

成品的如下图所示:

1b9b6925a2222a86392481eee6553702.jpg

通过蓝牙主发送:FF 41 80 80 41 A5就可以让蓝牙小车向前。通过发送: FF 00 00 00 00 A5让蓝牙小车停止。

附工程源码

blueCar.zip





关键词: stm32f103     蓝牙     小车    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]