项目七:智能小车

1. 让小车动起来

对应源代码:smartCar_project1

硬件接线

B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10

其余接线参考C51小车项目。

代码实现

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. 串口控制小车

对应源代码:smartCar_project2 代码实现 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. 点动控制小车

对应源代码:smartCar_project3

代码实现 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

// main函数里
HAL_NVIC_SetPriority(SysTick_IRQn,0,0); //或者通过cubeMX配置
while(1)
{
    stop();
}

4. 硬件PWM调速

对应源代码:smartCar_project4 硬件接线

B-1A -- PA0 B-1B -- PB1 A-1A -- PA1 A-1B -- PB10

其余接线参考上官一号小车项目。

cubeMX配置

TIM2配置如下图。

这两节里配置有误,正确的应该是PSC=7199,ARR=199,大家注意修正!! 设置 PSC=71 ,ARR=19,PWM 周期则为 20ms 。

将控制车轮的4个 GPIO 口配置修改如下,否则小车动不起来。

原因:L9110每个控制口需要一高一低才可以动起来,如果PWM有效电平为高电平,则另一个 GPIO口则需要输出低电平才可以驱动轮子。

代码实现

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. 左右轮各自调速

对应源代码:smartCar_project5

代码实现

main.c

// 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. 循迹小车

对应源代码:smartCar_project6

硬件接线

B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10

循迹模块(左) -- PB3 循迹模块(右) -- PB4 其余接线参考c51小车项目。

代码实现

#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. 循迹小车解决转弯平滑问题

对应源代码:smartCar_project7

硬件接线

B-1A -- PA0 B-1B -- PB1 A-1A -- PA1 A-1B -- PB10

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

其余接线参考c51小车项目。

代码实现

#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. 跟随小车

对应源代码:smartCar_project8

硬件接线

B-1A -- PB0 B-1B -- PB1 A-1A -- PB2 A-1B -- PB10 跟随模块(左) -- PB5 跟随模块(右) -- PB6 其余接线参考c51小车项目

代码实现

#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. 摇头避障小车

对应源代码:smartCar_project9

9.1 封装摇头功能

对应源代码:smartCar_project9_1

硬件接线

sg90 -- PB9

cubeMX配置

代码实现

sg90.c

#include "sg90.h"
#include "gpio.h"
#include "tim.h"
void initSG90(void) {
  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 封装超声波传感器

对应源代码:smartCar_project9_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 封装电机驱动

对应源代码:smartCar_project9_3

硬件接线

与 “让小车动起来” 完全一样 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. 小车测速

对应源代码:smartCar_project10

硬件接线

测速模块: 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显示速度

对应源代码:smartCar_project11

硬件接线

SCL -- PB6 SDA -- PB7

封装Oled模块

对应源代码:smartCar_project11_1

实现测速并使用Oled显示速度

对应源代码:smartCar_project11_2

代码实现 很很长,大家直接去看源代码吧。。

来看看最后成果吧

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值