STM32 HAL库实战(智能小车项目详解)第四部分

STM32-HAL库(下4-智能小车项目)

269 智能小车项目概述

(1)小车项目综合了stm32各个知识点,具有代表性;

270 智能小车车身基础安装

(1)小车组装后下载代码验证确保硬件无误;

271 车身基础安装完整版

272 电机驱动模块L9110S

(1)参考文档链接:https://www.lxlinux.net/e/stm32/l9110s-tutorial.html
(2)电机驱动模块:是一种用于控制和驱动电机的设备,它能够将控制信号转化为适合电机操作的电流和电压。
(2)L9110S模块有二路可以驱动2个直流电机,A-1A 输入高电平,A-1B 输入低电平,MotorA 电机正转;A-1A 输入低电平,A-1B 输入高电平,MotorA 电机反转;
B-1A 输入高电平,B-1B 输入低电平,MotorB 电机正转;B-1A 输入低电平,B-1B 输入高电平,MotorB 电机反转。

273 让小车动起来

(1)编写电机初始化函数motor_init(),电机向前函数motor_go_forward(),电机向后函数motor_go_backward(),电机向左函数motor_go_left(),电机向右函数motor_go_right(),电机停止函数motor_stop()。
-(63. 智能小车项目/1. 让小车动起来-main.c,motor.c,motor.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    printf("hello world!\r\n");
    while(1)
    { 
        motor_go_forward();
        delay_ms(1000);
        motor_go_backward();
        delay_ms(1000);
        motor_go_left();
        delay_ms(1000);
        motor_go_right();
        delay_ms(1000);
        motor_stop();
        delay_ms(1000);
    }
}




/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 
/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

274 串口控制小车

(1)参考"63. 智能小车项目/1. 让小车动起来"代码,添加蓝牙模块,uart1文件中添加串口2,蓝牙模块中断服务函数USART2_IRQHandler()中增加蓝牙接收的数据控制小车转向;
-(63. 智能小车项目/2. 串口控制小车-main.c,bluetooth.c,bluetooth.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "bluetooth.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    bt_init(9600);
    printf("hello world!\r\n");
    while(1)
    { 
//        motor_go_forward();
//        delay_ms(1000);
//        motor_go_backward();
//        delay_ms(1000);
//        motor_go_left();
//        delay_ms(1000);
//        motor_go_right();
//        delay_ms(1000);
//        motor_stop();
//        delay_ms(1000);
    }
}

/*
------------------------------------------------------------------------
bluetooth.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "bluetooth.h"
#include "string.h"
#include "stdarg.h"
#include "motor.h"

UART_HandleTypeDef uart2_handle;                                            /* UART2句柄 */

uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE];                                    /* UART2接收缓冲区 */
uint16_t uart2_rx_len = 0;                                                  /* UART2接收字符长度 */


/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void bt_init(uint32_t baudrate)
{
    /*UART2 初始化设置*/
    uart2_handle.Instance = USART2;                                         /* USART2 */
    uart2_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart2_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart2_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart2_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart2_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart2_handle);                                           /* HAL_UART_Init()会使能UART2 */
}

/**
 * @brief       UART2接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart2_rx_clear(void)
{
    memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf));                          /* 清空接收缓冲区 */
    uart2_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口1中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart2_rx_len >= sizeof(uart2_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart2_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart2_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart2_rx_buf[uart2_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("bt recv: %s\r\n", uart2_rx_buf);                               /* 将接收到的数据打印出来 */
        if(strcmp((char *)uart2_rx_buf,"M1") == 0)
            motor_go_forward();
        else if(strcmp((char *)uart2_rx_buf,"M2") == 0)
            motor_go_backward();
        else if(strcmp((char *)uart2_rx_buf,"M3") == 0)
            motor_go_left();
        else if(strcmp((char *)uart2_rx_buf,"M4") == 0)
            motor_go_right();
        else
            motor_stop();            
        uart2_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart2_handle);                           /* 清除UART总线空闲中断 */
    }
}

//void bt_send(char *send_buf,uint8_t size)
//{
//    //HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
//    HAL_UART_Transmit(&uart2_handle,(uint8_t *)send_buf,size,100);
//}    
void bt_send(char * format, ...)
{
    uint8_t send_buf[128] ={0};
    va_list arg;
    va_start(arg, format);
    vsprintf((char *)send_buf, format, arg);
    va_end(arg);
    HAL_UART_Transmit(&uart2_handle,send_buf,sizeof(send_buf),100);
    
}    

/*
------------------------------------------------------------------------
bluetooth.h:
-------------------------------------------------------------------------
*/
#ifndef __BLUETOOTH__H__
#define __BLUETOOTH__H__

#include "stdio.h"
#include "sys.h"


/* UART收发缓冲大小 */
#define UART2_RX_BUF_SIZE            128
#define UART2_TX_BUF_SIZE            64


void bt_init(uint32_t baudrate);            /* 串口初始化函数 */
//void bt_send(char *send_buf,uint8_t size);
void bt_send(char * format, ...);

#endif



275 蓝牙控制小车

(1)直接采用"63. 智能小车项目/2. 串口控制小车"代码,将串口2接蓝牙模块,通过手机蓝牙助手即可控制小车。-待测试

276 点动控制小车

(1)参考"63. 智能小车项目/2. 串口控制小车"代码,蓝牙模块中断服务函数USART2_IRQHandler()中增加延时函数delay_ms(10),main函数中while循环中为电机停止函数motor_stop()。
-(63. 智能小车项目/3. 点动控制小车-main.c,bluetooth.c,bluetooth.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "bluetooth.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    bt_init(9600);
    printf("hello world!\r\n");
    while(1)
    { 
        motor_stop();
    }
}




/*
------------------------------------------------------------------------
bluetooth.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "bluetooth.h"
#include "string.h"
#include "stdarg.h"
#include "motor.h"
#include "delay.h"

UART_HandleTypeDef uart2_handle;                                            /* UART2句柄 */

uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE];                                    /* UART2接收缓冲区 */
uint16_t uart2_rx_len = 0;                                                  /* UART2接收字符长度 */


/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void bt_init(uint32_t baudrate)
{
    /*UART2 初始化设置*/
    uart2_handle.Instance = USART2;                                         /* USART2 */
    uart2_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart2_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart2_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart2_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart2_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart2_handle);                                           /* HAL_UART_Init()会使能UART2 */
}

/**
 * @brief       UART2接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart2_rx_clear(void)
{
    memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf));                          /* 清空接收缓冲区 */
    uart2_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口1中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart2_rx_len >= sizeof(uart2_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart2_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart2_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart2_rx_buf[uart2_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("bt recv: %s\r\n", uart2_rx_buf);                               /* 将接收到的数据打印出来 */
        if(strcmp((char *)uart2_rx_buf,"M1") == 0)
            motor_go_forward();          
        else if(strcmp((char *)uart2_rx_buf,"M2") == 0)
            motor_go_backward();          
        else if(strcmp((char *)uart2_rx_buf,"M3") == 0)
            motor_go_left();            
        else if(strcmp((char *)uart2_rx_buf,"M4") == 0)
            motor_go_right();
        else
            motor_stop();   
        delay_ms(10);
        uart2_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart2_handle);                           /* 清除UART总线空闲中断 */
    }
}

//void bt_send(char *send_buf,uint8_t size)
//{
//    //HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
//    HAL_UART_Transmit(&uart2_handle,(uint8_t *)send_buf,size,100);
//}    
void bt_send(char * format, ...)
{
    uint8_t send_buf[128] ={0};
    va_list arg;
    va_start(arg, format);
    vsprintf((char *)send_buf, format, arg);
    va_end(arg);
    HAL_UART_Transmit(&uart2_handle,send_buf,sizeof(send_buf),100);
    
}    

/*
------------------------------------------------------------------------
bluetooth.h:
-------------------------------------------------------------------------
*/
#ifndef __BLUETOOTH__H__
#define __BLUETOOTH__H__

#include "stdio.h"
#include "sys.h"


/* UART收发缓冲大小 */
#define UART2_RX_BUF_SIZE            128
#define UART2_TX_BUF_SIZE            64


void bt_init(uint32_t baudrate);            /* 串口初始化函数 */
//void bt_send(char *send_buf,uint8_t size);
void bt_send(char * format, ...);

#endif



277 pwm调速小车

(1)参考"63. 智能小车项目/1. 让小车动起来"代码,添加呼吸灯中pwm模块,pwm模块中采用定时器TIM2中的通道1,通道2分别控制左轮,右轮电压占空比值,从而达到pwm调速的目的。
pwm模块中添加了左轮值设定pwm_left_motor_set(),右轮值设定pwm_right_motor_set()。
-(63. 智能小车项目/4. pwm调速小车-main.c,pwm.c,pwm.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "pwm.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    pwm_init(20-1,72-1);
    printf("hello world!\r\n");
    while(1)
    { 
        pwm_left_motor_set(8);
        pwm_right_motor_set(15);
        delay_ms(1000);
        pwm_left_motor_set(15);
        pwm_right_motor_set(8);
        delay_ms(1000);        
    }
}




/*
------------------------------------------------------------------------
pwm.c:
-------------------------------------------------------------------------
*/
#include "pwm.h"

TIM_HandleTypeDef pwm_handler = {0};
//pwm初始化
void pwm_init(uint16_t arr,uint16_t psc)
{
    TIM_OC_InitTypeDef pwm_config = {0};
    pwm_handler.Instance = TIM2 ;
    pwm_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    pwm_handler.Init.Period = arr;
    pwm_handler.Init.Prescaler = psc;
    //HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    HAL_TIM_PWM_Init(&pwm_handler);
//    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
//                                            const TIM_OC_InitTypeDef *sConfig,
//                                            uint32_t Channel)
    
    pwm_config.OCMode = TIM_OCMODE_PWM1;//模式1
    pwm_config.Pulse = 0; //设定比较值CCR,开始设定一次,后面__HAL_TIM_SET_COMPARE()函数中会修改
    pwm_config.OCPolarity = TIM_OCNPOLARITY_HIGH;//有效电平为高电平
    HAL_TIM_PWM_ConfigChannel(&pwm_handler,&pwm_config,TIM_CHANNEL_1);
    HAL_TIM_PWM_ConfigChannel(&pwm_handler,&pwm_config,TIM_CHANNEL_2);
    //HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    HAL_TIM_PWM_Start(&pwm_handler,TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&pwm_handler,TIM_CHANNEL_2);
}    

//msp初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM4)
    {
    
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    __HAL_RCC_TIM2_CLK_ENABLE();//使能TIM2时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    gpio_initstruct.Mode = GPIO_MODE_AF_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);        
    }        
}

//修改CCR寄存器值
void pwm_left_motor_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&pwm_handler,TIM_CHANNEL_1,val);
}  

void pwm_right_motor_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&pwm_handler,TIM_CHANNEL_2,val);
}    

/*
------------------------------------------------------------------------
pwm.h:
-------------------------------------------------------------------------
*/
#ifndef __PWM_H__
#define __PWM_H__
#include "sys.h"
void pwm_init(uint16_t arr,uint16_t psc);
void pwm_left_motor_set(uint16_t val);
void pwm_right_motor_set(uint16_t val);
#endif

278 循迹模块介绍

(1)参考文档链接:https://www.lxlinux.net/e/stm32/tcrt5000-tutorial.html
(2)循迹模块TCRT5000不断发射红外信号,当红外信号:
1.有反射回来,DO 输出低电平,开关指示灯(绿灯)亮。
2.没反射回来,DO 输出高电平,开关指示灯(绿灯)灭。

279 循迹小车

(1)参考"63. 智能小车项目/1. 让小车动起来"代码,添加"智能台灯项目"中的红外传感器模块作为循迹模块,循迹模块中修改初始化函数track_init()中gpio口,
新增获取左模块值标志track_left_flag(),新增获取右模块值标志track_right_flag();main函数中根据左右模块值的不同来控制小车前左右停。
-(63. 智能小车项目/5. 循迹小车-main.c,track.c,track.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "track.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
   track_init();
    printf("hello world!\r\n");
    while(1)
    { 
        if(track_left_flag() == TRUE && track_right_flag() == TRUE)
            motor_go_forward();
        else if(track_left_flag() == FALSE && track_right_flag() == TRUE)
            motor_go_left();
        else if(track_left_flag() == TRUE && track_right_flag() == FALSE)
            motor_go_right();
        else if (track_left_flag() == FALSE && track_right_flag() == FALSE)
            motor_stop();        
    }
}




/*
------------------------------------------------------------------------
track.c:
-------------------------------------------------------------------------
*/
#include "track.h"
#include "sys.h"

//初始化exti函数
void track_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOA时钟
    gpio_initstruct.Pin = GPIO_PIN_13 | GPIO_PIN_14; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct); 
}


uint8_t track_left_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}

uint8_t track_right_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}



/*
------------------------------------------------------------------------
track.h:
-------------------------------------------------------------------------
*/
#ifndef __TRACK_H__
#define __TRACK_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void track_init(void);
uint8_t track_left_flag(void);
uint8_t track_right_flag(void);
#endif

280 循迹+pwm调速小车

(1)参考"63. 智能小车项目/4. pwm调速小车",添加循迹模块代码,main函数里面根据左右模块值的不同来控制小车前左右停(前后左右用pwm中左右轮设定值pwm_left_motor_set(),pwm_right_motor_set())。
-(63. 智能小车项目/6. 循迹+pwm调速小车-main.c,track.c,pwm.c,track.h,pwm.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "pwm.h"
#include "track.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    pwm_init(200-1,720-1);
    printf("hello world!\r\n");
    while(1)
    { 
        if(track_left_flag() == TRUE && track_right_flag() == TRUE)
        {
            pwm_left_motor_set(95);
            pwm_right_motor_set(95);
        }
        else if(track_left_flag() == FALSE && track_right_flag() == TRUE)
        {
            pwm_left_motor_set(0);
            pwm_right_motor_set(95);           
        }
        else if(track_left_flag() == TRUE && track_right_flag() == FALSE)
        {
            pwm_left_motor_set(95);
            pwm_right_motor_set(0);            
        }
        else if(track_left_flag() == FALSE && track_right_flag() == FALSE)
            pwm_left_motor_set(0); 
            pwm_right_motor_set(0); 
    }
}





/*
------------------------------------------------------------------------
track.c:
-------------------------------------------------------------------------
*/
#include "track.h"
#include "sys.h"

//初始化exti函数
void track_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOA时钟
    gpio_initstruct.Pin = GPIO_PIN_13 | GPIO_PIN_14; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct); 
}


uint8_t track_left_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}

uint8_t track_right_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}




/*
------------------------------------------------------------------------
pwm.c:
-------------------------------------------------------------------------
*/
#include "pwm.h"

TIM_HandleTypeDef pwm_handler = {0};
//pwm初始化
void pwm_init(uint16_t arr,uint16_t psc)
{
    TIM_OC_InitTypeDef pwm_config = {0};
    pwm_handler.Instance = TIM2 ;
    pwm_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    pwm_handler.Init.Period = arr;
    pwm_handler.Init.Prescaler = psc;
    //HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    HAL_TIM_PWM_Init(&pwm_handler);
//    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
//                                            const TIM_OC_InitTypeDef *sConfig,
//                                            uint32_t Channel)
    
    pwm_config.OCMode = TIM_OCMODE_PWM1;//模式1
    pwm_config.Pulse = 0; //设定比较值CCR,开始设定一次,后面__HAL_TIM_SET_COMPARE()函数中会修改
    pwm_config.OCPolarity = TIM_OCNPOLARITY_HIGH;//有效电平为高电平
    HAL_TIM_PWM_ConfigChannel(&pwm_handler,&pwm_config,TIM_CHANNEL_1);
    HAL_TIM_PWM_ConfigChannel(&pwm_handler,&pwm_config,TIM_CHANNEL_2);
    //HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    HAL_TIM_PWM_Start(&pwm_handler,TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&pwm_handler,TIM_CHANNEL_2);
}    

//msp初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM4)
    {
    
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    __HAL_RCC_TIM2_CLK_ENABLE();//使能TIM2时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    gpio_initstruct.Mode = GPIO_MODE_AF_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);        
    }        
}

//修改CCR寄存器值
void pwm_left_motor_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&pwm_handler,TIM_CHANNEL_1,val);
}  

void pwm_right_motor_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&pwm_handler,TIM_CHANNEL_2,val);
}    

/*
------------------------------------------------------------------------
track.h:
-------------------------------------------------------------------------
*/
#ifndef __TRACK_H__
#define __TRACK_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void track_init(void);
uint8_t track_left_flag(void);
uint8_t track_right_flag(void);
#endif

/*
------------------------------------------------------------------------
pwm.h:
-------------------------------------------------------------------------
*/
#ifndef __PWM_H__
#define __PWM_H__
#include "sys.h"
void pwm_init(uint16_t arr,uint16_t psc);
void pwm_left_motor_set(uint16_t val);
void pwm_right_motor_set(uint16_t val);
#endif

281 跟随小车

(1)参考"63. 智能小车项目/1. 让小车动起来",添加"63. 智能小车项目/5. 循迹小车"中的循迹模块,修改函数名;主函数逻辑改为左边检测到物体,左转即右轮转动,右边检测到物体,右转即左轮转动,
左右两边检测到物体,向前走即左右轮一块转。-(63. 智能小车项目/7. 跟随小车-main.c,follow.c,motor.c,follow.h,motor.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "follow.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    follow_init();
    printf("hello world!\r\n");
    while(1)
    { 
        if(follow_left_flag() == TRUE && follow_right_flag() == TRUE)
            motor_go_forward();
        else if(follow_left_flag() == FALSE && follow_right_flag() == TRUE)
            motor_go_left();
        else if(follow_left_flag() == TRUE && follow_right_flag() == FALSE)
            motor_go_right();
        else if (follow_left_flag() == FALSE && follow_right_flag() == FALSE)
            motor_stop();   
    }
}




/*
------------------------------------------------------------------------
follow.c:
-------------------------------------------------------------------------
*/
#include "follow.h"
#include "sys.h"

//初始化exti函数
void follow_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOA时钟
    gpio_initstruct.Pin = GPIO_PIN_13 | GPIO_PIN_14; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct); 
}


uint8_t follow_left_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}

uint8_t follow_right_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}



/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 

/*
------------------------------------------------------------------------
follow.h:
-------------------------------------------------------------------------
*/
#ifndef __FOLLOW_H__
#define __FOLLOW_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void follow_init(void);
uint8_t follow_left_flag(void);
uint8_t follow_right_flag(void);
#endif


/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

282 避障小车

(1)参考"63. 智能小车项目/1. 让小车动起来",添加舵机模块,超声波模块,舵机模块中添加向左转函数sg90_turn_left(),向中转函数sg90_turn_middle(),向右转函数sg90_turn_right();
主函数中根据距离障碍物距离决定向那个方向行驶;-(63. 智能小车项目/8. 避障小车-main.c,motor.c,sg90.c,hcsr04.c,motor.h,sg90.h,hcsr04.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "sg90.h"
#include "hcsr04.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    hcsr04_init();
    sg90_init();
    printf("hello world!\r\n");
    double dis_left = 0,dis_middle = 0,dis_right = 0;
    sg90_turn_middle();
    while(1)
    { 
        dis_middle = hcsr04_get_length();
        if(dis_middle > 35)
            motor_go_forward();
        else if(dis_middle <15)
            motor_go_backward();
        else
        {
            motor_stop();
            sg90_turn_left();
            delay_ms(500);
            dis_left = hcsr04_get_length();
            
            sg90_turn_middle();
            delay_ms(500);
            
            sg90_turn_right();
            delay_ms(500);
            dis_right = hcsr04_get_length();
            if(dis_left < dis_right)
                motor_go_right();
            else
                motor_go_left();
            delay_ms(200);
            motor_stop();
            sg90_turn_middle();       
        }
        delay_ms(100);
    }
}

/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 
/*
------------------------------------------------------------------------
sg90.c:
-------------------------------------------------------------------------
*/
#include "sg90.h"


TIM_HandleTypeDef tim3_handler = {0};
//pwm初始化
void tim3_init(void)
{
    TIM_OC_InitTypeDef pwm_config = {0};
    tim3_handler.Instance = TIM3 ;
    tim3_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim3_handler.Init.Period = 200 - 1;
    tim3_handler.Init.Prescaler = 7200-1;
    //HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    HAL_TIM_PWM_Init(&tim3_handler);
//    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
//                                            const TIM_OC_InitTypeDef *sConfig,
//                                            uint32_t Channel)
    
    pwm_config.OCMode = TIM_OCMODE_PWM1;
    pwm_config.Pulse = 100;
    pwm_config.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&tim3_handler,&pwm_config,TIM_CHANNEL_1);
    //HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    HAL_TIM_PWM_Start(&tim3_handler,TIM_CHANNEL_1);
}    

//msp初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM3)
    {
    
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOB时钟
    __HAL_RCC_TIM3_CLK_ENABLE();//使能TIM3时钟
    //调用GPIO初始化函数
    //HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)

    gpio_initstruct.Pin = GPIO_PIN_6; 
    gpio_initstruct.Mode = GPIO_MODE_AF_PP; // 复合推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);        
    }        
}

//修改CCR寄存器值
void tim3_compare_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&tim3_handler,TIM_CHANNEL_1,val);
}    

//sg90初始化
void sg90_init(void)
{
    tim3_init();
}

//舵机角度设定
void sg90_angle_set(uint16_t angle)
{
    uint16_t CCRx = (1.0/9.0)*angle + 5.0;
    tim3_compare_set(CCRx);
}

//向左转函数sg90_turn_left()
void sg90_turn_left(void)
{
    sg90_angle_set(180);
}    

//向中转函数sg90_turn_middle()
void sg90_turn_middle(void)
{
    sg90_angle_set(90);
}    

//向右转函数sg90_turn_right

void sg90_turn_right(void)
{
    sg90_angle_set(0);
}


/*
------------------------------------------------------------------------
hcsr04.c:
-------------------------------------------------------------------------
*/
#include "hcsr04.h"
#include "delay.h"

TIM_HandleTypeDef tim2_handler ={0};
//定时器初始化函数
void tim2_init(void)
{
    
    tim2_handler.Instance =TIM2;
    tim2_handler.Init.Prescaler = 72 - 1;
    tim2_handler.Init.Period = 65536 - 1;
    tim2_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim2_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&tim2_handler);
    HAL_TIM_Base_Start_IT(&tim2_handler);
}    

//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
    }
}

//定时器开启
void tim2_start(void)
{
    HAL_TIM_Base_Start(&tim2_handler);
}
//定时器关闭
void tim2_stop(void)
{
    HAL_TIM_Base_Stop(&tim2_handler);
}   
//获取定时器的计数器值
uint16_t tim2_get_cnt(void)
{
   return __HAL_TIM_GetCounter(&tim2_handler);
}    

//设定定时器的计数器值
void tim2_set_cnt(uint16_t val)
{
    __HAL_TIM_SetCounter(&tim2_handler,val);
}    

//hcsr04所用GPIO初始化
void hcsr04_gpio_init(void)
{
   GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    TRIG_GPIO_CLK_ENABLE();
    ECHO_GPIO_CLK_ENABLE();
    //初始化Trig引脚
    gpio_initstruct.Pin = TRIG_PIN;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_NOPULL; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(TRIG_PORT,&gpio_initstruct);
    //初始化Echo引脚
    gpio_initstruct.Pin = ECHO_PIN;
    gpio_initstruct.Mode = GPIO_MODE_INPUT; //输入
    HAL_GPIO_Init(ECHO_PORT,&gpio_initstruct);    
}    

//hcsr04初始化
void hcsr04_init(void)
{
    tim2_init();
    hcsr04_gpio_init();
}    

//hcsr04获取距离
float hcsr04_get_length(void)
{   
    uint16_t total_time = 0;
    float distance = 0;
    //1.Trig,给Trig端口至少10us的高电平
    TRIG_HIGH();
    delay_us(15);
    TRIG_LOW();
    //2.Echo引脚,由低电平跳转到高电平,表示开始发送波
    while(ECHO_STATUS() == GPIO_PIN_RESET);
    tim2_start();
    tim2_set_cnt(0);
    //3.Echo,由高电平跳转回低电平,表示波回来了
        //Echo引脚维持高电平的时间,波发出去的那一下,开始启动定时器,波回来的那一下,我们开始停止定时器,
    while(ECHO_STATUS() == GPIO_PIN_SET);
    tim2_stop();
    //4.计算出中间经过多少时间
    total_time = tim2_get_cnt();
    //5.距离 = 速度(343m/s) * 时间 / 2       
    distance = total_time*0.01715;
    return distance;
}   


/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

/*
------------------------------------------------------------------------
sg90.h:
-------------------------------------------------------------------------
*/
#ifndef __SG90_H__
#define __SG90_H__
#include "sys.h"
void sg90_init(void);
void sg90_turn_left(void);
void sg90_turn_middle(void);
void sg90_turn_right(void);
#endif

/*
------------------------------------------------------------------------
hcsr04.h:
-------------------------------------------------------------------------
*/

#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "sys.h"
#define TRIG_PORT               GPIOB
#define TRIG_PIN                GPIO_PIN_6
#define TRIG_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE();
#define TRIG_HIGH()             HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_SET)
#define TRIG_LOW()              HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_RESET)

#define ECHO_PORT               GPIOB
#define ECHO_PIN                GPIO_PIN_7
#define ECHO_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE();
#define ECHO_STATUS()           HAL_GPIO_ReadPin(ECHO_PORT,ECHO_PIN)
void hcsr04_init(void);
float hcsr04_get_length(void);
#endif

283 测速模块介绍

(1)参考文档链接:https://www.lxlinux.net/e/stm32/speed-sensor-tutorial.html
(2)原理:有遮挡,输出高电平;无遮挡,输出低电平;20格的码盘转一圈就会经历20个下降沿中断,一个下降沿中断就是走了 3.14×6.5/20 = 1.0205cm,约等于一个中断走1cm。
测距离 = 3.14×直径/码盘格子×中断次数;测速度 = 定时器每秒输出 3.14×直径/码盘格子×中断次数;

284 测速小车

(1)参考"63. 智能小车项目/2. 串口控制小车",新增测速模块代码,包含了中断模块,及定时器模块这两部分的代码。
-(63. 智能小车项目/9. 测速小车-main.c,motor.c,speed.c,motor.h,speed.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "bluetooth.h"
#include "speed.h"
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    bt_init(9600);
    speed_init();
    printf("hello world!\r\n");
    while(1)
    { 
    }
}


/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 


/*
------------------------------------------------------------------------
speed.c:
-------------------------------------------------------------------------
*/
#include "speed.h"
#include "stdio.h"
uint16_t speed_cnt = 0;
TIM_HandleTypeDef timer_handler ={0};
void speed_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_12; //按键对应引脚
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,0);// 设置EXTI0中断线的优先级
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);// 使能中断
   
}

//定时器初始化函数
void speed_timer_init(uint16_t arr,uint16_t psc)
{
    
    timer_handler.Instance =TIM2;
    timer_handler.Init.Prescaler = psc;
    timer_handler.Init.Period = arr;
    timer_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    timer_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&timer_handler);
    HAL_TIM_Base_Start_IT(&timer_handler);
}    
void speed_init(void)
{
    speed_gpio_init();
    speed_timer_init(10000 - 1,7200 -1);
}

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_12)
    {
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)
        {
            speed_cnt++;
//            printf("speed: %d\r\n", speed_cnt);
        }
    }
}
//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
        HAL_NVIC_SetPriority(TIM2_IRQn,2,2);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
    }
}
//中断服务函数
void TIM2_IRQHandler(void)
{
     HAL_TIM_IRQHandler(&timer_handler);
}
//更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        printf("speed:%d\r\n",speed_cnt);
        speed_cnt = 0;
    }
}    

/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

/*
------------------------------------------------------------------------
speed.h:
-------------------------------------------------------------------------
*/
#ifndef __SPEED_H__
#define __SPEED_H__
#include "sys.h"
void speed_init(void);
#endif

285 测速小车OLED显示并上传蓝牙

(1)参考"63. 智能小车项目/9. 测速小车",添加蓝牙模块,oled模块代码,在测速模块里面的定时器回调函数中进行oled显示oled_show_string(),发送给蓝牙数据bt_send(),蓝牙模块中修改sizeof为strlen;
-(63. 智能小车项目/10. 测速小车OLED显示并上传蓝牙-main.c,motor.c,speed.c,bluetooth.c,motor.h,speed.h,bluetooth.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "bluetooth.h"
#include "speed.h"
#include "oled.h"
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    bt_init(9600);
    speed_init();
    oled_init();
    printf("hello world!\r\n");
    motor_go_forward();
    while(1)
    { 
    }
}




/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 

/*
------------------------------------------------------------------------
speed.c:
-------------------------------------------------------------------------
*/
#include "speed.h"
#include "stdio.h"
#include "bluetooth.h"
#include "oled.h"
#include "string.h"
uint16_t speed_cnt = 0;
char speed_str[24] = {0};
TIM_HandleTypeDef timer_handler ={0};
void speed_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_12; //按键对应引脚
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,0);// 设置EXTI0中断线的优先级
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);// 使能中断
   
}

//定时器初始化函数
void speed_timer_init(uint16_t arr,uint16_t psc)
{
    
    timer_handler.Instance =TIM2;
    timer_handler.Init.Prescaler = psc;
    timer_handler.Init.Period = arr;
    timer_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    timer_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&timer_handler);
    HAL_TIM_Base_Start_IT(&timer_handler);
}    
void speed_init(void)
{
    speed_gpio_init();
    speed_timer_init(10000 - 1,7200 -1);
}

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_12)
    {
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)
        {
            speed_cnt++;
//            printf("speed: %d\r\n", speed_cnt);
        }
    }
}
//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
        HAL_NVIC_SetPriority(TIM2_IRQn,2,2);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
    }
}
//中断服务函数
void TIM2_IRQHandler(void)
{
     HAL_TIM_IRQHandler(&timer_handler);
}
//更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        printf("speed:%d\r\n",speed_cnt);
        memset(speed_str,0,sizeof(speed_str));
        sprintf(speed_str,"speed:%2dcm/s",speed_cnt);
        bt_send(speed_str);
        bt_send("\r\n");
        oled_show_string(10,2,speed_str,16);       
        speed_cnt = 0;
    }
}    

/*
------------------------------------------------------------------------
bluetooth.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "bluetooth.h"
#include "string.h"
#include "stdarg.h"
#include "motor.h"

UART_HandleTypeDef uart2_handle;                                            /* UART2句柄 */

uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE];                                    /* UART2接收缓冲区 */
uint16_t uart2_rx_len = 0;                                                  /* UART2接收字符长度 */


/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void bt_init(uint32_t baudrate)
{
    /*UART2 初始化设置*/
    uart2_handle.Instance = USART2;                                         /* USART2 */
    uart2_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart2_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart2_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart2_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart2_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart2_handle);                                           /* HAL_UART_Init()会使能UART2 */
}

/**
 * @brief       UART2接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart2_rx_clear(void)
{
    memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf));                          /* 清空接收缓冲区 */
    uart2_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口1中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart2_rx_len >= sizeof(uart2_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart2_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart2_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart2_rx_buf[uart2_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("bt recv: %s\r\n", uart2_rx_buf);                               /* 将接收到的数据打印出来 */
        if(strcmp((char *)uart2_rx_buf,"M1") == 0)
            motor_go_forward();
        else if(strcmp((char *)uart2_rx_buf,"M2") == 0)
            motor_go_backward();
        else if(strcmp((char *)uart2_rx_buf,"M3") == 0)
            motor_go_left();
        else if(strcmp((char *)uart2_rx_buf,"M4") == 0)
            motor_go_right();
        else
            motor_stop();            
        uart2_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart2_handle);                           /* 清除UART总线空闲中断 */
    }
}

//void bt_send(char *send_buf,uint8_t size)
//{
//    //HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
//    HAL_UART_Transmit(&uart2_handle,(uint8_t *)send_buf,size,100);
//}    
void bt_send(char * format, ...)
{
    uint8_t send_buf[128] ={0};
    va_list arg;
    va_start(arg, format);
    vsprintf((char *)send_buf, format, arg);
    va_end(arg);
    HAL_UART_Transmit(&uart2_handle,send_buf,strlen((char *)send_buf),100);
    
}    

/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

/*
------------------------------------------------------------------------
speed.h:
-------------------------------------------------------------------------
*/
#ifndef __SPEED_H__
#define __SPEED_H__
#include "sys.h"
void speed_init(void);
#endif

/*
------------------------------------------------------------------------
bluetooth.h:
-------------------------------------------------------------------------
*/
#ifndef __BLUETOOTH__H__
#define __BLUETOOTH__H__

#include "stdio.h"
#include "sys.h"


/* UART收发缓冲大小 */
#define UART2_RX_BUF_SIZE            128
#define UART2_TX_BUF_SIZE            64


void bt_init(uint32_t baudrate);            /* 串口初始化函数 */
//void bt_send(char *send_buf,uint8_t size);
void bt_send(char * format, ...);

#endif



286 wifi控制小车并发送速度

(1)参考"63. 智能小车项目/10. 测速小车OLED显示并上传蓝牙",添加wifi模块esp8266,定时器回调函数中发送数据给主机esp8266_send_data(),主函数中接收来自主机信号esp8266_receive_data()用来控制小车行驶;
-(63. 智能小车项目/11. wifi控制小车并发送速度-main.c,motor.c,speed.c,esp8266.c,motor.h,speed.h,esp8266.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "speed.h"
#include "oled.h"
#include "esp8266.h"
#include "string.h"
#include "string.h"
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    speed_init();
    oled_init();
    esp8266_init(115200);
    printf("hello world!\r\n");
    motor_go_forward();
    char recv_data[ESP8266_RX_BUF_SIZE];
    while(1)
    { 
        esp8266_receive_data(recv_data);
        if(strstr(recv_data,"M1") != NULL)
            motor_go_forward();
        else if(strstr(recv_data,"M2") != NULL)
            motor_go_backward();
        else if(strstr(recv_data,"M3") != NULL)
            motor_go_left();
        else if(strstr(recv_data,"M4") != NULL)
            motor_go_right();
        else
            motor_stop();  
        delay_ms(10);
    }
}




/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 


/*
------------------------------------------------------------------------
speed.c:
-------------------------------------------------------------------------
*/
#include "speed.h"
#include "stdio.h"
#include "oled.h"
#include "string.h"
#include "esp8266.h"
uint16_t speed_cnt = 0;
char speed_str[24] = {0};
TIM_HandleTypeDef timer_handler ={0};
void speed_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_12; //按键对应引脚
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING; // 下降沿触发
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,0);// 设置EXTI0中断线的优先级
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);// 使能中断
   
}

//定时器初始化函数
void speed_timer_init(uint16_t arr,uint16_t psc)
{
    
    timer_handler.Instance =TIM2;
    timer_handler.Init.Prescaler = psc;
    timer_handler.Init.Period = arr;
    timer_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    timer_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&timer_handler);
    HAL_TIM_Base_Start_IT(&timer_handler);
}    
void speed_init(void)
{
    speed_gpio_init();
    speed_timer_init(10000 - 1,7200 -1);
}

void EXTI15_10_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_12)
    {
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET)
        {
            speed_cnt++;
//            printf("speed: %d\r\n", speed_cnt);
        }
    }
}
//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
        HAL_NVIC_SetPriority(TIM2_IRQn,2,2);
        HAL_NVIC_EnableIRQ(TIM2_IRQn);
    }
}
//中断服务函数
void TIM2_IRQHandler(void)
{
     HAL_TIM_IRQHandler(&timer_handler);
}
//更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        printf("speed:%d\r\n",speed_cnt);
        memset(speed_str,0,sizeof(speed_str));
        sprintf(speed_str,"speed:%2dcm/s",speed_cnt);
        oled_show_string(10,2,speed_str,16); 
        esp8266_send_data(speed_str);
        speed_cnt = 0;
    }
}    

/*
------------------------------------------------------------------------
esp8266.c:
-------------------------------------------------------------------------
*/
#include "esp8266.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"

uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];
uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];
uint16_t esp8266_cnt = 0, esp8266_cntPre = 0;

UART_HandleTypeDef esp8266_handle = {0};
void esp8266_uart_init(uint32_t baudrate)
{
    esp8266_handle.Instance = USART1;
    esp8266_handle.Init.BaudRate = baudrate;
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&esp8266_handle);
}



void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle, UART_FLAG_RXNE) != RESET)
    {
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))
            esp8266_cnt = 0;
        HAL_UART_Receive(&esp8266_handle, &receive_data, 1, 1000);
        esp8266_rx_buf[esp8266_cnt++] = receive_data;
        //esp8266_cnt++;
        //HAL_UART_Transmit(&esp8266_handle, &receive_data, 1, 1000);
    }
}



uint8_t esp8266_wait_receive(void)
{
    if(esp8266_cnt == 0)
        return ESP8266_ERROR;
    
    if(esp8266_cnt == esp8266_cntPre)
    {
        esp8266_cnt = 0;
        return ESP8266_EOK;
    }
    
    esp8266_cntPre = esp8266_cnt;
    return ESP8266_ERROR;
}

void esp8266_rx_clear(void)
{
    memset(esp8266_rx_buf, 0, sizeof(esp8266_rx_buf));
    esp8266_cnt = 0;
}

uint16_t esp8266_receive_data(char *recv_data)
{
    if(esp8266_wait_receive() == ESP8266_EOK)
    {
        printf("esp8266 recv: %s\r\n", esp8266_rx_buf);
        memcpy(recv_data,esp8266_rx_buf,strlen((char *)esp8266_rx_buf));
        esp8266_rx_clear();
        return strlen((char *)esp8266_rx_buf);
    }
    return 0;
}

void esp8266_send_data(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    va_start(ap,fmt);
    vsprintf((char *)esp8266_tx_buf,fmt,ap);
    va_end(ap);
    len = strlen((const char *)esp8266_tx_buf);
    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,len,100);
}    

uint8_t esp8266_send_command(char *cmd,char *res)
{
    uint8_t time_out = 250;
    esp8266_rx_clear();
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);
    while(time_out--)
    {
        if(esp8266_wait_receive() == ESP8266_EOK)
        {
            if(strstr((const char*)esp8266_rx_buf,res) != NULL)
            {
                return ESP8266_EOK;
            }
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
}
//esp8266的at指令测试
uint8_t esp8266_at_test(void)
{
    return (esp8266_send_command("AT\r\n","OK"));
}    

uint8_t esp8266_set_mode(uint8_t mode)
{
    switch(mode)
    {
        case ESP8266_STA_MODE:
             return esp8266_send_command("AT+CWMODE=1\r\n","OK");
        case ESP8266_AP_MODE:
             return esp8266_send_command("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
             return esp8266_send_command("AT+CWMODE=3\r\n","OK");        
        default:
             return ESP8266_EINVAL;
    
    }                
}


uint8_t esp8266_join_ap(char *ssid,char *pwd)
{
    char cmd[64];
    sprintf(cmd,"AT+CWJAP=\"%s\",\"%s\r\n\"",ssid,pwd);
    return esp8266_send_command(cmd,"WIFI GOT IP");
}

uint8_t esp8266_connection_mode(uint8_t mode)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);
    return esp8266_send_command(cmd,"OK");
}

uint8_t esp8266_connect_tcp_server(char *server_ip,char *server_port)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",server_ip,server_port);
    return esp8266_send_command(cmd,"CONNECT"); 
}
uint8_t esp8266_enter_unvarnished(void)
{
    uint8_t ret;
    ret = esp8266_send_command("AT+CIPMODE=1\r\n","OK");
    ret += esp8266_send_command("AT+CIPSEND\r\n",">");
    if(ret == ESP8266_EOK)
        return ESP8266_EOK;
    else
        return ESP8266_ERROR;
}    
void esp8266_init(uint32_t baudrate)
{
    printf("esp8266初始化开始...\r\n");
    esp8266_uart_init(baudrate);
    //esp8266的其他初始化
    printf("1.测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    printf("2.设置工作模式为STA...\r\n");
    while(esp8266_set_mode(ESP8266_STA_MODE))
        delay_ms(500);
    printf("3.设置单路链接模式...\r\n");
    while(esp8266_connection_mode(ESP8266_SINGLE_CONNECTION))
        delay_ms(500);
    printf("4.连接wifi,SSID: %s, PWD: %s\r\n",WIFI_SSID,WIFI_PWD);    
    while(esp8266_join_ap(WIFI_SSID,WIFI_PWD))
        delay_ms(1500); 
    printf("5.连接TCP服务器,server_ip: %s, server_port: %s\r\n",TCP_SERVER_IP,TCP_SERVER_PORT);    
    while(esp8266_connect_tcp_server(TCP_SERVER_IP,TCP_SERVER_PORT))
        delay_ms(500);
    printf("6.进入透传模式...\r\n");
    while(esp8266_enter_unvarnished())
        delay_ms(500);
    printf("ESP8266已连接上TCP服务器并进入透传模式\r\n");   
    printf("ESP8266初始化完成!\r\n");    
    
}  


/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

/*
------------------------------------------------------------------------
speed.h:
-------------------------------------------------------------------------
*/
#ifndef __SPEED_H__
#define __SPEED_H__
#include "sys.h"
void speed_init(void);
#endif

/*
------------------------------------------------------------------------
esp8266.h:
-------------------------------------------------------------------------
*/
#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "sys.h"

#define ESP8266_RX_BUF_SIZE  128
#define ESP8266_TX_BUF_SIZE  64

#define ESP8266_EOK        0
#define ESP8266_ERROR      1
#define ESP8266_ETIMEOUT   2
#define ESP8266_EINVAL     3

#define ESP8266_STA_MODE 1
#define ESP8266_AP_MODE 2
#define ESP8266_STA_AP_MODE 3

#define WIFI_SSID "wifi账号"
#define WIFI_PWD  "wifi密码"

#define ESP8266_SINGLE_CONNECTION 0
#define ESP8266_MULTI_CONNECTION 1

#define TCP_SERVER_IP "主机ip地址"
#define TCP_SERVER_PORT "主机端口号"

void esp8266_init(uint32_t baudrate);
void esp8266_send_data(char *fmt, ...);
uint16_t esp8266_receive_data(char *recv_data);
#endif

287 4G控制小车

(1)参考"63. 智能小车项目/9. 测速小车",4G模块跟蓝牙模块一样采用内网穿透原理,仅需4G模块配置后采用蓝牙模块一样代码进行控制小车行驶;-待测试

288 语音控制模块介绍

(1)SU-03T模组规格书了解。语音识别模块,会烧录程序使用即可。

289 SU-03T配置详解

(1)在智能公元网址:http://www.smartpi.cn/#/ 中配置,配置小车跟随,循迹,避障3种模式。-待测试

290 SU-03T镜像烧录

(1)烧录工具软件:UniOneUpdateTool;烧录内容:智能公元中下载的固件包里的bin文件;用usb转ttl链接语音模块,下载时语音模块需要拨动开关下电后上电;-待测试

291 语音控制小车

(1)参考"63. 智能小车项目/1. 让小车动起来",添加跟随模块(follow文件),循迹模块(track文件),避障模块(sg90,hcsr04文件)代码;新增voice模块进行声言模块初始化GPIO口voice_init();
主函数中封装好循迹模式track_mode(),跟随模式follow_mode(),避障模式avoid_mode(),while循环中通过3个GPIO口的电平来判定是那种模式。
-(63. 智能小车项目/12. 语音控制小车-main.c,motor.c,follow.c,track.c,hcsr04.c,sg90.c,voice.c,motor.h,follow.h,track.h,hcsr04.h,sg90.h,voice.h)–待测试

/*
------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "motor.h"
#include "track.h"
#include "follow.h"
#include "sg90.h"
#include "hcsr04.h"
#include "voice.h"

double dis_left = 0,dis_middle = 0,dis_right = 0;
//循迹模式track_mode()
void track_mode(void)
{
        if(track_left_flag() == TRUE && track_right_flag() == TRUE)
            motor_go_forward();
        else if(track_left_flag() == FALSE && track_right_flag() == TRUE)
            motor_go_left();
        else if(track_left_flag() == TRUE && track_right_flag() == FALSE)
            motor_go_right();
        else if (track_left_flag() == FALSE && track_right_flag() == FALSE)
            motor_stop();      
}    
//跟随模式follow_mode()
void follow_mode(void)
{
        if(follow_left_flag() == TRUE && follow_right_flag() == TRUE)
            motor_go_forward();
        else if(follow_left_flag() == FALSE && follow_right_flag() == TRUE)
            motor_go_left();
        else if(follow_left_flag() == TRUE && follow_right_flag() == FALSE)
            motor_go_right();
        else if (follow_left_flag() == FALSE && follow_right_flag() == FALSE)
            motor_stop();   
}    
//避障模式avoid_mode()
void avoid_mode(void)
{
        dis_middle = hcsr04_get_length();
        if(dis_middle > 35)
            motor_go_forward();
        else if(dis_middle <15)
            motor_go_backward();
        else
        {
            motor_stop();
            sg90_turn_left();
            delay_ms(500);
            dis_left = hcsr04_get_length();
            
            sg90_turn_middle();
            delay_ms(500);
            
            sg90_turn_right();
            delay_ms(500);
            dis_right = hcsr04_get_length();
            if(dis_left < dis_right)
                motor_go_right();
            else
                motor_go_left();
            delay_ms(200);
            motor_stop();
            sg90_turn_middle();       
        }
        delay_ms(100);
}    
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    motor_init();
    track_init();
    follow_init();
    hcsr04_init();
    voice_init();
    sg90_init();
    printf("hello world!\r\n");
    sg90_turn_middle();
    while(1)
    { 
    if(TRACK_PIN == GPIO_PIN_RESET && FOLLOW_PIN == GPIO_PIN_SET && AVOID_PIN == GPIO_PIN_SET)
        track_mode();
    if(TRACK_PIN == GPIO_PIN_SET && FOLLOW_PIN == GPIO_PIN_RESET && AVOID_PIN == GPIO_PIN_SET)
        follow_mode();
    if(TRACK_PIN == GPIO_PIN_SET && FOLLOW_PIN == GPIO_PIN_SET && AVOID_PIN == GPIO_PIN_RESET)
        avoid_mode();    
    }
}





/*
------------------------------------------------------------------------
motor.c:
-------------------------------------------------------------------------
*/
#include "motor.h"

//电机初始化函数motor_init()
void motor_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    motor_stop();
}    


//电机向前函数motor_go_forward()
void motor_go_forward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    

//电机向后函数motor_go_backward()
void motor_go_backward(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_SET);    
}    
//电机向左函数motor_go_left()
void motor_go_left(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}   
//电机向右函数motor_go_right()
void motor_go_right(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
}    
//电机停止函数motor_stop()
void motor_stop(void)
{
    //左轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);
    //右轮
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2,GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10,GPIO_PIN_RESET);    
} 
/*
------------------------------------------------------------------------
follow.c:
-------------------------------------------------------------------------
*/
#include "follow.h"
#include "sys.h"

//初始化exti函数
void follow_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOA时钟
    gpio_initstruct.Pin = GPIO_PIN_5 | GPIO_PIN_6; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct); 
}


uint8_t follow_left_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}

uint8_t follow_right_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}



/*
------------------------------------------------------------------------
track.c:
-------------------------------------------------------------------------
*/
#include "track.h"
#include "sys.h"

//初始化exti函数
void track_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOA时钟
    gpio_initstruct.Pin = GPIO_PIN_13 | GPIO_PIN_14; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    HAL_GPIO_Init(GPIOB,&gpio_initstruct); 
}


uint8_t track_left_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}

uint8_t track_right_flag(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_RESET)
        return TRUE;
    else 
        return FALSE;
}



/*
------------------------------------------------------------------------
hcsr04.c:
-------------------------------------------------------------------------
*/
#include "hcsr04.h"
#include "delay.h"

TIM_HandleTypeDef tim2_handler ={0};
//定时器初始化函数
void tim2_init(void)
{
    
    tim2_handler.Instance =TIM2;
    tim2_handler.Init.Prescaler = 72 - 1;
    tim2_handler.Init.Period = 65536 - 1;
    tim2_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim2_handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_Base_Init(&tim2_handler);
    HAL_TIM_Base_Start_IT(&tim2_handler);
}    

//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        __HAL_RCC_TIM2_CLK_ENABLE();
    }
}

//定时器开启
void tim2_start(void)
{
    HAL_TIM_Base_Start(&tim2_handler);
}
//定时器关闭
void tim2_stop(void)
{
    HAL_TIM_Base_Stop(&tim2_handler);
}   
//获取定时器的计数器值
uint16_t tim2_get_cnt(void)
{
   return __HAL_TIM_GetCounter(&tim2_handler);
}    

//设定定时器的计数器值
void tim2_set_cnt(uint16_t val)
{
    __HAL_TIM_SetCounter(&tim2_handler,val);
}    

//hcsr04所用GPIO初始化
void hcsr04_gpio_init(void)
{
   GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    TRIG_GPIO_CLK_ENABLE();
    ECHO_GPIO_CLK_ENABLE();
    //初始化Trig引脚
    gpio_initstruct.Pin = TRIG_PIN;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_NOPULL; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(TRIG_PORT,&gpio_initstruct);
    //初始化Echo引脚
    gpio_initstruct.Pin = ECHO_PIN;
    gpio_initstruct.Mode = GPIO_MODE_INPUT; //输入
    HAL_GPIO_Init(ECHO_PORT,&gpio_initstruct);    
}    

//hcsr04初始化
void hcsr04_init(void)
{
    tim2_init();
    hcsr04_gpio_init();
}    

//hcsr04获取距离
float hcsr04_get_length(void)
{   
    uint16_t total_time = 0;
    float distance = 0;
    //1.Trig,给Trig端口至少10us的高电平
    TRIG_HIGH();
    delay_us(15);
    TRIG_LOW();
    //2.Echo引脚,由低电平跳转到高电平,表示开始发送波
    while(ECHO_STATUS() == GPIO_PIN_RESET);
    tim2_start();
    tim2_set_cnt(0);
    //3.Echo,由高电平跳转回低电平,表示波回来了
        //Echo引脚维持高电平的时间,波发出去的那一下,开始启动定时器,波回来的那一下,我们开始停止定时器,
    while(ECHO_STATUS() == GPIO_PIN_SET);
    tim2_stop();
    //4.计算出中间经过多少时间
    total_time = tim2_get_cnt();
    //5.距离 = 速度(343m/s) * 时间 / 2       
    distance = total_time*0.01715;
    return distance;
}   


/*
------------------------------------------------------------------------
sg90.c:
-------------------------------------------------------------------------
*/
#include "sg90.h"


TIM_HandleTypeDef tim3_handler = {0};
//pwm初始化
void tim3_init(void)
{
    TIM_OC_InitTypeDef pwm_config = {0};
    tim3_handler.Instance = TIM3 ;
    tim3_handler.Init.CounterMode = TIM_COUNTERMODE_UP;
    tim3_handler.Init.Period = 200 - 1;
    tim3_handler.Init.Prescaler = 7200-1;
    //HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim)
    HAL_TIM_PWM_Init(&tim3_handler);
//    HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
//                                            const TIM_OC_InitTypeDef *sConfig,
//                                            uint32_t Channel)
    
    pwm_config.OCMode = TIM_OCMODE_PWM1;
    pwm_config.Pulse = 100;
    pwm_config.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&tim3_handler,&pwm_config,TIM_CHANNEL_1);
    //HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
    HAL_TIM_PWM_Start(&tim3_handler,TIM_CHANNEL_1);
}    

//msp初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM3)
    {
    
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOB时钟
    __HAL_RCC_TIM3_CLK_ENABLE();//使能TIM3时钟
    //调用GPIO初始化函数
    //HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)

    gpio_initstruct.Pin = GPIO_PIN_6; 
    gpio_initstruct.Mode = GPIO_MODE_AF_PP; // 复合推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);        
    }        
}

//修改CCR寄存器值
void tim3_compare_set(uint16_t val)
{
    //__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
    __HAL_TIM_SET_COMPARE(&tim3_handler,TIM_CHANNEL_1,val);
}    

//sg90初始化
void sg90_init(void)
{
    tim3_init();
}

//舵机角度设定
void sg90_angle_set(uint16_t angle)
{
    uint16_t CCRx = (1.0/9.0)*angle + 5.0;
    tim3_compare_set(CCRx);
}

//向左转函数sg90_turn_left()
void sg90_turn_left(void)
{
    sg90_angle_set(180);
}    

//向中转函数sg90_turn_middle()
void sg90_turn_middle(void)
{
    sg90_angle_set(90);
}    

//向右转函数sg90_turn_right

void sg90_turn_right(void)
{
    sg90_angle_set(0);
}




/*
------------------------------------------------------------------------
voice.c:
-------------------------------------------------------------------------
*/
#include "voice.h"

//voice模块进行声言模块初始化GPIO口voice_init()
void voice_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    __HAL_RCC_GPIOA_CLK_ENABLE(); 
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);    
}    

/*
------------------------------------------------------------------------
motor.h:
-------------------------------------------------------------------------
*/
#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "sys.h"
void motor_init(void);
void motor_go_forward(void);
void motor_go_backward(void);
void motor_go_left(void);
void motor_go_right(void);
void motor_stop(void);
#endif

/*
------------------------------------------------------------------------
follow.h:
-------------------------------------------------------------------------
*/
#ifndef __FOLLOW_H__
#define __FOLLOW_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void follow_init(void);
uint8_t follow_left_flag(void);
uint8_t follow_right_flag(void);
#endif

/*
------------------------------------------------------------------------
track.h:
-------------------------------------------------------------------------
*/
#ifndef __TRACK_H__
#define __TRACK_H__
#include "stdint.h"
#define TRUE 1
#define FALSE 0
void track_init(void);
uint8_t track_left_flag(void);
uint8_t track_right_flag(void);
#endif

/*
------------------------------------------------------------------------
hcsr04.h:
-------------------------------------------------------------------------
*/
#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "sys.h"
#define TRIG_PORT               GPIOB
#define TRIG_PIN                GPIO_PIN_6
#define TRIG_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE();
#define TRIG_HIGH()             HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_SET)
#define TRIG_LOW()              HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_RESET)

#define ECHO_PORT               GPIOB
#define ECHO_PIN                GPIO_PIN_7
#define ECHO_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE();
#define ECHO_STATUS()           HAL_GPIO_ReadPin(ECHO_PORT,ECHO_PIN)
void hcsr04_init(void);
float hcsr04_get_length(void);
#endif

/*
------------------------------------------------------------------------
sg90.h:
-------------------------------------------------------------------------
*/
#ifndef __SG90_H__
#define __SG90_H__
#include "sys.h"
void sg90_init(void);
void sg90_turn_left(void);
void sg90_turn_middle(void);
void sg90_turn_right(void);
#endif

/*
------------------------------------------------------------------------
voice.h:
-------------------------------------------------------------------------
*/
#ifndef __VOICE_H__
#define __VOICE_H__
#include "sys.h"
#define TRACK_PIN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2)
#define AVOID_PIN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1)
#define FOLLOW_PIN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
void voice_init(void);
#endif

作者:Aspiring Q

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 HAL库实战(智能小车项目详解)第四部分

发表回复