240602_-1_进度搬运_第2个校园团队项目_STM32F103ZET6四轮智能红外循迹避障小车
实践报告格式:
《嵌入式系统创新设计实践——STM32小车实践报告》
- 实践目的
内容一:
在STM32F103ZET6的小车平台上点亮一个LED灯,掌握如何控制GPIO引脚输出。
内容二:
实现小车的前进、后退以及转向功能,并调整小车的运行速度
掌握电机控制基本原理,并分析电机模块与STM32单片机的接口电路。
掌握STM32单片机驱动电机控制小车行走程序设计的基本方法。
内容三:
掌握智能车检测传感器的基本工作原理,包括红外循迹传感器、红外避障传感器和超声波模块,掌握多功能智能车程序设计的基本方法。
实现智能小车循迹程序的设计,设计T型或十字型路线,实现循迹程序的设计。
设计程序能够让小车在行动过程中进行自主避障
- 实践环境与器材
硬件环境:STM32F103ZET6小车开发板、LED灯、电阻、导线、烧录线等。
软件环境:Keil 5 MDK-ARM集成开发环境、STM32F103ZET6芯片手册、ST-LINK调试器等。
三、实践方案(设计内容原理分析,设计方案,硬件结构与接口电路图,软件流程图)
内容一实践方案:
内容分析:
本设计旨在通过应用STM32F103ZET6芯片的通用输入/输出(GPIO)功能,实现对LED灯点亮及熄灭的控制。通过将GPIO引脚配置为输出模式,并据此调整引脚电平至高或低,从而控制LED的工作状态。
设计方案:
- 将LED的正极与GPIO引脚相连,负极接地,并在二者之间串接一只适当的电阻以限制电流。
- 启用相应的GPIO端口时钟,并将GPIO引脚设置为输出模式。
- 编制程序代码,通过控制GPIO引脚输出高电平或低电平,以实现LED的点亮与熄灭。
硬件结构与接口电路图:
软件流程图:
内容二实践方案:
2-1电机驱动部分:
设计内容原理分析:
电机驱动小车运动的基本原理在于,通过控制左右电机引脚的高低电平输出。对于左电机而言,当芯片输出引脚AIN1和AIN2均为低电平时,小车保持静止状态;若AIN1为低电平而AIN2为高电平,则小车向前行驶;反之,若AIN1为高电平而AIN2为低电平,则小车后退。右电机的控制逻辑与左电机相同,即BIN1和BIN2的电平组合决定了小车的停止、前进或后退。此外,通过调整左右电机的运动状态,可以实现小车的左转、右转及停止等操作。
设计方案:
在本设计方案中,电机速度的调控是通过两路PWM信号实现的,这两路PWM信号分别连接至STM32的PB6和PB9引脚,对应于TIM4的第一通道和第四通道。然而,鉴于本设计采用的STM32型号为STM32F103ZET6,其外设并不包含TIM4,因此采用了通过改变定时器周期来生成PWM信号的方法。理论上,可以将TB6612的PWMA和PWMB直接接至高电平,使电机在给定电压下以最高功率运行,但这并不利于精确控制。在采用定时器周期变化生成PWM信号之前,首先需要初始化TB6612与STM32连接的所有GPIO引脚,并对STM32的定时器进行初始化,包括使能相应的总线时钟、设置定时器的定时时间及工作模式、启动定时器,并编写定时器中断服务程序。
硬件结构与接口电路图:
软件流程图:
2-2调速部分:
原理分析:脉宽调制(PWM)的基本原理在于通过对逆变电路中开关器件的通断控制,以产生一系列幅值恒定的脉冲,代替正弦波或其他所需波形。具体而言,是在输出波形的半周期内生成多个脉冲,通过调整这些脉冲的宽度,使其等效电压呈现正弦波形态,从而获得平滑的输出波形,且低次谐波较少。将正弦半波波形等分为N份,视之为由N个相互连接的脉冲组成的波形,这些脉冲的宽度相等,但幅值不同,并且脉冲顶部呈曲线状,按正弦规律变化。通过使用数量相同但宽度不等的矩形脉冲序列替代,使得矩形脉冲的中点与相应正弦等分点重合,并保持矩形脉冲与相应正弦部分面积相等,便可得到PWM波形。在PWM波形中,各脉冲的幅值相等,通过调整脉冲宽度的比例系数,可改变等效输出正弦波的幅值。因此,在交-直-交变频器中,PWM逆变电路输出的脉冲电压即为直流侧电压的幅值。根据给定的正弦波频率、幅值及半周期内的脉冲数,可准确计算出PWM波形各脉冲的宽度和间隔,并据此控制电路中各开关器件的通断,以产生所需的PWM波形。
设计方案:通过预设小车芯片中的调速代码,控制电机电压,进而调节电机转速。在实际控制中,通过H桥控制直流电机的正反转,当T1和T4二极管导通,形成粉色通路;当T2和T3二极管导通,形成蓝色通路,实现弱电控制强电。通过控制二极管的通断时间,即PWM控制,可自由调节Us的电压值,从而控制电机转速。D1-D4二极管起到续流作用,因电机中含绕组,断电后电感电流不能瞬时归零,故断电后电流通过棕色和绿色通路放电。在一个周期内,我们通过控制通电的时间就可以调控平均电压,而平均电压的高低直接控制电机的转速,通电时间/周期,就可以得到占空比,我们也就是通过控制电机的占空比来控制电机的转速的。
硬件结构与接口电路图:
软件流程图:
内容三实践方案:
3-1红外寻迹部分:
设计内容原理分析:循迹模块利用红外传感器检测黑线,通过红外发射管发出的光线,遇白色反射、遇黑色吸收的原理,实现对黑线的识别。红外传感器遇黑线输出高电平,否则输出低电平。因此,左侧传感器遇黑线时小车左拐,右侧传感器遇黑线时小车右拐。
设计方案:STM32智能小车主要由STM32F103C8T6微控制器、L298N电机驱动模块、超声波模块和舵机云台组成。L298N驱动两路电机,超声波模块控制舵机角度,STM32通过GPIO和TIMER控制电机转向、测距和避障。系统使用12V锂电池供电,配备循迹模块和下载器,底盘可选三轮或四轮。
硬件结构与接口电路图:
软件流程图:
3-2红外避障部分:
硬件设计原理:红外对管模块通过发射红外线并接收其反射信号,转换为电信号输出,用于测定障碍物距离和方位。
软件设计原理:
初始化GPIO引脚,将红外发射管引脚设为输出模式,红外接收管引脚设为输入模式。
控制红外发射管通过GPIO引脚高电平发射红外线。
通过读取红外接收管GPIO引脚电平,判断是否接收到反射红外线,以便识别障碍物。
根据障碍物检测结果,控制小车避障或前进。
设计方案:
正确安装并调试传感器,确保传感器在有无障碍物时能正确反应。
使用空程序进行调试,调整传感器直至在5-10cm范围内检测到障碍物时亮灯。
硬件结构与接口电路图:
软件流程图:
四、实践过程及实现(包括实践要求中需要分析的问题及主要实现程序)
内容一:
具体分析:
具体落实到实践中应该怎么进行硬件软件初次操作?
硬件连接
将LED的正极引脚连接到小车板上的一个GPIO引脚。
将LED的负极引脚连接到地线(GND)。
最好在LED的正极还串联一个适当的电阻,以限制电流。
软件配置
使用Keil或其他IDE打开STM32F103VET6的工程项目。
在工程中找到与GPIO相关的头文件和源文件,通常在"stm32f10x_gpio.h"和"stm32f10x_gpio.c"中。
使能对应GPIO端口的时钟。
配置将要用于LED的GPIO引脚为输出模式。
编写控制代码
在main.c或其他合适的文件中编写控制LED的代码。
使用库函数GPIO_WriteBit或者GPIO_Write将对应引脚设置为高电平(打开LED)或低电平(关闭LED)。
如果需要LED闪烁,可以在循环中切换GPIO引脚状态,并使用延时函数控制闪烁频率。
主要实现程序:
#include "stm32f10x.h"
#include "interface.h"
int main()
{
GPIOCLKInit(); //调用IO口使能时钟函数
UserLEDInit(); //调用LED灯函数
while(1)
{
LED_RESET; //低电平点高LED灯
}
}
内容二:
2-1电机驱动部分:
问题及分析:
如何通过人工操作实现对小车的控制(包括红外遥控小车的前进、后退及转向):
通过实施红外遥控技术,实现对小车的人为操控。
主要实现程序:
#include "stm32f10x.h"
#include "interface.h" //连接IO口定义头文件
#include "LCD1602.h"
#include "IRCtrol.h"
#include "motor.h"
//全局变量定义
unsigned int speed_count=0;//占空比计数器 50次一周期
char front_left_speed_duty=SPEED_DUTY;
char front_right_speed_duty=SPEED_DUTY;
char behind_left_speed_duty=SPEED_DUTY;
char behind_right_speed_duty=SPEED_DUTY;
unsigned char tick_5ms = 0;//5ms计数器,作为主函数的基本周期
unsigned char tick_1ms = 0;//1ms计数器,作为电机的基本计数器
unsigned char tick_200ms = 0;//刷新显示
char ctrl_comm = COMM_STOP;//控制指令
unsigned char continue_time=0;
int main(void)
{
delay_init();
GPIOCLKInit();
UserLEDInit();
LCD1602Init();
IRCtrolInit();
TIM2_Init();
MotorInit();
// ServoInit();
while(1)
{
if(tick_5ms >= 5)//5ms
{
tick_5ms = 0;
tick_200ms++;
if(tick_200ms >= 40)
{
tick_200ms = 0;
LEDToggle(LED_PIN);
}
continue_time--;//200ms 无接收指令就停车
if(continue_time == 0)
{
continue_time = 1;
CarStop();//关闭本指令之后,将变成红外遥控小车时要按下停止按钮才能停,为节省遥控器电量建议关闭
}
//do something
if(ir_rec_flag == 1)//接收到红外信号
{
ir_rec_flag = 0;
switch(ctrl_comm)
{
case COMM_UP: CarGo();break;
case COMM_DOWN: CarBack();break;
case COMM_LEFT: CarLeft();break;
case COMM_RIGHT: CarRight();break;
case COMM_STOP: CarStop();break;
default : break;
}
LCD1602WriteCommand(ctrl_comm);
2-2调速部分:
问题分析:
如何调节电机速度?
芯片的通用输入输出(GPIO)接口内置振荡源,并且该寄存器支持多种输出模式,包括推挽输出和脉冲宽度调制(PWM)输出等。通过编程将寄存器配置为PWM输出模式,可以直接从GPIO接口输出PWM波形。此PWM波形可直接连接至舵机引脚,用以控制小车的转速。
主要实现程序:
htim7.Instance = TIM7;
htim7.Init.Prescaler = 72-1;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 100-1;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
{
Error_Handler();
电机正转反转部分:
#include "stm32f10x.h"
#include "interface.h"
#include "LCD1602.h"
#include "IRCtrol.h"
#include "motor.h"
#include "uart.h"
#include "redvoid.h"
//È«¾Ö±äÁ¿¶¨Òå
unsigned int speed_count=0;//Õ¼¿Õ±È¼ÆÊýÆ÷ 50´ÎÒ»ÖÜÆÚ
char front_left_speed_duty=SPEED_DUTY;
char front_right_speed_duty=SPEED_DUTY;
char behind_left_speed_duty=SPEED_DUTY;
char behind_right_speed_duty=SPEED_DUTY;
unsigned char tick_5ms = 0;//5ms¼ÆÊýÆ÷£¬×÷ΪÖ÷º¯ÊýµÄ»ù±¾ÖÜÆÚ
unsigned char tick_1ms = 0;//1ms¼ÆÊýÆ÷£¬×÷Ϊµç»úµÄ»ù±¾¼ÆÊýÆ÷
unsigned char tick_200ms = 0;//Ë¢ÐÂÏÔʾ
char ctrl_comm = COMM_STOP;//¿ØÖÆÖ¸Áî
char ctrl_comm_last = COMM_STOP;//ÉÏÒ»´ÎµÄÖ¸Áî
unsigned char continue_time=0;
unsigned char bt_rec_flag=0;//À¶ÑÀ¿ØÖƱê־λ
// ¼ì²â×ó±ß´«¸ÐÆ÷º¯Êý£¬ÓÐÎïÌåµç»úǰ½ø£¬ÎÞÎïÌåµç»úºóÍË
//IN1=1 ×óºó
//IN2=1 ×óǰ
//IN3=1 ÓÒºó
//IN4=1 ÓÒǰ
void VoidRun2(void) //ÓÐÎïʱºóÍË£¬Ã»ÓÐÎïÌåʱǰ½ø
{
//L×ó±ß¼ì²âµ½ÎïÌå
if(VOID_L_IO == BARRIER_Y)//ǰ·½ÓÐÎïÌå0
{
LED_RESET;//¿ªµÆ µÍµçƽ
//IN1 ¸ßµçƽ×óºóÍË
//IN2 µÍµçƽ
//IN1=1 IN2=0 ×óºóÍ˺¯Êý
FRONT_RIGHT_F_RESET; //IN1 ¸ßµçƽ
FRONT_RIGHT_B_SET; //IN2 µÍµçƽ
}
if(VOID_L_IO == BARRIER_N)//ǰ·½ÎÞÎïÌå1
{
LED_SET; //¹ØµÆ ¸ßµçƽ
//IN1 µÍµçƽ
//IN2 ¸ßµçƽǰ½ø
//IN1=0 IN2=1 ×óǰ½øº¯Êý
FRONT_RIGHT_F_SET; //IN1 µÍµçƽ
FRONT_RIGHT_B_RESET; //IN2 ¸ßµçƽ
}
}
int main(void)
{
delay_init();
GPIOCLKInit();
UserLEDInit();
LCD1602Init();
//IRCtrolInit();
TIM2_Init();
MotorInit();
ServoInit();
RedRayInit();
//USART3Conf(9600);
while(1)
{
VoidRun2();
//LED_RESET;//¿ªµÆ µÍµçƽ
//LED_SET; //¹ØµÆ ¸ßµçƽ
BEHIND_RIGHT_EN;
//BEHIND_LEFT_GO; //×óǰ½øº¯Êý
//BEHIND_LEFT_BACK; //ǰºóÍ˺¯Êý
//FRONT_RIGHT_GO; //ÓÒǰ½øº¯Êý
//FRONT_RIGHT_BACK; //ÓÒºóÍ˺¯Êý
}
内容三:
3-1红外寻迹部分:
问题及分析:当小车拐弯时,如何实现让其减速拐弯?
分析:检测寻迹后提前调整转速。
主要实现程序:
void CarGo(void)
{
front_right_speed_duty=20; //右边前进,改变电机PWM值可实现速度调节
behind_left_speed_duty=20; //左边前进,改变电机PWM值可实现速度调节
}
//后退
void CarBack(void)
{
front_right_speed_duty=-SPEED_DUTY; //右边后退,全速
behind_left_speed_duty=-SPEED_DUTY; //左边后退,全速
}
//向左
void CarLeft(void)
{
front_right_speed_duty=25; //右边前进,实现左转
behind_left_speed_duty=-20; //左边后退
}
//向右
void CarRight(void)
{
front_right_speed_duty=-20; //右边后退
behind_left_speed_duty=25;//左前进,实现右转
}
//停止
void CarStop(void)
{
front_right_speed_duty=0;
behind_left_speed_duty=0;
}
void MotorInit(void)
{
MotorGPIO_Configuration();
CarStop();
//全局变量定义
unsigned int speed_count=0;//占空比计数器 50次一周期
//char front_left_speed_duty=SPEED_DUTY;
char front_right_speed_duty=SPEED_DUTY;
char behind_left_speed_duty=SPEED_DUTY;
//char behind_right_speed_duty=SPEED_DUTY;
unsigned char tick_5ms = 0;//5ms计数器,作为主函数的基本周期
unsigned char tick_1ms = 0;//1ms计数器,作为电机的基本计数器
unsigned char tick_200ms = 0;//刷新显示
char ctrl_comm = COMM_STOP;//控制指令
char ctrl_comm_last = COMM_STOP;//上一次的指令
unsigned char continue_time=0;
unsigned char bt_rec_flag=0;//
3-2红外避障部分:
问题描述:如何实现小车的自主左转、右转、前进及后退操作?
分析过程:首先,需要编写一套控制程序,该程序包含了控制小车左转、右转、前进及后退的相关函数。随后,将此程序通过编程工具烧录至小车的控制单元中,以赋予小车上述的自主移动能力。
主要实现程序:
#include "redvoid.h"
#include "interface.h"
#include "motor.h"
extern char ctrl_comm;
//»ñÈ¡ºìÍâ±ÜÕÏÄ£¿é״̬
char GetVoidStatus(void)
{
char left=0,right=0;
char count;
if(VOID_L_IO == BARRIER_Y)
{
count = 2;
while(--count)//10ms ²É¼¯2´Î¾ùÒª²É¼¯µ½Ç°ÃæÕϰÎïÐÅÏ¢£¬Â˲¨
{
if(VOID_L_IO == BARRIER_N)
break;
Delayms(1);
}
if(count == 0) left = 1;
}
if(VOID_R_IO == BARRIER_Y)
{
count = 2;
while(--count)//10ms ²É¼¯2´Î¾ùÒª²É¼¯µ½Ç°ÃæÕϰÎïÐÅÏ¢£¬Â˲¨
{
if(VOID_R_IO == BARRIER_N)
break;
Delayms(1);
}
if(count == 0) right = 2;
}
return left + right;
}
//ÑÓʱµÄͬʱ¼ì²âºìÍ⣬һµ©·¢ÉúÕϰÎ¾ÍÍ£Ö¹²¢Ìø³öÑÓʱ
void DelayCheck(int ms)
{
while(ms--)
{
Delayms(1);
if(VOID_NONE != GetVoidStatus())
{
CarStop();
return;
}
}
}
//ºìÍâ±ÜÕÏ´¦Àí
//´¦Àí·½Ê½£º×ó±ß¼ì²âµ½ ºóÍË500ms ÓÒת500ms
// Óұ߼ì²âµ½ ºóÍË500ms ×óת500ms
// Á½±ß¼ì²âµ½ ºóÍË700ms ÓÒת500ms
// û¼ì²âµ½ Ö±ÐÐ
void VoidRun(void)
{
char status;
status = GetVoidStatus();
switch(status)
{
case VOID_LEFT:
ctrl_comm = COMM_RIGHT;CarBack(); Delayms(500); CarRight(); DelayCheck(500);
break;
case VOID_RIGHT:
ctrl_comm = COMM_LEFT;CarBack(); Delayms(500); CarLeft(); DelayCheck(500);
break;
case VOID_BOTH:
ctrl_comm = COMM_RIGHT;CarBack(); Delayms(700); CarRight(); DelayCheck(500);
break;
case VOID_NONE:
ctrl_comm = COMM_UP;CarGo();
break;
default: break;
}
}
五、结果与分析(结果描述,实践中遇到的问题及处理方法)
内容一:
问题描述:在启动小车后,观察到指示灯未能点亮。
分析与排查过程:经过仔细检查,确认硬件与软件配置均无异常,且通过USB接口供电时设备运行正常,因此推断问题可能源于电池电量耗尽。随后对电池进行充电,问题得到有效解决。
解决结果:通过程序控制,小车成功执行点灯操作,LED灯顺利点亮。
结果描述:小车LED灯亮起
内容二:
2-1电机驱动部分
遇到的问题及分析:
问题描述:小车在刚开始运行时出现无法控制的旋转现象。
解决措施:经检查发现,问题源于函数代码输入不完整,导致程序运行错误。重新完整 输入函数代码后,小车恢复了正常运行状态。
结果描述:通过红外遥控技术,小车能够完成前进、后退以及旋转等一系列动作。
2-2调速部分
遇到的问题及分析:
在小车运行过程中出现间歇性停顿的问题。
解决方案:
将GPIO结构体配置为全局变量,以解决局部变量与全局变量在作用域和周期上的差异。局部变量仅在函数内有效,其周期限于函数执行期间,函数执行完毕后,其占用的内存将被回收。相反,全局变量在整个文件中有效,其周期贯穿程序运行全程,内存不会被回收。此外,全局变量在定义时会被初始化为零,而局部变量则不会自动清零,其初始值是不确定的。这导致PWM波形可能不是标准的方波。通过初始化所有定义的对象,确保变量的赋值与函数输出一致,从而使小车能够正常运行。
结果描述:小车配备了自动调速功能,能够无缝实现速度从快到慢的渐变过程。
内容三:
3-1红外寻迹部分:
遇到的问题及分析:
问题描述:小车在执行转向动作时出现振动现象。
解决策略:通过调整程序,降低小车的基础运行速度,并在速度变化过程中加入防抖动算法,以减轻小车在转向时的振动情况。
结果描述:小车成功实现了T字形循迹、十字形循迹以及绕圈循迹,并且在执行循迹功能时表现出了平稳的性能。
3-2红外避障部分:
遇到的问题:第一次运行小车时避障会出现避障动作进行一半停滞现象。
处理方法:固定小车的硬件,尽量不让硬件松动,重新烧入程序,使小车能够进行完全避障。
结果描述:把小车放在地上,小车能够自主的移动,自主的进行前进后退左转和右转,并且在运动中,如果前方会碰到障碍的话,小车会进行自主避障。
红外寻迹+红外避障