CAN_FilterTypeDef sFilterConfig;
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 = 0;
if (HAL\_CAN\_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) {
// 错误处理
}
- 启动CAN:
if (HAL\_CAN\_Start(&hcan) != HAL_OK) {
// 错误处理
}
- 发送和接收数据:
if (HAL\_CAN\_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) != HAL_OK) {
// 错误处理
}
if (HAL\_CAN\_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) {
// 错误处理
}
6.3 实现的整体代码
// 包含所需的头文件
#include "stm32f4xx\_hal.h"
// CAN消息结构体
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint8\_t TxData[8];
uint8\_t RxData[8];
void CAN\_Configuration(void)
{
// 初始化CAN控制器
hcan.Instance = CAN1;
hcan.Init.Prescaler = 10;
hcan.Init.Mode = CAN_MODE_NORMAL;
hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan.Init.TimeSeg1 = CAN_BS1_8TQ;
hcan.Init.TimeSeg2 = CAN_BS2_7TQ;
hcan.Init.TimeTriggeredMode = DISABLE;
hcan.Init.AutoBusOff = ENABLE;
hcan.Init.AutoWakeUp = DISABLE;
hcan.Init.AutoRetransmission = ENABLE;
hcan.Init.ReceiveFifoLocked = DISABLE;
HAL\_CAN\_Init(&hcan);
// 配置CAN过滤器
CAN_FilterTypeDef sFilterConfig;
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.Filter
继续
MaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
HAL\_CAN\_ConfigFilter(&hcan, &sFilterConfig);
// 启动CAN通信
HAL\_CAN\_Start(&hcan);
// 配置CAN消息头
TxHeader.StdId = 0x123;
TxHeader.ExtId = 0x00;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.IDE = CAN_ID_STD;
TxHeader.DLC = 8;
TxHeader.TransmitGlobalTime = DISABLE;
}
void CAN\_SendData(uint8\_t\* data, uint32\_t length)
{
// 填充发送消息的数据
for (uint8\_t i = 0; i < length; i++) {
TxData[i] = data[i];
}
// 发送消息
if (HAL\_CAN\_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) == HAL_OK) {
HAL\_CAN\_Transmit(&hcan, 100);
}
}
void CAN\_ReceiveData(void)
{
// 接收消息
if (HAL\_CAN\_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) > 0) {
if (HAL\_CAN\_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
// 处理接收到的数据
// …
}
}
}
int main(void)
{
// 初始化HAL库和其他外设
// 配置CAN通信
CAN\_Configuration();
while (1) {
// 发送数据
uint8\_t sendData[] = {0x01, 0x02, 0x03};
CAN\_SendData(sendData, sizeof(sendData));
// 接收数据
CAN\_ReceiveData();
}
}
以上示例代码演示了一个简单的CAN发送和接收流程。首先,在CAN_Configuration
函数中,配置CAN控制器和过滤器。然后,在主函数中,使用CAN_SendData
函数发送数据,使用CAN_ReceiveData
函数接收数据。
此外,为了调试和监测CAN通信,HAL库提供了一些有用的函数和工具。例如,可以使用HAL_CAN_GetState()
函数获取CAN控制器的当前状态,包括初始化、准备就绪、发送中、传输完成等。还可以使用HAL_CAN_GetErrorCounter()
函数获取错误计数器的值,以及使用HAL_CAN_GetRxMessage()
函数获取接收到的CAN帧的相关信息。
7. 使用标准库实现CAN通信
除了HAL库,还可以使用标准库进行CAN通信的实现。标准库相对较底层,需要直接操作寄存器和位操作来配置和控制CAN控制器。
与HAL库类似,使用标准库进行CAN通信需要进行CAN总线的初始化、过滤器的配置、数据的发送和接收等操作。不同之处在于,需要直接操作寄存器来完成这些任务。
7.1 实现步骤
- 配置GPIO端口和引脚,用于连接CAN总线。
- 配置CAN控制器的工作模式、波特率、位定时参数等。
- 配置CAN过滤器,设置过滤器的标识符、执行类型等。
- 使用CAN发送函数将数据发送到总线上。
- 使用CAN接收函数接收来自其他节点的数据。
7.2 步骤的代码实现
当使用标准库实现STM32的CAN通信时,需要按照以下步骤进行配置和操作:
- 配置CAN1时钟:
RCC\_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
- 初始化CAN1:
CAN_InitTypeDef CAN_InitStructure;
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler = 10;
CAN\_Init(CAN1, &CAN_InitStructure);
- 配置CAN过滤器:
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN\_FilterInit(&CAN_FilterInitStructure);
- 使能CAN1接收中断:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC\_Init(&NVIC_InitStructure);
CAN\_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
- 实现CAN1接收中断处理函数:
void CAN1\_RX0\_IRQHandler(void) {
if (CAN\_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
CAN\_Receive(CAN1, CAN_FIFO0, &RxMessage);
// 处理接收到的消息
}
}
- 编写CAN发送函数:
void CAN\_SendData(uint8\_t\* data, uint8\_t length) {
// 填充发送消息的数据
for (uint8\_t i = 0; i < length; i++) {
TxMessage.Data[i] = data[i];
}
// 设置发送消息的参数
TxMessage.StdId = 0x123;
TxMessage.ExtId = 0x00;
TxMessage.IDE = CAN_Id_Standard;
TxMessage.RTR = CAN_RTR_DATA;
TxMessage.DLC = length;
// 发送消息
uint8\_t mailbox;
CAN\_Transmit(CAN1, &TxMessage);
}
- 在主函数中调用相关函数:
int main(void) {
// 初始化CAN配置
CAN\_Configuration();
while ((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {
// 等待CAN1退出初始化模式
}
while (1) {
// 发送数据
uint8\_t sendData[] = {0x01, 0x02, 0x03};
CAN\_SendData(sendData, sizeof(sendData));
// 延时一段时间
for (volatile uint32\_t i = 0; i < 1000000; i++) {}
}
}
7.3 实现的整体代码
#include "stm32f4xx.h"
// CAN消息结构体
CanTxMsgTypeDef TxMessage;
CanRxMsgTypeDef RxMessage;
void CAN\_Configuration(void) {
// 使能CAN1时钟
RCC\_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// CAN1初始化
CAN_InitTypeDef CAN_InitStructure;
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler = 10;
CAN\_Init(CAN1, &CAN_InitStructure);
// CAN过滤器配置
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN\_FilterInit(&CAN_FilterInitStructure);
// CAN接收中断使能
CAN\_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
// 使能CAN1
CAN\_Cmd(CAN1, ENABLE);
// NVIC中断配置
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC\_Init(&NVIC_InitStructure);
}
void CAN\_SendData(uint8\_t\* data, uint8\_t length) {
// 填充发送消息的数据
for (uint8\_t i = 0; i < length; i++) {
TxMessage.Data[i] = data[i];
}
// 设置发送消息的参数
TxMessage.StdId = 0x123;
TxMessage.ExtId = 0x00;
TxMessage.IDE = CAN_Id_Standard;
TxMessage.RTR = CAN_RTR_DATA;
TxMessage.DLC = length;
// 发送消息
uint8\_t transmissionMailbox = 0;
CAN\_Transmit(CAN1, &TxMessage);
}
void CAN1\_RX0\_IRQHandler(void) {
if (CAN\_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
// 接收到消息
CAN\_Receive(CAN1, CAN_FIFO0, &RxMessage);
// 处理接收到的消息
// ...
}
}
int main(void) {
// 初始化CAN配置
CAN\_Configuration();
while ((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {
// 等待CAN1退出初始化模式
}
while (1) {
// 发送数据
uint8\_t sendData[] = {0x01, 0x02, 0x03};
CAN\_SendData(sendData, sizeof(sendData));
// 延时一段时间
for (volatile uint32\_t i = 0; i < 1000000; i++) {}
}
}
8. CAN通信实际案例分析
在汽车电控系统中,CAN通信被广泛应用于各个控制单元之间的数据传输。例如,在引擎控制单元(ECU)中,通过CAN总线与刹车系统的控制单元、仪表盘的控制单元进行通信。引擎控制单元可以向刹车系统发送刹车指令,同时获取仪表盘上的车速和引擎转速等信息。
在工业控制系统中,CAN通信常用于连接不同的设备和传感器,以实现实时数据交换和协调工作。例如,在机器人系统中,通过CAN总线连接各个关节控制器和传感器,实现机器人的协调运动和数据传输。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!
29146897)]
[外链图片转存中…(img-8P9yCS0S-1715629146897)]
[外链图片转存中…(img-OKVKAkqu-1715629146898)]
[外链图片转存中…(img-fMhYAJov-1715629146898)]
[外链图片转存中…(img-zjy7ht76-1715629146899)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!