基于stm32的智能小车

目录

一、功能实现

二、硬件清单

三、代码实现

1.先让小车动起来

2.串口控制小车行动

3.点动控制小车

4.硬件pwm调速

5. 左右轮各自调速

6. 循迹小车

7. 解决转弯平滑问题

8. 跟随小车

9. 摇头避障小车

9.1封装摇头功能

9.2封装超声波

9.3 封装电机驱动

10.小车测速实现

11.  串口控制小车并使用Oled显示速度

12. Wi-Fi测速小车并本地Oled显示

13. 语音控制小车


一、功能实现

左右转与前进后退:通过控制左组轮和右组轮的配合实现。pwm调速使其更平滑

循迹功能:基于光电传感器原理,通过判断黑线和白线来决定左转或者右转

跟随功能:通过超声波测出小车和跟随物的距离决定移动方向

避障功能:通过超声波检测出前方障碍物,做出改变方向的决定

语音模块控制:多种语音改变多种引脚的电平,通过语音控制实现以上多种功能的切换

old屏显示速度:将测速模块的数据通过oled屏显示

二、硬件清单

1.stm32f103(其他型号也行)板子

2.智能小车底盘、电机马达

3.电池盒和电池

4.超声波模块

5.sg90舵机模块

(黄pwm 红vcc 灰gnd)

6.old屏

7.测速模块

8.红外模块

9.esp8266

10.语音识别模块

三、代码实现

1.先让小车动起来

电机接线:B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10

motor.c
#include "motor.h"
void goForward(void)//前进
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goBack(void)后退
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
}
void goLeft(void)//左转
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goRight(void)//右转
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void stop(void)//停止
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "main.h"
void goForward(void);
void goBack(void);
void goLeft(void);
void goRight(void);
void stop(void);
#endif
main.c
#include "motor.h"

//main函数的while循环部分:
while (1)
{
    /* USER CODE END WHILE */
    goForward();
    HAL_Delay(1000);
    goBack();
    HAL_Delay(1000);
    goLeft();
    HAL_Delay(1000);
    goRight();
    HAL_Delay(1000);
    stop();
    HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
}

2.串口控制小车行动

usart.c
#include "string.h"
#include "stdio.h"
#include "motor.h"

//串口接收缓存(1字节)
uint8_t buf=0;

//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200

// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];

// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
uint16_t UART1_RX_STA=0;
#define SIZE 12
char buffer[SIZE];

// 接收完成回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    //判断中断由哪个串口触发
    if(huart->Instance == USART1)
    {
        //判断接收是否完成(UART1_RX_STA bit15 位是否为1)
        if((UART1_RX_STA & 0x8000) == 0)
        {
            //如果已经收到了 0x0d (回车),
            if(UART1_RX_STA & 0x4000)
            {
                //判断是否收到 0x0a (换行)
                if(buf == 0x0a)
                {
                    //如果 0x0a和0x0d都收到,则将bit15位置为1
                    UART1_RX_STA |= 0x8000;
                    
                    if(!strcmp(UART1_RX_Buffer, "M1"))
                        goForward();
                    else if(!strcmp(UART1_RX_Buffer, "M2"))
                        goBack();
                    else if(!strcmp(UART1_RX_Buffer, "M3"))
                        goLeft();
                    else if(!strcmp(UART1_RX_Buffer, "M4"))
                        goRight();
                    else
                        stop();
                    memset(UART1_RX_Buffer, 0, UART1_REC_LEN);
                    UART1_RX_STA = 0;
                }
                else
                    //否则认为接收错误,重新开始
                    UART1_RX_STA = 0;
            }
            else // 如果没有收到了 0x0d (回车)            
            {
                //则先判断收到的这个字符是否是 0x0d (回车)
                if(buf == 0x0d)
                {
                    //是的话则将 bit14 位置为1
                    UART1_RX_STA |= 0x4000;
                }
                else
                {
                    //否则将接收到的数据保存在缓存数组里
                    UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
                    UART1_RX_STA++;
                    //如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
                    if(UART1_RX_STA > UART1_REC_LEN - 1)
                        UART1_RX_STA = 0;
                }
            }
        }
        //重新开启中断
        HAL_UART_Receive_IT(&huart1, &buf, 1);
    }
}
int fputc(int ch, FILE *f)
{
    unsigned char temp[1]={ch};
    HAL_UART_Transmit(&huart1,temp,1,0xffff);
    return ch;
}

main.c
#include "motor.h"
extern uint8_t buf;
//main函数
HAL_UART_Receive_IT(&huart1, &buf, 1);

3.点动控制小车

usart.c
if (!strcmp(UART1_RX_Buffer, "M1"))
{
    goForward();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M2"))
{
    goBack();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M3"))
{
    goLeft();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M4"))
{
    goRight();
    HAL_Delay(10);
}
else
    stop();
main.c
HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //或者通过cubeMX配置
while(1)
{
    stop();
}

4.硬件pwm调速

cubeMX 配置

 根据公式配置psc和arr

 

 代码实现

main.c

// main函数里
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
while (1)
{
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 8);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 8);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 10);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 10);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 15);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 15);
    HAL_Delay(1000);
}

5. 左右轮各自调速

代码实现
// main函数里
while (1)
{
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,8);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,15);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,15);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,8);
    HAL_Delay(1000);
}

6. 循迹小车

循迹模块(左) -- PB3  循迹模块(右) -- PB4

代码实现

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
// main函数里
while (1)
{
    if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
    goForward();
    if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
    goLeft();
    if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
    goRight();
    if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
    stop();
}

7. 解决转弯平滑问题

代码实现
#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
// main函数里
while (1)
{
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,19);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,19);
    }
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,15);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,8);
    }
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,8);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,15);
    }
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,0);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,0);
    }
}

8. 跟随小车

跟随模块(左) -- PB5  跟随模块(右) -- PB6
代码实现
#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)
// main函数里
while (1)
{
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
        goForward();
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
        goRight();
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
        goLeft();
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
        stop();
}

9. 摇头避障小车

9.1封装摇头功能

舵机接线:sg90 -- PB9
sg90.c
#include "sg90.h"
#include "gpio.h"
#include "tim.h"

void initSG90(void)//初始化90度
{
    HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4); //启动定时器4
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}

void sgMiddle(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}

void sgRight(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
}

void sgLeft(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 25); //将舵机置为180度
}

sg90.h

#ifndef __SG90_H__
#define __SG90_H__

void initSG90(void);
void sgMiddle(void);
void sgRight(void);
void sgLeft(void);

#endif

main.c

initSG90();

HAL_Delay(1000);

while (1)
{
    sgLeft();
    HAL_Delay(1000);
    sgMiddle();
    HAL_Delay(1000);
    sgRight();
    HAL_Delay(1000);
    sgMiddle();
    HAL_Delay(1000);
}

9.2封装超声波

超声波接线 Trig       --    PB7  Echo     -- PB8

cubeMX 配置

 

 

代码实现
sr04.c
#include "sr04.h"
#include "gpio.h"
#include "tim.h"
//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
    /* 使能定时器2计数 */
    __HAL_TIM_ENABLE(&htim2);
    __HAL_TIM_SetCounter(&htim2, 0);
    while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
    /* 关闭定时器2计数 */
    __HAL_TIM_DISABLE(&htim2);
}
double get_distance(void)
{
    int cnt=0;
    //1. Trig ,给Trig端口至少10us的高电平
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);//拉高
    TIM2_Delay_us(20);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);//拉低
    //2. echo由低电平跳转到高电平,表示开始发送波
    //波发出去的那一下,开始启动定时器
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET);//等待输入电平拉高
    HAL_TIM_Base_Start(&htim2);
    __HAL_TIM_SetCounter(&htim2,0);
    //3. 由高电平跳转回低电平,表示波回来了
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET);//等待输入电平变低
    //波回来的那一下,我们开始停止定时器
    HAL_TIM_Base_Stop(&htim2);
    //4. 计算出中间经过多少时间
    cnt = __HAL_TIM_GetCounter(&htim2);
    //5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
    return (cnt*340/2*0.000001*100); //单位:cm
}
sr04.h
#ifndef __SR04_H__
#define __SR04_H__

double get_distance(void);

#endif
main.c
while (1)
{
    if(dir != MIDDLE)
    {
        sgMiddle();
        dir = MIDDLE;
        HAL_Delay(300);
    }
    disMiddle = get_distance();
    if(disMiddle > 35)
    {
        //前进
    }
    else
    {
        //停止
        //测左边距离
        sgLeft();
        HAL_Delay(300);
        disLeft = get_distance();
        sgMiddle();
        HAL_Delay(300);
        sgRight();
        dir = RIGHT;
        HAL_Delay(300);
        disRight = get_distance();
    }
}

9.3 封装电机驱动

硬件接线与1一样: B-1A -- PB0  B-1B -- PB1  A-1A -- PB2  A-1B -- PB10
代码实现
while (1)
{
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    if(dir != MIDDLE){
        sgMiddle();
        dir = MIDDLE;
        HAL_Delay(300);
    }
    disMiddle = get_distance();
    if(disMiddle > 35){
        //前进
        goForward();
    }else if(disMiddle < 10){
        goBack();
    }else
    {
        //停止
        stop();
        //测左边距离
        sgLeft();
        HAL_Delay(300);
        disLeft = get_distance();
        sgMiddle();
        HAL_Delay(300);
        sgRight();
        dir = RIGHT;
        HAL_Delay(300);
        disRight = get_distance();
        if(disLeft < disRight){
            goRight();
            HAL_Delay(150);
            stop();
        }
        if(disRight < disLeft){
            goLeft();
            HAL_Delay(150);
            stop();
        }
    }
    HAL_Delay(50);
}         

10.小车测速实现

硬件接线 测速模块: VCC -- 3.3V 不能接5V,否则遮挡一次会触发 3 次中断  OUT -- PB14
cubeMX 配置

 

 

 代码实现

unsigned int speedCnt;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_14)
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
            speedCnt++;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    printf("speed: %d\r\n", speedCnt);
    speedCnt = 0;
}
main函数里:
HAL_TIM_Base_Start_IT(&htim2);

11.  串口控制小车并使用Oled显示速度

硬件接线 SCL -- PB6 SDA -- PB7
封装 Oled 模块
代码实现
oled.c
#include "oled.h"
#include "i2c.h"
#include "oledfont.h"

void Oled_Write_Cmd(uint8_t dataCmd)
{
	
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,
										&dataCmd, 1, 0xff);
}

void Oled_Write_Data(uint8_t dataData)
{
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,
										&dataData, 1, 0xff);
}

void Oled_Init(void){
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel		
}

void Oled_Screen_Clear(void){
	char i,n;
	Oled_Write_Cmd (0x20);                    //set memory addressing mode
	Oled_Write_Cmd (0x02);                    //page addressing mode

	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xb0+i);               //éè??ò3μ??·£¨0~7£?
		Oled_Write_Cmd(0x00);                 //éè????ê??????aáDμíμ??·
		Oled_Write_Cmd(0x10);                 //éè????ê??????aáD??μ??·   
		for(n=0;n<128;n++)Oled_Write_Data(0x00); 			
	}	
}

void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
	unsigned int  i;
	Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high	
	for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}

	Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high
	for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}		
}


/******************************************************************************/
// 函数名称:Oled_Show_Char 
// 输入参数:oledChar 
// 输出参数:无 
// 函数功能:OLED显示单个字符
/******************************************************************************/
void Oled_Show_Str(char row,char col,char *str){
	while(*str!=0){
		Oled_Show_Char(row,col,*str);
		str++;
		col += 8;	
	}		
}
oled显示速度
代码实现
extern uint8_t buf;
unsigned int speedCnt = 0;
char speedMes[24];  //主程序发送速度数据的字符串缓冲区

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == GPIO_PIN_14)
		if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
			speedCnt++;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	printf("speed: %d\r\n", speedCnt);
	sprintf(speedMes,"speed:%2d cm/s",speedCnt);//串口数据的字符串拼装,speed是格子,每个格子1cm
	Oled_Show_Str(2,2,speedMes);
	speedCnt = 0;
}

12. Wi-Fi测速小车并本地Oled显示

硬件接线  把esp8266插进串口 1
代码实现
main.c
#define MIDDLE 0
#define LEFT 1
#define RIGHT 2

#define BZ 1
#define XJ 2
#define GS 3

#define LeftWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

#define LeftWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8)
#define RightWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9)

#define A25 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define A26 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13)
#define A27 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14)

char dir;

void xunjiMode()
{
	if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_RESET)
		goForward();
	if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_RESET)
		goLeft();
	if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_SET)
		goRight();
	if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_SET)
		stop();
}

void gensuiMode()
{
	if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_RESET)
		goForward();
	if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_RESET)
		goRight();
	if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_SET)
		goLeft();
	if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_SET)
		stop();
}

void bizhangMode()
{
	double disMiddle;
	double disLeft;
	double disRight;

	if(dir != MIDDLE){
		sgMiddle();
		dir = MIDDLE;
		HAL_Delay(300);
	}
	disMiddle = get_distance();
	
	if(disMiddle > 35){
		//前进
		goForward();
	}else if(disMiddle < 10){
		goBack();
		
	}else
	{
		//停止
		stop();
		//测左边距离
		sgLeft();
		HAL_Delay(300);
		disLeft = get_distance();
		
		sgMiddle();
		HAL_Delay(300);
		
		sgRight();
		dir = RIGHT;
		HAL_Delay(300);
		disRight = get_distance();
		
		if(disLeft < disRight){
			goRight();
			HAL_Delay(150);
			stop();
		}
		if(disRight < disLeft){
			goLeft();
			HAL_Delay(150);
			stop();
		}
	}
	HAL_Delay(50);
}

//main部分
  MX_GPIO_Init();
  MX_TIM4_Init();
  MX_TIM2_Init();
  MX_I2C1_Init();

	initSG90();
	HAL_Delay(1000);
	dir = MIDDLE;
	Oled_Init();
	Oled_Screen_Clear();
	Oled_Show_Str(2,2,"-----Ready----");

  while (1)
  {
		//满足寻迹模式的条件
		if(A25 == 1 && A26 == 1 && A27 == 0){
			if(mark != XJ){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----XunJi----");
			}
			mark = XJ;
			xunjiMode();
		}
		//满足跟随模式的条件
		if(A25 == 0 && A26 == 1 && A27 == 1){
			if(mark != GS){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----GenSui----");
			}
			mark = GS;
			gensuiMode();
		}
		//满足避障模式的条件
		if(A25 == 1 && A26 == 0 && A27 == 1){
			if(mark != BZ){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----BiZhang----");
			}
			mark = BZ;
			bizhangMode();
		}
  }
}

13. 语音控制小车

语音模块硬件接线 A25 -- PA15 (跟随) A26 -- PA13 (避障) A27 -- PA14 (循迹)
cubeMX配置

 

 代码实现

#include "sg90.h"
#include "sr04.h"
#include "motor.h"
#include "oled.h"
#include "string.h"
#define MIDDLE 0
#define LEFT 1
#define RIGHT 2
#define BZ 1
#define XJ 2
#define GS 3
#define LeftWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
#define LeftWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8)
#define RightWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9)
#define XJ_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14)
#define GS_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define BZ_VALUE HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13)
char dir;
void xunjiMode()
{
    if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_RESET)
        goForward();
    if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_RESET)
        goLeft();
    if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_SET)
        goRight();
    if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_SET)
        stop();
}
void gensuiMode()
{
    if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_RESET)
        goForward();
    if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_RESET)
        goRight();
    if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_SET)
        goLeft();
    if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_SET)
        stop();
}
void bizhangMode()
{
    double disMiddle;
    double disLeft;
    double disRight;
    if(dir != MIDDLE){
        sgMiddle();
        dir = MIDDLE;
        HAL_Delay(300);
    }
    disMiddle = get_distance();
    if(disMiddle > 35){
        //前进
        goForward();
    }else if(disMiddle < 10){
        goBack();
    }else
    {
        //停止
        stop();
        //测左边距离
        sgLeft();
        HAL_Delay(300);
        disLeft = get_distance();
        sgMiddle();
        HAL_Delay(300);
        sgRight();
        dir = RIGHT;
        HAL_Delay(300);
        disRight = get_distance();
        if(disLeft < disRight){
            goRight();
            HAL_Delay(150);
            stop();
        }
        if(disRight < disLeft){
            goLeft();
            HAL_Delay(150);
            stop();
        }
    }
    HAL_Delay(50);
}
int main(void)
{
    int mark = 0;
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM4_Init();
    MX_TIM2_Init();
    MX_I2C1_Init();

    initSG90();
    HAL_Delay(1000);
    dir = MIDDLE;
    Oled_Init();
    Oled_Screen_Clear();

    Oled_Show_Str(2,2,"-----Ready----");
    while (1)
    {
        if(XJ_VALUE == GPIO_PIN_RESET && GS_VALUE == GPIO_PIN_SET && BZ_VALUE ==
                GPIO_PIN_SET)
        {
            if(mark != XJ)
            {
                Oled_Screen_Clear();
                Oled_Show_Str(2,2,"-----XunJi----");
            }
            mark = XJ;
            xunjiMode();
        }
        //满足循迹模式的条件
        if(XJ_VALUE == GPIO_PIN_SET && GS_VALUE == GPIO_PIN_RESET && BZ_VALUE ==
                GPIO_PIN_SET)
        {
            if(mark != GS)
            {
                Oled_Screen_Clear();
                Oled_Show_Str(2,2,"-----GenSui----");
            }
            mark = GS;
            gensuiMode();
        }
        //满足避障模式的条件
        if(XJ_VALUE == GPIO_PIN_SET && GS_VALUE == GPIO_PIN_SET && BZ_VALUE ==
                GPIO_PIN_RESET)
        {
            if(mark != BZ)
            {
                Oled_Screen_Clear();
                Oled_Show_Str(2,2,"-----BiZhang----");
            }
            mark = BZ;
            bizhangMode();
        }
        HAL_Delay(50);
    }
}

猜你喜欢

转载自blog.csdn.net/2301_77164542/article/details/131524512