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

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进入正常工作模式,实现数据收发。
STM32F407 CAN2 通信代码测试收发通过_第1张图片

CAN总线芯片连接电路图

can总线芯片与CPU使用高速光耦隔离
STM32F407 CAN2 通信代码测试收发通过_第2张图片

代码中需要定义的宏

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

你可能感兴趣的:(嵌入式硬件,嵌入式软件)