基于stm32cubeMX的的HAL库开发的智能小车------变速和红外寻迹小车

我的第一辆智能小车

提示:小编也是初学者,本文适用于想完成一个基础智能四轮车的初学者,大佬还请勿喷,欢迎各位指出错误的地方

暑假在家无聊,刚好也在学习STM32的HAL库,就想着做个小车巩固自己学到的知识,顺便记录自己所遇到的错误

小编也是现学现写,现已学会变速和红外寻迹,准备做一个蓝牙遥控红外寻迹超声波避障小车

这篇博客讲述的就是如何去制作变速和寻迹小车,

1,相关传感器的介绍

1.1TCRT5000红外寻迹模块的介绍

TCRT5000红外寻迹模块是一种基于红外反射原理的传感器,用于检测和跟踪目标物体的位置。

红外对管传感器
其原理很简单:

// 未碰到黑线(接收到红外光):对应状态 = 0
 // 碰到黑线(未接收到红外光):对应状态 = 1

                                                                                                           

1.2L298N直流电机驱动板

L298N直流电机驱动板是一种常用的双H桥驱动器,可控制直流电机的转动方向和速度,适用于机器人、小车等电机驱动应用。

具体的用法:上一期博客

                                                                                                           
                                                            

 2.stm32f103c8t6对应功能的引脚分配

具体的引脚分配要根据STM32F103C8T6引脚定义表来分配,这个我会放在文末的资源包里面

可以和我的不一样,这里注意了具有PWM输出比较功能的定时器只有通用和高级定时器,基本定时器是没有这个功能的。

STM32F103C8T6微控制器的定时器资源包括:
- 3个通用定时器(TIM2、TIM3、TIM4)
- 1个高级定时器(TIM1)
- 2个基本定时器(TIM6、TIM7)

总共有6个定时器可供使用。

选用控制电极速度的引脚是PB6/7/8/9
分别对应的是TIM4_CH1/CH2/CH3/CH4
都在一起,方便调试
选择控制正反转的引脚是PA0/1/2/3/4/5/6/7  选择GPIO_Output
 轮子          EN           IN1  IN2       IN3   IN4
左前轮        PB6       PA0    PA1
右前轮        PB7                            PA2    PA3
左后轮        PB8                            PA6    PA7
右后轮        PB9       PA4    PA5 

寻迹模块的使用引脚是PB0/1/3/4                选择GPIO_input
                                     IN1/2/3/4 

3.stm32cubeMX的配置

1.引脚的功能分配

                                       

2,RCC外部时钟的配置

这里选择的是外部高速晶振HSE

3,时钟树的配置

这里不懂的强烈推荐去看原子哥的时钟树讲解

点击这里跳转

 4,GPIO的设置以及器宏名

5,SYS的配置,我用的是ST-Link烧录器,这里选择的是Serial Wire

6,Timer的配置

这里是使用了TIM4的四个通道,并将对应的ARR和PSC的值分别设置,不懂的可以看看下面这张图片,这里的ARR的值最好设置为100,使得我们调整CCR(0-100)的值就等同于调整占空比

直流电机的PWM(脉宽调制)频率通常会根据具体的应用和需求而有所不同。然而,一般来说,对于直流电机的PWM控制,频率在几千赫兹到几万赫兹之间是常见的范围。

较高的PWM频率可以提供更精确的控制和速度调节,同时减少噪音和振动。然而,较高的频率可能需要更高的计算和驱动能力。

一般来说,对于直流电机的PWM控制,建议选择频率在5kHz到20kHz之间。这个范围通常能够提供良好的控制性能和较低的噪音水平。我这里设置的是20KHZ,对应的PSC+1=36,ARR+1=100。

 7,工程文件夹的配置

上面那个Project的配置就不细说了,这里推荐勾选这个,将.C和.H文件分开管理

最后点击创建文件

观看了上面的内容还是不会配置的建议下载文件资源包,里面有具体的配置文件

 4,代码展示部分

注意: 因为大部分代码都是软件生成的,里面有很多注释,这里为了直观就都删除了

需要改动的部分都贴出来了

软件生成的代码别乱删

main.c

#include "main.h"
#include "tim.h"
#include "gpio.h"
#include "motor.h"
void SystemClock_Config(void);
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
        HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);
        HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
        HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
        Change_speed(62);//初始速度:速度区间0-100
  while (1)
  {
    /* USER CODE END WHILE */
       Sensor(70,65);//寻迹
    /* USER CODE BEGIN 3 */
  }
}

main.h

#include "stm32f1xx_hal.h"
#include "sensor.h"

motor.c

#include "motor.h"
/*  小车轮子转动驱动代码*/
void Forward(void)
{/* 直行 */
    HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1  1
    HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_RESET);//前左轮-IN2   0   正转
    
    HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3   1
    HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_RESET);//前右轮-IN4  0   正转
    /*            因为L298N驱动模块是对相安装   */
    HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_RESET);//后左轮-IN3  0
    HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4    1  反转
     
    HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_RESET);//后右轮-IN1  0
    HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2     1 反转
}

void Backward()
{/* 后行 */
    HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_RESET);//前左轮-IN1 
    HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2 
    
    HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_RESET);//前右轮-IN3   
    HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4 
    /*            因为L298N驱动模块是对相安装   */
    HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3  
    HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_RESET);//后左轮-IN4    
     
    HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1  
    HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_RESET);//后右轮-IN2    
}
void Turn_Left()
{/* 左转 */
    HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_RESET);//前左轮-IN1 0
    HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2  1 反转
    
    HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3  1
    HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_RESET);//前右轮-IN4   0正转
    /*            因为L298N驱动模块是对相安装   */
    HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_RESET);//后左轮-IN3  0
    HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4   1反转 
     
    HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1  1
    HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_RESET);//后右轮-IN2   0 正转   
}
void Turn_Right()
{/* 右转 */
    HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1 1
    HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_RESET);//前左轮-IN2  0 正转
    
    HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_RESET);//前右轮-IN3  0
    HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4   1反转
    /*            因为L298N驱动模块是对相安装   */
    HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3  1
    HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_RESET);//后左轮-IN4   0 正转 
     
    HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_RESET);//后右轮-IN1  0
    HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2   1 反转  
}
void Stopward()
{/* 停止 */
    HAL_GPIO_WritePin(motorF1_GPIO_Port,motorF1_Pin,GPIO_PIN_SET);//前左轮-IN1 
    HAL_GPIO_WritePin(motorF2_GPIO_Port,motorF2_Pin,GPIO_PIN_SET);//前左轮-IN2 
    
    HAL_GPIO_WritePin(motorF3_GPIO_Port,motorF3_Pin,GPIO_PIN_SET);//前右轮-IN3   
    HAL_GPIO_WritePin(motorF4_GPIO_Port,motorF4_Pin,GPIO_PIN_SET);//前右轮-IN4 
    /*            因为L298N驱动模块是对相安装   */
    HAL_GPIO_WritePin(motorR1_GPIO_Port,motorR1_Pin,GPIO_PIN_SET);//后左轮-IN3  
    HAL_GPIO_WritePin(motorR2_GPIO_Port,motorR2_Pin,GPIO_PIN_SET);//后左轮-IN4    
     
    HAL_GPIO_WritePin(motorR3_GPIO_Port,motorR3_Pin,GPIO_PIN_SET);//后右轮-IN1  
    HAL_GPIO_WritePin(motorR4_GPIO_Port,motorR4_Pin,GPIO_PIN_SET);//后右轮-IN2   
}

motor.h

#ifndef __MOTOR_H_
#define __MOTOR_H_
 
#include "main.h"
void Forward(void);

void Backward(void);
void Turn_Left(void);
void Turn_Right(void);
void Stopward(void);
#endif


sensor.c

这里做出了一些改动,现在小车可以寻直线/曲线/直角转弯

#include "sensor.h"
#include "motor.h"
 void Change_speed(uint16_t speed)
{/* 变速 */
    // 设置电机速度范围(60-100),越大越快
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed);
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed);
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, speed);
    __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, speed);
}
void Sensor(uint16_t value,uint16_t pos)
{//value是小车正常行驶时候的速度,POS是转弯时候的速度
    	if(L1==0&&L2==0&&R1==0&&R2==0)//如果4个全部没有读取黑线,直走;   Forward();
		{
            Change_speed(value);
			Forward();
			HAL_Delay(5);
		}
		
		if(L1==0&&L2==1&&R1==1&&R2==0)//如果2,3读取黑线,直走;   Forward();
		{
            Change_speed(value);
			Forward();
			HAL_Delay(5);
		}
		
		if(L1==0&&L2==1&&R1==0&&R2==0)//如果2读取黑线,左转;   Turn_Left();
		{
            Change_speed(pos);
			Turn_Left();
			HAL_Delay(5);
		}
		
		if(L1==0&&L2==0&&R1==1&&R2==0)//如果3读取黑线,右转;   Turn_Right();
		{
            Change_speed(62);
			Turn_Right();
			HAL_Delay(5);
		}
		      //大左转
     if(L1==1&&(L2==1)&&(R1==0)&&R2==0)
     {
         HAL_Delay(20);//等待响应
         while(1)
         {
             Change_speed(65);
            Turn_Left();
             HAL_Delay(40);//等待响应
            if(L1==0&&(L2==0)&&(R1==1)&&R2==0)
            break;                
         } 
     }
     //大右转
     if(L1==0&&(L2==0)&&(R1==1)&&R2==1)
     {
         HAL_Delay(20);//等待响应
         while(1)
         {
             Change_speed(65);
            Turn_Right();
             HAL_Delay(40);//等待响应
            if(L1==0&&(L2==1)&&(R1==0)&&R2==0)
            break;                
         }
     }
 	
 }

sensor.h

#ifndef __SENSOR_H_
#define __SENSOR_H_
 
#include "main.h"
#include "tim.h"
extern void Sensor(uint16_t value,uint16_t pos);
void Change_speed(uint16_t speed);
#define  L1 HAL_GPIO_ReadPin(sensor4_GPIO_Port,sensor4_Pin)//左 IN4 B4
#define  L2 HAL_GPIO_ReadPin(sensor3_GPIO_Port,sensor3_Pin)//左 IN3 B3
#define  R1 HAL_GPIO_ReadPin(sensor2_GPIO_Port,sensor2_Pin)//右 IN2 B2
#define  R2 HAL_GPIO_ReadPin(sensor1_GPIO_Port,sensor1_Pin) //右 IN1 B1
#endif

5,总结

代码总体是由stm32cubeMX一键生成的,需要改动和添加的地方都在上面了,源码和资源包我也上传了,需要的自提

工程代码:点击这里

6,效果展示

下一篇博客预知-----蓝牙小车

寻迹小车演示视频

  • 22
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
以下是基于STM32F4的HX1838红外遥控程序示例: ```c #include "stm32f4xx.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "misc.h" #define IR_PIN GPIO_Pin_0 #define IR_GPIO GPIOA #define IR_RCC RCC_AHB1Periph_GPIOA volatile uint32_t tick_count = 0; volatile uint32_t last_edge_time = 0; volatile uint32_t ir_code = 0; void SysTick_Handler(void) { tick_count++; } void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0) != RESET) { uint32_t current = tick_count; uint32_t elapsed = current - last_edge_time; last_edge_time = current; if(elapsed > 7000) // Start bit { ir_code = 0; } else if(elapsed > 3500) // End bit { // Process received IR code here } else // Data bit { ir_code <<= 1; if(elapsed > 1000) // Logic 1 { ir_code |= 1; } } EXTI_ClearITPendingBit(EXTI_Line0); } } void init_systick(void) { SysTick_Config(SystemCoreClock / 1000); } void init_ir_receiver(void) { GPIO_InitTypeDef gpio_init; EXTI_InitTypeDef exti_init; NVIC_InitTypeDef nvic_init; RCC_AHB1PeriphClockCmd(IR_RCC, ENABLE); gpio_init.GPIO_Pin = IR_PIN; gpio_init.GPIO_Mode = GPIO_Mode_IN; gpio_init.GPIO_Speed = GPIO_Speed_50MHz; gpio_init.GPIO_OType = GPIO_OType_PP; gpio_init.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(IR_GPIO, &gpio_init); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); exti_init.EXTI_Line = EXTI_Line0; exti_init.EXTI_Mode = EXTI_Mode_Interrupt; exti_init.EXTI_Trigger = EXTI_Trigger_Rising_Falling; exti_init.EXTI_LineCmd = ENABLE; EXTI_Init(&exti_init); nvic_init.NVIC_IRQChannel = EXTI0_IRQn; nvic_init.NVIC_IRQChannelPreemptionPriority = 0x00; nvic_init.NVIC_IRQChannelSubPriority = 0x00; nvic_init.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic_init); } int main(void) { init_systick(); init_ir_receiver(); while(1) { // Your code here } } ``` 这个程序使用了STM32F4的SysTick定时器来计算时间,并使用了外部中断EXTI0来接收HX1838红外解码器的信号。当接收到红外信号时,程序将计算时间间隔并解码数据。你可以在"Process received IR code here"注释下面的代码中添加你自己的逻辑来处理解码后的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值