基于HAL库的CAN通信三:移植canopen,实现主机发送SYNC同步帧
协议栈:canfestival;
主要参考GXTon_阿通的教程:https://www.bilibili.com/read/readlist/rl452550?spm_id_from=333.999.0.0
移植步骤:
- 官网打不开,我在GITEE找到了一份源码,下载地址:https://gitee.com/the_bestonly/CanFestival-transplanted2stm32
- (可以先了解协议栈,也可以先移植,边用边学)协议栈的文件结构:
我们需要使用include文件和src文件,将这两个文件夹拷贝到自己的工程
打开src文件夹,删除win32文件夹、canfestival.pc.in、Makefile.in、symbols.c
打开include文件夹,删除下列选中的文件:
打开include/avr文件夹,删除can_AVR.h、can_drv.h、iar.h - 将.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,
- 主函数
//主函数
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)
{
}
}
- 程序完成初始化后在while(1)等待,定时器中断触发,进入TimeDispatch()函数,
- 结果如图所示:
这里需要将模式切换为:指令模式,否则收不到数据。
我的程序:链接:https://pan.baidu.com/s/1l4eilc0nTYkisgUeleiSww?pwd=lmo6
提取码:lmo6