【STM32F103RCT6】CAN通信

【软件设计】

CAN引脚初始化

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

	/* Enable GPIO clock */
	RCC_APB2PeriphClockCmd(CAN_TX_GPIO_CLK | CAN_RX_GPIO_CLK, ENABLE);
	//重映射引脚
	GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);

	/* Configure CAN TX pins */
	GPIO_InitStructure.GPIO_Pin = CAN_TX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	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_IPU; // 上拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
}

CAN中断优先级配置

/*
 * 函数名: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;		  //CAN1 RX0中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		  //子优先级为0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

CAN模式配置

/*
 * 函数名: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_1tq;	  //BTR-SJW 重新同步跳跃宽度 2个时间单元

	/* ss=1 bs1=9 bs2=8 位时间宽度为(1+8+9) 波特率即为时钟周期tq*(1+8+9)  */
	CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq; //BTR-TS1 时间段1 占用了9个时间单元
	CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq; //BTR-TS1 时间段9 占用了8个时间单元

	/* CAN Baudrate = 1 MBps (1MBps已为stm32的CAN最高速率) (CAN 时钟频率为 APB1 = 36 MHz) */
	CAN_InitStructure.CAN_Prescaler = 48; BTR-BRP 波特率分频器  定义了时间单元的时间长度 36/(1+8+9)/4= 0.5 Mbps
	CAN_Init(CANx, &CAN_InitStructure);
}

CAN过滤器配置

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

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

	//标准数据帧的配置
		CAN_FilterInitStructure.CAN_FilterIdHigh   = (((u32)0x45<<21)&0xffff0000)>>16;
		CAN_FilterInitStructure.CAN_FilterIdLow   = (((u32)0x45<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;
		CAN_FilterInitStructure.CAN_FilterMaskIdHigh  = 0xFFFF;
		CAN_FilterInitStructure.CAN_FilterMaskIdLow   = 0xFFFF;	
	
//扩展数据帧的配置
//	CAN_FilterInitStructure.CAN_FilterIdHigh = ((((u32)0x45 << 3) | CAN_ID_STD | CAN_RTR_DATA) & 0xFFFF0000) >> 16; //要筛选的ID高位
//	CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)0x45 << 3) | CAN_ID_STD | CAN_RTR_DATA) & 0xFFFF;			  //要筛选的ID低位
//	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;															  //筛选器高16位每位必须匹配
//	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;															  //筛选器低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整合配置

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

初始化 RxMessage数据结构体

/**
  * @brief  初始化 RxMessage数据结构体
  * @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_SetMsg
 * 描述  :CAN通信报文内容设置,设置一个数据内容为0-7的数据包
 * 输入  :发送报文结构体
 * 输出  : 无
 * 调用  :外部调用
 */
void CAN_SetMsg(CanTxMsg *TxMessage)
{
//	uint8_t ubCounter = 0;

	TxMessage->StdId=0x45;		//使用的标准ID
	//TxMessage->ExtId = 0x45;	   
	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;
//	}
	
	TxMessage->Data[0] = 0;
	TxMessage->Data[1] = speedct*1000;
	TxMessage->Data[2] = poct*1000;
	TxMessage->Data[3] = 0;
	TxMessage->Data[4] = 0;
	TxMessage->Data[5] = 0;
	TxMessage->Data[6] = 0;		
	TxMessage->Data[7] = 0;
}

CAN接受中断服务

/*
 * 函数名:USB_LP_CAN1_RX0_IRQHandler
 * 描述  :USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。
 * 输入  :无
 * 输出  : 无	 
 * 调用  :无
 */
void CAN_RX_IRQHandler(void)
{
	/*从邮箱中读出报文*/
	CAN_Receive(CANx, CAN_FIFO0, &RxMessage);

	/* 比较ID是否为0x1314 */ 
	if((RxMessage.StdId==0x45) && (RxMessage.IDE==CAN_ID_STD) && (RxMessage.DLC==8) )
	{
	flag = 1; 					       //接收成功  
	}
	else
	{
	flag = 0; 					   //接收失败
	}
}

主函数

int main(void)
{	
	
	MY_NVIC_PriorityGroupConfig(2);	//=====设置中断分组
	delay_init();  					//=====延时函数初始化	
	KEY_Init();                     //=====按键初始化
	usart1_init(115200);			//=====串口1初始化 	
	CAN_Config();					/*初始化can,在中断接收CAN数据包*/
	MiniBalance_PWM_Init(7199, 0); //=====初始化PWM 10KHZ,用于驱动电机 如需初始化电调接口
	TIM5_Cap_Init(0XFFFF,72-1);	  //=====超声波始化 默认注释 超声波接线 参考timer.h文件
	TIM3_Cap_Init(0XFFFF,72-1);	  //=====超声波始化 默认注释 超声波接线 参考timer.h文件
	
    while(1)
	{			
		/*设置要发送的报文*/
		CAN_SetMsg(&TxMessage);

		/*把报文存储到发送邮箱,发送*/
		CAN_Transmit(CANx, &TxMessage);
		
		can_delay(10000);//等待发送完毕,可使用CAN_TransmitStatus查看状态
			
		if(flag==1)
		{		
			printf("\r\nCAN接收到数据:\r\n");	
			CAN_DEBUG_ARRAY(RxMessage.Data,8); 
			x = RxMessage.Data[0];
			ang = RxMessage.Data[1];
			flag=0;
		}		
			
	}
}

CAN头文件

#ifndef __CAN_H
#define __CAN_H

#include "stm32f10x.h"
#include "usart.h"

#define CANx CAN1
#define CAN_CLK RCC_APB1Periph_CAN1
#define CAN_RX_IRQ USB_LP_CAN1_RX0_IRQn
#define CAN_RX_IRQHandler USB_LP_CAN1_RX0_IRQHandler

#define CAN_RX_PIN GPIO_Pin_8
#define CAN_TX_PIN GPIO_Pin_9
#define CAN_TX_GPIO_PORT GPIOB
#define CAN_RX_GPIO_PORT GPIOB
#define CAN_TX_GPIO_CLK (RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB)
#define CAN_RX_GPIO_CLK RCC_APB2Periph_GPIOB

/*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;                             \
        float *a = array;                    \
        if (CAN_DEBUG_ARRAY_ON)                \
        {                                      \
            printf("<<-CAN-DEBUG-ARRAY->>\n"); \
            for (i = 0; i < (num); i++)        \
            {                                  \
                printf("%f   ", (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

在下菜鸟,大家的鼓励是我继续创作的动力,如果觉得写的不错,欢迎关注,点赞,收藏,转发,谢谢!

基于STM32F103RCT6的CAN通信电路是一种基于CAN总线协议的通信电路,用于在嵌入式系统中实现设备之间的高速数据传输。STM32F103RCT6是一款基于ARM Cortex-M3核心的微控制器,具有强大的处理能力和丰富的外设。 CAN通信电路的主要组成部分包括STM32F103RCT6微控制器、CAN收发器、CAN总线等。STM32F103RCT6作为主控制器,负责对CAN总线进行控制和数据的发送和接收。CAN收发器则负责将STM32F103RCT6的CAN信号转换为CAN总线信号,并将CAN总线信号转换为STM32F103RCT6能够处理的信号。通过CAN总线,不同设备之间可以以高速、可靠的方式进行数据的传输。 在使用基于STM32F103RCT6的CAN通信电路时,需要首先配置STM32F103RCT6的GPIO引脚作为CAN引脚,然后初始化CAN模块。在CAN模块初始化完成后,就可以通过编程的方式进行数据的发送和接收。 CAN通信电路的优势主要有以下几点:首先,CAN总线具有高速传输的优势,能够满足对数据传输速度要求较高的应用场景;其次,CAN总线支持多设备并行通信,能够满足系统中多个设备之间的数据交互需求;最后,CAN总线采用差分信号传输,具有较好的抗干扰能力,可以在工业环境等噪声干扰较大的场景下稳定运行。 基于STM32F103RCT6的CAN通信电路可以应用于许多领域,例如工业自动化、汽车电子、航空航天等。它在这些领域中能够实现设备之间的快速、可靠的数据交换,提高系统的响应速度和可靠性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会用魔法的叮当猫

蟹蟹٩('ω')و!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值