> 技术文档 > stm32循迹小车_l289n

stm32循迹小车_l289n

        

目录

材料:

循迹模块

电机驱动

单片机

套件

原理

代码:

电机驱动函数

传感器

延时函数

主函数


        网上的大部分stm32循迹小车都是VIP内容,也没有停车这个功能,于是我写了一个完整含有代码的一篇循迹小车,希望帮助大家更好的了解循迹小车。具体的L289N和循迹模块大家可以看其他博主的,组装B站也有视频。

材料:

循迹模块

        

工作电压:DC 3.3 ~ 5V

检测反射距离:1mm ~ 25mm 适用

 

        模块中蓝色的电位器用于调节灵敏度,顺时针旋转,灵敏度变高;逆时针越小,灵敏度变低。

        上电后电源指示灯(绿灯)亮。

        有反射回来,DO 输出低电平,开关指示灯(绿灯)亮。

        没反射回来,DO 输出高电平,开关指示灯(绿灯)灭。

引脚功能:

VCC 3.3/5V GND GND D0 任意 GPIO 口 A0 有 ADC 功能的引脚(一般不使用)

内容参考自循迹模块详解,详细内容可阅读此文章。

电机驱动

 驱动采用L298N

供电控制:
        只需要在12V供电处接上7-12V电压,供电GND处与单片机共地即可,5V供电处会输出一个5V的电压,可以用于给单片机供电,做小车时最常用的就是这种方式。使用这种方式时,板载5V使能不用管。 

L298N 电源 12V 电源12V GND 电源负 L298N stm32 OUT1和OUT2 电机1的两个端子 OUT3和OUT4 电机2的两个端子 ENA PA0 ENB PA2 IN1和IN2 PA4和PA5 IN3和IN4 PA6和PA7 VSS 5V GND GND

        L298N详细信息大家可以看电机驱动----L298N,这里就不再重复了。

单片机

        采用stm32f103RCT6(f1系列应该都可以用)。

套件

        淘宝上有很多4轮三轮都行。

原理

        简单来说就是当循迹模块检测到黑线后,低电平,单片机根据不同的循迹状态来改变PWM值进而改变直流电机电机的速度来完成拐弯操作。

比如0111,最左侧的循迹模块检测到黑线,车的位置偏右,应当向左拐。

代码:

电机驱动函数

PWM.c

#include \"stm32f10x.h\"  // Device headervoid PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;//CCRTIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);}

PWM.h

#ifndef __PWM_H#define __PWM_H#include \"stm32f10x.h\" #define R(speed) TIM_SetCompare1(TIM2, speed);#define L(speed) TIM_SetCompare3(TIM2, speed)void PWM_Init(void);#endif

Motor.h

#include \"stm32f10x.h\"  // Device header#include \"PWM.h\"void Motor_Init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);PWM_Init();}void Motor_SetRightSpeed(int8_t Speed){if (Speed >0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);R(Speed);}else if(Speed==0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);R(Speed);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);R(-Speed);}}void Motor_SetLeftSpeed(int8_t Speed){if (Speed>0){GPIO_SetBits(GPIOA, GPIO_Pin_6);GPIO_ResetBits(GPIOA, GPIO_Pin_7);L(Speed);}else if(Speed==0){GPIO_SetBits(GPIOA, GPIO_Pin_6);GPIO_SetBits(GPIOA, GPIO_Pin_7);L(Speed);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_6);GPIO_SetBits(GPIOA, GPIO_Pin_7);L(-Speed);}}

Motor.h

#ifndef __MOTOR_H#define __MOTOR_H#include \"stm32f10x.h\" void Motor_Init(void);void Motor_SetLeftSpeed(int8_t Speed);void Motor_SetRightSpeed(int8_t Speed);#endif

car.c

#include \"stm32f10x.h\"  // Device header#include \"Motor.h\"#include \"Delay.h\"void Car_Init(){Motor_Init();}void Go_Ahead(){Motor_SetLeftSpeed(35);Motor_SetRightSpeed(35);}void Turn_Right(){Motor_SetRightSpeed(45);Motor_SetLeftSpeed(-30);}void Turn_Left(){Motor_SetLeftSpeed(45);Motor_SetRightSpeed(-30);}void Self_Left(){Motor_SetLeftSpeed(85);Motor_SetRightSpeed(-85);}void Self_Right(){Motor_SetLeftSpeed(-85);Motor_SetRightSpeed(85);}void Car_Stop(){Motor_SetLeftSpeed(0);Motor_SetRightSpeed(0);}void Car_SlowDown(){Motor_SetLeftSpeed(25);Motor_SetRightSpeed(25);}

 

        小车的速度在car.c里面更改。

car.h

#ifndef __CAR_H#define __CAR_Hvoid Car_Init(void);void Self_Right(void);void Self_Left(void);void Turn_Right(void);void Turn_Left(void);void Go_Ahead(void);void Car_Stop(void);void Car_SlowDown(void);#endif

传感器

Get.c

#include \"stm32f10x.h\"  // Device headervoid Get_Init(){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5| GPIO_Pin_6| GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);}

Get,h

#ifndef __Get_H#define __Get_Hvoid Get_Init(void);#endif

延时函数

        采用阻塞延时(简单粗暴)。

Delay.c

#include \"stm32f10x.h\"/** * @brief 微秒级延时 * @param xus 延时时长,范围:0~233015 * @retval 无 */void Delay_us(uint32_t xus){SysTick->LOAD = 72 * xus;//设置定时器重装值SysTick->VAL = 0x00;//清空当前计数值SysTick->CTRL = 0x00000005;//设置时钟源为HCLK,启动定时器while(!(SysTick->CTRL & 0x00010000));//等待计数到0SysTick->CTRL = 0x00000004;//关闭定时器}/** * @brief 毫秒级延时 * @param xms 延时时长,范围:0~4294967295 * @retval 无 */void Delay_ms(uint32_t xms){while(xms--){Delay_us(1000);}} /** * @brief 秒级延时 * @param xs 延时时长,范围:0~4294967295 * @retval 无 */void Delay_s(uint32_t xs){while(xs--){Delay_ms(1000);}} 

Delay.h

#ifndef __DELAY_H#define __DELAY_Hvoid Delay_us(uint32_t us);void Delay_ms(uint32_t ms);void Delay_s(uint32_t s);#endif

主函数

main

#include \"stm32f10x.h\"  // Device header#include \"Delay.h\"#include \"Car.h\"#include \"Get.h\"int L1,L2,R1,R2;int count = 0; // 计数器,用于记录传感器状态变化的次数int last_state = 0; // 记录上一次传感器状态int current_state;void read_sensors(){ L1 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4); L2 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5); R1 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_6); R2 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7);}int main(void){Get_Init();Car_Init();while(1){read_sensors(); current_state = (L1 << 3) | (L2 << 2) | (R1 <= 11)// {// Car_Stop(); // 计数器达到11,车辆停止//while(1);// }//}// else//{switch (current_state){case 0x0: Go_Ahead(); break;case 0x8: Self_Left(); Delay_ms(50); break;case 0xC: Self_Left(); Delay_ms(50); break;case 0x4: Turn_Left(); Delay_ms(10); break;case 0x2: Turn_Right(); Delay_ms(10); break;case 0x1: Self_Right(); Delay_ms(50); break;case 0x3: Self_Right(); Delay_ms(50); break;case 0xF: Car_SlowDown(); break;case 0x6: Car_SlowDown(); Delay_ms(50); break;default: break;}}//  //}}

        注释是停车功能,可根据赛道实际情况进行更改。(这个原理就是数赛道上赛道上的黑线,当检测到是其他状态而上一次是全黑后计数+1, 我们跑完两圈正好是10次,所以到11就停了)。

        希望可以帮助到有需要的人。(下次想写智能风扇or桌宠,大概在寒假而且所有博客都会免费的)