基于stm32 f407vet6芯片 使用hal库开发 can
简单讲解一下can的基础使用
CubeMX配置
这里打开CAN1 并且设置好波特率和NVIC相关的配置
波特率使用波特率计算器软件
使用采样率最高的这段 填入
得到波特率1M bit/s
然后编写代码
环形缓冲区
#include "driver_buffer.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
RingBuffer USERRxDataBuffer1; //定义用户缓冲区
RingBuffer USERRxDataBuffer2;
/* 初始化环形缓冲区 */
int Driver_Buffer_Init(ptRingBuffer buffer, uint16_t size)
{
if (buffer == NULL || size == 0)
return -1; /* 判断合法性 */
if (buffer->fifo == NULL) /* 判断是否为内存大小空*/
{
buffer->fifo = (uint8_t *)malloc(size); /* 动态分配内存 */
if (buffer->fifo == NULL)
{
//printf("Malloc %d bytes failed.\r\n", size);
return -1;
}
}
buffer->pw = buffer->pr = 0;
buffer->buf_size = size;
return 0;
}
/* 环形缓冲区写一个字节 */
int Driver_Buffer_Write(ptRingBuffer buffer, const uint8_t data)
{
if (buffer == NULL || buffer->fifo == NULL)
return -1; /* 判断合法性 */
int i = (buffer->pw + 1) % buffer->buf_size;
if (i != buffer->pr) /* 判断是否写满 */
{
buffer->fifo[buffer->pw] = data; /* */
buffer->pw = i; /* 重置写指针 */
return 0;
}
return -1;
}
/* 环形缓冲区写多个字节 */
int Driver_Buffer_WriteBytes(ptRingBuffer buffer, const uint8_t *data_stream, uint8_t len)
{
int i;
if (buffer == NULL || buffer->fifo == NULL)
return -1; /* 判断合法性 */
if (data_stream == NULL || len == 0)
return -1;
for (i = 0; i < len; i++)
{
if (Driver_Buffer_Write(buffer, data_stream[i]) != 0)
break;
}
return i;
}
/* 环形缓冲区 读一个字节 */
int Driver_Buffer_Read(ptRingBuffer buffer, uint8_t *data)
{
if (buffer == NULL || buffer->fifo == NULL)
return -1; /* 判断合法性 */
if (data == NULL)
return -1;
if (buffer->pr == buffer->pw)
return -1; /* 满 */
*data = buffer->fifo[buffer->pr];
buffer->pr = (buffer->pr + 1) % buffer->buf_size; /* 自增 */
return 0;
}
/* 环形缓冲区 读多个字节 */
int Driver_Buffer_ReadBytes(ptRingBuffer buffer, uint8_t *data_stream, uint8_t len)
{
int i = 0;
if (buffer == NULL || buffer->fifo == NULL)
return -1; /* 判断合法性 */
if (data_stream == NULL || len == 0)
return -1;
for (i = 0; i < len; i++)
{
if (Driver_Buffer_Read(buffer, &data_stream[i]) != 0)
break;
}
return i;
}
/* 清空环形缓冲区 */
int Driver_Buffer_Clean(ptRingBuffer buffer)
{
if (buffer == NULL || buffer->fifo == NULL)
return -1; /* 判断合法性 */
memset(buffer->fifo, 0, buffer->buf_size); /* 清空 */
buffer->pr = buffer->pw = 0; /* 归零 */
return 0;
}
/**
* @brief 更新数据到数组
* @param buffer
* @param data_stream
* @return 返回更新的数据长度
*/
int Driver_Buffer_RefreshData(ptRingBuffer buffer, uint8_t *data_stream)
{
uint16_t len = 0;
if (buffer->pw == buffer->buf_size)
buffer->pw = 0;
while (buffer->pw != buffer->pr)
{
data_stream[len++] = buffer->fifo[buffer->pr];
buffer->fifo[buffer->pr] = 0;
buffer->pr++;
if (buffer->pr >= buffer->buf_size)
buffer->pr = 0;
if (len >= buffer->buf_size)
break;
}
return len;
}
#ifndef __DRIVER_BUFFER_H
#define __DRIVER_BUFFER_H
#include "stdint.h"
typedef struct{
uint8_t *fifo;
uint16_t pw; /*写地址*/
uint16_t pr;
uint16_t buf_size;
}RingBuffer,*ptRingBuffer;
extern RingBuffer USERRxDataBuffer1;
extern RingBuffer USERRxDataBuffer2;
int Driver_Buffer_Init(ptRingBuffer buffer, uint16_t size);
int Driver_Buffer_Write(ptRingBuffer buffer, const uint8_t data);
int Driver_Buffer_WriteBytes(ptRingBuffer buffer, const uint8_t *data_stream, uint8_t len);
int Driver_Buffer_Read(ptRingBuffer buffer, uint8_t *data);
int Driver_Buffer_ReadBytes(ptRingBuffer buffer, uint8_t *data_stream, uint8_t len);
int Driver_Buffer_Clean(ptRingBuffer buffer);
int Driver_Buffer_RefreshData(ptRingBuffer buffer, uint8_t *data_stream);
#endif
#include "driver_can.h"
#include "can.h"
#include "driver_buffer.h"
#include <stdio.h> //使用printf函数
#include <stdint.h>
HAL_StatusTypeDef CAN_Init(void)
{
HAL_StatusTypeDef result = HAL_OK;
Driver_Buffer_Init(&USERRxDataBuffer1, 256); /* 开辟环形缓冲区空间 */
result = CAN_Filter_Config_Scale32_IdMask(&hcan1, 0x100, 0x100); // 过滤器设置
return result;
}
HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdMask(CAN_HandleTypeDef *hcan, uint32_t id, uint32_t mask)
{
HAL_CAN_Stop(hcan); // 停止can
HAL_StatusTypeDef result = HAL_OK;
CAN_FilterTypeDef sFilterConfig;
/* 配置过滤器参数 */
sFilterConfig.FilterBank = 0; // 过滤器组编号(0-27)
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式(或列表模式)
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位位宽
// ID分解(右移13位取高16位,左移3位处理IDE/RTR位)
sFilterConfig.FilterIdHigh = (id >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (id << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/
// 掩码设置为0xFFFF0000(匹配前16位)
sFilterConfig.FilterMaskIdHigh = (mask >> 13) & 0xFFFF;
sFilterConfig.FilterMaskIdLow = (mask << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收FIFO选择
sFilterConfig.FilterActivation = ENABLE; // 启用过滤器
sFilterConfig.SlaveStartFilterBank = 14; // 双CAN时从过滤器组起始编号 单can无意义
/* 应用过滤器配置 */
if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
result = HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断
result = HAL_CAN_Start(hcan); // 启动CAN外设
return result;
}
/* 32位列表模式 */
HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdList(CAN_HandleTypeDef *hcan, uint32_t id1, uint32_t id2)
{
HAL_CAN_Stop(hcan); // 停止can
HAL_StatusTypeDef result = HAL_OK;
CAN_FilterTypeDef sFilterConfig;
/* 基础参数配置 */
sFilterConfig.FilterBank = 0; // 使用过滤器组0(CAN1默认组0-13)
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式,需精确匹配ID
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位位宽,支持标准帧和扩展帧
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0
sFilterConfig.FilterActivation = ENABLE; // 启用过滤器
sFilterConfig.SlaveStartFilterBank =14; // CAN2使用过滤器组14-27
/* 设置两个目标扩展ID(0x18F60000和0x18F60001) */
uint32_t target_id1 = id1 | CAN_ID_EXT; // 扩展帧需设置IDE位
uint32_t target_id2 = id2 | CAN_ID_EXT;
// 扩展ID分解:高16位右移13位,低16位左移3位(IDE/RTR位对齐)
sFilterConfig.FilterIdHigh = (target_id1 >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (target_id1 << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/
sFilterConfig.FilterMaskIdHigh = (target_id2 >> 13) & 0xFFFF; // 第二个ID的高16位
sFilterConfig.FilterMaskIdLow = (target_id2 << 3) & 0xFFF8| CAN_ID_EXT|CAN_RTR_DATA; /*只接受拓展帧 和数据帧*/
/* 应用过滤器配置 */
if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
HAL_CAN_Start(hcan);
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断
// 启动CAN外设
return result;
}
HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdMask(CAN_HandleTypeDef *hcan, uint16_t id, uint16_t mask)
{
HAL_CAN_Stop(hcan); // 停止can
HAL_StatusTypeDef result = HAL_OK;
CAN_FilterTypeDef sFilterConfig;
/* 配置过滤器参数 */
sFilterConfig.FilterBank = 0; // 过滤器组编号(0-27)
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式(或列表模式)
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; // 32位位宽
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0
sFilterConfig.FilterActivation = ENABLE; // 启用过滤器
sFilterConfig.SlaveStartFilterBank = 0; // CAN2使用过滤器组14-27
// 标准帧ID左移5位对齐(STID[10:0]占高11位)
sFilterConfig.FilterIdHigh = (id << 5); // ID高16位寄存器(实际存储前11位)
sFilterConfig.FilterIdLow = 0x0000; // ID低16位寄存器(未使用)
sFilterConfig.FilterMaskIdHigh = (mask << 5); // 掩码高16位寄存器
sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码低16位寄存器(未使用)
/* 应用过滤器配置 */
if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
// 启动CAN外设
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断
HAL_CAN_Start(hcan);
return result;
}
/* 16位列表模式 */
HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdList(CAN_HandleTypeDef *hcan, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4)
{
HAL_CAN_Stop(hcan); // 停止can
HAL_StatusTypeDef result = HAL_OK;
CAN_FilterTypeDef sFilterConfig;
/* 基础参数配置 */
sFilterConfig.FilterBank = 0; // 使用过滤器组0(CAN1默认组0-13)
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式,需精确匹配ID
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 接收报文存入FIFO0
sFilterConfig.FilterActivation = ENABLE; // 启用过滤器
sFilterConfig.SlaveStartFilterBank = 0; // CAN2使用过滤器组14-27
sFilterConfig.FilterIdHigh = id1 << 5; // 标准ID 0x100
sFilterConfig.FilterIdLow = id2 << 5; // 标准ID 0x101
sFilterConfig.FilterMaskIdHigh = id3 << 5; // 标准ID 0x102
sFilterConfig.FilterMaskIdLow = id4 << 5; // 标准ID 0x103
/* 应用过滤器配置 */
if (HAL_CAN_ConfigFilter(hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
HAL_CAN_Start(hcan); // 启动CAN外设
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // FIFO0消息挂起中断
return result;
}
/*
* @brief 发送一帧CAN数据
* @param hcan: CAN句柄指针
* @param id: 报文标识符(标准ID或扩展ID)
* @param data: 数据缓冲区指针(最大8字节)
* @param len: 数据长度(0-8)
* @param isExtId: 是否为扩展ID(1=扩展帧,0=标准帧)
* @retval HAL状态:HAL_OK=成功,其他=失败
*/
HAL_StatusTypeDef CAN_Send_Frame(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *data, uint8_t len, uint8_t isExtId)
{
CAN_TxHeaderTypeDef txHeader;
uint32_t mailbox;
HAL_StatusTypeDef result = HAL_OK;
/* 校验参数合法性 */
if (len > 8 || data == NULL)
return HAL_ERROR;
/* 配置报文头部 */
if (isExtId)
{
txHeader.ExtId = id; // 扩展ID
txHeader.IDE = CAN_ID_EXT; // 扩展帧标识
}
else
{
txHeader.StdId = id; // 标准ID
txHeader.IDE = CAN_ID_STD; // 标准帧标识
}
txHeader.RTR = CAN_RTR_DATA; // 数据帧(非远程请求)
txHeader.DLC = len; // 数据长度码
txHeader.TransmitGlobalTime = DISABLE; // 不记录全局时间戳
/* 提交发送请求 */
result = HAL_CAN_AddTxMessage(hcan, &txHeader, data, &mailbox);
while (HAL_CAN_GetTxMailboxesFreeLevel(hcan) != 3) // 3 个邮箱都为空
; /*等待发送完成 防止丢包*/
return result;
}
/* CAN发送多帧数据 */
void CAN_Send_Data(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *buf, uint32_t len, uint8_t isExtId)
{
uint32_t transmission_times = 0; /* 发送次数 */
uint32_t remian_bytes = 0; /* 剩余字节 */
uint32_t frame_length = 0; /* 帧长度 */
frame_length = 8; /* 标准can最大8 */
transmission_times = len / frame_length;
remian_bytes = len % frame_length;
int i = 0;
while (i < transmission_times)
{
CAN_Send_Frame(hcan, id, buf + i * frame_length, frame_length, isExtId);
i++;
}
if (remian_bytes > 0) // 尾帧
{
CAN_Send_Frame(hcan, id, buf + transmission_times * frame_length, remian_bytes, isExtId);
}
}
/* CAN 接收数据 */
uint32_t CAN_Receive_Message(CAN_HandleTypeDef *hcan, uint32_t RxFifo, uint8_t *buf)
{
CAN_RxHeaderTypeDef RxHeader;
if (HAL_CAN_GetRxFifoFillLevel(hcan, RxFifo) == 0) // 检查邮箱
{
return 0; // 没有数据
}
HAL_CAN_GetRxMessage(hcan, RxFifo, &RxHeader, buf);
return RxHeader.DLC; // 返回接收长度
}
/**
* @brief 接收FIFO0的回调函数 (中断方式)
* @param hcan
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t can_rec_data[8];
uint32_t len = 0;
len = CAN_Receive_Message(hcan, CAN_RX_FIFO0, can_rec_data);
Driver_Buffer_WriteBytes(&USERRxDataBuffer1, can_rec_data, len); /*将收到的数据写到缓冲区*/
char buffer[10] = "";
char *ptr = buffer;
for (size_t i = 0; i < 8; i++)
{
ptr += sprintf(ptr, "%02X ", can_rec_data[i]); // 将元素转为十六进制字符串
}
//usb_printf("%s\n", buffer); // 一次性输出整个字符串
}
//void MX_CAN_Init(void)
//{
// CAN_FilterTypeDef sFilterConfig;
//
// /*CANµ¥Ԫ³õʼ»¯*/
//
// hCAN.Instance = CANx; /* CAN͢ɨ */
// hCAN.Init.Prescaler = 3; /* BTR-BRP ²¨̘Š·ֆµƷ ¶¨ҥÁˊ±¼䵥ԪµĊ±¼䳤¶Ƞ42/(1+10+3)/3=1Mbps */
// hCAN.Init.Mode = CAN_MODE_NORMAL; /* ս³£¹¤ģʽ */
// hCAN.Init.SyncJumpWidth = CAN_SJW_1TQ; /* BTR-SJW ֘Ђͬ²½̸Ծ¿2¸öʱ¼䵥Ԫ */
// hCAN.Init.TimeSeg1 = CAN_BS1_10TQ; /* BTR-TS1 ʱ¼䶎1 ռӃÁ˶¸öʱ¼䵥Ԫ */
// hCAN.Init.TimeSeg2 = CAN_BS2_3TQ; /* BTR-TS1 ʱ¼䶎2 ռӃÁ˳¸öʱ¼䵥Ԫ */
// hCAN.Init.TimeTriggeredMode = DISABLE; /* MCR-TTCM ¹رՊ±¼䴥·¢ͨЅģʽʹĜ */
// hCAN.Init.AutoBusOff = ENABLE; /* MCR-ABOM ה¶¯À돟¹܀
// hCAN.Init.AutoWakeUp = ENABLE; /* MCR-AWUM ʹӃה¶¯»½Бģʽ */
// hCAN.Init.AutoRetransmission = DISABLE; /* MCR-NART ½ûֹ±¨΄ה¶¯֘´« DISABLE-ה¶¯֘´« */
// hCAN.Init.ReceiveFifoLocked = DISABLE; /* MCR-RFLM ½ӊՆIFO ˸¶¨ģʽ DISABLE-ҧ³öʱЂ±¨΄»Ḳ¸ǔӐ±¨΄ */
// hCAN.Init.TransmitFifoPriority = DISABLE; /* MCR-TXFP ·¢ˍFIFOӅψ¼¶ DISABLE-Ӆψ¼¶ȡ¾öӚ±¨΄±ꊾ·û */
// HAL_CAN_Init(&hCAN);
//
// /*CAN¹ý‹Ʒ³õʼ»¯*/
// sFilterConfig.FilterBank = 0; /* ¹ý‹Ʒש0 */
// sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; /* ¹¤Ԛ±ꊶ·ûƁ±Ύ»ģʽ */
// sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; /* ¹ý‹Ʒλ¿펪µ¥¸ö32λ¡£*/
// sFilterConfig.FilterIdHigh = (((uint32_t)0x1314<<3)&0xFFFF0000)>>16;; /* Ҫ¹ý‹µĉD¸ߎ» */
// sFilterConfig.FilterIdLow = (((uint32_t)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;; /* Ҫ¹ý‹µĉDµ͎» */
// sFilterConfig.FilterMaskIdHigh = 0xFFFF; /* ¹ý‹Ʒ¸߱6λÿλ±ؐ놥Ť */
// sFilterConfig.FilterMaskIdLow = 0xFFFF; /* ¹ý‹Ʒµͱ6λÿλ±ؐ놥Ť */
// sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; /* ¹ý‹Ʒ±»¹ªµ½FIFO 0 */
// sFilterConfig.FilterActivation = ENABLE; /* ʹĜ¹ý‹Ʒ */
// sFilterConfig.SlaveStartFilterBank = 0; /* ӃÀ´ѡԱ´ӹý‹ƷµļĴ憷± */
//
// HAL_CAN_ConfigFilter(&hCAN, &sFilterConfig);
//
//
//}
#ifndef __DRIVER_CAN_H__
#define __DRIVER_CAN_H__
#include "main.h"
HAL_StatusTypeDef CAN_Init(void);
HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdMask(CAN_HandleTypeDef *hcan, uint32_t id, uint32_t mask);
HAL_StatusTypeDef CAN_Filter_Config_Scale32_IdList(CAN_HandleTypeDef *hcan, uint32_t id1, uint32_t id2);
HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdMask(CAN_HandleTypeDef *hcan, uint16_t id, uint16_t mask);
HAL_StatusTypeDef CAN_Filter_Config_Scale16_IdList(CAN_HandleTypeDef *hcan, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4);
HAL_StatusTypeDef CAN_Send_Frame(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *data, uint8_t len, uint8_t isExtId);
void CAN_Send_Data(CAN_HandleTypeDef *hcan, uint32_t id, uint8_t *buf, uint32_t len, uint8_t isExtId);
uint32_t CAN_Receive_Message(CAN_HandleTypeDef *hcan, uint32_t RxFifo, uint8_t *buf);
#endif
提供了32位掩码和列表 16位掩码和列表的过滤器
编写应用层代码
void APP_User_Task(void)
{
for(int i =0 ;i<8;i++)
{
buf[i] = i;
}
/*发送丢包测试*/
for(int i =0 ;i<1024;i++)
{
tx_Pathping[i] = i%256;
}
CAN_Send_Data(&hcan1,0x100,tx_Pathping,1024,1);
for(;;)
{
/*接收丢包测试*/
if(Driver_Buffer_RefreshData(&USERRxDataBuffer1,tx_buf))
{
tx_buf[7] = 0xa5;
CAN_Send_Data(&hcan1,0x5A,tx_buf,8,1);
}
}
}
实验效果
一开机就输出了128帧数据 可以看到数据都是连续的没有丢包
然后发送1024帧数据 可以看到也没有丢包
发送的数据接收到环形缓冲区 然后读出数据打印
此工程代码已经在STM32F407VET6 和STM32F103CBT6芯片上都验证过了 没有太大问题