Abstract: 用STM32做的蓝牙小车
目录:
用到的器材
STM32C8T6最小系统板
JDY-31蓝牙模块
3.3V稳压模块
L298N模块
蜂鸣器模块
2轮智能小车底盘套件
3.7V 18650锂电池及电池盒
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模块使用时需要和单片机共地(重要)
- 成品小车出现轨迹倾斜的情况,可能的原因:车轮或电机固定时有倾斜、电机供电线不同影响电机转速
- 二轮小车底盘存在一些不重要的问题,之后考虑使用四轮的底盘