智能小车课设(过程)实验
课设(过程)实验–代码文件包
智能小车课设(过程)实验2 - 遥控测试程序
智能小车的电机驱动模块
电机驱动模块无疑是智能小车不可或缺的关键组件,它负责将电能转化为机械能,驱动小车进行各种运动。在我们的智能小车设计中,我们特别选用了L298N电机驱动芯片作为驱动核心。这款芯片以其出色的驱动能力和卓越的稳定性而著称,能够轻松应对智能小车在各种复杂环境中的运行需求。
通过L298N电机驱动芯片,我们成功实现了对四个直流电机的精准驱动和控制。这四个电机分别负责小车的左右前轮和左右后轮,通过调整它们的转速和转向,我们可以灵活地控制小车的运动状态。无论是前进、后退,还是左转、右转,甚至是原地旋转等复杂动作,都可以通过精确控制电机的运动来实现。
值得一提的是,L298N电机驱动芯片还具备过热保护和短路保护等安全功能。在长时间工作或负载过大的情况下,电机可能会产生过热现象,这时L298N芯片会自动切断电源,以保护电机免受损坏。同时,如果电路中出现短路等异常情况,芯片也会迅速响应,确保整个电机驱动系统的安全性和稳定性。
综上所述,L298N电机驱动芯片在智能小车中的应用不仅提高了小车的运动性能和灵活性,还为其提供了可靠的安全保障。如图2所示:
图2 L298N电机驱动芯片
功能概括
根据提供的代码,这是一个基于STM32F10x系列单片机的四轮全向移动小车控制程序,主要实现电机驱动和多方向运动控制。以下是核心功能概括:
- 硬件初始化
- 定时器配置:
TIM2
和TIM4
初始化为PWM输出模式(72MHz主频)TIM2
控制GPIOA的PA0-PA3(通道1-4)TIM4
控制GPIOB的PB6-PB9(通道1-4)- PWM参数:预分频720-1 → 计数频率100kHz,周期1000 → PWM频率100Hz
- GPIO配置:
- 电机控制引脚设为复用推挽输出(50MHz)
- LED引脚初始化为普通输出(但实际被电机复用)
- 电机驱动逻辑
- H桥控制:每个电机使用两个PWM通道实现正反转
- 正转:A路PWM + B路低电平
- 反转:A路低电平 + B路PWM
- 电机方向定义:
- 电机1/4:正转方向为视觉反转(Dir=0反转)
- 电机2/3:正转方向为视觉正转(Dir=1正转)
- 速度限制:占空比范围0-1000(对应0-100%)
-
运动控制函数
| 函数名 | 运动模式 | 电机控制逻辑 |
|---------------------|---------------|--------------------------------------|
|Car_Forward()
| 直线前进 | 所有电机正转 |
|Car_Backward()
| 直线后退 | 所有电机反转 |
|Car_TransLeft()
| 向左平移 | 左轮正转 + 右轮反转 |
|Car_TransRight()
| 向右平移 | 左轮反转 + 右轮正转 |
|Car_TurnRight()
| 顺时针旋转 | 对角电机正转 + 另一对角反转 |
|Car_TurnLeft()
| 逆时针旋转 | 对角电机反转 + 另一对角正转 | -
主程序逻辑
- 运动序列(每个动作通过空循环延时500000次):
- 前进 → 后退 → 左平移 → 右平移
- 顺时针旋转 → 逆时针旋转
- 右前方45°斜移(仅左下/右上轮工作)
- 左后方平移(仅左下/右上轮反转)
- 万向平移(分两阶段控制不同轮组)
- 关键问题
- 硬件冲突:LED初始化覆盖了PWM引脚配置(GPIOA和GPIOB被重复初始化为普通输出,实际会破坏PWM功能)
- 定时计算错误:代码注释声称定时器1秒溢出,实际计算为:
72MHz / 720 (预分频) = 100kHz → 周期1000计数 = 10ms (非1秒)
- 阻塞式延时:依赖低效的
for
循环延时,无精准时间控制
总结
该代码实现了一个全向移动小车的底层驱动,支持八种运动模式(含复合运动),但存在硬件初始化冲突和定时计算错误,需修正GPIO配置并优化定时逻辑才能实际运行。运动控制通过协调四个电机的正反转组合实现平面任意方向移动。
课设(过程)实验2代码
#include "stm32f10x.h"
void Init_NVIC_TIM2()
{
//--------------定时器初始化---------------
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//GPIOA时钟
GPIO_InitTypeDef GPIO_Struce;
GPIO_Struce.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Struce.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;//pin0~3
GPIO_Struce.GPIO_Speed=GPIO_Speed_50MHz;//高速
GPIO_Init(GPIOA,&GPIO_Struce);//初始化pin0~3
//tim2基本功能初始化
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定时器初始化结构体
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟不分频 = 72MHz
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1; //自动重载值 = 9999,累加10000次溢出,刚好1秒溢出
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频 = 7200,计数频率 = 72MHz / 7200 = 10000Hz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //不重复计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //初始化TIM2
//tim2比较通道初始化
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM2,&TIM_OCInitStructure);//通道1-PA0
TIM_OC2Init(TIM2,&TIM_OCInitStructure);//通道2-PA1
TIM_OC3Init(TIM2,&TIM_OCInitStructure);//通道3-PA2
TIM_OC4Init(TIM2,&TIM_OCInitStructure);//通道4-PA3
TIM_Cmd(TIM2, ENABLE); //使能TIM2,开始计数
}
void Init_NVIC_TIM4()
{
//--------------定时器初始化---------------
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM4时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//GPIOB时钟
GPIO_InitTypeDef GPIO_Struce;
GPIO_Struce.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Struce.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;//pin6~9
GPIO_Struce.GPIO_Speed=GPIO_Speed_50MHz;//高速
GPIO_Init(GPIOB,&GPIO_Struce);//初始化pin6~9
//tim4基本功能初始化
TIM_InternalClockConfig(TIM4);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定时器初始化结构体
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟不分频 = 72MHz
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1; //自动重载值 = 999,累加1000次溢出,刚好1秒溢出
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频 = 7200,计数频率 = 72MHz / 7200 = 10000Hz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //不重复计数
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); //初始化TIM4
//tim4比较通道初始化
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM4,&TIM_OCInitStructure);//通道1 -PB6
TIM_OC2Init(TIM4,&TIM_OCInitStructure);//通道2 -PB7
TIM_OC3Init(TIM4,&TIM_OCInitStructure);//通道3 -PB8
TIM_OC4Init(TIM4,&TIM_OCInitStructure);//通道4 -PB9
TIM_Cmd(TIM4, ENABLE); //使能TIM4,开始计数
}
/**********电机1 速度方向控制***********/
//PA0->TIM2_CH1->MOTORLA->Backward
///PA1->TIM2_CH2->MOTORLB->Forward
//motor1 正转方向为视觉上的反转 即Dir = 0
void Motor1_SetSpeed(uint8_t Dir,uint16_t Speed)
{
if(Speed>=1000)Speed=1000;//占空比限幅: 最大1000
if(Dir)//方向指令判断,正转
{
TIM_SetCompare2(TIM2,0);//通道2占空比0= ---一直低电平
TIM_SetCompare1(TIM2,Speed);//通道1占空比=高电平占空比
}
else if(!Dir)//反转
{
TIM_SetCompare2(TIM2,Speed);//通道2占空比=高电平占空比
TIM_SetCompare1(TIM2,0);//通道1占空比0= ---一直低电平
}
}
/**********电机2 速度方向控制***********/
//PA2->TIM2_CH3->MOTOR2A->Backward
///PA3->TIM2_CH4->MOTOR2B->Forward
//motor2 正转方向为视觉上的正转 即Dir = 1
void Motor2_SetSpeed(uint8_t Dir,uint16_t Speed)
{
if(Speed>=1000)Speed=1000;//占空比限幅: 最大1000
if(Dir)
{
TIM_SetCompare3(TIM2,0);//通道3占空比0= ---一直低电平
TIM_SetCompare4(TIM2,Speed);//通道4占空比=高电平占空比
}
else if(!Dir)
{
TIM_SetCompare3(TIM2,Speed);//通道3占空比=高电平占空比
TIM_SetCompare4(TIM2,0);//通道4占空比0= ---一直低电平
}
}
/**********电机3 速度方向控制***********/
//PB6->TIM4_CH1->MOTOR3A->Backward
///PB7->TIM4_CH2->MOTOR3B->Forward
//motor3 正转方向为视觉上的正转 即Dir = 1
void Motor3_SetSpeed(uint8_t Dir,uint16_t Speed)
{
if(Speed>=1000)Speed=1000;//占空比限幅: 最大1000
if(Dir)
{
TIM_SetCompare1(TIM4,0);//通道1占空比0= ---一直低电平
TIM_SetCompare2(TIM4,Speed);//通道2占空比=高电平占空比
}
else if(!Dir)
{
TIM_SetCompare1(TIM4,Speed);//通道1占空比=高电平占空比
TIM_SetCompare2(TIM4,0);//通道2占空比0= ---一直低电平
}
}
/**********电机4 速度方向控制***********/
//PB8->TIM4_CH3->MOTOR4A->Backward
///PB9->TIM4_CH4->MOTOR4B->Forward
//motor4 正转方向为视觉上的反转 即Dir = 0
void Motor4_SetSpeed(uint8_t Dir,uint16_t Speed)
{
if(Speed>=1000)Speed=1000;//占空比限幅: 最大1000
if(Dir)//方向指令判断,正转
{
TIM_SetCompare4(TIM4,0);//通道4占空比0= ---一直低电平
TIM_SetCompare3(TIM4,Speed);//通道3占空比=高电平占空比
}
else if(!Dir)//反转
{
TIM_SetCompare4(TIM4,Speed);//通道4占空比=高电平占空比
TIM_SetCompare3(TIM4,0);//通道3占空比0= ---一直低电平
}
}
/*********直线向前********/
void Car_Forward(uint16_t Speed)
{
Motor1_SetSpeed(1,Speed);//左下轮正转
Motor2_SetSpeed(1,Speed);//右下轮正转
Motor3_SetSpeed(1,Speed);//右上轮正转
Motor4_SetSpeed(1,Speed);//左上轮正转
}
/*********直线后退********/
void Car_Backward(uint16_t Speed)
{
Motor1_SetSpeed(0,Speed);//左下轮反转
Motor2_SetSpeed(0,Speed);//右下轮反转
Motor3_SetSpeed(0,Speed);//右上轮反转
Motor4_SetSpeed(0,Speed);//左上轮反转
}
/*********向左平移********/
void Car_TransLeft(uint16_t Speed)
{
Motor1_SetSpeed(1,Speed);//左下轮正转
Motor2_SetSpeed(0,Speed);//右下轮反转
Motor3_SetSpeed(1,Speed);//右上轮正转
Motor4_SetSpeed(0,Speed);//左上轮反转
}
/*********向右平移********/
void Car_TransRight(uint16_t Speed)
{
Motor1_SetSpeed(0,Speed);//左下轮反转
Motor2_SetSpeed(1,Speed);//右下轮正转
Motor3_SetSpeed(0,Speed);//右上轮反转
Motor4_SetSpeed(1,Speed);//左上轮正转
}
/*****顺时针旋转***/
void Car_TurnRight(uint16_t Speed)
{
Motor1_SetSpeed(1,Speed);//左下轮正转
Motor2_SetSpeed(0,Speed);//右下轮反转
Motor3_SetSpeed(0,Speed);//右上轮反转
Motor4_SetSpeed(1,Speed);//左上轮正转
}
/*****逆时针旋转***/
void Car_TurnLeft(uint16_t Speed)
{
Motor1_SetSpeed(0,Speed);//左下轮反转
Motor2_SetSpeed(1,Speed);//右下轮正转
Motor3_SetSpeed(1,Speed);//右上轮正转
Motor4_SetSpeed(0,Speed);//左上轮反转
}
//---------流水灯初始化---------
void LED_Init()
{
//GPIOA初始化结构体
GPIO_InitTypeDef GPIO_InitStructure;
//关闭下载调试复用功能、恢复普通GPIO
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
//GPIOA时钟、复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE);
//四个流水灯:PA8,PA11,PA12,PA15
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//GPIO速度50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
//推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIOA初始化
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
//GPIO速度50MHz
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
//推挽输出
GPIO_Init(GPIOB,&GPIO_InitStructure);//GPIOA初始化
}
int main()
{
LED_Init();
Init_NVIC_TIM2();
Init_NVIC_TIM4();
//Sensor_Init();
while(1)
{
int i;
//向前平移20cm
for(i=0;i<500000;i++)
{
Car_Forward(1000);
}
//向后平移20cm
for(i=0;i<500000;i++)
{
Car_Backward(1000);
}
//向左平移20cm
for(i=0;i<500000;i++)
{
Car_TransLeft(1000);
}
//向右平移20cm
for(i=0;i<500000;i++)
{
Car_TransRight(1000);
}
//向左旋转180°
for(i=0;i<500000;i++)
{
Car_TurnRight(1000);
}
//向右旋转180°
for(i=0;i<500000;i++)
{
Car_TurnLeft(1000);
}
//向右前方45°平移20cm
for(i=0;i<500000;i++)
{
Motor1_SetSpeed(1,1000);//左下轮
Motor2_SetSpeed(0,0);//右下轮
Motor3_SetSpeed(1,1000);//右上轮
Motor4_SetSpeed(0,0);//左上轮
}
for(i=0;i<500000;i++)
{
}
//向左后方平移20cm
for(i=0;i<500000;i++)
{
Motor1_SetSpeed(0,1000);//左下轮
Motor2_SetSpeed(0,0);//右下轮
Motor3_SetSpeed(0,1000);//右上轮
Motor4_SetSpeed(0,0);//左上轮
}
for(i=0;i<500000;i++)
{
}
//万向平移
for(i=0;i<500000;i++)
{
Motor1_SetSpeed(0,0);//左下轮
Motor2_SetSpeed(1,1000);//右下轮
Motor3_SetSpeed(0,0);//右上轮
Motor4_SetSpeed(1,1000);//左上轮
}
for(i=0;i<500000;i++)
{
Motor1_SetSpeed(0,0);//左下轮
Motor2_SetSpeed(0,1000);//右下轮
Motor3_SetSpeed(0,0);//右上轮
Motor4_SetSpeed(0,1000);//左上轮
}
}
}