CUBEMX+CANOPEN教程二:can功能代码完善

教程一基础上进行can功能完善

主要工作:

  1. can筛选器配置
  2. can发送与接收的相关结构体构建
  3. can发送与接收等函数构建
  4. can festival移植
  5. 定时器配置

1. can筛选器配置

在bsp_can.c文件中添加

void CAN_Filter_Init(void)
{
	CAN_FilterTypeDef CAN_FilterInitStructure;

	CAN_FilterInitStructure.FilterActivation       	= ENABLE; 
	CAN_FilterInitStructure.FilterBank				= 0;
	CAN_FilterInitStructure.FilterFIFOAssignment   	= CAN_FILTER_FIFO0;
	CAN_FilterInitStructure.FilterIdHigh           	= 0x0000;
	CAN_FilterInitStructure.FilterIdLow           	= 0x0000;
	CAN_FilterInitStructure.FilterMaskIdHigh        = 0x0000;
	CAN_FilterInitStructure.FilterMaskIdLow         = 0x0000;
	CAN_FilterInitStructure.FilterMode				= CAN_FILTERMODE_IDMASK;
	CAN_FilterInitStructure.FilterScale            	= CAN_FILTERSCALE_32BIT;
	CAN_FilterInitStructure.SlaveStartFilterBank	= 14;
	
	if(HAL_CAN_ConfigFilter(&hcan1, &CAN_FilterInitStructure) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
	if(HAL_CAN_Start(&hcan1) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
	if(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
	{
		_Error_Handler(__FILE__, __LINE__);
	}
}

2. can发送与接收的相关数据结构构建

CAN1发送与接收数据帧头定义与标准库有所不同

/* bsp_can.c */
/* CAN1发送与接收数据帧头 */
CAN_TxHeaderTypeDef				CAN1_TxHeaderMessage;
CAN_RxHeaderTypeDef				CAN1_RxHeaderMessage;

/* CAN1发送与接收实际数据 */
CAN_Msgdata can1_tx_msg;
CAN_Msgdata can1_rx_msg;
/* bsp_can.h */
 typedef struct{
	Message m;
}CANOpen_Message;

typedef struct
{
	uint8_t Data[8];
}CAN_Msgdata;

其中Message为结构体在can.h文件中定义

/* can.h */
typedef struct {
  UNS16 cob_id;	/**< message's ID */
  UNS8 rtr;		/**< remote transmission request. (0 if not rtr message, 1 if rtr message) */
  UNS8 len;		/**< message's length (0 to 8) */
  UNS8 data[8]; /**< message's datas */
} Message;

#define Message_Initializer {0,0,0,{0,0,0,0,0,0,0,0}}

typedef UNS8 (*canSend_t)(Message *);

3. can发送与接收等函数构建

发送函数

/* bsp_can.c */
u8 canSend(CAN_HandleTypeDef *hcan,Message *m)
{
	unsigned char i;
	CAN_TxHeaderTypeDef TxMessage;
	
	TxMessage.StdId = (uint32_t)(m->cob_id);
	TxMessage.ExtId = 0x00;
	TxMessage.RTR = m->rtr; 							  
	TxMessage.IDE = CAN_ID_STD; 						  
	TxMessage.DLC = 8; 	
	TxMessage.DLC = m->len; 		
	for(i=0;i<m->len;i++)								  
	{
		can1_tx_msg.Data[i] = m->data[i];
	}
	if(HAL_CAN_AddTxMessage(&hcan1, &TxMessage, can1_tx_msg.Data, (uint32_t*)CAN_TX_MAILBOX0) != HAL_OK)
	{
		return 1;
//	 	printf("发送失败\r\n");
//		_Error_Handler(__FILE__, __LINE__);
	}
	return 0;
}

can接收队列挂起中断回调函数

/* bsp_can.c */
CANOpen_Message CAN1_Rx_m;
Message RxMSG = Message_Initializer;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance == CAN1)
	{
		/* 得到can接收数据 */
		 HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0, &CAN1_RxHeaderMessage, can1_rx_msg.Data);
		
		/* 处理can接收数据按照 canDispatch函数要求的数据格式*/
		 RxMSG.cob_id = CAN1_RxHeaderMessage.StdId;
		 RxMSG.len = CAN1_RxHeaderMessage.DLC;
		 RxMSG.rtr = CAN1_RxHeaderMessage.RTR;
		 memcpy(RxMSG.data,can1_rx_msg.Data,CAN1_RxHeaderMessage.DLC);
	}

//   AnalysisMessagefromDriver();
//	SEGGER_RTT_printf(0, "can master revcive data!!!!!!!!!!!!\n");
//	canDispatch(CANOpenMasterObject, &(RxMSG));
}

注意以上代码最后三行的三个被注销函数,第一个是分析canopen网络主机接收数据的,实际项目应用;第二个是打印,不重要;第三个是canopen报文分析的,很重要;

4. can festival移植

分析源码可以知道,canopen实现的最重要的就是用定时器来控制canopen网络的报文发送和接受时序和裁决。在移植好can festival后主要就是讲定时器融合到festival源码的所用的定时器功能中去。

5. 定时器配置

定时为1ms

/* tim.c */
/* TIM4 init function */
void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 84-1;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 1000-1;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_OC_Init(&htim4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_TIMING;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_OC_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

在bsp_timer.c中实现几个函数,主要是提供给festival源码中调用

  1. 实现定时器设置自动重装载值
  2. 实现定时器得到当前计数值
  3. 实现定时器初始化函数
  4. 实现定时器比较输出中断回调函数
#ifdef CANOPEN_MY
#include <stdbool.h>
#include "canfestival.h"
#include "timer.h"

#endif

#ifdef CANOPEN_MY
static TIMEVAL last_time_set = TIMEVAL_MAX;

/**
  * @brief  setTimer
  * @param  value:Set time value 0x0000-0xffff
  * @retval NONE
  */
void setTimer(TIMEVAL value)
{
	__HAL_TIM_SetAutoreload(&htim4, value);
}
/**
  * @brief  getElapsedTime
  * @param  NONE
	* @retval TIMEVAL:Return current timer value
  */
TIMEVAL getElapsedTime(void)
{
	uint16_t timer = __HAL_TIM_GetCounter(&htim4);
	

	return timer > last_time_set ? timer - last_time_set : last_time_set - timer; 	
}

/**
  * @brief  TIM4_start
  * @param  NONE
  * @retval NONE
  */
void TIM4_start(void)
{
		MX_TIM4_Init();
}
/**
  * @brief  initTimer
  * @param  NONE
  * @retval NONE
  */
void initTimer(void)
{
		TIM4_start();
}

其中#define CANOPEN_MY 已经在main.h文件中定义,定时器开启并不是在主函数中调用,而是在festival源码中调用开启定时器。

/* CANOpenObjDictConfig.c */
void Master_operational(CO_Data* d)
{
	UNS32 SyncTimePeriod = 2000;
	UNS32 size = sizeof(SyncTimePeriod);
	
	writeLocalDict( d, /*CO_Data* d*/
			0x1006, /*UNS16 index*/
			0x00, /*UNS8 subind*/ 
			&SyncTimePeriod, /*void * pSourceData,*/ 
			&size, /* UNS8 * pExpectedSize*/
			RW);  /* UNS8 checkAccess */
	stopSYNC(d);
	startSYNC(d);
	setTimer(100);
//	TIM_Cmd(TIM4, ENABLE); //20190408 FreeRTOS 移植 CANopen
	HAL_TIM_Base_Start_IT(&htim4);
	SEGGER_RTT_printf(0, "Master_operational\n");
}

在主函数初始化时调用canopen网络初始化,CanopenInit();此函数在festival源码中已有定义,定义如下:

/**
  * @brief  CanopenInit
  * @param  NONE
  * @retval NONE
  */
void CanopenInit(void)
{
	UNS32 i;
	
	initTimer();   
	CANOpenMasterObject->canHandle = CAN1;
	CANOpenMasterInit(CANOpenMasterObject);
	setState(CANOpenMasterObject,Initialisation);
	setNodeId (CANOpenMasterObject, 127);
//	canInit(CAN1,CAN_BAUD_1M);      
	canInit(); //20190408 FreeRTOS 移植 CANopen	
	for(i=0; i<65536; i++);
	for(i=0; i<65536; i++);
	for(i=0; i<65536; i++);
	for(i=0; i<65536; i++);
	for(i=0; i<65536; i++);
}

源码中的can初始化是可以配置波特率的,应为cubemx中已经配置好波特率,因此将canInit(CAN1,CAN_BAUD_1M);函数注销,自主实现canInit();函数,此函数定义如下:

u8 canInit(void)
{
	MX_CAN1_Init();
	CAN_Filter_Init();
	return 0;
}

此函数就是调用cubemx生成的can初始化函数,在加上自己实现的can过滤器初始化函数。

至此完成can festival移植已经完成,实现canopen通讯网络主机功能。

小结

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值