feat: add ASSI lamp control and CAN protocol docs

This commit is contained in:
shenlefengnai-rgb
2026-09-18 21:42:28 +08:00
parent 04da25e2d1
commit be4f167b83
6 changed files with 236 additions and 62 deletions
@@ -68,14 +68,17 @@ Mcu.Pin28=PB9
Mcu.Pin29=PE0 Mcu.Pin29=PE0
Mcu.Pin3=PB0 Mcu.Pin3=PB0
Mcu.Pin30=PE1 Mcu.Pin30=PE1
Mcu.Pin31=VP_SYS_VS_Systick Mcu.Pin31=PE9
Mcu.Pin32=PE10
Mcu.Pin33=PE11
Mcu.Pin34=VP_SYS_VS_Systick
Mcu.Pin4=PB10 Mcu.Pin4=PB10
Mcu.Pin5=PB11 Mcu.Pin5=PB11
Mcu.Pin6=PB14 Mcu.Pin6=PB14
Mcu.Pin7=PD8 Mcu.Pin7=PD8
Mcu.Pin8=PD9 Mcu.Pin8=PD9
Mcu.Pin9=PD10 Mcu.Pin9=PD10
Mcu.PinsNb=32 Mcu.PinsNb=35
Mcu.ThirdPartyNb=0 Mcu.ThirdPartyNb=0
Mcu.UserConstants= Mcu.UserConstants=
Mcu.UserName=STM32F407VETx Mcu.UserName=STM32F407VETx
@@ -139,6 +142,9 @@ PD8.Signal=GPXTI8
PD9.Signal=GPXTI9 PD9.Signal=GPXTI9
PE0.Signal=GPIO_Output PE0.Signal=GPIO_Output
PE1.Signal=GPIO_Output PE1.Signal=GPIO_Output
PE9.Signal=GPIO_Output
PE10.Signal=GPIO_Output
PE11.Signal=GPIO_Output
PinOutPanel.RotationAngle=0 PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false ProjectManager.BackupPrevious=false
+90 -23
View File
@@ -66,12 +66,20 @@ typedef struct
#define CAN_HEARTBEAT_PERIOD_MS 1000U #define CAN_HEARTBEAT_PERIOD_MS 1000U
#define PWM_TIMEOUT_MS 1000U #define PWM_TIMEOUT_MS 1000U
#define CAN_HEARTBEAT_STD_ID 0x100U #define CAN_HEARTBEAT_STD_ID 0x6A0U
#define CAN_GPIO_REPORT_STD_ID 0x330U #define CAN_ADC_REPORT_STD_ID 0x6A1U
#define CAN_ADC_REPORT_STD_ID 0x102U #define CAN_PWM_REPORT_STD_ID 0x6A2U
#define CAN_PWM_REPORT_STD_ID 0x103U #define CAN_DAC_CMD_STD_ID 0x6A3U
#define CAN_DAC_CMD_STD_ID 0x321U #define CAN_DAC_ACK_STD_ID 0x6A4U
#define CAN_DAC_ACK_STD_ID 0x322U #define CAN_ASSI_LAMP_CMD_STD_ID 0x6A5U
#define CAN_GPIO_REPORT_STD_ID 0x6A6U
#define ASSI_LAMP_FLASH_HALF_PERIOD_MS 250U
#define ASSI_STATE_OFF 0U
#define ASSI_STATE_READY 1U
#define ASSI_STATE_DRIVING 2U
#define ASSI_STATE_EMERGENCY 3U
#define ASSI_STATE_FINISHED 4U
/* USER CODE END PD */ /* USER CODE END PD */
@@ -110,7 +118,8 @@ static uint32_t adc_filter_sum;
static uint8_t adc_filter_count; static uint8_t adc_filter_count;
static uint8_t adc_filter_index; static uint8_t adc_filter_index;
static char uart_line[UART_LINE_SIZE]; static char uart_line[UART_LINE_SIZE];
static uint8_t uart_line_len; static uint8_t uart_line_len;
static uint8_t assi_lamp_state;
/* USER CODE END PV */ /* USER CODE END PV */
@@ -133,8 +142,10 @@ static void PollCanBus(CAN_HandleTypeDef *hcan, const char *name);
static void PollCaptureChannels(void); static void PollCaptureChannels(void);
static void PollGpioChanges(void); static void PollGpioChanges(void);
static void SendPeriodicReport(void); static void SendPeriodicReport(void);
static void ServiceHeartbeat(void); static void ServiceHeartbeat(void);
static void SendCanHeartbeat(void); static void ServiceAssiLamp(void);
static void SendCanHeartbeat(void);
static void HandleAssiLampSetRequest(const char *source, uint8_t state);
static void HandleTextCommand(const char *source, const char *line); static void HandleTextCommand(const char *source, const char *line);
static void HandleDacSetRequest(const char *source, uint8_t dac_id, uint16_t millivolts); static void HandleDacSetRequest(const char *source, uint8_t dac_id, uint16_t millivolts);
static void UartWrite(const char *text); static void UartWrite(const char *text);
@@ -221,9 +232,10 @@ int main(void)
/* USER CODE BEGIN 3 */ /* USER CODE BEGIN 3 */
PollUart(); PollUart();
PollCanBus(&hcan1, "CAN1"); PollCanBus(&hcan1, "CAN1");
PollCanBus(&hcan2, "CAN2"); PollCanBus(&hcan2, "CAN2");
PollCaptureChannels(); ServiceAssiLamp();
PollCaptureChannels();
PollGpioChanges(); PollGpioChanges();
SendPeriodicReport(); SendPeriodicReport();
ServiceHeartbeat(); ServiceHeartbeat();
@@ -666,7 +678,7 @@ static void MX_GPIO_Init(void)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */ /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11, GPIO_PIN_RESET);
/*Configure GPIO pins : PD8 PD9 PD10 PD11 /*Configure GPIO pins : PD8 PD9 PD10 PD11
PD12 PD13 PD14 PD0 PD12 PD13 PD14 PD0
@@ -687,8 +699,8 @@ static void MX_GPIO_Init(void)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PE0 PE1 */ /*Configure GPIO pins : PE0 PE1 PE9 PE10 PE11 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
@@ -753,14 +765,16 @@ static void AppInit(void)
adc_filter_sum = 0U; adc_filter_sum = 0U;
adc_filter_count = 0U; adc_filter_count = 0U;
adc_filter_index = 0U; adc_filter_index = 0U;
uart_line_len = 0U; uart_line_len = 0U;
assi_lamp_state = ASSI_STATE_OFF;
(void)DacSetMillivolts(1U, 0U); (void)DacSetMillivolts(1U, 0U);
(void)DacSetMillivolts(2U, 0U); (void)DacSetMillivolts(2U, 0U);
UartWrite("\r\nA11 F407 monitor ready\r\n"); UartWrite("\r\nA11 F407 monitor ready\r\n");
UartWrite("UART: DAC1 1.234 or DAC2 2500\r\n"); UartWrite("UART: DAC1 1.234 or DAC2 2500\r\n");
UartWrite("CAN cmd 0x321: [dac_id][mV_L][mV_H] or ASCII text\r\n"); UartWrite("CAN cmd 0x6A3: [dac_id][mV_L][mV_H] or ASCII text\r\n");
UartWrite("CAN cmd 0x6A5: [ASSI state 0=OFF,1=READY,2=DRIVING,3=EMERGENCY,4=FINISHED]\r\n");
BroadcastGpioReport(0U, gpio_last_state); BroadcastGpioReport(0U, gpio_last_state);
} }
@@ -810,7 +824,7 @@ static void PollCanBus(CAN_HandleTypeDef *hcan, const char *name)
continue; continue;
} }
if (rx_header.StdId == CAN_DAC_CMD_STD_ID) if (rx_header.StdId == CAN_DAC_CMD_STD_ID)
{ {
if ((rx_header.DLC >= 3U) && (rx_data[0] >= 1U) && (rx_data[0] <= 2U)) if ((rx_header.DLC >= 3U) && (rx_data[0] >= 1U) && (rx_data[0] <= 2U))
{ {
@@ -825,8 +839,15 @@ static void PollCanBus(CAN_HandleTypeDef *hcan, const char *name)
memcpy(line, rx_data, length); memcpy(line, rx_data, length);
line[length] = '\0'; line[length] = '\0';
HandleTextCommand(name, line); HandleTextCommand(name, line);
} }
} }
else if (rx_header.StdId == CAN_ASSI_LAMP_CMD_STD_ID)
{
if ((rx_header.DLC >= 1U) && (rx_data[0] <= ASSI_STATE_FINISHED))
{
HandleAssiLampSetRequest(name, rx_data[0]);
}
}
} }
} }
@@ -918,7 +939,7 @@ static void SendPeriodicReport(void)
} }
} }
static void ServiceHeartbeat(void) static void ServiceHeartbeat(void)
{ {
uint32_t now = HAL_GetTick(); uint32_t now = HAL_GetTick();
@@ -927,7 +948,53 @@ static void ServiceHeartbeat(void)
last_heartbeat_ms = now; last_heartbeat_ms = now;
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_0); HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_0);
} }
} }
static void ServiceAssiLamp(void)
{
GPIO_PinState red = GPIO_PIN_RESET;
GPIO_PinState green = GPIO_PIN_RESET;
GPIO_PinState blue = GPIO_PIN_RESET;
bool flash_on = ((HAL_GetTick() / ASSI_LAMP_FLASH_HALF_PERIOD_MS) & 1U) == 0U;
switch (assi_lamp_state)
{
case ASSI_STATE_READY:
red = GPIO_PIN_SET;
green = GPIO_PIN_SET;
break;
case ASSI_STATE_DRIVING:
red = flash_on ? GPIO_PIN_SET : GPIO_PIN_RESET;
green = flash_on ? GPIO_PIN_SET : GPIO_PIN_RESET;
break;
case ASSI_STATE_EMERGENCY:
blue = flash_on ? GPIO_PIN_SET : GPIO_PIN_RESET;
break;
case ASSI_STATE_FINISHED:
blue = GPIO_PIN_SET;
break;
case ASSI_STATE_OFF:
default:
break;
}
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, red);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, green);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, blue);
}
static void HandleAssiLampSetRequest(const char *source, uint8_t state)
{
char reply[64];
assi_lamp_state = state;
snprintf(reply, sizeof(reply), "OK %s ASSI state=%u\r\n", source, (unsigned int)state);
UartWrite(reply);
}
static void SendCanHeartbeat(void) static void SendCanHeartbeat(void)
{ {
@@ -945,7 +1012,7 @@ static void SendCanHeartbeat(void)
can_heartbeat_sequence++; can_heartbeat_sequence++;
gpio_state = ReadGpioInputState(); gpio_state = ReadGpioInputState();
/* CAN ID 0x100, sent independently on CAN1 and CAN2: /* CAN ID 0x6A0, sent independently on CAN1 and CAN2:
* [0] 0xA1 board identifier; [1] firmware protocol version 1; * [0] 0xA1 board identifier; [1] firmware protocol version 1;
* [2..3] sequence counter, little-endian; [4..7] uptime in ms, little-endian. * [2..3] sequence counter, little-endian; [4..7] uptime in ms, little-endian.
*/ */
+11 -10
View File
@@ -99,20 +99,21 @@
<p>所有字段均为小端序(低字节在前)。板卡主动上报的帧会分别发到 CAN1 和 CAN2。</p> <p>所有字段均为小端序(低字节在前)。板卡主动上报的帧会分别发到 CAN1 和 CAN2。</p>
<table> <table>
<tr><th style="width:13%">CAN ID</th><th style="width:19%">名称</th><th style="width:22%">方向 / 时机</th><th>数据定义</th></tr> <tr><th style="width:13%">CAN ID</th><th style="width:19%">名称</th><th style="width:22%">方向 / 时机</th><th>数据定义</th></tr>
<tr><td><code>0x100</code></td><td>心跳</td><td>板卡发送,每 1 s</td><td><code>A1 01 seq_L seq_H uptime_0..3</code>;板号 A1、协议版本 1、序号、运行时间 ms。</td></tr> <tr><td><code>0x6A0</code></td><td>心跳</td><td>板卡发送,每 1 s</td><td><code>A1 01 seq_L seq_H uptime_0..3</code>;板号 A1、协议版本 1、序号、运行时间 ms。</td></tr>
<tr><td><code>0x102</code></td><td>输入电压</td><td>板卡发送,每 500 ms</td><td><code>uint16</code>,单位 mV。例如 <code>90 2F</code> = 0x2F90 = 12176 mV = 12.176 V。</td></tr> <tr><td><code>0x6A1</code></td><td>输入电压</td><td>板卡发送,每 500 ms</td><td><code>uint16</code>,单位 mV。例如 <code>90 2F</code> = 0x2F90 = 12176 mV = 12.176 V。</td></tr>
<tr><td><code>0x103</code></td><td>四路频率</td><td>板卡发送,每 500 ms</td><td>4 个 <code>uint16</code>,单位 Hz;依次为 PA0、PA2、PA6、PB14。</td></tr> <tr><td><code>0x6A2</code></td><td>四路频率</td><td>板卡发送,每 500 ms</td><td>4 个 <code>uint16</code>,单位 Hz;依次为 PA0、PA2、PA6、PB14。</td></tr>
<tr><td><code>0x321</code></td><td>DAC 设置</td><td>外部发送给板卡</td><td><code>[DAC 编号][mV_L][mV_H]</code>,编号仅允许 1 或 2。</td></tr> <tr><td><code>0x6A3</code></td><td>DAC 设置</td><td>外部发送给板卡</td><td><code>[DAC 编号][mV_L][mV_H]</code>,编号仅允许 1 或 2。</td></tr>
<tr><td><code>0x322</code></td><td>DAC 应答</td><td>板卡发送,设置后</td><td><code>[结果][DAC 编号][mV_L][mV_H]</code>;结果 1 成功,0 失败。</td></tr> <tr><td><code>0x6A4</code></td><td>DAC 应答</td><td>板卡发送,设置后</td><td><code>[结果][DAC 编号][mV_L][mV_H]</code>;结果 1 成功,0 失败。</td></tr>
<tr><td><code>0x330</code></td><td>15 路状态</td><td>板卡发送,上电或状态变化</td><td>状态 <code>uint16</code>、变化掩码 <code>uint16</code>、时间戳 <code>uint32 ms</code>。</td></tr> <tr><td><code>0x6A5</code></td><td>ASSI RGB 灯控</td><td>外部发送给板卡</td><td><code>byte0</code>:0=关、1=黄常亮、2=黄闪、3=蓝闪、4=蓝常亮。</td></tr>
<tr><td><code>0x6A6</code></td><td>15 路状态</td><td>板卡发送,上电或状态变化</td><td>状态 <code>uint16</code>、变化掩码 <code>uint16</code>、时间戳 <code>uint32 ms</code>。</td></tr>
</table> </table>
<h3>DAC 设置示例</h3> <h3>DAC 设置示例</h3>
<p>电压 V 到 CAN 数据的换算:<code>mV = round(V × 1000)</code>,随后拆为低字节和高字节。</p> <p>电压 V 到 CAN 数据的换算:<code>mV = round(V × 1000)</code>,随后拆为低字节和高字节。</p>
<pre>DAC1 输出 3.000 V:ID = 0x321,DLC = 3,DATA = 01 B8 0B <pre>DAC1 输出 3.000 V:ID = 0x6A3,DLC = 3,DATA = 01 B8 0B
DAC2 输出 1.140 V:ID = 0x321,DLC = 3,DATA = 02 74 04 DAC2 输出 1.140 V:ID = 0x6A3,DLC = 3,DATA = 02 74 04
应答示例(DAC1 成功设为 3.000 V):ID = 0x322,DATA = 01 01 B8 0B</pre> 应答示例(DAC1 成功设为 3.000 V):ID = 0x6A4,DATA = 01 01 B8 0B</pre>
<div class="notice">DAC 输出范围为 0–5000 mV。软件中 DAC1、DAC2 到板级 MC_L、MC_R 的实际对应关系应以实物测量为准。</div> <div class="notice">DAC 输出范围为 0–5000 mV。软件中 DAC1、DAC2 到板级 MC_L、MC_R 的实际对应关系应以实物测量为准。</div>
<h2>4. ADC 电压说明</h2> <h2>4. ADC 电压说明</h2>
@@ -124,7 +125,7 @@ DAC2 输出 1.140 V:ID = 0x321,DLC = 3,DATA = 02 74 04
<pre>DAC1 1.234 <pre>DAC1 1.234
DAC2 2500 DAC2 2500
D1 2.5V</pre> D1 2.5V</pre>
<p>命令不区分大小写,支持伏特小数或毫伏整数。设置完成后串口会回显结果,CAN1/CAN2 同时发送 <code>0x322</code> 应答。</p> <p>命令不区分大小写,支持伏特小数或毫伏整数。设置完成后串口会回显结果,CAN1/CAN2 同时发送 <code>0x6A4</code> 应答。</p>
<h2>6. 频率输入说明</h2> <h2>6. 频率输入说明</h2>
<p>频率使用相邻上升沿时间差计算;连续 1 秒没有新边沿时,该通道输出 0 Hz。当前版本只测频率,不输出占空比。</p> <p>频率使用相邻上升沿时间差计算;连续 1 秒没有新边沿时,该通道输出 0 Hz。当前版本只测频率,不输出占空比。</p>
+21 -16
View File
@@ -34,46 +34,51 @@ BS_:
BU_: SDC_ACQ_DAC VehicleController BU_: SDC_ACQ_DAC VehicleController
BO_ 256 SDC_Heartbeat: 8 SDC_ACQ_DAC BO_ 1696 SDC_Heartbeat: 8 SDC_ACQ_DAC
SG_ Board_Identifier : 0|8@1+ (1,0) [0|255] "" VehicleController SG_ Board_Identifier : 0|8@1+ (1,0) [0|255] "" VehicleController
SG_ Protocol_Version : 8|8@1+ (1,0) [0|255] "" VehicleController SG_ Protocol_Version : 8|8@1+ (1,0) [0|255] "" VehicleController
SG_ Heartbeat_Sequence : 16|16@1+ (1,0) [0|65535] "" VehicleController SG_ Heartbeat_Sequence : 16|16@1+ (1,0) [0|65535] "" VehicleController
SG_ Uptime : 32|32@1+ (0.001,0) [0|4294967.295] "s" VehicleController SG_ Uptime : 32|32@1+ (0.001,0) [0|4294967.295] "s" VehicleController
BO_ 258 SDC_ADC_InputVoltage: 2 SDC_ACQ_DAC BO_ 1697 SDC_ADC_InputVoltage: 2 SDC_ACQ_DAC
SG_ Input_Voltage : 0|16@1+ (0.001,0) [0|65.535] "V" VehicleController SG_ Input_Voltage : 0|16@1+ (0.001,0) [0|65.535] "V" VehicleController
BO_ 259 SDC_InputFrequencies: 8 SDC_ACQ_DAC BO_ 1698 SDC_InputFrequencies: 8 SDC_ACQ_DAC
SG_ Frequency_PA0 : 0|16@1+ (1,0) [0|65535] "Hz" VehicleController SG_ Frequency_PA0 : 0|16@1+ (1,0) [0|65535] "Hz" VehicleController
SG_ Frequency_PA2 : 16|16@1+ (1,0) [0|65535] "Hz" VehicleController SG_ Frequency_PA2 : 16|16@1+ (1,0) [0|65535] "Hz" VehicleController
SG_ Frequency_PA6 : 32|16@1+ (1,0) [0|65535] "Hz" VehicleController SG_ Frequency_PA6 : 32|16@1+ (1,0) [0|65535] "Hz" VehicleController
SG_ Frequency_PB14 : 48|16@1+ (1,0) [0|65535] "Hz" VehicleController SG_ Frequency_PB14 : 48|16@1+ (1,0) [0|65535] "Hz" VehicleController
BO_ 801 SDC_DAC_Set: 3 VehicleController BO_ 1699 SDC_DAC_Set: 3 VehicleController
SG_ DAC_Select : 0|8@1+ (1,0) [1|2] "" SDC_ACQ_DAC SG_ DAC_Select : 0|8@1+ (1,0) [1|2] "" SDC_ACQ_DAC
SG_ DAC_Command_Voltage : 8|16@1+ (0.001,0) [0|5] "V" SDC_ACQ_DAC SG_ DAC_Command_Voltage : 8|16@1+ (0.001,0) [0|5] "V" SDC_ACQ_DAC
BO_ 802 SDC_DAC_Ack: 4 SDC_ACQ_DAC BO_ 1700 SDC_DAC_Ack: 4 SDC_ACQ_DAC
SG_ DAC_Set_Result : 0|8@1+ (1,0) [0|1] "" VehicleController SG_ DAC_Set_Result : 0|8@1+ (1,0) [0|1] "" VehicleController
SG_ DAC_Select : 8|8@1+ (1,0) [1|2] "" VehicleController SG_ DAC_Select : 8|8@1+ (1,0) [1|2] "" VehicleController
SG_ DAC_Output_Voltage : 16|16@1+ (0.001,0) [0|5] "V" VehicleController SG_ DAC_Output_Voltage : 16|16@1+ (0.001,0) [0|5] "V" VehicleController
BO_ 816 SDC_GPIO_Status: 8 SDC_ACQ_DAC BO_ 1701 ASSI_Lamp_Set: 1 VehicleController
SG_ ASSI_State : 0|8@1+ (1,0) [0|4] "" SDC_ACQ_DAC
BO_ 1702 SDC_GPIO_Status: 8 SDC_ACQ_DAC
SG_ SDC_Input_State : 0|15@1+ (1,0) [0|32767] "" VehicleController SG_ SDC_Input_State : 0|15@1+ (1,0) [0|32767] "" VehicleController
SG_ SDC_Changed_Mask : 16|15@1+ (1,0) [0|32767] "" VehicleController SG_ SDC_Changed_Mask : 16|15@1+ (1,0) [0|32767] "" VehicleController
SG_ Timestamp : 32|32@1+ (0.001,0) [0|4294967.295] "s" VehicleController SG_ Timestamp : 32|32@1+ (0.001,0) [0|4294967.295] "s" VehicleController
VAL_ 256 Board_Identifier 161 "A11_F407" ; VAL_ 1696 Board_Identifier 161 "A11_F407" ;
VAL_ 801 DAC_Select 1 "DAC1" 2 "DAC2" ; VAL_ 1699 DAC_Select 1 "DAC1" 2 "DAC2" ;
VAL_ 802 DAC_Set_Result 0 "Failed" 1 "OK" ; VAL_ 1700 DAC_Set_Result 0 "Failed" 1 "OK" ;
VAL_ 802 DAC_Select 1 "DAC1" 2 "DAC2" ; VAL_ 1700 DAC_Select 1 "DAC1" 2 "DAC2" ;
VAL_ 1701 ASSI_State 0 "AS_OFF" 1 "AS_READY" 2 "AS_DRIVING" 3 "AS_EMERGENCY" 4 "AS_FINISHED" ;
CM_ BO_ 256 "Standard ID 0x100. Sent every 1 s on CAN1 and CAN2."; CM_ BO_ 1696 "Standard ID 0x6A0. Sent every 1 s on CAN1 and CAN2.";
CM_ BO_ 258 "Standard ID 0x102. Filtered and calibrated physical input voltage before the hardware divider."; CM_ BO_ 1697 "Standard ID 0x6A1. Filtered and calibrated physical input voltage before the hardware divider.";
CM_ BO_ 259 "Standard ID 0x103. Sent every 500 ms. Frequency order is PA0, PA2, PA6, PB14."; CM_ BO_ 1698 "Standard ID 0x6A2. Sent every 500 ms. Frequency order is PA0, PA2, PA6, PB14.";
CM_ BO_ 801 "Standard ID 0x321. Accepted on CAN1 and CAN2. The on-wire voltage is an unsigned mV value."; CM_ BO_ 1699 "Standard ID 0x6A3. Accepted on CAN1 and CAN2. The on-wire voltage is an unsigned mV value.";
CM_ BO_ 802 "Standard ID 0x322. Sent on CAN1 and CAN2 after a DAC command. Result 0 indicates the I2C write failed."; CM_ BO_ 1700 "Standard ID 0x6A4. Sent on CAN1 and CAN2 after a DAC command. Result 0 indicates the I2C write failed.";
CM_ BO_ 816 "Standard ID 0x330. Sent at startup and whenever PD0-PD14 state changes, on CAN1 and CAN2."; CM_ BO_ 1701 "Standard ID 0x6A5. Accepted on CAN1 and CAN2. Byte 0 selects the latched ASSI RGB lamp state: AS_OFF, AS_READY, AS_DRIVING, AS_EMERGENCY, or AS_FINISHED.";
CM_ BO_ 1702 "Standard ID 0x6A6. Sent at startup and whenever PD0-PD14 state changes, on CAN1 and CAN2.";
CM_ SG_ 256 Board_Identifier "Fixed board identifier 0xA1."; CM_ SG_ 256 Board_Identifier "Fixed board identifier 0xA1.";
CM_ SG_ 259 Frequency_PA0 "TIM5_CH1 input capture on PA0."; CM_ SG_ 259 Frequency_PA0 "TIM5_CH1 input capture on PA0.";
CM_ SG_ 259 Frequency_PA2 "TIM9_CH1 input capture on PA2."; CM_ SG_ 259 Frequency_PA2 "TIM9_CH1 input capture on PA2.";
+89
View File
@@ -0,0 +1,89 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /STSong-Light /DescendantFonts [ <<
/BaseFont /STSong-Light /CIDSystemInfo <<
/Ordering (GB1) /Registry (Adobe) /Supplement 0
>> /DW 1000 /FontDescriptor <<
/Ascent 752 /CapHeight 737 /Descent -271 /Flags 6 /FontBBox [ -25 -254 1000 880 ] /FontName /STSongStd-Light
/ItalicAngle 0 /Leading 148 /MaxWidth 1000 /MissingWidth 500 /StemH 91 /StemV 58
/Type /FontDescriptor /XHeight 553
>> /Subtype /CIDFontType0 /Type /Font
/W [ 1 [ 207 270 342 467 462 797 710 239 374 ] 10 [ 374 423 605 238 375 238 334 462 ] 18 26 462 27 28 238
29 31 605 32 [ 344 748 684 560 695 739 563 511 729 793
318 312 666 526 896 758 772 544 772 628
465 607 753 711 972 647 620 607 374 333
374 606 500 239 417 503 427 529 415 264
444 518 241 230 495 228 793 527 524 ] 81 [ 524 504 338 336 277 517 450 652 466 452
407 370 258 370 605 ] ]
>> ] /Encoding /UniGB-UCS2-H /Name /F2 /Subtype /Type0 /Type /Font
>>
endobj
4 0 obj
<<
/Contents 8 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 7 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
>>
endobj
6 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20260918211423+08'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260918211423+08'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (\376\377\000S\000D\000C\000-\000A\000C\000Q\000_\000D\000A\000C\000 \000C\000A\000N\000 b\245e\207\213\364f\016\210h) /Trapped /False
>>
endobj
7 0 obj
<<
/Count 1 /Kids [ 4 0 R ] /Type /Pages
>>
endobj
8 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2111
>>
stream
Gb!;fh/h((&:`#5Tg!Re16%B=ojKYo"7u]ZKS7Mh@60e&L5&MI+XA`F*r+L%P0]<QZgZ0h,jhBBQ?KZ>Xn:@RY>6o>J'tgP:)LT+A(Q3m9EL\HB2W`gB%u\8fuDbU3Tj?Ff<R4ZdpT]f%5a-e>Ss\;1G4Zm_CuIBs87+oABM-8@C$VN!gkOp&tn%^JB2R.5kNa%$e3En#VgJH:TjN@2-[5o'tP(14:Nj(^qu9Wg[Sd/'e"K0JZok[XO*p/Q&p_]il1Y.p6*\'Z)ptQ1;SYCqTL'>[p#-D%/gT$"pV@H'S%)>a3k5t0Wp*^$<XNrijuBokoSYpGZ+pfTe+?"WeA%<ZX4RYEIGnR:nb:^5]@b2)A*n6s2m3SY5-6umt.p)HDXYMV0]].q_./?4/l&DKC@s^n`b/arcHar*OH.$mtHs87'dW&q-9WEF@8Zp\F7^Vk=4D(H@9al$2]OiDCss+D@ke^-h\NDAlVB.8lXVVeqTY,9$+m&^p"L_V_jH8AJRhF^lie9m/2Z&^ICQGhjd1PU;_ascGN:$V'Utp2MIi_<*IYK%("G%P!Sa1XH6\UQ%CSuaAp2O\ZgHWhJ&+u&0;(\i3G2mda[G(r(n2GkknZp[Xsts"XH$;p].^T\/B4&]M5L7$[9]pNeSNGVD@4nUm4C[WC%0?b#p#U#'J?C$OTHMGU[aCH'I6[$a>6f!\#X!Am/V9WH?^C;IE$d^6K+.;JB6VB&:pOHS65#8u=3(KVIBQXNX\EkHN7'SNa1V@HUsl_gKuW3OumcCL%9A?jUgGN7$r`K38ff_\Y@443J"?mGN[^Y,&JS5J/rTV?2;+fCqW<HPfaWUb0.CH-0U<kpDn9]Defs$=&RB1#uY/0I@EemsV&fJJXP]/A:gI1fhK,jM#D,/!K0^\&'Z#E4HpQ#M-YTRRVBMjdIFG]FEQLp/:235^aG(PEWfV1sH@3=la<5=NuHS[Yt$#9KmR3.C69S8K$!Oo=N%-pn7eV$q61;2$2b-eEnJ!VMl7s99"OL-V6r(kRQ]J'g:5GPYKiOO'YgoFHZYT*'F<*0%8FnZ+_P`];tHZH-.>-RYD;g4^Z[)Y+Kf@:Ejc1ojld"%G(^B>u.4hT+7VYO+RlA:6+2sWQ/+NV=t#7VZGQ/)jgX[2o(kGgqB?6H9]%H7D,`*RXe$6)N4i'VKQ#CZohp'$tu';rAl[I;<Ha;NA,ks^nc.?T5n-C<$3iAR:S88!XhH,aKNS`dAI)=L4JJ%qK,QScrfUY&<ks3`[53B1M5(?gL1J)(#EeIM/^LtE6hL$"kl&Jm\#$s$V$mS:KO@d:.+$-l.W6\5-$s%4VR@Va;Dj>VD6\Q2i`W:ShBuB5OR1FkGI\3M5RfACWtZ48KOp.C1-bWCdGGRcOVN,d7H1f8o3Rspp9"c<gSV<2%lOLb$@RqcI3Lb0?<(YIV#h)D<#a#MYOFjQ\ZT6C8P:gJ>sLseN@+AT_b&X.3;F;;\=^j"2:m[\tHb$5V)PaB%pZ!4</8<k2'bD\#VcNiY"PV7tNKp\LRuTH+Hm?9,Z&pL)`lG%?3#tZa2SSG.'3eQCpN'Am09c36KWfbgWD<FoU^mA&rqVl5S@W9FZm$72+;tL^62A6D4mH*WONg`;g4^fpc#ilm0QXZZO_A%;3U1gL>+S7M(5MB8]WDR(9f/n9p_4-8Q:ks.`1bk-pN%b0gtkWpYthLA*`']cMhLi_@(NNlc5P(e#6_*W`"gdffuI^ji9_re5)`k7nj*Hds`,O"NWH<T7CcEj&Yqp];Y'9(Ls3l<*[>h<N&-4$)B^`>Uc3YOqk<%;sPph.C!?J+X'<]fR/Q2>]I_2F!%jJmJ+.RsL62'1=T,>)Y&!!C?.[H]-srJY\Ij>rRifSHX"6C"a9d2$=;(!qdI`.bY$j2$?IZh^i]=p/b"CjuI<NC0g]B7h2(\#D9[Wh)n1W$ETBJaJ%)0-UU+bE.Y0k.nfgL=p0ShFMsCOdO7V$'ZoO\*PPbYJ*U/j`Va@%(fAp(f_fu(\,0XeH$PLr)amsP-I-k@IAr84-eBgDmC/q3hlb`SMEBJ9ITp0O_k]^*5Aq=/U?IF,+uJhR,DJ/BhP@6p'UfRsEZ]VX532S;J3HcE2Z<`&/6i#~>endstream
endobj
xref
0 9
0000000000 65535 f
0000000061 00000 n
0000000102 00000 n
0000000209 00000 n
0000001142 00000 n
0000001345 00000 n
0000001413 00000 n
0000001796 00000 n
0000001855 00000 n
trailer
<<
/ID
[<0c601b021e0ca62988154610c4965733><0c601b021e0ca62988154610c4965733>]
% ReportLab generated PDF document -- digest (opensource)
/Info 6 0 R
/Root 5 0 R
/Size 9
>>
startxref
4057
%%EOF
+17 -11
View File
@@ -30,6 +30,7 @@
| CAN1 | `PB8` RX、`PB9` TX | 标准帧,500 kbit/s | | CAN1 | `PB8` RX、`PB9` TX | 标准帧,500 kbit/s |
| CAN2 | `PB5` RX、`PB6` TX | 标准帧,500 kbit/s | | CAN2 | `PB5` RX、`PB6` TX | 标准帧,500 kbit/s |
| DAC I2C | `PB10` SCL、`PB11` SDA / `I2C2` | 控制两颗 MCP4725,5 V 基准 | | DAC I2C | `PB10` SCL、`PB11` SDA / `I2C2` | 控制两颗 MCP4725,5 V 基准 |
| ASSI RGB 灯 MOS | `PE9` R、`PE10` G、`PE11` B | 推挽输出,高电平使能外部 MOS |
| 调试串口 | `PA9` TX、`PA10` RX / `USART1` | 115200、8N1、无流控 | | 调试串口 | `PA9` TX、`PA10` RX / `USART1` | 115200、8N1、无流控 |
| 运行/故障 LED | `PE0` / `PE1` | 正常心跳 / 故障指示 | | 运行/故障 LED | `PE0` / `PE1` | 正常心跳 / 故障指示 |
@@ -77,27 +78,32 @@ CAN1 和 CAN2 使用相同协议,所有主动上报均分别发送到两条总
| ID | 名称 | 周期/触发 | 数据 | | ID | 名称 | 周期/触发 | 数据 |
|---:|---|---|---| |---:|---|---|---|
| `0x100` | 心跳 | 每 1 s | `A1 01 seq_L seq_H uptime_0..3` | | `0x6A0` | 心跳 | 每 1 s | `A1 01 seq_L seq_H uptime_0..3` |
| `0x102` | ADC 电压 | 每 500 ms | 输入电压 `uint16`,单位 mV | | `0x6A1` | ADC 电压 | 每 500 ms | 输入电压 `uint16`,单位 mV |
| `0x103` | 四路频率 | 每 500 ms | 4 个 `uint16`,单位 Hz,顺序 PA0/PA2/PA6/PB14 | | `0x6A2` | 四路频率 | 每 500 ms | 4 个 `uint16`,单位 Hz,顺序 PA0/PA2/PA6/PB14 |
| `0x330` | GPIO 状态 | 上电、任一输入变化 | 状态 `uint16`、变化掩码 `uint16`、时间戳 `uint32 ms` | | `0x6A3` | DAC 设置命令 | 接收 | `[DAC 编号][mV_L][mV_H]` |
| `0x321` | DAC 设置命令 | 接收 | `[DAC 编号][mV_L][mV_H]` | | `0x6A4` | DAC 应答 | 每次 DAC 设置后 | `[结果][DAC 编号][mV_L][mV_H]` |
| `0x322` | DAC 应答 | 每次 DAC 设置后 | `[结果][DAC 编号][mV_L][mV_H]` | | `0x6A5` | ASSI 灯控 | 接收 | `byte0`:`0=AS_OFF`、`1=AS_READY`、`2=AS_DRIVING`、`3=AS_EMERGENCY`、`4=AS_FINISHED` |
| `0x6A6` | GPIO 状态 | 上电、任一输入变化 | 状态 `uint16`、变化掩码 `uint16`、时间戳 `uint32 ms` |
心跳帧中板号为 `0xA1`、协议版本为 `0x01`,序号与上电时间均为低字节在前。完整信号定义和量纲以 [DBC 文件](SDC_ACQ_DAC.dbc) 为准。 心跳帧中板号为 `0xA1`、协议版本为 `0x01`,序号与上电时间均为低字节在前。完整信号定义和量纲以 [DBC 文件](SDC_ACQ_DAC.dbc) 为准。
### ASSI RGB 状态灯
`PE9/PE10/PE11` 分别控制外部红、绿、蓝灯 MOS,均为高电平有效。`0x6A5` 可由 CAN1 或 CAN2 接收,状态在下一帧有效灯控报文到达前保持不变;上电默认 `AS_OFF`。`AS_READY` 为红绿常亮(黄),`AS_DRIVING` 为红绿以 2 Hz、50% 占空比闪烁(各 250 ms 亮/灭),`AS_EMERGENCY` 为蓝灯以相同节奏闪烁,`AS_FINISHED` 为蓝灯常亮。`PE0` 运行心跳和 `PE1` 故障指示保持原行为。
### DAC CAN 报文示例 ### DAC CAN 报文示例
将 DAC1 设为 2.500 V: 将 DAC1 设为 2.500 V:
```text ```text
ID=0x321 DLC=3 DATA=01 C4 09 ID=0x6A3 DLC=3 DATA=01 C4 09
``` ```
成功应答: 成功应答:
```text ```text
ID=0x322 DLC=4 DATA=01 01 C4 09 ID=0x6A4 DLC=4 DATA=01 01 C4 09
``` ```
DAC 编号 1 的 I2C 7 位地址为 `0x61`,编号 2 为 `0x60`。两路与板级 `MC_L`、`MC_R` 网络的实际对应关系需要以实物测量确认后再固化到线束文档。 DAC 编号 1 的 I2C 7 位地址为 `0x61`,编号 2 为 `0x60`。两路与板级 `MC_L`、`MC_R` 网络的实际对应关系需要以实物测量确认后再固化到线束文档。
@@ -111,7 +117,7 @@ DAC 编号 1 的 I2C 7 位地址为 `0x61`,编号 2 为 `0x60`。两路与板
```text ```text
A11 F407 monitor ready A11 F407 monitor ready
UART: DAC1 1.234 or DAC2 2500 UART: DAC1 1.234 or DAC2 2500
CAN cmd 0x321: [dac_id][mV_L][mV_H] or ASCII text CAN cmd 0x6A3: [dac_id][mV_L][mV_H] or ASCII text
``` ```
支持的 DAC 命令不区分大小写: 支持的 DAC 命令不区分大小写:
@@ -122,7 +128,7 @@ DAC2 2500
D1 2.5V D1 2.5V
``` ```
数值可使用伏特小数或毫伏整数;允许范围为 0 至 5000 mV。命令执行后会回显结果,并在两条 CAN 上发送 `0x322` 应答。 数值可使用伏特小数或毫伏整数;允许范围为 0 至 5000 mV。命令执行后会回显结果,并在两条 CAN 上发送 `0x6A4` 应答。
## 8. 编译、生成与下载 ## 8. 编译、生成与下载
@@ -158,6 +164,6 @@ Release 固件为 `build/Release/A11_F407_SDC_ACQ_DAC.bin`。若改动了 `.ioc`
- 变更 CubeMX 配置后必须重新生成并重新编译,检查 `main.c` 的用户代码区是否完整保留。 - 变更 CubeMX 配置后必须重新生成并重新编译,检查 `main.c` 的用户代码区是否完整保留。
- 修改 CAN 速率时,CAN1 与 CAN2 的波特率及外部分析仪配置必须一致。 - 修改 CAN 速率时,CAN1 与 CAN2 的波特率及外部分析仪配置必须一致。
- 修改 ADC 分压、标定或滤波参数时,应使用已知直流电压复测,并确认 CAN `0x102` 与串口数值一致。 - 修改 ADC 分压、标定或滤波参数时,应使用已知直流电压复测,并确认 CAN `0x6A1` 与串口数值一致。
- 修改 DAC 地址、参考电压或输出范围时,同时更新 DBC、本文和 `DAC*_ADDR7`、`DAC_REFERENCE_MV` 宏。 - 修改 DAC 地址、参考电压或输出范围时,同时更新 DBC、本文和 `DAC*_ADDR7`、`DAC_REFERENCE_MV` 宏。
- 本工程不包含构建目录和 `.bin`、`.elf`、`.hex` 等固件二进制;发布生产固件前应从当前提交重新编译生成。 - 本工程不包含构建目录和 `.bin`、`.elf`、`.hex` 等固件二进制;发布生产固件前应从当前提交重新编译生成。