TMS320F28379D笔记4:CAN通信的收发配置

今日配置下CAN通信,顺带理解下CAN 的一些基础知识

目录

CAN基础知识:

CAN控制器

CAN收发器

CAN总线上的0和1

CAN通信示波器信号直观感受:

CAN盒与MCU的连接:

[Ti 例程代码注意点:](#Ti 例程代码注意点:)

代码贴出:

#include "my_can.h"

主函数:

测试效果:

[CAN BUSOFF](#CAN BUSOFF)


CAN基础知识:

CAN控制器

CAN控制器内部结构还是挺复杂的,一般现在CAN控制器都是与处理器集成在一起

其实对于编程的人来说,无非也就是包含一些控制、状态、配置等寄存器。

比如我们看到有些STM32芯片带有CAN,也就是说CAN控制器已经集成在STM32芯片中了,我们只需要编程操作其中的寄存器即可。
F28379D里面有CAN芯片:

CAN收发器

将CAN收发引脚(CAN_TX和CAN_RX)的TTL信号转换成CAN总线的电平信号

CAN总线上的0和1

CAN总线为**「两线」「差分」信号**,用隐形代表逻辑1,显性代表逻辑0。

CAN通信示波器信号直观感受:

CAN的波形差不多是这样的,这里由于Ti例程的时钟影响,说不清是什么波特率的CAN,但波形是正确的,只是频率未知:


加了逻辑分析的效果如下:

CAN盒与MCU的连接:

CAN盒子
CAN-H 接 CAN-H

CAN-L 接 CAN-L

GND 接 GND


设置普通CAN通信,波特率:


正常通信 就能看到 如图所示:

右下角会有接收成功与错误计数,一般都是波特率不匹配,总线电平不对会错误帧:

Ti 例程代码注意点:

Ti的CAN例程,时钟频率不是很对,这会导致没法通信成功

主要是device.h这俩块需要注意对比清楚,必要时示波器分析:


我的程序在使用时发现需要将他的频率计算/2才正常:

代码贴出:

#include "my_can.h"

复制代码
#ifndef _MY_CAN_H_
#define _MY_CAN_H_


#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"

#define GPIO_CFG_CANRXB      GPIO_17_CANRXB  // "pinConfig" for CANB RX
#define GPIO_CFG_CANTXB      GPIO_12_CANTXB  // "pinConfig" for CANB TX

#define MSG_DATA_LENGTH    8
#define MSG_DATARX_LENGTH    0
#define TX_MSG_OBJ_ID      1       // 发送邮箱
#define RX_MSG_OBJ_ID      2       // 接收邮箱
#define CAN_ID             0x1     // 收发ID都是 0x1



extern uint16_t txMsgData[8];
extern uint16_t txMsgData2[8];
extern uint16_t rxMsgData[8];

void MY_can_bsp_init();
__interrupt void canB_ISR(void);// 接收中断函数


#endif

#include "my_can.h"

uint16_t txMsgData[8];
uint16_t txMsgData2[8];
uint16_t rxMsgData[8];
uint16_t rxMsgCount = 0;

void MY_can_bsp_init()
{
    txMsgData[0] = 0x55;txMsgData[1] = 0xff;txMsgData[2] = 0x55;txMsgData[3] = 0xff;
    txMsgData[4] = 0x55;txMsgData[5] = 0xff;txMsgData[6] = 0x55;txMsgData[7] = 0xff;

    txMsgData2[0] = 0x12;txMsgData2[1] = 0x34;txMsgData2[2] = 0x56;txMsgData2[3] = 0x78;
    txMsgData2[4] = 0x21;txMsgData2[5] = 0x43;txMsgData2[6] = 0x65;txMsgData2[7] = 0x87;

    GPIO_setPinConfig(GPIO_CFG_CANRXB);  // CANB RX
    GPIO_setPinConfig(GPIO_CFG_CANTXB);  // CANB TX
    // Initialize the CAN controllers
    CAN_initModule(CANB_BASE);

    // Set up the CAN bus bit rate to 500 kbps
    //    500k     20
    //    250k     20 / 16
    //    1000k    10
    CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ/2,500000, 20); // CANB
    //CAN_enableTestMode(CANB_BASE, CAN_TEST_EXL);
    // Initialize the transmit message object used for sending CAN messages.
    // Message Object Parameters:
    //      CAN Module: A
    //      Message Object ID Number: 1
    //      Message Identifier: 0x01
    //      Message Frame: Standard
    //      Message Type: Transmit
    //      Message ID Mask: 0x0
    //      Message Object Flags: None
    //      Message Data Length: 4 Bytes
    //
    CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID, CAN_ID,
                           CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_TX, 0,
                           CAN_MSG_OBJ_NO_FLAGS, MSG_DATA_LENGTH);
    // 配置接收邮箱 2
    //      Message Data Length: "Don't care" for a Receive mailbox
    CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, CAN_ID,
                           CAN_MSG_FRAME_STD, CAN_MSG_OBJ_TYPE_RX, 0,
                           CAN_MSG_OBJ_USE_ID_FILTER | CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
    // 注册 CANB 中断
    //CAN_enableInterrupt(CANB_BASE, CAN_INT_IE0 | CAN_INT_ERROR | CAN_INT_STATUS);  // CANB
    CAN_enableInterrupt(CANB_BASE, CAN_INT_IE0 | CAN_INT_ERROR |CAN_INT_STATUS);  // CANB

    Interrupt_register(INT_CANB0, &canB_ISR);
    Interrupt_enable(INT_CANB0);
    CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);

    // Start CANB module operations
    CAN_startModule(CANB_BASE);


}


uint32_t status;

// 接收中断函数
__interrupt void canB_ISR(void)
{
    int i=0;
    uint32_t errReg;

    status = CAN_getInterruptCause(CANB_BASE);
    if(status == CAN_INT_INT0ID_STATUS)
    {
        errReg = CAN_getStatus(CANB_BASE);
        if((errReg & 0x8000U) != 0U) // BUSOFF触发
        {
            // 软复位CAN退出BUSOFF
            CAN_initModule(CANB_BASE);
            CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ/2,500000, 20);
            CAN_startModule(CANB_BASE);
        }
    }
    else if(status == TX_MSG_OBJ_ID)
    {
        CAN_clearInterruptStatus(CANB_BASE, TX_MSG_OBJ_ID);
        //errorFlag = 0;
    }
    else if(status == RX_MSG_OBJ_ID)
    {
        CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, rxMsgData);
        CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
        for(i=0;i<8;i++)
        {
            txMsgData[i] = rxMsgData[i];
        }
        rxMsgCount++;
        //errorFlag = 0;
    }

    CAN_clearGlobalInterruptStatus(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

主函数:

cpp 复制代码
#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"


#include "my_can.h"


#define delay_s(x) SysCtl_delay(((((long double)(x)) / (2.0L /(long double)DEVICE_SYSCLK_FREQ)) - 9.0L) / 5.0L)
#define delay_ms(x) SysCtl_delay(((((long double)(x)) / (2000.0L /(long double)DEVICE_SYSCLK_FREQ)) - 9.0L) / 5.0L)
#define delay_us(x) SysCtl_delay(((((long double)(x)) / (2000000.0L /(long double)DEVICE_SYSCLK_FREQ)) - 9.0L) / 5.0L)

void main(void)
{
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();
    EINT;
    ERTM;

    Board_init();

    //GPIO11 用于呼吸灯,指示程序有没有卡住
    GPIO_setPinConfig(GPIO_11_GPIO11);
    GPIO_setPadConfig(11, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(11, GPIO_QUAL_SYNC);
    GPIO_setDirectionMode(11, GPIO_DIR_MODE_OUT);
    GPIO_setControllerCore(11, GPIO_CORE_CPU1);

    //C2000Ware_libraries_init();

    MY_can_bsp_init();
    Interrupt_enableMaster(); //开启总中断

    while(1)
    {
        CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH, txMsgData);
        // Poll TxOk bit in CAN_ES register to check completion of transmission
        //while(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_TXOK)) !=  CAN_ES_TXOK){}
        delay_ms(10);
        CAN_sendMessage(CANB_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH, txMsgData2);
        // Poll TxOk bit in CAN_ES register to check completion of transmission
        //while(((HWREGH(CANB_BASE + CAN_O_ES) & CAN_ES_TXOK)) !=  CAN_ES_TXOK){}

        GPIO_togglePin(11);
        delay_ms(1000);
    }
}
点击并拖拽以移动

测试效果:

我的程序很简单,DSP每隔约1s先后发送俩条信息

其中第一条可以被接收中断替换掉

如果接收中断收到新信息,那DSP发送的第一条就被替换为收到的信息

CAN BUSOFF

CAN 控制器里面有两个错误计数器发送错误 / 接收错误 计数器

错一次 +1 正常 -1

≥ 128BUSOFF(直接断开总线)

我的代码有软启恢复CAN的笨办法,因为我不知道为何通信老是进CAN BUSOFF:

相关推荐
疯狂打码的少年1 小时前
【程序语言与编译】文法的分类(0-3型,乔姆斯基体系)
人工智能·笔记·分类·数据挖掘
AOwhisky2 小时前
Redis 学习笔记(第二期):核心数据类型与消息队列实战
运维·数据库·redis·笔记·学习·云计算
江屿风2 小时前
C++图论基础拓扑排序算法流食般投喂
开发语言·c++·笔记·算法·排序算法
OSwich2 小时前
【UE5学习笔记】UMG中控件命名规范
笔记·学习·ue5
问心无愧051310 小时前
ctf show web入门111
android·前端·笔记
和平宇宙15 小时前
AI笔记005. hermes-DeepSeek V4 Pro, 128K上下文引发的探索
前端·人工智能·笔记
十月的皮皮15 小时前
C语言学习笔记20260606- 求月份天数三种写法
c语言·笔记·学习
cmes_love16 小时前
Level 2逐笔成交历史数据下载方法笔记
数据库·笔记·oracle
Cloud_Shy61816 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 30 - 32)
开发语言·人工智能·笔记·python·学习方法