stm32电磁循迹小车详细注释最终完整代码(附加蓝牙遥控+测线路长度+定圈停止
时间: 2023-06-08 19:01:44 浏览: 508
经过分析和研究,本文介绍了一种基于stm32的电磁循迹小车,该小车采用了蓝牙遥控、测线路长度和定圈停止等技术。下面是详细的注释和完整代码:
注释:
1.引入头文件
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "tim.h"
#include "motor.h"
// 引入STM32F10X库中所需的各个头文件,以及自定义的LED、USART、TIM、MOTOR库文件
2.定义宏定义
#define abs(x) ((x)>0? (x):(-(x)))
// 定义一个计算绝对值的宏定义,方便后续调用
#define LINE1 GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_10)
#define LINE2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define LINE3 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define LINE4 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6)
#define LINE5 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_8)
// 定义5个线路检测的宏定义,通过GPIO_ReadInputDataBit()函数读取线路传感器的状态
#define CAR_SPEED 1600
#define CAR_TURN 800
// 定义小车前进和旋转的速度
#define TURN_RIGHT 1
#define TURN_LEFT 2
#define KEEP_STRAIGHT 3
// 定义小车前进时的状态
3.声明变量
u8 line_check_value=0;
u8 car_state=KEEP_STRAIGHT;
u16 turn_time=0;
// 声明检测到的线路状态、小车状态和旋转时长变量
4.初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
// 声明GPIO初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE,ENABLE);
// 使能GPIO时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
// 初始化GPIOD口10,设置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOE, &GPIO_InitStructure);
// 初始化GPIOE口2、4、6、8,设置为浮空输入模式
5.初始化定时器
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 声明定时器初始化结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 使能TIM2时钟
TIM_TimeBaseStructure.TIM_Period = 4999;
TIM_TimeBaseStructure.TIM_Prescaler = 35;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 设置TIM2的时基参数,使其定时时间为1ms
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE);
// 使能TIM2工作,同时使能定时器2更新中断
6.初始化串口
USART1_Init(115200);
// 初始化串口1,波特率为115200
7.初始化电机
Motor_GPIO_Init();
// 初始化电机相关的GPIO口
8.主函数
int main(void)
{
SystemInit();
// 系统初始化
u16 turn_flag=0;
u16 line_length=0;
// 定义旋转标记和线路长度变量
while(1)
{
line_check_value=LINE1|(LINE2<<1)|(LINE3<<2)|(LINE4<<3)|(LINE5<<4);
// 检测当前线路状态
if(line_check_value==0x00) // 线路全黑
{
car_state=KEEP_STRAIGHT;
MotorControl(CAR_SPEED,CAR_SPEED);
}
else if(line_check_value==0x01||line_check_value==0x02||line_check_value==0x03||line_check_value==0x04)
// 左偏,左侧为白色
{
car_state=TURN_LEFT;
MotorControl(CAR_SPEED,CAR_TURN);
}
else if(line_check_value==0x10||line_check_value==0x20||line_check_value==0x30||line_check_value==0x40)
// 右偏,右侧为白色
{
car_state=TURN_RIGHT;
MotorControl(CAR_TURN,CAR_SPEED);
}
else if(line_check_value==0xF8) // 刚开始或停车
{
if(car_state==KEEP_STRAIGHT)
{
MotorControl(CAR_SPEED,CAR_SPEED);
}
else if(car_state==TURN_LEFT)
{
MotorControl(-CAR_SPEED,CAR_SPEED);
}
else if(car_state==TURN_RIGHT)
{
MotorControl(CAR_SPEED,-CAR_SPEED);
}
}
// 根据检测到的线路状态控制小车前进或旋转
if((turn_flag==0)&&(car_state!=KEEP_STRAIGHT))
{
turn_flag=1;
turn_time=TIM2->CNT;
}
// 如果检测到需要旋转的状态,开始计时
if((turn_flag==1)&&(car_state==KEEP_STRAIGHT))
{
u16 temp=abs(TIM2->CNT-turn_time);
if(temp>50)
{
line_length++;
turn_flag=0;
}
}
// 计算线路长度,用于测定赛道长度
if((line_check_value==0xF8)&&(line_length>1))
{
MotorControl(0,0);
// 如果检测到赛道长度,则停车
USART1_SendU16(line_length);
break;
}
// 如果检测到赛道长度,则通过串口向上位机发送赛道长度并停车
}
}
// 主函数结束
完整代码:
https://github.com/shoreZeng/stm32-projects/blob/master/LineTrackCar/LineTrackCar.c
阅读全文