oscarlly 发表于 2020-8-17 10:30:45

基于stm32单片机的红外遥控超声波避障小车

简述
19年11月到12月,和同学一起在学校参加院电子设计大赛做的项目,捋捋这段经历。
我们在做的时候又多加了测距显示和差速调节(让小车可以从完全停止到最高速度),后面我会分块尽量详细叙述小车的功能原理及代码介绍。

视频演示
https://www.bilibili.com/video/av85501350/
电源
我们采用的是三节18650供电,三节电池就有12v,用来驱动小车绰绰有余,为了获得更稳定符合小车需求的电压,我们又采用了一个LM2596S降压模块,把12V的电压给降到3v给单片机供电。
在安装电源的时候,其实我们犯了一个错误,把电池给安装在了小车的第二层,这样在取放电池时就需要拆卸螺丝,比较麻烦。
驱动
驱动模块使用的是经典的L298N,主要是实验室一抓一大把,关于模块的详细说明可以搜索得到,不再赘述。
我们做的是4轮驱动,把轮子分左右用一个驱动模块进行驱动,为了用PWM对小车进行速度控制,所以我们需要调用时钟,这里调用TI***,使能PB8对左电机进行方向控制,使能PB9作为左电机的PWM信号,使能PA6对右电机进行方向控制,使能PB10作为右电机的PWM信号。
一边有俩电机对应俩轮子,所以,这里还进行了映射,PB8映射到PB5和PB6,对应左边的in1和in2,进行方向控制。
PA6映射到PA5和PA6,对应左边的in3和in4,进行方向控制。
更多具体的配置都在函数里面。
当时我们在对于进行差速控制部分有一个想法,让它实现从零开始逐步加速或者最高速逐步减速,同时也完成要求的三挡速度。
对于要求的三挡速度,其他选了小车的组,据我观察,应该都是在函数里面写好了预先配置3个的PWM占空比,来实现。
当时是我负责的这个功能的实现,我觉得这样写只能单一完成那个要求,然后为了达成我们预想的差速调节,于是我在主函数设置一个变量来代表占空比,然后motor.c里面引进并在后面的调速函数和三挡预置速度函数调用,就能够实现这两个功能了。里面更改占空比的数值是我们测试调节修改出来的。
void speedchange(signed char flag)
{
if(flag==1)
{
i=2000;
TIM_SetCompare2(TI***,i);
TIM_SetCompare4(TI***,i);
}else if(flag==2)
{
i=1000;
TIM_SetCompare2(TI***,i);
TIM_SetCompare4(TI***,i);
}else if(flag==3)
{
i=1;
TIM_SetCompare2(TI***,i);
TIM_SetCompare4(TI***,i);
}
}
void speeddown(void)
{
i+=100;
TIM_SetCompare2(TI***,i);
TIM_SetCompare4(TI***,i);
}
void speedup(void)
{
if(1)
{
   i-=100;
   TIM_SetCompare2(TI***,i);
   TIM_SetCompare4(TI***,i);
while(i<=0)
{
   i=1;
   break;
}
}
在控制方向上,我们有***和有一定精度的角度的***。功能完成也是依靠调节占空比,不再赘述。
下面是驱动的motor.h代码。

moto.h
#ifndef __MOTOR_H_
#define __MOTOR_H_

#include "stm32f10x.h"

void TI***_PWM_Init(unsigned short arr,unsigned short psc);
//电机驱动IO定义
/*
LEFT_MOTOR_GO   PB8 左电机方向控制
LEFT_MOTOR_PWM PB9 左电机PWM

RIGHT_MOTOR_GO PA6   右电机方向控制
RIGHT_MOTOR_PWM PB10   右电机电机PWM
*/
#define LEFT_MOTOR_GOin1             GPIO_Pin_5
#define LEFT_MOTOR_GOin1_GPIO      GPIOB
#define LEFT_MOTOR_GOin1_SET         GPIO_SetBits(LEFT_MOTOR_GOin1_GPIO,LEFT_MOTOR_GOin1)
#define LEFT_MOTOR_GOin1_RESET       GPIO_ResetBits(LEFT_MOTOR_GOin1_GPIO,LEFT_MOTOR_GOin1)

#define LEFT_MOTOR_GOin2             GPIO_Pin_6
#define LEFT_MOTOR_GOin2_GPIO      GPIOB
#define LEFT_MOTOR_GOin2_SET         GPIO_SetBits(LEFT_MOTOR_GOin2_GPIO,LEFT_MOTOR_GOin2)
#define LEFT_MOTOR_GOin2_RESET       GPIO_ResetBits(LEFT_MOTOR_GOin2_GPIO,LEFT_MOTOR_GOin2)

#define LEFT_MOTOR_PWM            GPIO_Pin_7
#define LEFT_MOTOR_PWM_GPIO       GPIOB
#define LEFT_MOTOR_PWM_SET      GPIO_SetBits(LEFT_MOTOR_PWM_GPIO,LEFT_MOTOR_PWM)
#define LEFT_MOTOR_PWM_RESET      GPIO_ResetBits(LEFT_MOTOR_PWM_GPIO,LEFT_MOTOR_PWM)

#define RIGHT_MOTOR_GOin3             GPIO_Pin_4
#define RIGHT_MOTOR_GOin3_GPIO      GPIOA
#define RIGHT_MOTOR_GOin3_SET         GPIO_SetBits(RIGHT_MOTOR_GOin3_GPIO,RIGHT_MOTOR_GOin3)
#define RIGHT_MOTOR_GOin3_RESET       GPIO_ResetBits(RIGHT_MOTOR_GOin3_GPIO,RIGHT_MOTOR_GOin3)

#define RIGHT_MOTOR_GOin4             GPIO_Pin_5
#define RIGHT_MOTOR_GOin4_GPIO      GPIOA
#define RIGHT_MOTOR_GOin4_SET         GPIO_SetBits(RIGHT_MOTOR_GOin4_GPIO,RIGHT_MOTOR_GOin4)
#define RIGHT_MOTOR_GOin4_RESET       GPIO_ResetBits(RIGHT_MOTOR_GOin4_GPIO,RIGHT_MOTOR_GOin4)

#define RIGHT_MOTOR_PWM            GPIO_Pin_9
#define RIGHT_MOTOR_PWM_GPIO       GPIOB
#define RIGHT_MOTOR_PWM_SET      GPIO_SetBits(RIGHT_MOTOR_PWM_GPIO,RIGHT_MOTOR_PWM)
#define RIGHT_MOTOR_PWM_RESET      GPIO_ResetBits(RIGHT_MOTOR_PWM_GPIO,RIGHT_MOTOR_PWM)

#endif
红外遥控
红外遥控部分我们没有进行修改,直接用了正点原子的例程,不多赘述。
值得一提的是,我们在开始项目之前,没有好好查找资料,不知道板子上就有红外,在网上买了额外的红外接收模块HX1838,不过实际效果很好用,而且拉风,就是竖着的那个天线(我的设计,酷炫)。
下面的remote.h的代码
remote.h
#ifndef __RED_H
#define __RED_H
#include "sys.h"   
#define RDATAPAin(1)   //红外数据输入脚

//红外遥控识别码(ID),每款遥控器的该值基本都不一样,但也有一样的.
//我们选用的遥控器识别码为0
#define REMOTE_ID 0
extern u8 RmtCnt;   //按键按下的次数
void Remote_Init(void);   //红外传感器接收头引脚初始化
u8 Remote_Scan(void);   
#endif超声波
超声波部分我们采用的模块是HC-SR04,同样是一个比较经典的模块,这一部分比较搞的是什么,是超声波模块需要5v供电,及其重要,我们一开始代码调试好后,一直显示不出来正确的数据,一直为0(我们有加OLED显示模块,所以可以方便测试),从驱动做好后一直顺风顺水突然在这卡壳了,弄得我们自闭许久。后来在网上查到是5v供电后,一改立马成功。
下面是hcsr04.h的代码
hcsr04.h
#ifndef __CS_H
#define __CS_H

#include "stm32f10x.h"
#include "delay.h"
//使用了TIM3
#include "sys.h"
#define uint unsigned int
#define TRIG_Send PAout(6)
#define ECHO_Reci PAin(7)

void CH_SR04_Init(void);//超声波模块相关配置初始化
float Senor_Using(void);//测距函数,返回值即为距离
void NVIC_Config(void);   //中断配置

#endif
OLED显示
我们用的0.96寸7针显示模块,代码部分也没什么好说的,网上找到读懂后直接调用就行了
oled.h

//            ----------------------------------------------------------------
//            GND    电源地
//            VCC接5V或3.3v电源
//            D0   接PD6(SCL)
//            D1   接PD7(SDA)
//            RES接PD4
//            DC   接PD5
//            CS   接PD3               
#ifndef __OLED_H
#define __OLED_H      
#include "sys.h"
#include "stdlib.h"      
//OLED模式设置
//0:4线串行模式
//1:并行8080模式
#define OLED_MODE 0
#define SIZE 16
#define XLevelL0x00
#define XLevelH0x10
#define Max_Column 128
#define Max_Row64
#define Brightness 0xFF
#define X_WIDTH128
#define Y_WIDTH64            
//-----------------OLED端口定义----------------         
#define OLED_CS_Clr()GPIO_ResetBits(GPIOD,GPIO_Pin_3)//CS
#define OLED_CS_Set()GPIO_SetBits(GPIOD,GPIO_Pin_3)

#define OLED_RST_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_4)//RES
#define OLED_RST_Set() GPIO_SetBits(GPIOD,GPIO_Pin_4)

#define OLED_DC_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_5)//DC
#define OLED_DC_Set() GPIO_SetBits(GPIOD,GPIO_Pin_5)

#define OLED_WR_Clr() GPIO_ResetBits(GPIOG,GPIO_Pin_14)
#define OLED_WR_Set() GPIO_SetBits(GPIOG,GPIO_Pin_14)

#define OLED_RD_Clr() GPIO_ResetBits(GPIOG,GPIO_Pin_13)
#define OLED_RD_Set() GPIO_SetBits(GPIOG,GPIO_Pin_13)

//PC0~7,作为数据线
#define DATAOUT(x) GPIO_Write(GPIOC,x);//输出
//使用4线串行接口时使用

#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_6)//CLK
#define OLED_SCLK_Set() GPIO_SetBits(GPIOD,GPIO_Pin_6)

#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_7)//DIN
#define OLED_SDIN_Set() GPIO_SetBits(GPIOD,GPIO_Pin_7)

#define OLED_CMD0 //写命令
#define OLED_DATA 1 //写数据

//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);   
void OLED_Display_On(void);
void OLED_Display_Off(void);                  
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y, u8 *p);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowCHinese(u8 x,u8 y,u8 no);
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
#endif
主函数
#include "usart.h"
#include "remote.h"
#include "oled.h"
#include "hcsr04.h"
/*
void ZYSTM32_run(int speed,int time);       //前进函数
void ZYSTM32_brake(int time);               //刹车函数
void ZYSTM32_Spin_Left(int speed,int time); //左***函数
void ZYSTM32_Spin_Right(int speed,int time);//右***函数
void ZYSTM32_back(int speed,int time);      //后退函数
*/
float length=0,sum=0;
u16 tim;
uint j=0;
int i=2000;
int main(void)
{
u8 key;
   float distance;
delay_init();
TI***_PWM_Init(7199,0);//初始化PWM
Remote_Init();   //红外接收初始化
CH_SR04_Init();
   OLED_Init();   //初始化OLED
OLED_Clear();
ZYSTM32_brake(500);
NVIC_Config();
while(1)
{   
    key=Remote_Scan();
   distance=Senor_Using();   
   OLED_ShowString(0,2,"distance is");
   OLED_ShowNum(0,4,distance,8,20);
   if(distance>30)
   switch(key)
   {   
    case 98:ZYSTM32_run(100);break;   
    case 2:ZYSTM32_brake(100);break;         
    case 34:ZYSTM32_Spin_Left(100);break;   
    case 168:ZYSTM32_back(100);break;   
    case 194:ZYSTM32_Spin_Right(100);break;
      case 104:speedchange(1);break;
      case 152:speedchange(2);break;
      case 176:speedchange(3);break;
    case 48:turnleft45(220);break;//4   
    case 24:turnright45(220);break;//5   
       case 16:turnleft45(50);break;   //7
      case 56:turnright45(50);break;//8
    case 224:speeddown();break;         
    case 144:speedup();break;
   }
   else
    {
   ZYSTM32_back(100);
   delay_us(50);
   ZYSTM32_brake(100);
   }
}
}

JuicyPeach 发表于 2021-6-22 14:41:09

加油!希望可以学到东西!

eefocus_3715263 发表于 2021-6-15 12:04:32

666666666

eefocus_3707654 发表于 2021-3-1 15:53:12

66666666
页: [1]
查看完整版本: 基于stm32单片机的红外遥控超声波避障小车

Baidu
map