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

STM32F407 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的时钟,同时要确保硬件连接正常。

  • 3
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F407是一款高性能、低功耗的MCU芯片,拥有丰富的外设模块,而其中的CAN2通信模块是一种常用的控制器局域网通信模块,可实现高速、可靠的数据传输。在STM32F407的应用中,利用CubeMX自动生成CAN2收发程序,可以方便快捷地实现CAN2通信功能。 在进行CAN2收发程序之前,需要在CubeMX中对CAN2进行配置。首先,在Pinout & Configuration中选中相应的IO口,配置成CAN2通信模式。然后,在中间的Configuraton选项卡中选择CAN2,配置CAN2的时钟源、波特率和工作模式等参数。对于CAN2的接收和发送功能,需要分别进行配置。 在程序实现中,我们首先要创建一个CAN_HandleTypeDef结构体变量,并设置该变量的CanHandle.Instance属性为CAN2。接下来,通过HAL_CAN_Init函数对CanHandle进行初始化。然后,可以通过HAL_CAN_Filter_Config函数进行CAN的滤波器配置。可以根据实际需要配置过滤器ID,通过设置filter_mask_id_type属性,可以选择ID的类型(标准ID或扩展ID)。 发送CAN2消息时,可以通过HAL_CAN_AddTxMessage函数来实现。该函数需要填写CAN消息的ID、发送数据的指针和发送数据的长度等信息。接收CAN2消息时,可通过HAL_CAN_GetRxMessage函数来获取CAN消息,并通过CAN_RX_HEADER结构体获取CAN消息的ID等信息。收发CAN2消息时,需要考虑CAN的报文格式,以便正确的发送和接收数据。 在STM32F407中,利用CAN2模块实现CAN通信十分方便。通过CubeMX生成CAN2收发程序,可以快速轻松地实现CAN2通信功能。对于开发者而言,掌握CAN2的收发原理,以及掌握基本的程序实现方法,是十分有必要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值