硬件篇:教你做STM32蓝牙+循迹+避障+pwm调速小车

前言

前面我学完STM32后做了一个蓝牙小车,完成了小车的基本前进后退以及转向,发布的博客也帮助了不少小伙伴,没看过的去看看吧~ 硬件篇:教你做STM32蓝牙小车(基于STM32F103ZET6)最近又心血来潮,打算给小车升升级,经过一个星期的研究,现在实现了多功能小车。

设计思路

在这里插入图片描述

材料准备

以下材料为新增材料,全部材料参照上一篇博客的介绍!!

  • TCRT5000循迹模块
  • HC-SR04超声波模块
  • SG90舵机(180度)
  • 超声波支架
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

程序设计

pwm调速

这里我们直接用上一次用于驱动转向舵机的定时器3的通道2生成一路PWM波用于调速;

在这里插入图片描述

循迹

这里我使用了常见的TCRT500模块三个实现循迹,可以根据自己的需求增加模块数量!
原理很简单,读取io口的电平,正常情况下返回低电平(0)、当遇到黑线时返回高电平(1)。

TCRT.c

#include "TCRT.h"

	//红外循迹部分
	
void TCRT_config(void)	
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;	
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE); // 使能PC端口时钟
	
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5  | GPIO_Pin_6;	//选择对应的引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//配置GPIO模式,输入上拉       
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PC端口
}

void Read_TCRT_Date(void)
{
    
    
	
	L;
	M;
	R;
}

TCRT.h

#ifndef __TCRT_H
#define	__TCRT_H

#include "stm32f10x.h"


#define L GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
#define M GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
#define R GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)

void TCRT_config(void);
void Read_TCRT_Date(void);  //读循迹模块返回的值

#endif

避障

避障我选用了一个超声波模块,通过舵机的左右转动实现障碍物的检测,进而选择前进的道路,另一种方案是采用左、右、中三个超声波模块实现避障,这样做可以保证小车在前进的同时实现障碍物的检测。可以根据自己的需求选择。
这个模块第一次使用,简要介绍一下原理:

HC-SR04基本工作原理:
(1)采用IO口TRIG触发测距,给最少10us的高电平信呈。
(2)模块自动发送840khz的方波,自动检测是否有信号返回;
(3)有信号返回, 通过IO口ECHO输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。 测试距离=(高电平时间*声速(340M/S))/2

这里的代码我参照了另一位大佬的代码进行了修改,原文链接丢失,感谢大佬的文章!!

避障模块左右转

这里我采用了一个SG90的180度舵机,用定时器2生成一路PWM波驱动,代码如下:

sg90.c

#include "sg90.h"

void SG90_pwm_init(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;   
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

	/*  配置GPIO的模式和IO口 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;// PA1
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//TIM2定时器初始化
	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(TIM2, & TIM_TimeBaseInitStructure);


	//PWM初始化	  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	//注意此处初始化时TIM_OC1Init而不是TIM_OCInit,否则会出错。因为固件库的版本不一样。
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能或者失能TIMx在CCR1上的预装载寄存器
	TIM_Cmd(TIM2,ENABLE);//使能或者失能TIMx外设
}

sg90.h

#ifndef __SG90_H
#define	__SG90_H

#include "stm32f10x.h"
#include "delay.h"
   
#define   SG90_Right_90     TIM_SetCompare2(TIM2, 195)		//右转90度
#define   SG90_Right_45		TIM_SetCompare2(TIM2, 190)		
#define   SG90_Front		TIM_SetCompare2(TIM2, 186)		//舵机摆正
#define   SG90_Left_45		TIM_SetCompare2(TIM2, 180)		//左转45度
#define   SG90_Left_90		TIM_SetCompare2(TIM2, 175)
		
void SG90_pwm_init(void);  //舵机pwm初始化

#endif

按键选择模式

这里我直接修改的原子例程里的按键实现,相信学过的都应该会按键的使用,需要注意的是每次选择前需要按一下复位键,让程序从main()函数开始运行;

int main()  
{
    
    	
	  vu8 key=0;
	  SystemInit();         	// 配置系统时钟为72M 
	  uart_init(115200);	   //串口初始化为115200
		Motor_12_Config();    //电机的初使化
		PWM_Init();          //舵机初始化
		BEEP_Init();        //初始化蜂鸣器端口
		delay_init();      //延时函数初始化
	  LED_Init();       //初始化LED端口
	  KEY_Init();      //初始化与按键连接的硬件接口
	  CH_SR04_Init(); //超声波定时器    TIM4
    TCRT_config(); //循迹模块初始化
	  SG90_pwm_init();  //舵机pwm	    TIM2
	
    while(1)  
    {
    
    
			
			key=KEY_Scan(0);	//得到键值
	   	if(key)
		{
    
    						   
			switch(key)
			{
    
    				 
				case WKUP_PRES:	main_1(); break;  //蓝牙小车
				case KEY1_PRES: main_2(); break;	//循迹小车 	
				case KEY0_PRES:	main_3(); break;  //避障小车		
			}
		}else delay_ms(10); 
	}	 
}

接线示意

在这里插入图片描述

成品展示

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

演示视频

视频已上传B站。需要观看的请自行前往!! 传送门

总结

进一步强化加深了对于STM32相关知识的理解和运用,相比于上一次,这一次明显容易了很多,文章写了比较仓促,很多内容写的不是很详细,有不懂的可以评论区留言或者私信我,需要工程文件的评论区留言留下邮箱地址~
如有问题,各位大佬指正~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/k1507157/article/details/115268626