基于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,效果展示

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

寻迹小车演示视频

<think>嗯,用户想基于STM32MLX90614红外传感器做一个电子测温装置的仿真测试,需要教程、配置示例。首先,我得回忆一下MLX90614的相关信息,比如它是通过I2C通信的,所以STM32需要配置I2C接口。用户可能已经看过引用资料,里面提到了PB6PB7作为SCLSDA引脚,这可能是指STM32F4系列的,比如STM32F407VET6之类的。 接下来,用户需要仿真测试的方法,可能用的是Proteus这样的仿真软件。但Proteus里有没有MLX90614的模型呢?可能需要用虚拟I2C设备来模拟传感器数据,或者用其他元件替代。比如用I2C EEPROM或者温度传感器模型,或者编写自定义的仿真模型。不过这可能比较复杂,用户可能需要手动发送模拟数据。 然后是STM32的配置部分,需要用STM32CubeMX来设置I2C,生成代码。用户可能需要知道如何初始化I2C,如何读取MLX90614的数据。MLX90614的地址是0x5A,读取温度数据需要发送特定的命令,比如读取物体温度的指令是0x07。代码示例需要包括这些步骤,比如发送读取命令,接收数据,然后进行数据处理,转换成实际温度值。 仿真测试步骤的话,可能需要配置Proteus中的STM32虚拟终端,或者用其他工具如STM32CubeIDE的模拟器,但可能不支持外设模拟。所以可能需要分步测试,比如先确保I2C通信正常,再模拟传感器数据,检查温度读取是否正确。 用户可能遇到的问题包括I2C地址错误、通信失败、数据处理不正确等,需要给出常见问题的解决方法,比如检查地址、上拉电阻、逻辑分析仪调试等。另外,可能还需要考虑传感器的发射率设置,这部分在引用中提到过,但用户的问题里没有具体提到,是否需要包含在仿真中呢?可能需要,但仿真中可能难以模拟,所以暂时先不处理,除非用户有特别需求。 最后生成相关问题的时候,要考虑用户可能的后续疑问,比如如何校准传感器、多传感器同步、低功耗设计等。这些都能帮助用户进一步深入项目。</think>### 基于STM32MLX90614的电子测温装置仿真测试方法 #### 一、仿真环境配置 1. **硬件要求** - STM32F4系列开发板(如STM32F407VET6) - MLX90614传感器模块(I2C接口) - 仿真工具:Proteus 8.9+(需安装STM32元件- 开发环境:STM32CubeMX + Keil MDK-ARM/IAR 2. **Proteus元件选择** - 主控芯片:STM32F407VG - 虚拟仪器:I2C Debugger - 传感器模型:可用虚拟I2C EEPROM模拟MLX90614数据输出[^2] #### 二、STM32CubeMX配置 1. 创建工程选择STM32F4系列芯片 2. 配置I2C1: ```plaintext Mode: I2C Speed: 100kHz SCL Pin: PB6 SDA Pin: PB7 ``` 3. 启用USART1用于调试输出(可选) 4. 生成代码时选择LLHAL #### 三、关键代码实现(HAL示例) ```c // I2C初始化 void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; HAL_I2C_Init(&hi2c1); } // 温度读取函数 float Read_Temperature(void) { uint8_t data[3]; HAL_I2C_Master_Receive(&hi2c1, 0x5A<<1, data, 3, 100); // 传感器地址0x5A float temp = ((data[1] << 8) | data[0]) * 0.02 - 273.15; return temp; } ``` #### 四、Proteus仿真步骤 1. 绘制电路图: - 连接STM32MLX90614的I2C线路 - 添加I2C调试工具监控通信 2. 配置虚拟传感器: ```plaintext 右键点击虚拟I2C器件 -> Edit Properties 设置从机地址:0x5A 预设温度数据:例如0x07 0x5C (对应25℃) ``` 3. 加载编译后的.hex文件 4. 添加电压探针逻辑分析仪观察信号波形[^1] #### 五、测试验证方法 1. **通信测试** - 使用逻辑分析仪验证I2C时序 - 检查ACK信号是否正常返回 2. **温度数据验证** ```c printf("当前温度: %.2f℃\n", Read_Temperature()); ``` 通过虚拟终端应显示预设温度值±0.5℃误差范围 #### 六、常见问题处理 | 现象 | 解决方案 | |------|----------| | I2C无响应 | 检查上拉电阻(4.7kΩ)是否添加 | | 温度值异常 | 验证数据转换公式:`temp = (raw*0.02)-273.15` | | 通信超时 | 调整HAL_Delay()参数,建议10-100ms | §§ 1. 如何校准MLX90614的红外测温精度? 2. STM32如何实现多路MLX90614传感器同步采集? 3. 在低功耗模式下如何优化MLX90614的供电设计? 4. 如何通过PWM控制MLX90614的测量频率? 5. 红外测温数据滤波算法的实现方法有哪些? : 引用[1] : 引用[2]
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值