LOADING

加载过慢请开启缓存 浏览器默认开启

STM32蓝牙小车

Abstract: 用STM32做的蓝牙小车


目录:


用到的器材

  1. STM32C8T6最小系统板

  2. JDY-31蓝牙模块

  3. 3.3V稳压模块

  4. L298N模块

  5. 蜂鸣器模块

  6. 2轮智能小车底盘套件

  7. 3.7V 18650锂电池及电池盒

  8. 1.5V碱性电池及电池盒

代码部分

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Motor.h"
#include "JDY31.h"


//U-加速 D-减速 L-左转 R-右转 S-前进 B-后退 1-蜂鸣器响

uint8_t Speed;

void Di_Init(void);
void Di(void);

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    Di_Init();
    JDY31_Init();
    Motor_Init();
    
    while(1)
    {
//		MotorA_SetSpeed(Speed);
//		MotorB_SetSpeed(Speed);
        
        if (JDY31_GetRxFlag()==1)
        {
            //处理接收到的数据
            if (JDY31_RxString[0]=='U') //加速
            {
                if (Speed<=70)
                {
                    Speed+=30;
                }
                else
                {
                    Speed=100;
                }
            }
            else if (JDY31_RxString[0]=='D') //减速
            {
                if (Speed>=30)
                {
                    Speed-=30;
                }
                else
                {
                    Speed=0;
                }
            }
            else if (JDY31_RxString[0]=='L') //左转
            {
                MotorA_SetSpeed(Speed);
                MotorB_SetSpeed(Speed/2);
                
                Delay_ms(200);
                
                MotorA_SetSpeed(0);
                MotorB_SetSpeed(0);
                
            }
            else if (JDY31_RxString[0]=='R') //右转
            {
                MotorB_SetSpeed(Speed);
                MotorA_SetSpeed(Speed/2);
                
                Delay_ms(200);
                
                MotorB_SetSpeed(0);
                MotorA_SetSpeed(0);
            }
            else if (JDY31_RxString[0]=='S') //前进
            {
                MotorA_SetSpeed(Speed);
                MotorB_SetSpeed(Speed);
                
                Delay_ms(200);
                
                MotorA_SetSpeed(0);
                MotorB_SetSpeed(0);
            }
            else if (JDY31_RxString[0]=='B') //后退
            {
                MotorA_SetSpeed(-Speed);
                MotorB_SetSpeed(-Speed);
                
                Delay_ms(200);
                
                MotorA_SetSpeed(0);
                MotorB_SetSpeed(0);
            }
            else if (JDY31_RxString[0]=='1') //蜂鸣器响
            {
                Di();
            }
            //JDY31_SendData(JDY31_RxString);
        }
    }
}

void Di_Init(void)
{
    //蜂鸣器初始化,PB1为I/O
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启时钟
    
    GPIO_InitTypeDef GPIO_InitStructure; //GPIO配置
    GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP; //复用推挽输出
    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1; //发送线
    GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOB,&GPIO_InitStructure);
}

void Di(void)
{
    //蜂鸣器发声
    GPIO_SetBits(GPIOB,GPIO_Pin_1);
    Delay_ms(100);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);
}

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_6; //TIM2_CH2 TIM3_CH1
     GPIO_Init(GPIOA, &GPIO_InitStructure);

    TIM_InternalClockConfig(TIM2); //用内部时钟驱动TIM2的时基单元
    TIM_InternalClockConfig(TIM3); //用内部时钟驱动TIM3的时基单元
    
    TIM_TimeBaseInitTypeDef Time_ClockInitStructure;
    Time_ClockInitStructure.TIM_ClockDivision= TIM_CKD_DIV1; //指定时钟分频
    Time_ClockInitStructure.TIM_CounterMode= TIM_CounterMode_Up; //计数模式
    Time_ClockInitStructure.TIM_Period= 100-1; //ARR自动重装器的值  定时频率: CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)
    Time_ClockInitStructure.TIM_Prescaler= 720-1; //PSC预分频器的值
    Time_ClockInitStructure.TIM_RepetitionCounter= 0; //重复计数器的值
    
    TIM_TimeBaseInit(TIM2,&Time_ClockInitStructure);
    TIM_TimeBaseInit(TIM3,&Time_ClockInitStructure);
    
    TIM_OCInitTypeDef TIME_OCInitStructure;
    TIM_OCStructInit(&TIME_OCInitStructure); //结构体赋初始值
    TIME_OCInitStructure.TIM_OCMode= TIM_OCMode_PWM1; //设置输出比较模式
    TIME_OCInitStructure.TIM_OCPolarity= TIM_OCPolarity_High; //设置极性
    TIME_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable; //输出使能
    TIME_OCInitStructure.TIM_Pulse= 0; //设置CCR  PWM频率=定时频率 PWM占空比:Duty=CCR/(ARR+1) PWM分辨率:1/(ARR+1)
    
    TIM_OC2Init(TIM2,&TIME_OCInitStructure);
    TIM_OC1Init(TIM3,&TIME_OCInitStructure);
    
    TIM_Cmd(TIM2,ENABLE); //开启定时器
    TIM_Cmd(TIM3,ENABLE); //开启定时器
}

void PWM_SetCompare1_TIM3(uint16_t Compare) //TIM3_CH1
{
    TIM_SetCompare1(TIM3,Compare); //设置CCR的值
}

void PWM_SetCompare2_TIM2(uint16_t Compare) //TIM2_CH2
{
    TIM_SetCompare2(TIM2,Compare); //设置CCR的值
}

void PWM_SetPrescaler(uint16_t prescaler)
{
    TIM_PrescalerConfig(TIM2,prescaler,TIM_PSCReloadMode_Immediate);
}

Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

#define INA1 GPIO_Pin_4
#define INA2 GPIO_Pin_5
#define INB1 GPIO_Pin_2
#define INB2 GPIO_Pin_3

//TIM2控制电机A,TIM3控制电机B

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 = INA1 | INA2 | INB1 | INB2; //电机方向控制脚 4,5 2,3
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    PWM_Init();
}

void MotorA_SetSpeed(int8_t Speend)
{
    if (Speend>=0)
    {
        GPIO_SetBits(GPIOA,INA2);
        GPIO_ResetBits(GPIOA,INA1);
        PWM_SetCompare2_TIM2(Speend);
    }
    else
    {
        GPIO_ResetBits(GPIOA,INA2);
        GPIO_SetBits(GPIOA,INA1);
        PWM_SetCompare2_TIM2(-Speend);
    }
}

void MotorB_SetSpeed(int8_t Speend)
{
    if (Speend>=0)
    {
        GPIO_SetBits(GPIOA,INB1);
        GPIO_ResetBits(GPIOA,INB2);
        PWM_SetCompare1_TIM3(Speend);
    }
    else
    {
        GPIO_ResetBits(GPIOA,INB1);
        GPIO_SetBits(GPIOA,INB2);
        PWM_SetCompare1_TIM3(-Speend);
    }
}

JDY31.h

在之前的文章

成果分析

  • 制作过程中想使用OLED显示屏,但是一直显示不正常,排除显示屏和代码的问题,原因未知,推测为接的线相互影响导致I2C通信不正常
  • 制作时使用了两个电源分别给电机驱动模块和单片机供电,在底盘面积足够的情况下应该是不错的选择
  • JDY-31模块莫名出问题,但已解决
  • L298N模块使用时需要和单片机共地(重要
  • 成品小车出现轨迹倾斜的情况,可能的原因:车轮或电机固定时有倾斜、电机供电线不同影响电机转速
  • 二轮小车底盘存在一些不重要的问题,之后考虑使用四轮的底盘