This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

请教:使用280049C CAN的同一邮箱连续发送多包数据时,接收器只能收到最后一包数据,是怎么回事?

各位大神,我现在使用CAN的同一个邮箱连续发送多个包数据,相当于每次都调用如下发送程序:

sTXCANMessage.ui32MsgID = MONITOR_PARA_ID;

sTXCANMessage.ui32MsgIDMask = 0

sTXCANMessage.ui32Flags = 0;

sTXCANMessage.ui32MsgLen = 8; 

sTXCANMessage.pucMsgData = CanTX_Para_Monitor;

CANMessageSet(CANA_BASE, MONITOR_PARA_MAIL_NUM, &sTXCANMessage, MSG_OBJ_TYPE_TX);

现在测试发现,只有最后一包的数据被其他通信设备接收,前面的包都没有接收到。我怀疑是根本没来得及发送出去就被后面的发送修改了。

所以,在这种使用情况下,是不是需要每次都要确认上一包发送状态,然后再发送下一包?如果是,怎样判断该邮箱的发送状态呢?

  • 请您参考下下面的代码

    //#############################################################################
    //
    // FILE:   can_ex3_external_transmit.c
    //
    // TITLE:   CAN External Transmit Example
    //
    //! \addtogroup driver_example_list
    //! <h1> CAN-A to CAN-B External Transmit </h1>
    //!
    //! This example initializes CAN module A and CAN module B for external
    //! communication. CAN-A module is setup to transmit incrementing data for "n"
    //! number of times to the CAN-B module, where "n" is the value of TXCOUNT.
    //! CAN-B module is setup to trigger an interrupt service routine (ISR) when
    //! data is received. An error flag will be set if the transmitted data doesn't
    //! match the received data. 
    //! 
    //! \note Both CAN modules on the device need to be
    //!       connected to each other via CAN transceivers.
    //!
    //! \b Hardware \b Required \n
    //!  - A C2000 board with two CAN transceivers
    //!
    //! \b External \b Connections \n
    //!  - ControlCARD CANA is on GPIO31 (CANTXA) and GPIO30 (CANRXA)
    //!  - ControlCARD CANB is on GPIO8 (CANTXB) and GPIO10 (CANRXB)
    //!
    //! \b Watch \b Variables \n
    //!  - TXCOUNT - Adjust to set the number of messages to be transmitted
    //!  - txMsgCount - A counter for the number of messages sent
    //!  - rxMsgCount - A counter for the number of messages received
    //!  - txMsgData - An array with the data being sent
    //!  - rxMsgData - An array with the data that was received
    //!  - errorFlag - A flag that indicates an error has occurred
    //!
    //
    //#############################################################################
    // $TI Release: F28004x Support Library v1.06.00.00 $
    // $Release Date: Mon May 27 06:42:25 CDT 2019 $
    // $Copyright:
    // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    //
    // Defines
    //
    #define TXCOUNT  100
    #define MSG_DATA_LENGTH    4
    #define TX_MSG_OBJ_ID    1
    #define RX_MSG_OBJ_ID    1
    
    //
    // Globals
    //
    volatile unsigned long i;
    volatile uint32_t txMsgCount = 0;
    volatile uint32_t rxMsgCount = 0;
    volatile uint32_t errorFlag = 0;
    uint16_t txMsgData[4];
    uint16_t rxMsgData[4];
    
    //
    // Function Prototypes
    //
    __interrupt void canbISR(void);
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and configure GPIO pins for CANTX/CANRX
        // on module A and B
        //
        Device_initGPIO();
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANRXB);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_CANTXB);
    
        //
        // Initialize the CAN controllers
        //
        CAN_initModule(CANA_BASE);
        CAN_initModule(CANB_BASE);
    
        //
        // Set up the CAN bus bit rate to 500kHz for each module
        // Refer to the Driver Library User Guide for information on how to set
        // tighter timing control. Additionally, consult the device data sheet
        // for more information about the CAN module clocking.
        //
        CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
        CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
    
        //
        // Enable interrupts on the CAN B peripheral.
        //
        CAN_enableInterrupt(CANB_BASE, CAN_INT_IE0 | CAN_INT_ERROR |
                            CAN_INT_STATUS);
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // Interrupts that are used in this example are re-mapped to
        // ISR functions found within this file.
        // This registers the interrupt handler in PIE vector table.
        //
        Interrupt_register(INT_CANB0, &canbISR);
    
        //
        // Enable the CAN-B interrupt signal
        //
        Interrupt_enable(INT_CANB0);
        CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    
        //
        // Initialize the transmit message object used for sending CAN messages.
        // Message Object Parameters:
        //      CAN Module: A
        //      Message Object ID Number: 1
        //      Message Identifier: 0x95555555
        //      Message Frame: Extended
        //      Message Type: Transmit
        //      Message ID Mask: 0x0
        //      Message Object Flags: None
        //      Message Data Length: 4 Bytes
        //
        CAN_setupMessageObject(CANA_BASE, TX_MSG_OBJ_ID, 0x95555555,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_TX, 0,
                               CAN_MSG_OBJ_NO_FLAGS, MSG_DATA_LENGTH);
    
        //
        // Initialize the receive message object used for receiving CAN messages.
        // Message Object Parameters:
        //      CAN Module: B
        //      Message Object ID Number: 1
        //      Message Identifier: 0x95555555
        //      Message Frame: Extended
        //      Message Type: Receive
        //      Message ID Mask: 0x0
        //      Message Object Flags: Receive Interrupt
        //      Message Data Length: 4 Bytes
        //
        CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, 0x95555555,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
    
        //
        // Initialize the transmit message object data buffer to be sent
        //
        txMsgData[0] = 0x12;
        txMsgData[1] = 0x34;
        txMsgData[2] = 0x56;
        txMsgData[3] = 0x78;
    
        //
        // Start CAN module A and B operations
        //
        CAN_startModule(CANA_BASE);
        CAN_startModule(CANB_BASE);
    
        //
        // Transmit messages from CAN-A to CAN-B
        //
        for(i = 0; i < TXCOUNT; i++)
        {
            //
            // Check the error flag to see if errors occurred
            //
            if(errorFlag)
            {
                asm("   ESTOP0");
            }
    
            //
            // Verify that the number of transmitted messages equal the number of
            // messages received before sending a new message
            //
            if(txMsgCount == rxMsgCount)
            {
                CAN_sendMessage(CANA_BASE, TX_MSG_OBJ_ID, MSG_DATA_LENGTH,
                                txMsgData);
                txMsgCount++;
            }
            else
            {
                errorFlag = 1;
            }
    
            //
            // Delay 0.25 second before continuing
            //
            DEVICE_DELAY_US(250000);
    
            //
            // Increment the value in the transmitted message data.
            //
            txMsgData[0] += 0x01;
            txMsgData[1] += 0x01;
            txMsgData[2] += 0x01;
            txMsgData[3] += 0x01;
            
            //
            // Reset data if exceeds a byte
            //
            if(txMsgData[0] > 0xFF)
            {
                txMsgData[0] = 0;
            }
            if(txMsgData[1] > 0xFF)
            {
                txMsgData[1] = 0;
            }
            if(txMsgData[2] > 0xFF)
            {
                txMsgData[2] = 0;
            }
            if(txMsgData[3] > 0xFF)
            {
                txMsgData[3] = 0;
            }         
        }
    
        //
        // Stop application
        //
        asm("   ESTOP0");
    }
    
    //
    // CAN B ISR - The interrupt service routine called when a CAN interrupt is
    //             triggered on CAN module B.
    //
    __interrupt void
    canbISR(void)
    {
        uint32_t status;
    
        //
        // Read the CAN-B interrupt status to find the cause of the interrupt
        //
        status = CAN_getInterruptCause(CANB_BASE);
    
        //
        // If the cause is a controller status interrupt, then get the status
        //
        if(status == CAN_INT_INT0ID_STATUS)
        {
            //
            // Read the controller status.  This will return a field of status
            // error bits that can indicate various errors.  Error processing
            // is not done in this example for simplicity.  Refer to the
            // API documentation for details about the error status bits.
            // The act of reading this status will clear the interrupt.
            //
            status = CAN_getStatus(CANB_BASE);
    
            //
            // Check to see if an error occurred.
            //
            if(((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_MSK) &&
               ((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_NONE))
            {
                //
                // Set a flag to indicate some errors may have occurred.
                //
                errorFlag = 1;
            }
        }
        //
        // Check if the cause is the CAN-B receive message object 1
        //
        else if(status == RX_MSG_OBJ_ID)
        {
            //
            // Get the received message
            //
            CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, rxMsgData);
    
            //
            // Getting to this point means that the RX interrupt occurred on
            // message object 1, and the message RX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
    
            //
            // Increment a counter to keep track of how many messages have been
            // received. In a real application this could be used to set flags to
            // indicate when a message is received.
            //
            rxMsgCount++;
    
            //
            // Since the message was received, clear any error flags.
            //
            errorFlag = 0;
        }
        //
        // If something unexpected caused the interrupt, this would handle it.
        //
        else
        {
            //
            // Spurious interrupt handling can go here.
            //
        }
    
        //
        // Clear the global interrupt flag for the CAN interrupt line
        //
        CAN_clearGlobalInterruptStatus(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    
        //
        // Acknowledge this interrupt located in group 9
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }
    
    //
    // End of File
    //

    请您在发送新的消息之前先检验一下手否收到了正确的数据

    以及 http://www.ti.com.cn/cn/lit/an/sprace5/sprace5.pdf 

  • 感谢你的解答!您的意思是通过接收来检测是否已正确发送。但是我的应用场景和协议是不允许接收侧回复我发送的数据的。
  • 感谢你的解答!您的意思是通过接收来检测是否已正确发送。但是我的应用场景和协议是不允许接收侧回复我发送的数据的。
    所以,是否有其他判断该邮箱是否发送成功的方法吗?
  • 您可以通过CAN_ES register Bit 4 [RxOk] or bit 3 [TxOk] 来判断数据是否成功接收或者发送。

    具体您可以看一下

    www.ti.com/.../sprui33c.pdf

    26.16.2.2 CAN_ES Register (Offset = 4h) [reset = 7h]
  • 嗯,我看到了CAN_ES register bit 3 [TxOk] 这一位。针对这一位,我有个疑惑:发送成功后,CPU什么时候读取并清零该位?
  • 根据寄存器的描述

    The bit will be reset after the CPU reads the register.

    在读完该状态位之后会自动reset

    上面我发的程序内就有相关的使用代码

    //
            // Check to see if an error occurred.
            //
            if(((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_MSK) &&
               ((status  & ~(CAN_STATUS_RXOK)) != CAN_STATUS_LEC_NONE))
            {
                //
                // Set a flag to indicate some errors may have occurred.
                //
                errorFlag = 1;
            }

  • 不不,我的意思是,CPU什么时候读取该位?
  • 因为我之前是这样写的,发完第一包,判断CAN_ES register bit 3 [TxOk] ==1,则发送第二包。测试发现,断点设置在“判断CAN_ES register bit 3 [TxOk] ==1”处,是可以置1,第二包能发送出去;但是不设置断点,就始终进不了发送第二包的程序。