打印
[APM32E1]

APM32E103 CAN总线双向通信开发指南(拿走不谢)

[复制链接]
147|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
APM32E103 CAN总线双向通信开发指南(拿走不谢)
1. 硬件连接
1.1 硬件要求
- 两块APM32E103开发板
- CAN收发器(TJA1050) 2
- 120Ω终端电阻 2
- 杜邦线若干
1.2 连接方式
```
APM32E103 Board A <--> APM32E103 Board B
CAN_TX   -------- CAN_TX
CAN_RX   -------- CAN_RX
GND      -------- GND
```
1.3 注意事项
1. 在总线两端各接一个120Ω电阻用于阻抗匹配
2. 确保两个开发板共地
3. 建议使用示波器或逻辑分析仪观察CAN总线波形
2. 软件配置
2.1 环境准备
- STM32CubeIDE
- APm32 HAL
2.2 CAN初始化代码
```c
// CAN初始化函数
void MX_CAN_Init(void)
{
    hcan.Instance = CAN1;
    hcan.Init.Prescaler = 16;
    hcan.Init.Mode = CAN_MODE_NORMAL;
    hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan.Init.TimeSeg1 = CAN_BS1_13TQ;
    hcan.Init.TimeSeg2 = CAN_BS2_2TQ;
    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();
    }
}
```
2.3 CAN过滤器配置
```c
// CAN过滤器配置
void CAN_FilterConfig(void)
{
    CAN_FilterTypeDef sFilterConfig;
   
    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    sFilterConfig.SlaveStartFilterBank = 14;
   
    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
   
    // 启动CAN
    if (HAL_CAN_Start(&hcan) != HAL_OK)
    {
        Error_Handler();
    }
   
    // 激活CAN RX中断
    if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    {
        Error_Handler();
    }
}
```
3. 通信实现
3.1 发送数据函数
```c
// CAN数据发送函数
HAL_StatusTypeDef CAN_SendData(uint8_t data, uint8_t size)
{
    CAN_TxHeaderTypeDef TxHeader;
    uint32_t TxMailbox;
   
    TxHeader.StdId = 0x123;  // 标准ID
    TxHeader.ExtId = 0x00;   // 扩展ID
    TxHeader.RTR = CAN_RTR_DATA;
    TxHeader.IDE = CAN_ID_STD;
    TxHeader.DLC = size;
    TxHeader.TransmitGlobalTime = DISABLE;
   
    return HAL_CAN_AddTxMessage(&hcan, &TxHeader, data, &TxMailbox);
}
```
3.2 接收数据函数
```c
// CAN数据接收函数
HAL_StatusTypeDef CAN_ReceiveData(uint8_t data, uint8_t size)
{
    CAN_RxHeaderTypeDef RxHeader;
   
    if (HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, data) == HAL_OK)
    {
        size = RxHeader.DLC;
        return HAL_OK;
    }
    return HAL_ERROR;
}
```
3.3 中断回调函数
```c
// CAN接收中断回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef hcan)
{
    uint8_t receivedData[8];
    uint8_t size;
   
    if (CAN_ReceiveData(receivedData, &size) == HAL_OK)
    {
        // 处理接收到的数据
        // 例如: 根据接收到的数据控制LED或发送回复
        
        // 示例: 收到数据后发送回复
        uint8_t replyData[] = {0xAA, 0xBB, 0xCC};
        CAN_SendData(replyData, sizeof(replyData));
    }
}
```
4. 主程序实现
4.1 主函数
```c
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_CAN_Init();
    CAN_FilterConfig();
   
    uint8_t buttonState = 0;
    uint8_t sendData[] = {0x01, 0x02, 0x03};
    uint8_t receiveData[8];
    uint8_t receiveSize;
   
    while (1)
    {
        // 检测按钮按下
        if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
        {
            HAL_Delay(50); // 消抖
            if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin) == GPIO_PIN_RESET)
            {
                buttonState = 1;
            }
        }
        
        // 按钮按下时发送数据
        if (buttonState == 1)
        {
            if (CAN_SendData(sendData, sizeof(sendData)) == HAL_OK)
            {
                buttonState = 0;
                HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 发送成功指示灯
            }
        }
        
        // 非阻塞接收数据
        if (CAN_ReceiveData(receiveData, &receiveSize) == HAL_OK)
        {
            // 处理接收到的数据
            HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // 接收成功指示灯
        }
        
        HAL_Delay(10);
    }
}
```
5. 调试与测试
5.1 常见问题排查
1. 通信失败:
   - 检查硬件连接是否正确
   - 确认终端电阻已正确连接
   - 检查波特率设置是否一致
2. 数据丢失:
   - 增加接收缓冲区大小
   - 优化中断优先级
   - 检查总线负载是否过高
3. 信号质量问题:
   - 使用示波器检查信号完整性
   - 确保总线终端电阻匹配
   - 检查电源稳定性
5.2 测试流程
1. 单独测试每个开发板的CAN发送功能
2. 测试单向通信(A发送,板B接收)
3. 测试双向通信
4. 测试按钮触发通信功能
5. 测试长时间通信稳定性
6. 注意事项
1. 总线拓扑:
   - 使用线性总线拓扑,避免星形连接
   - 总线长度不宜过长(建议小于40)
2. 信号完整性:
   - 使用双绞线连接
   - 避免与高频信号线平行走线
3. 软件设计:
   - 添加超时机制,避免总线故障导致程序卡死
   - 实现错误检测和恢复机制
   - 考虑添加心跳包检测通信状态
4. 性能优化:
   - 根据实际需求调整CAN波特率
   - 合理设置过滤器减少不必要的中断
   - 优化数据处理流程
通过以上配置和代码实现,两个APM32E103开发板可以通过CAN总线建立可靠的双向通信,并通过按钮触发数据交换。



使用特权

评论回复
沙发
天体书记| | 2025-6-27 08:50 | 只看该作者
CAN的过滤器设计真是厉害。
开始学习的时候因为配置不对,导致收不到消息帧。对这个东西还是很恼火的,但后来配置通了之后,这个东西的发明人实在是大佬啊!

使用特权

评论回复
板凳
Reli-eng-z|  楼主 | 2025-6-27 15:46 | 只看该作者
天体书记 发表于 2025-6-27 08:50
CAN的过滤器设计真是厉害。
开始学习的时候因为配置不对,导致收不到消息帧。对这个东西还是很恼火的,但后 ...

山外有山,人外有人

使用特权

评论回复
地板
丙丁先生| | 2025-6-27 18:53 | 只看该作者

极海吗?感谢分享

使用特权

评论回复
5
Reli-eng-z|  楼主 | 2025-6-27 21:15 | 只看该作者

<br /> <br /> 不客气

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

138

帖子

1

粉丝