我有一块 STM32F091RCT 板,我试图将其强制用作临时 CAN 节点。为了有一个起点,我查找了一些代码示例。我从 this one 开始,但它引用了一些 typedef(例如
CanTxMsgTypeDef
)和函数(例如 HAL_CAN_Transmit
),这些似乎不存在于 stm32f0xx_hal_can.h
标头中。因此,我使用了一个针对 F103 的示例,并最终得到了这段代码(自动生成的注释和与 CAN 无关的内容被删除):
CAN_HandleTypeDef hcan;
// other peripheral configuration, etc.
static void MX_CAN_Init(void)
{
hcan.Instance = CAN;
hcan.Init.Prescaler = 16;
hcan.Init.Mode = CAN_MODE_LOOPBACK; // also tried normal mode, same deal
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_1TQ;
hcan.Init.TimeSeg2 = CAN_BS2_1TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = DISABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = DISABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
hcan.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan) != HAL_OK)
{
Error_Handler();
}
CAN_FilterTypeDef sf;
sf.FilterMaskIdHigh = 0x0000;
sf.FilterMaskIdLow = 0x0000;
sf.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sf.FilterBank = 0;
sf.FilterMode = CAN_FILTERMODE_IDMASK;
sf.FilterScale = CAN_FILTERSCALE_32BIT;
sf.FilterActivation = CAN_FILTER_ENABLE;
if (HAL_CAN_ConfigFilter(&hcan, &sf) != HAL_OK) {
Error_Handler();
}
if (HAL_CAN_ConfigFilter(&hcan, &sf) != HAL_OK)
Error_Handler();
// this didn't want to work
// if (HAL_CAN_RegisterCallback(&hcan, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, can_irq)) {
// Error_Handler();
// }
if (HAL_CAN_Start(&hcan) != HAL_OK) {
Error_Handler();
}
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
Error_Handler();
}
}
void can_irq(CAN_HandleTypeDef *pcan) {
CAN_RxHeaderTypeDef msg;
uint8_t data[8];
HAL_CAN_GetRxMessage(pcan, CAN_RX_FIFO0, &msg, data);
// do something
}
// ...
int main(void)
{
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_TIM1_Init();
MX_CAN_Init();
while (1)
{
uint32_t mb;
CAN_TxHeaderTypeDef msg;
uint8_t data[] = "Hello!";
msg.StdId = 127;
msg.IDE = CAN_ID_STD;
msg.RTR = CAN_RTR_DATA;
msg.DLC = 6;
msg.TransmitGlobalTime = DISABLE;
if (HAL_CAN_AddTxMessage(&hcan, &msg, data, &mb) != HAL_OK) {
Error_Handler();
}
}
}
void send_CAN_test_message(void)
{
uint32_t mb;
CAN_TxHeaderTypeDef msg;
uint8_t data[] = "Hello!";
msg.StdId = 127;
msg.IDE = CAN_ID_STD;
msg.RTR = CAN_RTR_DATA;
msg.DLC = 6;
msg.TransmitGlobalTime = DISABLE;
if (HAL_CAN_AddTxMessage(&hcan, &msg, data, &mb) != HAL_OK) {
Error_Handler();
}
}
所以我希望它在主循环的每次迭代中都通过 CAN 总线传输一条消息。不幸的是,情况似乎并非如此,因为连接到 CAN_TX 引脚的示波器(也尝试过 RX 进行了良好的测量)仅在执行
MX_CAN_Init()
时显示电压从 0 V 上升到 3.3 V。为了澄清起见,我正在测量直接从 MCU 发出的信号,在收发器 (MCP2551) 之前。
我怀疑我在这里遗漏了一些非常明显的东西......有人知道那个非常明显的东西是什么吗?也许控制器引脚上存在伪冲突(TX 和 RX 之间的差异),而控制器只是无限期地等待它结束?
虽然有点晚了,但我找到了 CAN_MCR->DBF 标志。默认情况下设置为 1,定义如下:
位 16 DBF:调试冻结 0:调试时CAN工作 1:调试期间 CAN 接收/发送冻结。接收 FIFO 仍然可以正常访问/控制。
因此,如果您运行调试器,则 CAN 总线将失效。当你不知道的时候很烦人...