前面我学完STM32后做了一个蓝牙小车,完成了小车的基本前进后退以及转向,发布的博客也帮助了不少小伙伴,没看过的去看看吧~ 硬件篇:教你做STM32蓝牙小车(基于STM32F103ZET6)最近又心血来潮,打算给小车升升级,经过一个星期的研究,现在实现了多功能小车。
以下材料为新增材料,全部材料参照上一篇博客的介绍!!
这里我们直接用上一次用于驱动转向舵机的定时器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)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(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相关知识的理解和运用,相比于上一次,这一次明显容易了很多,文章写了比较仓促,很多内容写的不是很详细,有不懂的可以评论区留言或者私信我,需要工程文件的评论区留言留下邮箱地址~
如有问题,各位大佬指正~