【CAN通信】入门测试用_野火F407的串口(UART)转CAN的信号转接板程序(附代码)

文章提供了一段用于STM32F407微控制器的CAN2总线无过滤收发的代码实现,适用于新手学习。代码包括CAN接口的GPIO配置、NVIC设置、模式配置、过滤器配置以及中断服务例程,实现了串口发送10位信号并接收所有CAN信号的功能。此外,代码还包含了一些调试宏以帮助用户理解和调试。
摘要由CSDN通过智能技术生成
主要用于实现CAN2总线上的收发,无任何过滤,用于检验CAN信号,适合新手入门。

只要是在CAN2的信号线上都可以实现,不局限于开发板,本人移植到F103亲测成功!

can 头文件

#define CANx                       	CAN2
#define CAN_CLK                    RCC_APB1Periph_CAN1 |RCC_APB1Periph_CAN2
#define CAN_RX_IRQ									CAN2_RX0_IRQn
#define CAN_RX_IRQHandler					CAN2_RX0_IRQHandler

#define CAN_RX_PIN                 GPIO_Pin_12
#define CAN_TX_PIN                 GPIO_Pin_13
#define CAN_TX_GPIO_PORT          GPIOB
#define CAN_RX_GPIO_PORT          GPIOB
#define CAN_TX_GPIO_CLK           RCC_AHB1Periph_GPIOB
#define CAN_RX_GPIO_CLK           RCC_AHB1Periph_GPIOB
#define CAN_AF_PORT                GPIO_AF_CAN2
#define CAN_RX_SOURCE              GPIO_PinSource12
#define CAN_TX_SOURCE              GPIO_PinSource13 

效果如图

可发可收
可发任意信号,串口发送10位信号,前两位为id,其他位数据位,接受所有can信号

串口定义

串口参数含义
01ID高位
02ID低位
其他$1

CAN 头文件

#ifndef __CAN_H
#define	__CAN_H

#include "stm32f4xx.h"
#include <stdio.h>



#define CANx                       	CAN2
#define CAN_CLK                    RCC_APB1Periph_CAN1 |RCC_APB1Periph_CAN2
#define CAN_RX_IRQ									CAN2_RX0_IRQn
#define CAN_RX_IRQHandler					CAN2_RX0_IRQHandler

#define CAN_RX_PIN                 GPIO_Pin_12
#define CAN_TX_PIN                 GPIO_Pin_13
#define CAN_TX_GPIO_PORT          GPIOB
#define CAN_RX_GPIO_PORT          GPIOB
#define CAN_TX_GPIO_CLK           RCC_AHB1Periph_GPIOB
#define CAN_RX_GPIO_CLK           RCC_AHB1Periph_GPIOB
#define CAN_AF_PORT                GPIO_AF_CAN2
#define CAN_RX_SOURCE              GPIO_PinSource12
#define CAN_TX_SOURCE              GPIO_PinSource13 





/*debug*/

#define CAN_DEBUG_ON          1
#define CAN_DEBUG_ARRAY_ON   1
#define CAN_DEBUG_FUNC_ON    1
   
   
// Log define
#define CAN_INFO(fmt,arg...)           printf("<<-CAN-INFO->> "fmt"\n",##arg)
#define CAN_ERROR(fmt,arg...)          printf("<<-CAN-ERROR->> "fmt"\n",##arg)
#define CAN_DEBUG(fmt,arg...)          do{\
                                         if(CAN_DEBUG_ON)\
                                         printf("<<-CAN-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
                                       }while(0)

#define CAN_DEBUG_ARRAY(array, num)    do{\
                                         int32_t i;\
                                         uint8_t* a = array;\
                                         if(CAN_DEBUG_ARRAY_ON)\
                                         {\
											 printf("CAN-data:  ");\
                                            for (i = 0; i < (num); i++)\
                                            {\
                                                printf("%02x ", (a)[i]);\
                                                if ((i + 1 ) %10 == 0)\
                                                {\
                                                    printf("\n");\
                                                }\
                                            }\
                                            printf("\n");\
                                        }\
                                       }while(0)

#define CAN_DEBUG_FUNC()               do{\
                                         if(CAN_DEBUG_FUNC_ON)\
                                         printf("<<-CAN-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
                                       }while(0)






static void CAN_GPIO_Config(void);
static void CAN_NVIC_Config(void);
static void CAN_Mode_Config(void);
static void CAN_Filter_Config(void);
void CAN_Config(void);
void CAN_SetMsg(CanTxMsg *TxMessage);
void Init_RxMes(CanRxMsg *RxMessage);

#endif



CAN 主文件


/**
  ******************************************************************************
  * @file    bsp_can.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   can驱动(回环模式)
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 

#include "can.h"

extern __IO uint32_t flag ;		 //用于标志是否接收到数据,在中断函数中赋值
extern CanRxMsg RxMessage;				 //接收缓冲区
u16 RxMessage_jishu=0;
#if 0
//初始化
CAN_Config();
//发送代码
			CAN_SetMsg(&TxMessage);
			CAN_Transmit(CANx, &TxMessage);	
			delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态					
			printf("\r\n已使用CAN发送数据包!\r\n"); 			
			printf("\r\n发送的报文内容为:\r\n");
			printf("\r\n 扩展ID号ExtId:0x%x \r\n",TxMessage.ExtId);
			CAN_DEBUG_ARRAY(TxMessage.Data,8); 
			delay_ms(1000);	

#endif 

void CAN_RX_IRQHandler(void)
{
	RxMessage_jishu++;
	/*从邮箱中读出报文*/
	CAN_Receive(CANx, CAN_FIFO0, &RxMessage);
	printf(" %d-can 已接收-Stdid = %04x  " ,RxMessage_jishu,RxMessage.StdId);
	CAN_DEBUG_ARRAY(RxMessage.Data,8); 
	
	
	/* 比较ID是否为0x1314 */ 
//	if((RxMessage.ExtId==0x1314) && (RxMessage.IDE==CAN_ID_EXT) && (RxMessage.DLC==8) )
//	{
//	flag = 1; 					       //接收成功  
//	}
//	else
//	{
//	flag = 0; 					   //接收失败
//	}
}

/*
 * 函数名:CAN_GPIO_Config
 * 描述  :CAN的GPIO 配置
 * 输入  :无
 * 输出  : 无
 * 调用  :内部调用
 */
static void CAN_GPIO_Config(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
   	

  /* Enable GPIO clock */
  RCC_AHB1PeriphClockCmd(CAN_TX_GPIO_CLK|CAN_RX_GPIO_CLK, ENABLE);
	
	  /* Connect CAN pins to AF9 */
  GPIO_PinAFConfig(CAN_TX_GPIO_PORT, CAN_RX_SOURCE, CAN_AF_PORT);
  GPIO_PinAFConfig(CAN_RX_GPIO_PORT, CAN_TX_SOURCE, CAN_AF_PORT); 

	  /* Configure CAN TX pins */
  GPIO_InitStructure.GPIO_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_TX_GPIO_PORT, &GPIO_InitStructure);
	
	/* Configure CAN RX  pins */
  GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);


}

/*
 * 函数名:CAN_NVIC_Config
 * 描述  :CAN的NVIC 配置,第1优先级组,0,0优先级
 * 输入  :无
 * 输出  : 无
 * 调用  :内部调用
 */
static void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	/* Configure one bit for preemption priority */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	/*中断设置*/
	NVIC_InitStructure.NVIC_IRQChannel = CAN_RX_IRQ;	   //CAN RX0中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;		   //抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;			   //子优先级为0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

/*
 * 函数名:CAN_Mode_Config
 * 描述  :CAN的模式 配置
 * 输入  :无
 * 输出  : 无
 * 调用  :内部调用
 */
static void CAN_Mode_Config(void)
{
	CAN_InitTypeDef        CAN_InitStructure;
	/************************CAN通信参数设置**********************************/
	/* Enable CAN clock */
  RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE);

	/*CAN寄存器初始化*/
	CAN_DeInit(CANx);
	CAN_StructInit(&CAN_InitStructure);

	/*CAN单元初始化*/
	CAN_InitStructure.CAN_TTCM=DISABLE;			   //MCR-TTCM  关闭时间触发通信模式使能
	CAN_InitStructure.CAN_ABOM=ENABLE;			   //MCR-ABOM  自动离线管理 
	CAN_InitStructure.CAN_AWUM=ENABLE;			   //MCR-AWUM  使用自动唤醒模式
	CAN_InitStructure.CAN_NART=DISABLE;			   //MCR-NART  禁止报文自动重传	  DISABLE-自动重传
	CAN_InitStructure.CAN_RFLM=DISABLE;			   //MCR-RFLM  接收FIFO 锁定模式  DISABLE-溢出时新报文会覆盖原有报文  
	CAN_InitStructure.CAN_TXFP=DISABLE;			   //MCR-TXFP  发送FIFO优先级 DISABLE-优先级取决于报文标示符 
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;  //正常工作模式
	CAN_InitStructure.CAN_SJW=CAN_SJW_2tq;		   //BTR-SJW 重新同步跳跃宽度 2个时间单元
	 
	/* ss=1 bs1=4 bs2=2 位时间宽度为(1+4+2) 波特率即为时钟周期tq*(1+4+2)  */
	CAN_InitStructure.CAN_BS1=CAN_BS1_4tq;		   //BTR-TS1 时间段1 占用了4个时间单元
	CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;		   //BTR-TS1 时间段2 占用了2个时间单元	
	
	/* CAN Baudrate = 1 MBps (1MBps已为stm32的CAN最高速率) (CAN 时钟频率为 APB 1 = 42 MHz) */
	CAN_InitStructure.CAN_Prescaler =12;		   BTR-BRP 波特率分频器  定义了时间单元的时间长度 42/(1+4+2)/6=1 Mbps
	CAN_Init(CANx, &CAN_InitStructure);
}

/*
 * 函数名:CAN_Filter_Config
 * 描述  :CAN的过滤器 配置
 * 输入  :无
 * 输出  : 无
 * 调用  :内部调用
 */
static void CAN_Filter_Config(void)
{
	CAN_FilterInitTypeDef  CAN_FilterInitStructure;

	/*CAN筛选器初始化*/
	CAN_FilterInitStructure.CAN_FilterNumber=14;						//筛选器组14
	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;	//工作在掩码模式
	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;	//筛选器位宽为单个32位。
	/* 使能筛选器,按照标志的内容进行比对筛选,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */

	CAN_FilterInitStructure.CAN_FilterIdHigh= 0;		//要筛选的ID高位 
	CAN_FilterInitStructure.CAN_FilterIdLow= 0; //要筛选的ID低位 
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0;			//筛选器高16位每位必须匹配
	CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0;			//筛选器低16位每位必须匹配
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ;				//筛选器被关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;			//使能筛选器
	CAN_FilterInit(&CAN_FilterInitStructure);
	/*CAN通信中断使能*/
	CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);
}


/*
 * 函数名:CAN_Config
 * 描述  :完整配置CAN的功能
 * 输入  :无
 * 输出  : 无
 * 调用  :外部调用
 */
void CAN_Config(void)
{
  CAN_GPIO_Config();
  CAN_NVIC_Config();
  CAN_Mode_Config();
  CAN_Filter_Config();   
}


/**
  * @brief  初始化 Rx Message数据结构体
  * @param  RxMessage: 指向要初始化的数据结构体
  * @retval None
  */
void Init_RxMes(CanRxMsg *RxMessage)
{
  uint8_t ubCounter = 0;

	/*把接收结构体清零*/
  RxMessage->StdId = 0x00;
  RxMessage->ExtId = 0x00;
  RxMessage->IDE = CAN_ID_STD;
  RxMessage->DLC = 0;
  RxMessage->FMI = 0;
  for (ubCounter = 0; ubCounter < 8; ubCounter++)
  {
    RxMessage->Data[ubCounter] = 0x00;
  }
}


/*
 * 函数名:CAN_SetMsg
 * 描述  :CAN通信报文内容设置,设置一个数据内容为0-7的数据包
 * 输入  :发送报文结构体
 * 输出  : 无
 * 调用  :外部调用
 */	 
void CAN_SetMsg(CanTxMsg *TxMessage)
{	  

//  TxMessage->StdId=0x010f;						 
 // TxMessage->ExtId=0x0f;					 //使用的扩展ID
  TxMessage->IDE=CAN_ID_STD;					 //扩展模式
  TxMessage->RTR=CAN_RTR_DATA;				 //发送的是数据
  TxMessage->DLC=8;							 //数据长度为8字节
	
	/*设置要发送的数据0-7*/
//	for (ubCounter = 0; ubCounter < 8; ubCounter++)
//  {
//    TxMessage->Data[ubCounter] = ubCounter;
//  }
}
/**************************END OF FILE************************************/



main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "can.h"
//ALIENTEK 探索者STM32F407开发板 实验27
//CAN通信实验-库函数版本
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com  
//广州市星翼电子科技有限公司  
//作者:正点原子 @ALIENTEK

__IO uint32_t flag = 0;		 //用于标志是否接收到数据,在中断函数中赋值
CanTxMsg TxMessage;			     //发送缓冲区
CanRxMsg RxMessage;				 //接收缓冲区

u16 usart_len;
int main(void)
{ 
	u16 uart_jishu=0;
	u8 t=0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);    //初始化延时函数
	uart_init(115200);	//初始化串口波特率为115200
	LED_Init();					//初始化LED 
	KEY_Init(); 				//按键初始化  
	CAN_Config();
	printf("系统初始化完成!\n");		  	//显示当前计数值	
	printf("该系统只能在500k波特率、标准帧下进行!\n");		  	//显示当前计数值	
 	printf("\n");		  	//显示当前计数值							  
while(1)
	{
		if(WK_UP==1)//KEY0按下,发送一次数据
		{
			
			CAN_SetMsg(&TxMessage);
			CAN_Transmit(CANx, &TxMessage);	
			delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态					
			printf("\r\n已使用CAN发送数据包!\r\n"); 			
			printf("\r\n发送的报文内容为:\r\n");
			printf("\r\n 扩展ID号ExtId:0x%x \r\n",TxMessage.ExtId);
			CAN_DEBUG_ARRAY(TxMessage.Data,8); 
			delay_ms(1000);						   
		}	
				
		if(USART_RX_STA&0x8000)
		{			
			uart_jishu++;
			usart_len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf(" %d-can 已发送-StdId = %04x  sen-data = ",uart_jishu,TxMessage.StdId);			
			TxMessage.StdId=USART_RX_BUF[0]<<8|USART_RX_BUF[1];
			
			for(t=0;t<8;t++)
			{
				TxMessage.Data[t]=USART_RX_BUF[t+2];
				printf("%02x ",USART_RX_BUF[t+2]);
			}
			
			CAN_SetMsg(&TxMessage);
			CAN_Transmit(CANx, &TxMessage);	
			delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态		
			printf("\r\n");//插入换行
			USART_RX_STA=0;
		}
		
		t++; 
		delay_ms(5);
		
		if(t==100)
		{
			LED0=!LED0;//提示系统正在运行	
			t=0;
		}		   
	} 
	
}


附上代码链接
链接:https://pan.baidu.com/s/1PTQEcJziu7vZgcWV724yww
提取码:bk5v
–来自百度网盘超级会员V5的分享

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
RT1021-EVK是NXP公司推出的一款基于i.MX RT1021处理器的评估开发,它支持多种通信接口,包括CAN和UART。CAN是一种面向实时应用的通信协议,而UART是一种异步串行通信协议。下面我们来分析一下如何将CAN通信换为UART通信,并给出相应的代码示例。 在RT1021-EVK上,CAN通信UART通信实现都需要使用相应的外设模块。CAN通信需要使用FlexCAN模块,而UART通信需要使用UART模块。要将CAN通信换为UART通信,需要通过中断的方式获取CAN数据帧,然后将数据帧换为UART数据,发送到UART总线上。 下面是CANUART代码示例,仅供参考: ```c #include "fsl_flexcan.h" #include "fsl_uart.h" #define CAN_MSG_BUF_NUM 9U #define CAN_MSG_BUF_SIZE sizeof(flexcan_frame_t) flexcan_handle_t flexcanHandle; flexcan_mb_transfer_t rxXfer; flexcan_frame_t rxFrame; uart_handle_t uartHandle; uint8_t uartTxBuffer[CAN_MSG_BUF_SIZE]; void FLEXCAN_UserRxCallback(CAN_Type *base, flexcan_handle_t *handle, uint32_t mbIdx, void *userData) { UART_SendDataBlocking(UART5, uartTxBuffer, CAN_MSG_BUF_SIZE); } int main(void) { flexcan_config_t flexcanConfig; flexcan_rx_mb_config_t mbConfig; uart_config_t uartConfig; uint32_t i; BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); /* Configure the FlexCAN module */ FLEXCAN_GetDefaultConfig(&flexcanConfig); flexcanConfig.baudRate = 500000U; FLEXCAN_Init(CAN1, &flexcanConfig, CLOCK_GetFreq(kCLOCK_IpgClk)); /* Configure the FlexCAN RX message buffer */ mbConfig.format = kFLEXCAN_FrameFormatStandard; mbConfig.type = kFLEXCAN_FrameTypeData; mbConfig.id = 0x123U; FLEXCAN_SetRxMbConfig(CAN1, RX_MESSAGE_BUFFER_NUM, &mbConfig, true); /* Create the FlexCAN handle */ FLEXCAN_TransferCreateHandle(CAN1, &flexcanHandle, FLEXCAN_UserRxCallback, NULL); /* Configure the UART module */ UART_GetDefaultConfig(&uartConfig); uartConfig.baudRate_Bps = 115200U; uartConfig.enableTx = true; uartConfig.enableRx = false; UART_Init(UART5, &uartConfig, CLOCK_GetFreq(kCLOCK_IpgClk)); /* Create the UART handle */ UART_TransferCreateHandle(UART5, &uartHandle, NULL, NULL); /* Start the FlexCAN module */ FLEXCAN_Start(CAN1); while (1) { /* Wait for the FlexCAN message */ rxXfer.mbIdx = RX_MESSAGE_BUFFER_NUM; rxXfer.frame = &rxFrame; FLEXCAN_TransferReceiveNonBlocking(CAN1, &flexcanHandle, &rxXfer); /* Convert FlexCAN message to UART message */ for (i = 0; i < CAN_MSG_BUF_SIZE; i++) { uartTxBuffer[i] = ((uint8_t *)&rxFrame)[i]; } /* Send UART message */ UART_TransferSendBlocking(UART5, &uartHandle, uartTxBuffer, CAN_MSG_BUF_SIZE); } } ``` 在这个示例中,我们使用了FlexCAN模块和UART模块,其中FlexCAN用于接收CAN数据帧,UART用于发送UART数据。在主循环中,我们使用FLEXCAN_TransferReceiveNonBlocking函数从FlexCAN模块中接收CAN数据帧,并将其换为UART数据,然后使用UART_TransferSendBlocking函数将UART数据发送到UART总线上。同时,在CAN数据帧接收完成后,我们通过中断的方式调用了FLEXCAN_UserRxCallback函数,在该函数中可以进行一些额外的处理,例如打印日志或修改数据。 需要注意的是,由于CAN和UART是两种不同的通信协议,因此在换数据时需要进行一些协议换,例如将CAN数据帧的格式换为UART数据的格式。此外,由于CAN和UART的数据传输速率有所不同,因此在换数据时需要考虑数据传输的速率和延迟,以确保数据的正确性和实时性。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值