STM32F1CAN通讯

本次通讯试用到硬件开发板STM32F103C8T6(数据发送),STM32F103C6T6(数据接收),CAN收发器VP230。硬件连接如下图所示:
在这里插入图片描述
由于我使用的开发板不自带CAN收发器,所以只有外接CAN收发器才能保证两个开发板的正常通讯。
数据发送端(STM32F103C8T6)代码部分

/********************can.c**********************/
#include "can.h"

u8 CAN_RX_BUF[8];

unsigned char CAN_RX_FLAG = 0;

void CAN_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitSturcture;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	//CAN_RX PB8
	GPIO_InitSturcture.GPIO_Pin = CAN_RX_Pin;
	GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
	
	//CAN_TX PB9
	GPIO_InitSturcture.GPIO_Pin  =CAN_TX_Pin;
	GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(CAN_GPIO_PORT,&GPIO_InitSturcture);
}

void CAN_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}

void CAN_Mode_Init(u32 tsjw,u32 tbs1,u32 tbs2,u16 brp,u32 mode)
{
	CAN_InitTypeDef CAN_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
	
	GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE);
	
	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);
	
	CAN_InitStructure.CAN_SJW = tsjw;
	CAN_InitStructure.CAN_BS1 = tbs1;
	CAN_InitStructure.CAN_BS2 = tbs2;
	CAN_InitStructure.CAN_Mode = mode;
	CAN_InitStructure.CAN_Prescaler = brp;
	CAN_InitStructure.CAN_NART  =ENABLE;
	CAN_InitStructure.CAN_ABOM = DISABLE;
	CAN_InitStructure.CAN_AWUM = DISABLE;
	CAN_InitStructure.CAN_RFLM = ENABLE;
	CAN_InitStructure.CAN_TTCM = DISABLE;
	CAN_InitStructure.CAN_TXFP = DISABLE;
	
	CAN_Init(CAN1,&CAN_InitStructure);
}

/********数据发送端可不配置过滤器,设置默认值即可***********/
void CAN_Filter_Init(void)
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
	CAN_FilterInit(&CAN_FilterInitStructure);
}

void Can_Init(void)
{
	CAN_GPIO_Config();
	CAN_NVIC_Config();
	CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,12,CAN_Mode_Normal);
	//CAN_Mode_Normal  CAN_Mode_LoopBack
	CAN_Filter_Init();
}

u8 CAN_Send_Msg(u8* msg,u8 len)
{
	CanTxMsg TxMessage;
	u8 i,mbox;
	u16 cunt = 0;

	//TxMessage.StdId = 0x0000;
	TxMessage.ExtId = 0x1001;      //设置发送扩展ID
	TxMessage.IDE = CAN_ID_EXT;
	TxMessage.RTR = CAN_RTR_DATA;
	TxMessage.DLC = len;
	for(i = 0;i < len;i ++)
	{
		TxMessage.Data[i] = msg[i];
	}
	mbox = CAN_Transmit(CAN1,&TxMessage);
	
	while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(cunt<0XFFF))
		cunt++;
	if(cunt >= 0xFFF)
		return 0;
	return 1;
}

void USB_LP_CAN1_RX0_IRQHandler(void)
{
	CanRxMsg RxMessage;
	uint8_t i;
	
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) != RESET)
	{
		CAN_RX_FLAG = 1;
		CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);
		
		for(i = 0;i < 8;i ++)
			CAN_RX_BUF[i] = RxMessage.Data[i];
		
		CAN_FIFORelease(CAN1,CAN_FIFO0);
		CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
	}
}

主函数部分

#include "main.h"   
int main(void) 
{	
	u8 send_buf[8] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
	u8 i = 0x00;
	
	NVIC_Configuration();
	LED_Init();
	Delay_Init();
	Usart1_Init(9600);
	Can_Init();
	printf("这里是CAN的测试程序\r\n");
	LED0 = 1;
	while(1)                        //主循环
	{
		i++;
		send_buf[0] = i;
		CAN_Send_Msg(send_buf,8);
		Delay_Ms(100);
		LED0 = !LED0;
	}
}

/分割线//
以下是CAN通讯数据接收端(STM32F103C6T6)代码:
接收端的中断、GPIO和CAN_Mode配置都跟发送设置的一样,直接复制粘贴即可。下面是配置接收端的过滤器,接收扩展ID为1001设备的数据。其他数据一律过滤不接收,当然如果想不过滤ID,接收端过滤器配置全部设置成更发送端一样即可。

void CAN_Filter_Init(void)
{
	CAN_FilterInitTypeDef CAN_FilterInitStructure;
	
	//只接受ID为1001的设备
	CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)0x1001<<3)&0xFFFF0000)>>16;
	CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)0x1001<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
	CAN_FilterInit(&CAN_FilterInitStructure);
}

中断接收函数

void USB_LP_CAN1_RX0_IRQHandler(void)
{
	CanRxMsg RxMessage;
	uint8_t i;
	
	if(CAN_GetITStatus(CAN1,CAN_IT_FMP0) != RESET)
	{
		CAN_RX_FLAG = 1;
		CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);
		
		for(i = 0;i < 8;i ++)
			CAN_RX_BUF[i] = RxMessage.Data[i];
		
		CAN_FIFORelease(CAN1,CAN_FIFO0);
		CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
	}
}

主函数部分

#include "main.h"   
int main(void) 
{	 
	NVIC_Configuration();
	LED_Init();
	Delay_Init();
	Usart1_Init(9600);
	Can_Init();
	printf("这里是CAN的测试程序\r\n");
	LED0 = 1;
	while(1)                        //主循环
	{
		if(CAN_RX_FLAG == 1)
		{
			CAN_RX_FLAG = 0;
			USART1TxData_hex(CAN_RX_BUF,8);
		}
		
		Delay_Ms(100);
		LED0 = !LED0;
	}
}

通过串口调试助手打印出接收端接收到数据。
在这里插入图片描述

STM32F1系列微控制器是STMicroelectronics推出的一款单片机产品,其采用ARM Cortex-M3内核,具有丰富的外设资源和强大的性能,广泛应用于各种嵌入式系统中。为了实现CAN通信功能,STMicroelectronics提供了STM32F1HAL库,方便开发者进行CAN通信的编程。 首先,我们需要在STM32CubeMX软件中进行配置。选择相应的引脚,打开CAN外设,并配置波特率等参数。生成代码后,打开工程,进入main.c文件。 首先,我们需要包含相应的头文件,例如stm32f1xx_hal.h、stm32f1xx_hal_can.h等。 接着,在main函数中初始化HAL库和CAN外设,使用HAL_CAN_Init()函数初始化CAN外设。 然后,通过HAL_CAN_ConfigFilter()函数配置筛选器,确定CAN消息的接收规则。 随后,我们可以使用HAL_CAN_ActivateNotification()函数激活CAN通信的中断功能,以便接收到CAN消息时能够触发中断。 在while循环中,我们可以使用HAL_CAN_GetTxMailboxesFreeLevel()函数判断发送邮箱是否可用,如果可用,则调用HAL_CAN_AddTxMessage()函数发送CAN消息。 同时,我们可以使用HAL_CAN_GetRxFifoFilledLevel()函数判断接收缓冲区是否有新的CAN消息,如果有,则调用HAL_CAN_GetRxMessage()函数读取CAN消息。 在收发CAN消息的过程中,可以使用HAL_CAN_GetError()函数获取错误信息,以便进行错误处理。 最后,我们可以根据实际的需求和业务逻辑,进行CAN消息的处理和响应。 总之,通过上述步骤,我们可以使用STM32F1HAL库进行CAN通信的开发,实现CAN消息的发送和接收。这样,我们就可以在嵌入式系统中实现CAN总线通信功能,实现设备之间的数据交换和通信
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值