STM32F407 CAN2 通信代码测试收发通过

it2022-05-05  163

STM32F407 CAN2 通信代码测试收发通过

硬件电路图 CPU CAN2 接口CAN总线芯片连接电路图代码中需要定义的宏CAN2 配置代码 CAN2配置代码中断服务函数can2发送代码总结

最近一个项目用到CAN总线通信,由于在硬件画板是没有考虑到STM32F407芯片CAN1和CAN2的区别,在电路板上只使用了CAN2接口,在调试时,CAN2总线通信失败,通过网上查找资料,及查看官方代码例程,解决了CAN2通信问题。CAN2可以 CAN_Mode_Normal模式下通信,发送使用查询,接收使用中断。

 

硬件电路图

CPU CAN2 接口

使用STM32F47IGT6,CAN2使用PB5为CAN2_RX、PB6为CAN2_TX、PB7连接can芯片TJA1040的STB引脚,控制can总线芯片的通信模式。PB7配置成输出,输出低电平,使TJA1040进入正常工作模式,实现数据收发。

CAN总线芯片连接电路图

can总线芯片与CPU使用高速光耦隔离

代码中需要定义的宏

定义MCU个硬件接口 #define CAN_RX_PIN GPIO_Pin_5 #define CAN_RX_PORT GPIOB

#define CAN_TX_PIN GPIO_Pin_6 #define CAN_GPIO_PORT CAN_RX_PORT

#define CAN_STB_PIN GPIO_Pin_7 #define CAN_STB_PORT CAN_RX_PORT #define CAN_STB_SET(a) IO_SET(CAN_STB_PORT, CAN_STB_PIN, a)

#define CAN_GPIO_CLK RCC_AHB1Periph_GPIOB

#define CAN_AF_PORT GPIO_AF_CAN2 #define CAN_RX_SOURCE GPIO_PinSource5 #define CAN_TX_SOURCE GPIO_PinSource6 #define CAN_CLK RCC_APB1Periph_CAN2

#define CANx CAN2

#define CAN_StdId 0x321 #define CAN_ExtId 0x01

#define CAN_RINGINDEX_NUM 256

CAN2 配置代码

定义需要的变量 static CanRxMsg tgCanMsg[CAN_RINGINDEX_NUM]; CanRxMsg RxMessage; CanTxMsg TxMessage; const CanTxMsg canCfg = { .StdId = 0x321, .ExtId = 0x01, .RTR = CAN_RTR_DATA, .IDE = CAN_ID_STD, };

CAN2配置代码

由于STM32F47在单独配置CAN2时不能正常工作,必须要打开CAN1的时钟,并且CAN1时钟必须要先于CAN2时钟打开。在这里使用CAN2_RX0_IRQn中断号,配置CAN_IT_FMP0中断。

static void _can_init(void) { NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // CanTxMsg TxMessage; CAN_InitTypeDef CAN_InitStructure; CAN_FilterInitTypeDef CAN_FilterInitStructure;

/*can rx interrupt configuration*/ NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* CAN GPIOs configuration **************************************************/ /* Enable GPIO clock */ RCC_AHB1PeriphClockCmd(CAN_GPIO_CLK, ENABLE); /* Connect CAN pins to AF9 */ GPIO_PinAFConfig(CAN_GPIO_PORT, CAN_RX_SOURCE, CAN_AF_PORT); GPIO_PinAFConfig(CAN_GPIO_PORT, CAN_TX_SOURCE, CAN_AF_PORT); /* Configure CAN RX and TX pins */ GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN | CAN_TX_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(CAN_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = CAN_STB_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(CAN_STB_PORT, &GPIO_InitStructure); CAN_STB_SET( 0 ); /* CAN configuration ********************************************************/ /* Enable CAN clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE); //RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); /* CAN register init */ CAN_DeInit(CANx); /* CAN cell init */ CAN_InitStructure.CAN_TTCM = DISABLE; CAN_InitStructure.CAN_ABOM = DISABLE; CAN_InitStructure.CAN_AWUM = DISABLE; CAN_InitStructure.CAN_NART = DISABLE; CAN_InitStructure.CAN_RFLM = DISABLE; CAN_InitStructure.CAN_TXFP = DISABLE; CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

/* CAN_InitStucture.CAN_Mode = mode; CAN_InitStucture.CAN_SJW = CAN_SJW_1tq; CAN_InitStucture.CAN_BS1 = CAN_BS1_7tq; CAN_InitStucture.CAN_BS2 = CAN_BS2_6tq; CAN_InitStucture.CAN_Prescaler = 6; */

/* CAN Baudrate = 1 MBps (CAN clocked at 30 MHz) */ CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; CAN_InitStructure.CAN_BS1 = CAN_BS1_7tq; CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq; CAN_InitStructure.CAN_Prescaler = 6; CAN_Init(CANx, &CAN_InitStructure); /* CAN filter init */ CAN_FilterInitStructure.CAN_FilterNumber = 14; CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0; CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; CAN_FilterInit(&CAN_FilterInitStructure); /* Transmit Structure preparation */ TxMessage.StdId = 0x321; TxMessage.ExtId = 0x01; TxMessage.RTR = CAN_RTR_DATA; TxMessage.IDE = CAN_ID_STD; TxMessage.DLC = 1; /* Enable FIFO 0 message pending Interrupt */ CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);

}

中断服务函数

void CAN2_RX0_IRQHandler(void) { CAN_Receive(CAN2, CAN_FIFO0, &RxMessage); { CAN_ClearITPendingBit(CAN2, CAN_IT_FMP0); } if ((RxMessage.StdId == 0x321)&&(RxMessage.IDE == CAN_ID_STD)) { //接收处理代码 } }

can2发送代码

void _cantx_cfg(const CanTxMsg *pcfg, CanTxMsg *pmsg) { // TxMessage.RTR = CAN_RTR_DATA;//TxMessage.IDE = CAN_ID_STD; pmsg->StdId = pcfg->StdId; pmsg->ExtId = pcfg->ExtId; pmsg->RTR = pcfg->RTR; pmsg->IDE = pcfg->IDE; }

void canTransmit(const CanTxMsg *pcfg, const void *pdata, int len) { CanTxMsg TxMessage; const uint8_t *pd=(const uint8_t *)pdata; uint8_t mbox; uint16_t i; int slen = 0; if (len < 0 || pdata == NULL) return;

slen = len; _cantx_cfg(pcfg, &TxMessage); while(slen > 8) { XPRINTF((8, "slen1 = %d\r\n", slen)); TxMessage.DLC = 8; memcpy(TxMessage.Data, pd, 8); slen -= 8; pd += 8; #if 0 CAN_Transmit(CANx, &TxMessage); /* Wait until one of the mailboxes is empty */ while((CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP0) !=RESET) || \ (CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP1) !=RESET) || \ (CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP2) !=RESET)); #else mbox = CAN_Transmit(CAN2, &TxMessage); i = 0; while( (CAN_TransmitStatus(CAN2, mbox) == CAN_TxStatus_Failed) &&(i<0xfff))i++; #endif } TxMessage.DLC = slen; memcpy(TxMessage.Data, pd, slen);

#if 0 CAN_Transmit(CANx, &TxMessage); /* Wait until one of the mailboxes is empty */ while((CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP0) !=RESET) ||  (CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP1) !=RESET) ||  (CAN_GetFlagStatus(CANx, CAN_FLAG_RQCP2) !=RESET)); #endif mbox = CAN_Transmit(CAN2, &TxMessage); i = 0; while( (CAN_TransmitStatus(CAN2, mbox) == CAN_TxStatus_Failed) &&(i<0xfff))i++; }

void canSendData(const void *pdata, int len) { canTransmit(&canCfg, pdata, len); }

void canInit(void) { _can_init( ); }

##测试代码 const uint8_t testdata[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0f};

void testcan1(void) { canSendData(testdata, sizeof(testdata)); }

接收功能

总结

在调试CAN2总线收发过程中,官方给的代码例程是是CAN1的,根据CAN1的直接转换为CAN2,是不能正常收发的。单独使用CAN2的时候,必须先要打开CAN1的时钟,同时要确保硬件连接正常。


最新回复(0)