STM32CubeMX 下载和安装 详细教程
【HAL库】STM32CubeMX开发----STM32F407----目录
CAN通信----基本原理----详细介绍
本次实验以 STM32F407VET6 芯片为MCU,使用 25MHz 外部时钟源。
CAN通信波特率为 500K bps。
CAN通信引脚 与 MCU引脚 对应关系如下:
CAN通信引脚 | MCU引脚 |
---|---|
TX | PB9 |
RX | PB8 |
具体 STM32CubeMX 界面如下:
我们本次实验选择 STM32F407VET6 芯片做 MCU。
进入工程编辑,具体界面如下:
这一步必须选择一种烧写方式,否则烧写一次程序后,芯片中就没法再次烧写程序了。需要硬件重启才可以重新烧写程序。
STM32烧写程序连接方式详解
设置外部晶振为芯片系统时钟源。
STM32F407 时钟最大频率为 168M
CAN通信引脚选择如下表:
CAN引脚 | MCU引脚1 | MCU引脚2 | MCU引脚3 |
---|---|---|---|
CAN1_RX | PA11 | PB8 | PD0 |
CAN1_TX | PA12 | PB9 | PD1 |
CAN2_RX | PB5 | PB12 | / |
CAN2_TX | PB6 | PB13 | / |
我们这次选择:CAN1通信,PB8,PB9为通信引脚。
具体操作如下:
鼠标左键点击引脚,选择CAN通信功能。
最后结果如下:
本次实验的APB1时钟频率 = 42MHz,在 步骤6设置时钟 中有介绍。
CAN波特率 = APB1时钟频率 / Prescaler / (1 + BS1 + BS2)
CAN波特率 | APB1时钟频率 | Prescaler | BS1 | BS2 |
---|---|---|---|---|
500KBPS | 42MHz | 7 | 9 | 2 |
想要使用keil5打开工程,需要电脑先安装 keil5编译环境,具体操作流程。
可以点击下方文章链接:Keil5编译环境搭建流程
typedef enum
{
HAL_OK = 0x00U, //成功
HAL_ERROR = 0x01U, //错误
HAL_BUSY = 0x02U, //忙碌
HAL_TIMEOUT = 0x03U //超时
} HAL_StatusTypeDef;
STM32CubeMX生成CAN通信工程程序后,还需要做以下配置,才能实现CAN收发功能。
(1)配置 CAN接收过滤器
(2)启动 CAN外围设备
(3)激活 CAN接收中断
//配置CAN接收过滤器
HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);
//开启CAN通讯
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);
//关闭CAN通讯
HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef *hcan);
//进入休眠模式
HAL_StatusTypeDef HAL_CAN_RequestSleep(CAN_HandleTypeDef *hcan);
//从休眠模式中唤醒
HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef *hcan);
//检查是否成功进入休眠模式
uint32_t HAL_CAN_IsSleepActive(CAN_HandleTypeDef *hcan);
//启动CAN中断函数
HAL_StatusTypeDef HAL_CAN_ActivateNotification(CAN_HandleTypeDef *hcan, uint32_t ActiveITs);
//禁用CAN中断函数
HAL_StatusTypeDef HAL_CAN_DeactivateNotification(CAN_HandleTypeDef *hcan, uint32_t InactiveITs);
//CAN中断处理函数
void HAL_CAN_IRQHandler(CAN_HandleTypeDef *hcan);
void User_CAN1_Init(void)
{
/*配置CAN过滤器*/
CAN_FilterTypeDef FilterConfig;
FilterConfig.FilterBank = 0; //过滤器组号
FilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //过滤模式:屏蔽位模式--CAN_FILTERMODE_IDMASK,列表模式--CAN_FILTERMODE_IDLIST
FilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽:32位
FilterConfig.FilterIdHigh = 0x0000; //32位ID
FilterConfig.FilterIdLow = 0x0000;
FilterConfig.FilterMaskIdHigh = 0x0000; //32位MASK
FilterConfig.FilterMaskIdLow = 0x0000;
FilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;//过滤器0关联到FIFO0
FilterConfig.FilterActivation = ENABLE; //激活滤波器0
FilterConfig.SlaveStartFilterBank = 14; //单CAN此参数无意义
//过滤器配置
if (HAL_CAN_ConfigFilter(&hcan1, &FilterConfig) != HAL_OK)
{
Error_Handler();
}
//启动CAN外围设备
if(HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
//激活CAN接收中断
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
}
//向 Tx 邮箱中增加一个消息,并且激活对应的传输请求
HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);
//请求发送中断传输
HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);
//获取空闲Tx邮箱的数量
uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan);
//检查是否有传输请求在指定的 Tx 邮箱上等待
uint32_t HAL_CAN_IsTxMessagePending(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);
//如果启用时间触发通信模式,则返回发送的Tx消息的时间戳。
uint32_t HAL_CAN_GetTxTimestamp(CAN_HandleTypeDef *hcan, uint32_t TxMailbox);
typedef struct
{
uint32_t StdId; //标准帧标识符(11位)---取值范围:0 ~ 0x7FF
uint32_t ExtId; //扩展帧标识符(29位)---取值范围:0 ~ 0x1FFFFFFF
uint32_t IDE; //标识符类型:标准帧 CAN_ID_STD,扩展帧 CAN_ID_EXT
uint32_t RTR; //帧类型:数据帧 CAN_RTR_DATA,远程帧 CAN_RTR_REMOTE
uint32_t DLC; //帧长度---取值范围:0 ~ 8
FunctionalState TransmitGlobalTime; //必须启用时间触发通信模式,指定是否在DATA6和DATA7中发送帧传输开始时捕获的时间戳计数器值,以替换pData[6]和pData[7]。
//DLC必须编程为8字节,以便发送这2个字节。此参数可设置为ENABLE(启用)或DISABLE(禁用)
} CAN_TxHeaderTypeDef;
void CAN1_TX_Data(void)
{
CAN_TxHeaderTypeDef TxHeader;
uint8_t TX_data[8]={0,0,0,0,0,0,0,0};
TxHeader.StdId = 0; //标准标识符(11位)
TxHeader.ExtId = 0x12345678; //扩展标识符(29位)
TxHeader.IDE = CAN_ID_EXT ; //扩展帧
TxHeader.RTR = CAN_RTR_DATA; //数据帧
TxHeader.DLC = 8; //数据个数
TxHeader.TransmitGlobalTime = DISABLE;
TX_data[0] = 0x11;
TX_data[1] = 0x22;
TX_data[2] = 0x33;
TX_data[3] = 0x44;
TX_data[4] = 0x55;
TX_data[5] = 0x66;
TX_data[6] = 0x77;
TX_data[7] = 0x88;
uint32_t TxMailbox;
HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TX_data, &TxMailbox);
}
//从Rx FIFO区域获取CAN帧到消息
HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);
//返回Rx FIFO填充水平
uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo);
//RX FIFO 0 消息回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);
typedef struct
{
uint32_t StdId; //标准帧标识符(11位)---取值范围:0 ~ 0x7FF
uint32_t ExtId; //扩展帧标识符(29位)---取值范围:0 ~ 0x1FFFFFFF
uint32_t IDE; //标识符类型:标准帧 CAN_ID_STD,扩展帧 CAN_ID_EXT
uint32_t RTR; //帧类型:数据帧 CAN_RTR_DATA,远程帧 CAN_RTR_REMOTE
uint32_t DLC; //帧长度---取值范围:0 ~ 8
uint32_t Timestamp; //必须启用时间触发通信模式才可用,指定帧接收开始时捕获的时间戳计数器值。
//取值范围:0 ~ 0xFFFF
uint32_t FilterMatchIndex; //指定匹配接收筛选器元素的索引---取值范围:0 ~ 0xFF
} CAN_RxHeaderTypeDef;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle)
{
CAN_RxHeaderTypeDef RxHeader;
uint8_t RX_data[8]={0,0,0,0,0,0,0,0};
if(HAL_CAN_GetRxMessage(CanHandle, CAN_RX_FIFO0, &RxHeader, RX_data) != HAL_OK)
{
Error_Handler();
}
/*
处理接收到的数据
*/
}