基于HAL库的CAN通信三:移植canopen

文章讲述了如何基于STM32的HAL库移植CANopen协议栈canfestival,主要涉及删除不必要的文件、修改配置、添加自定义的CAN驱动mycan.c/h,并设置定时器中断发送SYNC同步帧。在完成初始化后,程序进入循环等待定时器中断触发TimeDispatch函数。
摘要由CSDN通过智能技术生成

基于HAL库的CAN通信三:移植canopen,实现主机发送SYNC同步帧

协议栈:canfestival;
主要参考GXTon_阿通的教程:https://www.bilibili.com/read/readlist/rl452550?spm_id_from=333.999.0.0

移植步骤:

  1. 官网打不开,我在GITEE找到了一份源码,下载地址:https://gitee.com/the_bestonly/CanFestival-transplanted2stm32
  2. (可以先了解协议栈,也可以先移植,边用边学)协议栈的文件结构:
    我们需要使用include文件和src文件,将这两个文件夹拷贝到自己的工程
    在这里插入图片描述
    打开src文件夹,删除win32文件夹、canfestival.pc.in、Makefile.in、symbols.c
    打开include文件夹,删除下列选中的文件:
    打开include/avr文件夹,删除can_AVR.h、can_drv.h、iar.h
  3. 将.c文件添加到工程,并将.h文件路径添加到头文件路径。
    打开config.h,屏蔽28至47行
    在这里插入图片描述
    搜索:start_and_seek_node,或者直接打开dcf.c,第94行,删除start_and_seek_node定义前的“inline”。
    搜索:start_node,或者直接找到dcf.c,第59行,删除start_node定义前的“inline”。
    添加mycan.c和mycan.h:
//mycan.c
#include "mycan.h"
#include "can_1.h"
#include "canfestival_master.h"
 
extern TIM_HandleTypeDef htim1;

uint8_t ubKeyNumber = 0x0;
CAN_TxHeaderTypeDef   TxHeader;
CAN_RxHeaderTypeDef   RxHeader;	

uint8_t canfestival_can_init(uint8_t tsjw,uint8_t tbs2,uint8_t tbs1,uint16_t brp,uint8_t mode)
{ 
  CAN_FilterTypeDef  sFilterConfig;

  /* Configure the CAN Filter */
  sFilterConfig.FilterBank = 0;
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterIdHigh = 0x0000;
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;
  sFilterConfig.FilterMaskIdLow = 0x0000;
  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.SlaveStartFilterBank = 14;

  if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    /* Filter configuration Error */
    Error_Handler();
  }

  /* Start the CAN peripheral */
  if (HAL_CAN_Start(&hcan) != HAL_OK)
  {
    /* Start Error */
    Error_Handler();
  }

  /* Activate CAN RX notification */
  if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
    /* Notification Error */
    Error_Handler();
  }
  
  /* Configure Transmission process */
	
	return 0;
}

/**
  * @brief  Rx Fifo 0 message pending callback in non blocking mode
  * @param  CanHandle: pointer to a CAN_HandleTypeDef structure that contains
  *         the configuration information for the specified CAN.
  * @retval None
  */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle)
{
//  unsigned int i = 0;
	Message RxMSG ;
  HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxMSG.data);
  RxMSG.cob_id = (uint16_t)(RxHeader.StdId);
  if( RxHeader.RTR == CAN_RTR_REMOTE )
  {
     RxMSG.rtr = 1;    
  }
  else
  {
      RxMSG.rtr = 0; 
  }  
	RxMSG.len = RxHeader.DLC;
	canDispatch(&Master_Data, &(RxMSG)); 
	
}

uint8_t canSend(CAN_PORT notused, Message *message)
{
	CanTxMsg TxMessage;
	uint32_t TxMailbox = 0;

	/* ×é×°CANÊý¾Ý°ü */
	TxHeader.DLC = message->len;							
	memcpy(TxMessage.Data, message->data, message->len);	
	TxHeader.IDE = CAN_ID_STD;								
	TxHeader.StdId = message->cob_id;				
	TxHeader.RTR = (message->rtr == CAN_RTR_DATA) ? 0 : 2;	

	while(( HAL_CAN_AddTxMessage(&hcan,&TxHeader,TxMessage.Data,&TxMailbox)!=HAL_OK))
	{
			return 0;
	}
	return 1;
}

void setTimer(TIMEVAL value)
{
	TIM1->ARR = TIM1->CNT + value;
}

TIMEVAL getElapsedTime(void)
{
	return TIM1->CNT;
}


void TIM1_UP_IRQHandler(void)
{
  /* USER CODE BEGIN TIM1_UP_IRQn 0 */

  /* USER CODE END TIM1_UP_IRQn 0 */
  HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_IRQn 1 */
	TimeDispatch();
  /* USER CODE END TIM1_UP_IRQn 1 */
}


//mycan.h
#ifndef __MYCAN_H__
#define __MYCAN_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"
	
#define KEY_PRESSED     0x00
#define KEY_NOT_PRESSED 0x01
extern uint8_t ubKeyNumber;
extern CAN_TxHeaderTypeDef   TxHeader;
extern CAN_RxHeaderTypeDef   RxHeader;

typedef struct
{
  uint32_t StdId;  /*!< Specifies the standard identifier.
                        This parameter can be a value between 0 to 0x7FF. */
  uint32_t ExtId;  /*!< Specifies the extended identifier.
                        This parameter can be a value between 0 to 0x1FFFFFFF. */
  uint8_t IDE;     /*!< Specifies the type of identifier for the message that 
                        will be transmitted. This parameter can be a value 
                        of @ref CAN_identifier_type */
  uint8_t RTR;     /*!< Specifies the type of frame for the message that will 
                        be transmitted. This parameter can be a value of 
                        @ref CAN_remote_transmission_request */
  uint8_t DLC;     /*!< Specifies the length of the frame that will be 
                        transmitted. This parameter can be a value between 
                        0 to 8 */
  uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0 
                        to 0xFF. */
} CanTxMsg;

void CAN_Config(void);
#ifdef __cplusplus
}
#endif
#endif /*__MYCAN_H__ */

//canfestival_master.c
//canfestival_master.h

修改time.c
由于我的定时器最大计数周期为5000,TIMEVAL_MAX不能超过最大计数周期,这里我设置为2000。
在这里插入图片描述

根据定时器配置进行修改。例如,我的定时器时钟是72MHz,72分频,对应一次计数就是1us,
在这里插入图片描述

  1. 主函数
//主函数
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_CAN_Init();
  MX_TIM1_Init();
	
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);										//启动定时器
	
	canfestival_can_init(0,0,0,0,0);									//初始化can过滤器
	setNodeId(&Master_Data, 0x00);
	setState(&Master_Data, Initialisation);
	setState(&Master_Data,Pre_operational);
	setState(&Master_Data, Operational);
	stopSYNC(&Master_Data);
	startSYNC(&Master_Data);
	masterSendNMTstateChange(&Master_Data,0x01,NMT_Start_Node);
  while (1)
  {
  }
}
  1. 程序完成初始化后在while(1)等待,定时器中断触发,进入TimeDispatch()函数,
  2. 结果如图所示:
    在这里插入图片描述
    这里需要将模式切换为:指令模式,否则收不到数据。

我的程序:链接:https://pan.baidu.com/s/1l4eilc0nTYkisgUeleiSww?pwd=lmo6
提取码:lmo6

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值