? 实现STM32的CAN通信的时候,我们无需关注本身复杂的CAN通信协议许多细枝末节的东西已经被厂商封装起来,我们可以先让程序跑起来,再通过调整各个参数来熟悉STM32中的CAN通信的原理。
? 实现CAN通信与实现SPI、I2C、串口等通信并无二致,都是先初始化引脚、片上外设、中断处理。然后在主函数中调用初始化,接着就可以当作通信使用,任何通信本质上都是接收receive)和发送(transmit).
? STM32中的CAN接收发送原型库函数。
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
{
uint8_t transmit_mailbox = 0;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
assert_param(IS_CAN_RTR(TxMessage->RTR));
assert_param(IS_CAN_DLC(TxMessage->DLC));
/* Select one empty transmit mailbox */
if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
{
transmit_mailbox = 0;
}
else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
{
transmit_mailbox = 1;
}
else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)
{
transmit_mailbox = 2;
}
else
{
transmit_mailbox = CAN_TxStatus_NoMailBox;
}
if (transmit_mailbox != CAN_TxStatus_NoMailBox)
{
/* Set up the Id */
CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ;
if (TxMessage->IDE == CAN_Id_Standard)
{
assert_param(IS_CAN_STDID(TxMessage->StdId));
CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \
TxMessage->RTR);
}
else
{
assert_param(IS_CAN_EXTID(TxMessage->ExtId));
CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
TxMessage->IDE | \
TxMessage->RTR);
}
/* Set up the DLC */
TxMessage->DLC &= (uint8_t)0x0000000F;
CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;
CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;
/* Set up the data field */
CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) |
((uint32_t)TxMessage->Data[2] << 16) |
((uint32_t)TxMessage->Data[1] << 8) |
((uint32_t)TxMessage->Data[0]));
CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) |
((uint32_t)TxMessage->Data[6] << 16) |
((uint32_t)TxMessage->Data[5] << 8) |
((uint32_t)TxMessage->Data[4]));
/* Request transmission */
CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;
}
return transmit_mailbox;
}
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_FIFO(FIFONumber));
/* Get the Id */
RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;
if (RxMessage->IDE == CAN_Id_Standard)
{
RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
}
else
{
RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);
}
RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;
/* Get the DLC */
RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;
/* Get the FMI */
RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);
/* Get the data field */
RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;
RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);
RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);
RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);
RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;
RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);
RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);
RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);
/* Release the FIFO */
/* Release FIFO0 */
if (FIFONumber == CAN_FIFO0)
{
CANx->RF0R |= CAN_RF0R_RFOM0;
}
/* Release FIFO1 */
else /* FIFONumber == CAN_FIFO1 */
{
CANx->RF1R |= CAN_RF1R_RFOM1;
}
}
使用它们时就是初始化参数,赋值参数然后调用函数。将以上步骤封装为函数。
can.h
#ifndef __STM32_CAN_H_
#define __STM32_CAN_H_
#include "stm32f4xx.h"
#define CAN_RX_INT_CONFIG 1 //配置CAN接收中断结构体
void CanTransPort_Init(void);
uint8_t sendMsgToCan(CanTxMsg *msg,uint8_t *data);//发送报文
uint16_t CanRecMsg(uint8_t *msg); //接收报文
#endif
?can.c
#include "stm32_can.h"
#include "usart.h"
CanRxMsg rxMessage;
CanTxMsg txMessage;
void CanTransPort_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO物理接口
CAN_InitTypeDef CAN_InitStructure; //CAN外设初始结构体 规定CAN通信速率 策略
CAN_FilterInitTypeDef CAN_FilterInitStructure; //CAN过滤器结构体 用于控制收发报文
#if CAN_RX_INT_CONFIG
NVIC_InitTypeDef NVIC_InitStructure;
#endif
//PD0 RX PD1 TX
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1);
//Configure CAN1 TX
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed=GPIO_Fast_Speed;
GPIO_Init(GPIOD,&GPIO_InitStructure);
//Configure CAN1 RX
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_Init(GPIOD,&GPIO_InitStructure);
//CAN外设初始化
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;
CAN_InitStructure.CAN_ABOM=ENABLE; //自动离线管理
CAN_InitStructure.CAN_AWUM=ENABLE; //自动唤醒
//42MHZ / (1+4+2)/ 12 = 500kbps
CAN_InitStructure.CAN_BS1=CAN_BS1_4tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;
CAN_InitStructure.CAN_SJW=CAN_SJW_2tq;
CAN_InitStructure.CAN_Prescaler=12;
CAN_InitStructure.CAN_RFLM=DISABLE; //锁定模式
CAN_InitStructure.CAN_NART=DISABLE; //自动重传
CAN_InitStructure.CAN_TTCM=DISABLE; //时间触发模式
CAN_InitStructure.CAN_TXFP=DISABLE; //报文发送优先级判定方法
CAN_Init(CAN1,&CAN_InitStructure);
//CAN过滤器初始化
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FilterFIFO0; //安装过滤器
CAN_FilterInitStructure.CAN_FilterIdHigh=0x00000000;
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000000;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //过滤器使能
CAN_FilterInit(&CAN_FilterInitStructure);
#if CAN_RX_INT_CONFIG
NVIC_InitStructure.NVIC_IRQChannel=CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
#endif
}
uint8_t Can_ReceiveMsg(uint8_t *MsgBuffer)
{
uint32_t i;
CanRxMsg rxMsg;
if(CAN_MessagePending(CAN1,CAN_FIFO0) == 0 ) return 0;
CAN_Receive(CAN1,CAN_FIFO0,&rxMsg);
for(i=0;i<8;i++)
MsgBuffer[i] = rxMsg.Data[i];
return rxMsg.DLC;
}
#if CAN_RX_INT_CONFIG
void CAN1_RX0_IRQHandler(void)
{
printf("enter CAN1_RX0_IRQHandler \r\n");
// if(CAN_GetFlagStatus(CAN1,CAN_IT_FMP0) != RESET) //添加中断会发送程序会死循环在中断里
// {
CAN_Receive(CAN1,CAN_FIFO0,&rxMessage);
printf("Data:%s\r\n",rxMessage.Data);
printf("ExtId:%d\r\n",rxMessage.ExtId);
// CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
// }
printf("exti CAN1_RX0_IRQHandler \r\n");
}
#endif
uint8_t sendMsgToCan(CanTxMsg *msg,uint8_t *data)
{
uint16_t i = 0;
uint8_t mailBox;
msg->ExtId=0x1e2c;
msg->IDE=CAN_Id_Extended;
msg->RTR=CAN_RTR_Data;
msg->DLC=8;
for(i = 0;i<8;i++)
{
msg->Data[i] = data[i];
}
i=0;
mailBox = CAN_Transmit(CAN1,msg);
while(CAN_TransmitStatus(CAN1,mailBox) !=CAN_TxStatus_Ok && i <= 2000)
{
i++;
}
if(i >= 2000)
{
return 1;
}
else
return 0;
}
在主函数中使用CAN通信
main.c
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stm32_can.h"
extern CanRxMsg rxMessage;
extern CanTxMsg txMessage;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uint8_t txBuf[8];
CanTransPort_Init();
usart2_init(115200);
delay_init(168);
uint8_t i = 0;
uint8_t cnt = 0;
txBuf[0]=0x0e;
txBuf[1]=0x1c;
txBuf[2]=0xee;
txBuf[3]=0xb0;
txBuf[4]=0xe7;
txBuf[5]=0xa1;
txBuf[6]=0x99;
txBuf[7]=0x35;
USART2_printf("传输开始!\r\n");
while(1)
{
// CanSendMsg(txBuf,8,0x00000000);
sendMsgToCan(&txMessage,txBuf);
txBuf[i]++;
i++;
if(i%8 == 0)
{
i = 0;
cnt++;
}
if(cnt%4 == 0)
{
cnt = 0;
for(i=0;i<8;i++)
{
txBuf[i]-=0x1F;
}
i=0;
}
delay_ms(2000);
}
}
usart 转 CAN USB模块
STM32 F407
can硬件电路
查阅Ascii码表?
发送:?48 65 6C 6C 6F 43 61 6E?
对应: H? e? ? ?l? ? l? ? ?o? ?C? ?a? n
实验现象:
上位机
串口接收
ZzlYang/STM32F4_CAN_Example: STM32F407 can example with usart_can model (github.com)