赞
踩
实现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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。