硬件篇:教你做STM32蓝牙小车(基于STM32F103ZET6)

重要声明

看过我前面51小车博客的都知道我是软件工程专业的,对于硬件方面都是因为感兴趣自学的,这不,因为今年寒假放假比较早,趁这个时间学习了STM32相关知识,经过近一个月的学习对于STM32算是入门了,为了检验自己的学习效果,我决定就着51小车的架子用STM32试试,经过一个下午的忙活算是成功了!!!所以再来和大家分享一下。

所需知识贮备

相信看到这篇文章的小伙伴都是有相关基础的,这里只是给和我一样自学的小伙伴提个醒。动手之前你需要这些:

  • 硬件电路连接相关能力
  • C语言基础能力
  • STM32定时器、中断、串口等基础知识
  • 查阅相关元件开发手册的能力
  • 一定的动手能力

准备材料

正点原子STM32精英开发板(STM32F103ZET6)、LM2596降压模块、HC-06蓝牙模块、MG995系列180度舵机、L298N电机驱动、任意品牌遥控车车架带电机、12V聚合物锂电池一块

部分原始材料图片

在这里插入图片描述

程序设计思路

  • STM32利用L298N电机驱动模块控制前后两路直流电机
motor.c
#include "motor.h"  //导入led头文件
#include "stm32f10x.h"  //导入STM32官方库
#include "stm32f10x_rcc.h"  //导入STM32的RCC时钟库
#include "delay.h"       //延时库
void Motor_12_Config(void)  //定义初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;   //定义GPIO_InitTypeDef结构体
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOF, ENABLE);  //开启引脚时GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; //定义IN引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //通用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //设置输出功率
GPIO_Init(GPIOF, &GPIO_InitStructure);  //初始化GPIOF的引脚参数,写进
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3); //所有引脚拉低
} 
void Motor_1_STOP(void)
{
	IN1(High);
	IN2(High);
} 
void Motor_1_PRun(void)
{
	IN1(Low);
	IN2(High);
} 
void Motor_1_NRun(void)
{
	IN1(High);
	IN2(Low);
}
void Motor_2_STOP(void)
{
	IN3(High);
	IN4(High);
}
void Motor_2_PRun(void)
{
	IN3(Low);
	IN4(High);
}
void Motor_2_NRun(void)
{
	IN3(High);
	IN4(Low);
}
motor.h
#ifndef __MOTOR1_H
#define __MOTOR1_H
#include "stm32f10x.h"
#include "stm32f10x_gpio.h" 
#define High    1
#define Low     0
#define IN1(a) if (a)  \
	GPIO_SetBits(GPIOF,GPIO_Pin_0);\
else  \
	GPIO_ResetBits(GPIOF,GPIO_Pin_0)
 
#define IN2(a) if (a)  \
	GPIO_SetBits(GPIOF,GPIO_Pin_1);\
else  \
	GPIO_ResetBits(GPIOF,GPIO_Pin_1)
 
#define IN3(a) if (a)  \
	GPIO_SetBits(GPIOF,GPIO_Pin_2);\
else  \
	GPIO_ResetBits(GPIOF,GPIO_Pin_2)
#define IN4(a) if (a)  \
	GPIO_SetBits(GPIOF,GPIO_Pin_3);\
else  \
	GPIO_ResetBits(GPIOF,GPIO_Pin_3)
void Motor_12_Config(void);
void Motor_1_STOP(void);
void Motor_1_PRun(void);
void Motor_1_NRun(void);
void Motor_2_STOP(void);
void Motor_2_PRun(void);
void Motor_2_NRun(void);
#endif
  • PWM波控制舵机角度用于转向
PWM.C
#include "PWM.h"
#include "stm32f10x.h"
/* 函 数 名         : pwm_init
 函数功能		   : IO端口及TIM3初始化函数	   */

void PWM_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   //声明一个结构体变量,用来初始化GPIO

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量,用来初始化定时器

	TIM_OCInitTypeDef TIM_OCInitStructure;//根据TIM_OCInitStruct中指定的参数初始化外设TIMx

	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

	/*  配置GPIO的模式和IO口 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;// PC6
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	//TIM3定时器初始化
	TIM_TimeBaseInitStructure.TIM_Period = 199; //PWM 频率=72000/(199+1)=36Khz//设置自动重装载寄存器周期的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7199;//设置用来作为TIMx时钟频率预分频值
	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//TIM向上计数模式
	TIM_TimeBaseInit(TIM3, & TIM_TimeBaseInitStructure);

	GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);//改变指定管脚的映射	//pC6

	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

	TIM_OC1Init(TIM3,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);//使能或者失能TIMx在CCR1上的预装载寄存器
	TIM_Cmd(TIM3,ENABLE);
}
  • HC_06蓝牙模块用于通信(我用的是USART1串口)
    (这部分代码参照原子视频代码即可!)
    因为文章只是分享一个大概,具体的控制外设CSDN上也有很多可以参考的文章,大家有需要可以自行搜索查看,有问题也可以私信我)

接线示意

这里只是示意图,比较简略,只为了展示元件之间的接线,具体的供电根据自己的情况,建议L298N、STM32和舵机全部单独供电,避免产生影响,需要注意的是共地的问题,有基础的应该不难理解!!
在这里插入图片描述

主程序代码

#include "stm32f10x.h"         //官方库
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "sys.h" 
#include "delay.h"
#include "motor.h"
#include "PWM.h"
#include "led.h"
#include "usart.h"
#include "beep.h"

 int main()  
{	
		u16 RxData;	
	  //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 
    
	  uart_init(115200);	 //串口初始化为115200
		Motor_12_Config(); //电机的初使化
		PWM_Init();         //舵机初始化
		BEEP_Init();         	//初始化蜂鸣器端口
		delay_init();  //延时函数初始化
	  LED_Init();    //初始化LED端口
   
    while(1)  
    {
			
			if(USART_GetFlagStatus( USART1, USART_FLAG_RXNE))
			{
				USART_ClearFlag(USART1, USART_FLAG_RXNE);
				RxData=USART_ReceiveData( USART1);
			}
				if(RxData == 0x01){	    //前进
						//GPIO_ResetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉低,亮 等同LED1=0;
						//GPIO_ResetBits(GPIOB,GPIO_Pin_5);//LED0对应引脚GPIOB.5拉低,亮  等同LED0=0
						//GPIO_SetBits(GPIOB,GPIO_Pin_8);
					Motor_1_PRun();
					Motor_2_PRun();
					}
				if(RxData == 0x02){             //后退
					Motor_1_NRun();
					Motor_2_NRun();
				}
				if(RxData == 0x03){         //左转
					TIM_SetCompare1(TIM3,190);
				}
				if(RxData == 0x04){        //回中
					TIM_SetCompare1(TIM3,185);
				}
				if(RxData == 0x05){     
					TIM_SetCompare1(TIM3,180);   //右转
				}
				if(RxData == 0x06){
					 GPIO_SetBits(GPIOB,GPIO_Pin_8);				
				}
				if(RxData == 0x07){         
					GPIO_ResetBits(GPIOB,GPIO_Pin_8);
				}
				if(RxData == 0x00){
						//GPIO_SetBits(GPIOB,GPIO_Pin_5);  //LED0对应引脚GPIOB.5拉高
						//GPIO_SetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉高	
					  //GPIO_ResetBits(GPIOB,GPIO_Pin_8);
					Motor_1_STOP();
					Motor_2_STOP();
					}
    }       
}  

成品展示

请忽略这草率的走线和供电,因为我只是对自己所学的一个检验,并没有像51小车那样把走线完善好,至于为什么没有放在地上跑,这看着也很明显啊,走线不允许啊!!!而且这里我用的精英开发板,如果是要做项目还是推荐mini板啊。
在这里插入图片描述

手机遥控界面

((((安卓的SPP蓝牙串口)))))
个人认为这款蓝牙助手用于开发界面简洁高效,推荐一波!(我可没收广告费)
在这里插入图片描述

总结

这次相对于上一次的51小车来说轻松了不少,一来是因为51给我奠定了一定的基础,对于硬件的理解更近了一步,二来是这次的时间更加充裕,我能够把STM32的基础知识都过一遍,文章写的比较简略,很多原理都没有细说!有需要的可以评论留言!
需要源码的评论区留言!
有做的不好的地方欢迎大家指出!

最近获取源码的小伙伴比较多,所以将源码放在了Gitee上,有需要的自取哦~
Gitee地址:点击这里跳转源码仓库!!!!!
别忘了关注哦~~
在这里插入图片描述

  • 97
    点赞
  • 731
    收藏
    觉得还不错? 一键收藏
  • 203
    评论
### 回答1: 基于STM32F103ZET6的小车循迹代码可以使用红外线传感器对地面上的黑线进行检测,从而实现小车的循迹功能。具体的代码如下: 1. 定义与引脚和传感器相关的常量,包括左右电机、传感器数组等。 2. 在主函数中进行初始化, 设置相关引脚为输入或输出模式,配置定时器等操作。 3. 在主循环中,根据传感器的检测结果,判断小车当前所处位置是否在黑线上。如果在黑线上,则直行;如果偏离了黑线,则根据偏离的方向进行转向。 4. 根据小车当前的转向情况,设置左右电机的工作模式和转速。例如,如果小车偏离了右边的黑线,那么左电机向前转,右电机向后转,从而使小车向左转向。 5. 重复以上步骤,实现小车的循迹功能。 需要注意的是,以上只是一个简单的代码框架,具体的实现还需根据实际情况进行调试和优化。另外,还可以根据具体需求添加其他功能,例如遇到障碍物时的停车等。 ### 回答2: 基于STM32F103ZET6的小车循迹代码是一种通过感应器和电机来实现小车自动行驶的程序。在写代码之前,我们需要明确循迹的原理和实现方法。 循迹原理是通过感应器检测地面上的黑线,并根据检测结果控制电机的转速和方向,从而实现小车沿着黑线行驶。 首先,我们需要将感应器的输出引脚连接到STM32F103ZET6的GPIO引脚上,并在代码中进行初始化。然后,我们可以使用GPIO读取输入的功能来获取感应器的输出结果。 接下来,根据感应器的输出结果,我们可以判断小车当前的位置。如果传感器检测到黑线,那么说明小车还在黑线上,我们需要保持电机的转速和方向不变。如果传感器检测不到黑线,那么说明小车已经偏离了黑线,我们需要相应地调整电机的速度和方向,使其重新回到黑线上。 代码实现的具体步骤如下: 1. 初始化GPIO引脚,将感应器输出引脚连接到正确的GPIO引脚上,并设置为输入模式。 2. 循环检测感应器输出结果。 3. 根据感应器输出结果判断小车当前位置,如果在黑线上,保持电机状态不变;如果偏离黑线,调整电机速度和方向。 4. 根据循迹需求,可以使用PWM控制电机的速度和方向。 5. 在循迹过程中,可以根据需要添加其他功能,例如避障等。 需要注意的是,循迹代码的具体实现可能因硬件和需求有所不同,以上只是一个基本的框架和示例,具体的细节还需要根据实际情况进行调整和完善。 ### 回答3: 基于STM32F103ZET6的小车循迹代码实现可以分为以下几个步骤: 1. 初始化:首先需要初始化STM32的IO口和定时器,以及设置传感器接口的引脚。这些初始化操作可以在代码中通过相关寄存器设置实现。 2. 读取传感器数据:根据循迹的需求,通常需要使用红外传感器或者光敏传感器来检测地面上的黑线。通过读取传感器的模拟信号或数字信号,可以判断小车当前位置的黑线情况。 3. 控制小车行驶:根据传感器数据的读取结果,通过控制小车的电机或舵机,实现小车的移动。一般情况下,通过控制电机的速度和方向来实现前进、后退、转向等操作。 4. 判断循迹方向:根据传感器数据,判断小车当前行驶方向是否在循迹轨道上。如果检测到黑线,那么小车应该保持直线行驶;如果检测不到黑线,就需要根据特定的算法判断偏离轨道的方向和角度,并进行修正。 5. 调整控制参数:为了实现更精确的循迹效果,可能需要调整传感器的灵敏度和小车的转向速度等控制参数。通过实验和调试,改进代码以达到最优的控制效果。 最后,需要注意的是,以上只是一个大致的代码实现思路,具体的代码编写还需要根据硬件设备的类型和功能进行详细设计。此外,循迹算法的设计也是一个重要的环节,可以通过PID控制算法、滑动平均等方式来实现更稳定和精确的循迹效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 203
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值