STM32 CAN总线通信详解
CAN总线是一种常用的实时通信协议,用于在微控制器之间进行可靠的数据传输。在本文中,我们将介绍STM32微控制器上CAN总线通信的基本原理,并提供一些代码示例来帮助您理解和实现CAN总线通信。
第一部分:CAN总线基础知识
-
CAN总线概述 CAN(Controller Area Network)总线是一种串行通信协议,最初由德国公司Bosch开发用于汽车电子系统。CAN总线特点包括高可靠性、实时性、抗干扰能力强等。它广泛应用于汽车、工业控制、航空航天等领域。
-
CAN总线结构 CAN总线由两根差分信号线CAN_H和CAN_L组成。CAN_H和CAN_L的电位差表示逻辑0或逻辑1。CAN总线可以支持多个节点,每个节点可以作为发送器和接收器。
-
CAN帧格式 CAN总线的数据传输单位是帧(Frame)。CAN总线的帧包括数据帧(Data Frame)和远程帧(Remote Frame)。数据帧用于实际数据传输,而远程帧用于请求远程节点发送数据。
-
CAN标识符 每个CAN帧都有一个唯一的标识符(Identifier)。标识符可以是11位或29位长,用于标识不同的帧。标识符可以用于过滤和识别帧。
第二部分:STM32上的CAN总线通信
在STM32微控制器上,CAN总线通信需要使用CAN控制器和CAN引脚。STM32提供了多个CAN控制器和相应的引脚,可以与其他设备进行CAN通信。
以下是一个简单的CAN总线通信示例,演示了如何在两个STM32微控制器之间进行数据的发送和接收。
发送端代码:
#include "stm32f4xx.h"
CAN_TypeDef* CANx = CAN1;
void CAN_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
// 启用CAN1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// 启用GPIOB时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
// 配置CAN1引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 将CAN引脚配置为CAN功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_CAN1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_CAN1);
// CAN配置
CAN_DeInit(CANx);
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_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
CAN_InitStructure.CAN_Prescaler = 5;
CAN_Init(CANx, &CAN_InitStructure);
// CAN过滤器配置
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 = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
// 启用CAN1发送邮箱0中断
CAN_ITConfig(CANx, CAN_IT_TME, ENABLE);
}
void CAN_SendData(uint8_t data)
{
CAN_TxMailBox_TypeDef *mailbox;
uint8_t mailbox_number = 0;
mailbox = CANx->sTxMailBox;
// 等待CAN发送邮箱空闲
while(!(mailbox->TIR & CAN_TI0R_TXRQ));
// 设置发送数据
mailbox->TDLR = data;
mailbox->TDTR = 1;
// 设置标识符
mailbox->TIR = (0x123 << 21) | CAN_TI0R_TXRQ;
}
int main(void)
{
// 初始化CAN总线
CAN_Configuration();
while(1)
{
// 发送数据
CAN_SendData(0xAA);
// 延时
for(int i = 0; i < 1000000; i++);
}
}
接收端代码:
#include "stm32f4xx.h"
CAN_TypeDef* CANx = CAN1;
void CAN_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
// 启用CAN1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
// 启用GPIOB时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
// 配置CAN1引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 将CAN引脚配置为CAN功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_CAN1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_CAN1);
// CAN配置
CAN_DeInit(CANx);
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_6tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;
CAN_InitStructure.CAN_Prescaler = 5;
CAN_Init(CANx, &CAN_InitStructure);
// CAN过滤器配置
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 = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
// 启用CAN1接收邮箱0中断
CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);
}
void CAN_ReceiveData(void)
{
CAN_FIFOMailBox_TypeDef* mailbox;
mailbox = CANx->sFIFOMailBox[0];
// 接收到数据
if((mailbox->RIR & CAN_RI0R_RTR) == 0 && (mailbox->RIR & CAN_RI0R_IDE) == 0
作者:大黄鸭duck.