小车通信模块解析

这个 Blog 是记录 TDPS 课程寻际小车搭建中的部分代码解析.

代码的根目录这里记为 TDPS/, 目录结构大致为:

1
2
3
4
5
6
7
8
9
$ tree -d -L 1
.
├── Communication
├── Control
├── Core
├── Drivers
├── HC_SR04
├── MDK-ARM
└── Middlewares

(只列出了 1 级)

这里门通信相关似乎只编写了小车部分, 而没有门部分.

这里主要借助 STM32F405RGTx 芯片的 PC10_UART3_TXPC11_UART3_RX 引脚与 HC-05 蓝牙模块, 以 UART 协议发送信息.
(需要找下 STM32F405RGTx 的手册)

通信原理简述

UART 通信本身是不能无线传输的, 但借助蓝牙模块之后便可以了.

蓝牙模块接收到来自 STM32 微控制器的 UART 信号后,将其转换为蓝牙无线信号。这些蓝牙信号可以被其他蓝牙设备接收和解码.

蓝牙设备接收到蓝牙信号后, 将其转换回 UART 信号, 然后通过 UART 接口发送给另一个 STM32 微控制器或其他设备, 这样,数据就可以在两个设备之间无线传输.

其过程可以简单描述为:

需要注意, 这种通信方式需要蓝牙模块和接收设备之间的蓝牙连接已经建立, 也就是说, 需要提前设置好两个蓝牙模块.

代码文件拆分

TDPS/Core/Inc/main.h

这里的 IncInclude, 表明该目录下放的是头文件.

main.h 是程序主体的函数声明文件, 这里主要导入了 stm32f4xx_hal.h 库.

TDPS/Control/Control.h

定义了几个类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 箭头识别相关控制变量
typedef enum {
Null_Direction,
Forward,
To_The_Right,
To_The_Left
} Arrow_Direction_t;

// 路灯识别相关控制变量
typedef enum {
Null_Color,
Red,
Green
} Traffic_Light_Color_t;

// OpenMV 工作模式切换
typedef enum {
Identification_Arrow,
Identify_Traffic_Lights,
Pedestrians_Crossing_The_Road,
Obstacle_Avoidance,
Open_The_Door
} Work_Mode_t;

// 小车的控制变量
typedef struct {
int Velocity_Offset;
int Velocity_Offset_Gain;
int Veocity_Rotated;
uint16_t Velocity_Based;
int Obstacle_Distance;

Work_Mode_t Work_Mode;
Arrow_Direction_t Arrow_Direction;
Traffic_Light_Color_t Traffic_Light_Color;
} Robot_t;

// 一个小车结构体
extern Robot_t Robot;

// 根据箭头转向控制
void Robot_Rotate(Arrow_Direction_t Arrow_Direction);

// 根据路灯做出反应
void Wait_Traffic_Light_Color(void);

// 根据行人做出反应
void Wait_Pedestrians(void);

// 绕过路障的行为
void Over_Obstacle(void);

TDPS/Core/Inc/usart.h

这里定义了两个 uart handler:

1
2
3
extern UART_HandleTypeDef huart1;

extern UART_HandleTypeDef huart3;

以及两个初始化函数:

1
2
void MX_USART1_UART_Init(void);
void MX_USART3_UART_Init(void);

注意这里 USART3 初始化为:

  • 波特率: 9600
  • 字长: UART_WORDLENGTH_8B, 即 0x00000000U, 一个字节 (无符号)
  • 无奇偶校验
  • Mode: TX_RX, 即发送和接收
  • 无硬件流控制
  • 过采样为 16

TDPS/Communication/Communication.h

定义了几个 gate control 的函数 (这里猜测其含义):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Open the door
void Open_Door(void);

// 可能是寻线部分的返回值接收
void Vision_Follow_Line_Decoder(void);

// 可能是箭头识别的返回值接收
void Vision_Identification_Arrow_Decoder(void);

// 可能是路灯识别的返回值接收
void Vision_Identify_Traffic_Lights_Decoder(void);

// 可能是 Vision 部分总的返回值接收
void Vision_Decoder(void);

TDPS/Communication/Communication.c

用于通信的数据结构为:

1
uint8_t Com_Open_Door[4];

该数组保存 UART 通信的状态信息. 长度是 4 个字节.

Open_Door() 函数的行为定义为:

1
2
3
4
5
6
7
8
void Open_Door(void)
{
Com_Open_Door[0] = '?';
Com_Open_Door[1] = '!';
Com_Open_Door[2] = 0x01;
Com_Open_Door[3] = '!';
HAL_UART_Transmit(&huart3,Com_Open_Door,4,500);
}

这里只是调用了 HAL_UART_Transmit() 函数 (HAL 库函数), 该函数声明在 TDPS/Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h 以及 .c 文件中.

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @brief Sends an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout);

huart3TDPS/Core/Inc/usart.h 文件中定义为 UART_HandleTypeDef 类型变量, 包含了 UART 通信时的设置.

UART 相关 HAL 库函数

初始化一个 uart instance

1
2
3
4
5
6
7
8
/**
* @brief Initializes the UART mode according to the specified parameters in
* the UART_InitTypeDef and create the associated handle.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)

UART_HandleTypeDef 类型是包含 UART instance 设置参数的结构体. (比如波特率, 字长等)

HAL_StatusTypeDef 类型结构体包含了 HAL 函数运行结束的一些状态信息. (比如是否 OK, ERROR, BUSY, TIMEOUT)

将一个 uart instance 参数清除

1
2
3
4
5
6
7
/**
* @brief DeInitializes the UART peripheral.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *huart)

发送数据

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @brief Sends an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

指定 huart instance, 以及要发送的数据, 数据大小, 超时时间.

接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @brief Receives an amount of data in blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @param Timeout Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

指定 huart instance, 以及要将数据接收到哪里, 数据大小, 超时时间.

中断条件下发送数据

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @brief Sends an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

指定 huart instance, 以及要发送的数据, 数据大小.

中断条件下接收数据

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @brief Receives an amount of data in non blocking mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

指定 huart instance, 以及要接收数据到哪里, 数据大小.

DMA 方式发送数据

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @brief Sends an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

指定 huart instance, 以及发送的数据, 数据大小.

DMA 方式接收数据

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @brief Receives an amount of data in DMA mode.
* @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the received data is handled as a set of u16. In this case, Size must indicate the number
* of u16 available through pData.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData Pointer to data buffer (u8 or u16 data elements).
* @param Size Amount of data elements (u8 or u16) to be received.
* @note When the UART parity is enabled (PCE = 1) the received data contains the parity bit.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

指定 huart instance, 以及要接收数据到哪里, 数据大小.

获取 UART 通信状态

1
2
3
4
5
6
7
/**
* @brief Returns the UART state.
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval HAL state
*/
HAL_UART_StateTypeDef HAL_UART_GetState(const UART_HandleTypeDef *huart)

指定 huart instance.

HAL_UART_StateTypeDef 类型结构体包含 UART 通信的信息. (包括 READY, BUSY, ERROR 等)

获取 UART 错误状态

1
2
3
4
5
6
7
/**
* @brief Return the UART error code
* @param huart Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART.
* @retval UART Error Code
*/
uint32_t HAL_UART_GetError(const UART_HandleTypeDef *huart)

同样指定 huart instance 即可.


小车通信模块解析
http://example.com/2024/05/03/小车通信模块解析/
作者
Jie
发布于
2024年5月3日
许可协议