典型的"多串口并发采集 + 无线传输"系统
STM32F103C8T6 刚好有 5 个串口(USART1~5),满足你的需求。
一、系统架构设计
| 串口 | 用途 | 波特率 |
|---|---|---|
| USART1 | 蓝牙(主机) | 115200 |
| USART2 | JY901 #1 | 115200 |
| USART3 | JY901 #2 | 115200 |
| UART4 | JY901 #3 | 115200 |
| UART5 | JY901 #4 | 115200 |
JY901 默认 115200, 8N1
二、JY901 数据格式
1、输出协议(默认)
-
每 10ms 自动输出一帧
-
帧长:11 字节
-
校验和:最后 1 字节
0x55 | 0x51 | AX_L | AX_H | AY_L | AY_H | AZ_L | AZ_H | T_L | T_H | SUM
| 类型 | 帧头 |
|---|---|
| 加速度 | 0x55 0x51 |
| 角速度 | 0x55 0x52 |
| 角度 | 0x55 0x53 |
三、串口接收方案
DMA + 空闲中断
每个 JY901:
- DMA 接收
- 空闲中断触发
- 环形缓冲
四、核心数据结构
c
typedef struct {
float acc_x;
float acc_y;
float acc_z;
float gyro_x;
float gyro_y;
float gyro_z;
float roll;
float pitch;
float yaw;
} JY901_Data_t;
extern JY901_Data_t jy901[4];
五、串口初始化(CubeMX)
USART1
- Mode:Asynchronous
- Baud:115200
- DMA TX:Enable
USART2 / 3 / 4 / 5
- Mode:Asynchronous
- Baud:115200
- DMA RX:Circular
- NVIC:Idle Interrupt Enable
六、DMA + 空闲中断接收代码
1、全局接收缓冲
c
#define JY_BUF_LEN 128
uint8_t jy_rx_buf[4][JY_BUF_LEN];
2、串口空闲中断回调
c
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if (huart->Instance == USART2) {
JY901_Parse(jy_rx_buf[0], Size, &jy901[0]);
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, jy_rx_buf[0], JY_BUF_LEN);
}
else if (huart->Instance == USART3) {
JY901_Parse(jy_rx_buf[1], Size, &jy901[1]);
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, jy_rx_buf[1], JY_BUF_LEN);
}
else if (huart->Instance == UART4) {
JY901_Parse(jy_rx_buf[2], Size, &jy901[2]);
HAL_UARTEx_ReceiveToIdle_DMA(&huart4, jy_rx_buf[2], JY_BUF_LEN);
}
else if (huart->Instance == UART5) {
JY901_Parse(jy_rx_buf[3], Size, &jy901[3]);
HAL_UARTEx_ReceiveToIdle_DMA(&huart5, jy_rx_buf[3], JY_BUF_LEN);
}
}
七、JY901 数据解析(核心)
c
void JY901_Parse(uint8_t *buf, uint16_t len, JY901_Data_t *data)
{
uint8_t i;
for (i = 0; i < len - 10; i++) {
if (buf[i] == 0x55 && buf[i+1] == 0x53) {
short roll = (buf[i+3] << 8) | buf[i+2];
short pitch = (buf[i+5] << 8) | buf[i+4];
short yaw = (buf[i+7] << 8) | buf[i+6];
data->roll = roll / 32768.0f * 180.0f;
data->pitch = pitch / 32768.0f * 180.0f;
data->yaw = yaw / 32768.0f * 180.0f;
}
}
}
八、蓝牙转发(串口1)
1、数据打包(防粘包)
c
void Send_JY901_To_Bluetooth(void)
{
char tx_buf[128];
int len;
len = sprintf(tx_buf,
"J1:%.1f,%.1f,%.1f\r\n"
"J2:%.1f,%.1f,%.1f\r\n"
"J3:%.1f,%.1f,%.1f\r\n"
"J4:%.1f,%.1f,%.1f\r\n",
jy901[0].roll, jy901[0].pitch, jy901[0].yaw,
jy901[1].roll, jy901[1].pitch, jy901[1].yaw,
jy901[2].roll, jy901[2].pitch, jy901[2].yaw,
jy901[3].roll, jy901[3].pitch, jy901[3].yaw
);
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buf, len);
}
参考代码 stm32 串口1为蓝牙 串口2、3、4、5读取4个JY901九轴陀螺仪模块 www.youwenfan.com/contentcsu/69818.html
九、主循环
c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
MX_UART4_Init();
MX_UART5_Init();
// 启动 DMA 接收
HAL_UARTEx_ReceiveToIdle_DMA(&huart2, jy_rx_buf[0], JY_BUF_LEN);
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, jy_rx_buf[1], JY_BUF_LEN);
HAL_UARTEx_ReceiveToIdle_DMA(&huart4, jy_rx_buf[2], JY_BUF_LEN);
HAL_UARTEx_ReceiveToIdle_DMA(&huart5, jy_rx_buf[3], JY_BUF_LEN);
while (1)
{
Send_JY901_To_Bluetooth();
HAL_Delay(100); // 10Hz 上传
}
}