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

≥ 128 → BUSOFF(直接断开总线)

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

相关推荐
蒸蒸yyyyzwd6 小时前
AI应用相关可能的面试问题
笔记
叼烟扛炮6 小时前
[Git 实战] 学习笔记:从生成 SSH 密钥到解决 TortoiseGit 推送报错全指南
linux·运维·笔记·git·学习
蒸蒸yyyyzwd7 小时前
学习笔记 八股手撕
笔记·学习
揣一尾游鱼yu8 小时前
Spring上(IOC)笔记
java·笔记·spring·ioc
小李不想当小白10 小时前
BKP备份寄存器与RTC实时时钟(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
瑞码空间12 小时前
JSP与Servlet核心开发与CRUD实战笔记
java·笔记·servlet·jsp
La Pulga13 小时前
【FreeRTOS源码学习笔记】链表的实现
数据结构·笔记·stm32·mcu·链表·嵌入式·freertos
wuyoutrans15 小时前
以色列专利OA答复翻译,重点要避开哪些坑?
笔记
宝绿特塑业再生科技15 小时前
HDPE再生颗粒户外家具表面粉化机理与改性技术全解析
笔记·户外家具·再生塑料·塑木桌椅
凉、介16 小时前
深入理解 ARMv7-A | Generic Timer
笔记·学习·嵌入式·arm