2. UDS协议栈初始化
任务目标
本案例完成UDS协议栈的最小可运行初始化:配置CAN控制器、注册UDS会话层回调,并验证协议栈能够正确接收和发送UDS消息。实现基于STM32F407 + CAN1外设,使用标准UDS寻址(物理请求ID 0x7E0,物理响应ID 0x7E8)。
核心实现
/* uds_stack.h */
#ifndef UDS_STACK_H
#define UDS_STACK_H
#include <stdint.h>
#define UDS_CAN_ID_REQUEST 0x7E0
#define UDS_CAN_ID_RESPONSE 0x7E8
typedef struct {
uint8_t data[8];
uint8_t len;
} CanFrame;
typedef void (*UdsRxCallback)(const uint8_t* data, uint8_t len);
void UDS_Init(UdsRxCallback rx_cb);
void UDS_SendResponse(const uint8_t* data, uint8_t len);
void UDS_Poll(void); /* 在CAN接收中断或主循环中调用 */
#endif
/* uds_stack.c */
#include "uds_stack.h"
#include <string.h>
/* 模拟CAN硬件层(实际工程替换为HAL_CAN_Transmit/Receive) */
static void Can_HwInit(void) {
/* 配置CAN1 500kbps, 中断使能 */
/* 实际接入点:HAL_CAN_Start(&hcan1); HAL_CAN_ActivateNotification(...) */
}
static void Can_SendFrame(uint32_t id, const uint8_t* data, uint8_t len) {
/* 实际接入点:HAL_CAN_AddTxMessage(&hcan1, &txHeader, data, &mailbox) */
(void)id; (void)data; (void)len;
}
static UdsRxCallback rx_callback = 0;
static uint8_t session_active = 0;
void UDS_Init(UdsRxCallback rx_cb) {
rx_callback = rx_cb;
session_active = 1; /* 默认进入默认会话 */
Can_HwInit();
}
void UDS_SendResponse(const uint8_t* data, uint8_t len) {
if (len > 8) len = 8; /* CAN FD场景可扩展 */
Can_SendFrame(UDS_CAN_ID_RESPONSE, data, len);
}
void UDS_Poll(void) {
CanFrame frame;
/* 从硬件接收队列取帧(实际工程由中断回调填充队列) */
if (Can_ReceiveFrame(&frame) && frame.id == UDS_CAN_ID_REQUEST) {
if (rx_callback && session_active) {
rx_callback(frame.data, frame.len);
}
}
}
/* 测试入口 */
#include <assert.h>
static uint8_t test_rx_data[8];
static uint8_t test_rx_len = 0;
static void TestRxHandler(const uint8_t* data, uint8_t len) {
memcpy(test_rx_data, data, len);
test_rx_len = len;
}
void UDS_InitTest(void) {
UDS_Init(TestRxHandler);
/* 模拟收到诊断请求 0x10 0x01 (会话控制) */
uint8_t req[] = {0x10, 0x01};
CanFrame frame = {.id = UDS_CAN_ID_REQUEST, .len = 2};
memcpy(frame.data, req, 2);
Can_InjectFrame(&frame); /* 测试辅助函数,注入帧到接收队列 */
UDS_Poll();
assert(test_rx_len == 2);
assert(test_rx_data[0] == 0x10 && test_rx_data[1] == 0x01);
/* 发送响应验证 */
uint8_t resp[] = {0x50, 0x01};
UDS_SendResponse(resp, 2);
/* 检查CAN发送队列中最后一帧ID为0x7E8且数据匹配 */
assert(Can_GetLastTxId() == UDS_CAN_ID_RESPONSE);
}
运行与验证
环境依赖:STM32CubeIDE + HAL库(或任意支持CAN的MCU平台),需提供Can_ReceiveFrame、Can_InjectFrame、Can_GetLastTxId三个硬件适配函数(测试辅助用)。
编译运行:
# 在CubeIDE中编译并烧录,或使用命令行:
arm-none-eabi-gcc -I. -c uds_stack.c -o uds_stack.o
# 链接时需包含硬件抽象层文件
验证步骤:
- 调用
UDS_InitTest()执行内置自测; - 若断言全部通过,说明协议栈初始化正确,CAN ID过滤和会话层回调工作正常;
- 实际硬件验证:用CAN工具发送
0x7E0上的10 01,观察0x7E8上是否收到响应(需在回调中实现响应逻辑)。
通过标准:自测断言全部通过,且CAN工具能收到协议栈发出的响应帧(ID=0x7E8)。