当前位置:   article > 正文

基于STM32F4的CAN通信例程(库函数版)_can_initstructure.can_rflm=disable;

can_initstructure.can_rflm=disable;

一、介绍

  实现STM32的CAN通信的时候,我们无需关注本身复杂的CAN通信协议许多细枝末节的东西已经被厂商封装起来,我们可以先让程序跑起来,再通过调整各个参数来熟悉STM32中的CAN通信的原理。

  实现CAN通信与实现SPI、I2C、串口等通信并无二致,都是先初始化引脚、片上外设、中断处理。然后在主函数中调用初始化,接着就可以当作通信使用,任何通信本质上都是接收receive)和发送(transmit).

  STM32中的CAN接收发送原型库函数。

  1. uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
  2. {
  3. uint8_t transmit_mailbox = 0;
  4. /* Check the parameters */
  5. assert_param(IS_CAN_ALL_PERIPH(CANx));
  6. assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
  7. assert_param(IS_CAN_RTR(TxMessage->RTR));
  8. assert_param(IS_CAN_DLC(TxMessage->DLC));
  9. /* Select one empty transmit mailbox */
  10. if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
  11. {
  12. transmit_mailbox = 0;
  13. }
  14. else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
  15. {
  16. transmit_mailbox = 1;
  17. }
  18. else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)
  19. {
  20. transmit_mailbox = 2;
  21. }
  22. else
  23. {
  24. transmit_mailbox = CAN_TxStatus_NoMailBox;
  25. }
  26. if (transmit_mailbox != CAN_TxStatus_NoMailBox)
  27. {
  28. /* Set up the Id */
  29. CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ;
  30. if (TxMessage->IDE == CAN_Id_Standard)
  31. {
  32. assert_param(IS_CAN_STDID(TxMessage->StdId));
  33. CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \
  34. TxMessage->RTR);
  35. }
  36. else
  37. {
  38. assert_param(IS_CAN_EXTID(TxMessage->ExtId));
  39. CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
  40. TxMessage->IDE | \
  41. TxMessage->RTR);
  42. }
  43. /* Set up the DLC */
  44. TxMessage->DLC &= (uint8_t)0x0000000F;
  45. CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;
  46. CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;
  47. /* Set up the data field */
  48. CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) |
  49. ((uint32_t)TxMessage->Data[2] << 16) |
  50. ((uint32_t)TxMessage->Data[1] << 8) |
  51. ((uint32_t)TxMessage->Data[0]));
  52. CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) |
  53. ((uint32_t)TxMessage->Data[6] << 16) |
  54. ((uint32_t)TxMessage->Data[5] << 8) |
  55. ((uint32_t)TxMessage->Data[4]));
  56. /* Request transmission */
  57. CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;
  58. }
  59. return transmit_mailbox;
  60. }
  1. void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
  2. {
  3. /* Check the parameters */
  4. assert_param(IS_CAN_ALL_PERIPH(CANx));
  5. assert_param(IS_CAN_FIFO(FIFONumber));
  6. /* Get the Id */
  7. RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;
  8. if (RxMessage->IDE == CAN_Id_Standard)
  9. {
  10. RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
  11. }
  12. else
  13. {
  14. RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);
  15. }
  16. RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;
  17. /* Get the DLC */
  18. RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;
  19. /* Get the FMI */
  20. RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);
  21. /* Get the data field */
  22. RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;
  23. RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);
  24. RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);
  25. RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);
  26. RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;
  27. RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);
  28. RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);
  29. RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);
  30. /* Release the FIFO */
  31. /* Release FIFO0 */
  32. if (FIFONumber == CAN_FIFO0)
  33. {
  34. CANx->RF0R |= CAN_RF0R_RFOM0;
  35. }
  36. /* Release FIFO1 */
  37. else /* FIFONumber == CAN_FIFO1 */
  38. {
  39. CANx->RF1R |= CAN_RF1R_RFOM1;
  40. }
  41. }

使用它们时就是初始化参数,赋值参数然后调用函数。将以上步骤封装为函数。

二、完整代码

can.h

  1. #ifndef __STM32_CAN_H_
  2. #define __STM32_CAN_H_
  3. #include "stm32f4xx.h"
  4. #define CAN_RX_INT_CONFIG 1 //配置CAN接收中断结构体
  5. void CanTransPort_Init(void);
  6. uint8_t sendMsgToCan(CanTxMsg *msg,uint8_t *data);//发送报文
  7. uint16_t CanRecMsg(uint8_t *msg); //接收报文
  8. #endif

 can.c

  1. #include "stm32_can.h"
  2. #include "usart.h"
  3. CanRxMsg rxMessage;
  4. CanTxMsg txMessage;
  5. void CanTransPort_Init(void)
  6. {
  7. GPIO_InitTypeDef GPIO_InitStructure; //GPIO物理接口
  8. CAN_InitTypeDef CAN_InitStructure; //CAN外设初始结构体 规定CAN通信速率 策略
  9. CAN_FilterInitTypeDef CAN_FilterInitStructure; //CAN过滤器结构体 用于控制收发报文
  10. #if CAN_RX_INT_CONFIG
  11. NVIC_InitTypeDef NVIC_InitStructure;
  12. #endif
  13. //PD0 RX PD1 TX
  14. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
  15. RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
  16. GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1);
  17. GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1);
  18. //Configure CAN1 TX
  19. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
  20. GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
  21. GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
  22. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
  23. GPIO_InitStructure.GPIO_Speed=GPIO_Fast_Speed;
  24. GPIO_Init(GPIOD,&GPIO_InitStructure);
  25. //Configure CAN1 RX
  26. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
  27. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
  28. GPIO_Init(GPIOD,&GPIO_InitStructure);
  29. //CAN外设初始化
  30. CAN_DeInit(CAN1);
  31. CAN_StructInit(&CAN_InitStructure);
  32. CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;
  33. CAN_InitStructure.CAN_ABOM=ENABLE; //自动离线管理
  34. CAN_InitStructure.CAN_AWUM=ENABLE; //自动唤醒
  35. //42MHZ / (1+4+2)/ 12 = 500kbps
  36. CAN_InitStructure.CAN_BS1=CAN_BS1_4tq;
  37. CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;
  38. CAN_InitStructure.CAN_SJW=CAN_SJW_2tq;
  39. CAN_InitStructure.CAN_Prescaler=12;
  40. CAN_InitStructure.CAN_RFLM=DISABLE; //锁定模式
  41. CAN_InitStructure.CAN_NART=DISABLE; //自动重传
  42. CAN_InitStructure.CAN_TTCM=DISABLE; //时间触发模式
  43. CAN_InitStructure.CAN_TXFP=DISABLE; //报文发送优先级判定方法
  44. CAN_Init(CAN1,&CAN_InitStructure);
  45. //CAN过滤器初始化
  46. CAN_FilterInitStructure.CAN_FilterNumber=0;
  47. CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  48. CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FilterFIFO0; //安装过滤器
  49. CAN_FilterInitStructure.CAN_FilterIdHigh=0x00000000;
  50. CAN_FilterInitStructure.CAN_FilterIdLow=0x0000000;
  51. CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
  52. CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //过滤器使能
  53. CAN_FilterInit(&CAN_FilterInitStructure);
  54. #if CAN_RX_INT_CONFIG
  55. NVIC_InitStructure.NVIC_IRQChannel=CAN1_RX0_IRQn;
  56. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;
  57. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
  58. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  59. NVIC_Init(&NVIC_InitStructure);
  60. CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
  61. #endif
  62. }
  63. uint8_t Can_ReceiveMsg(uint8_t *MsgBuffer)
  64. {
  65. uint32_t i;
  66. CanRxMsg rxMsg;
  67. if(CAN_MessagePending(CAN1,CAN_FIFO0) == 0 ) return 0;
  68. CAN_Receive(CAN1,CAN_FIFO0,&rxMsg);
  69. for(i=0;i<8;i++)
  70. MsgBuffer[i] = rxMsg.Data[i];
  71. return rxMsg.DLC;
  72. }
  73. #if CAN_RX_INT_CONFIG
  74. void CAN1_RX0_IRQHandler(void)
  75. {
  76. printf("enter CAN1_RX0_IRQHandler \r\n");
  77. // if(CAN_GetFlagStatus(CAN1,CAN_IT_FMP0) != RESET) //添加中断会发送程序会死循环在中断里
  78. // {
  79. CAN_Receive(CAN1,CAN_FIFO0,&rxMessage);
  80. printf("Data:%s\r\n",rxMessage.Data);
  81. printf("ExtId:%d\r\n",rxMessage.ExtId);
  82. // CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);
  83. // }
  84. printf("exti CAN1_RX0_IRQHandler \r\n");
  85. }
  86. #endif
  87. uint8_t sendMsgToCan(CanTxMsg *msg,uint8_t *data)
  88. {
  89. uint16_t i = 0;
  90. uint8_t mailBox;
  91. msg->ExtId=0x1e2c;
  92. msg->IDE=CAN_Id_Extended;
  93. msg->RTR=CAN_RTR_Data;
  94. msg->DLC=8;
  95. for(i = 0;i<8;i++)
  96. {
  97. msg->Data[i] = data[i];
  98. }
  99. i=0;
  100. mailBox = CAN_Transmit(CAN1,msg);
  101. while(CAN_TransmitStatus(CAN1,mailBox) !=CAN_TxStatus_Ok && i <= 2000)
  102. {
  103. i++;
  104. }
  105. if(i >= 2000)
  106. {
  107. return 1;
  108. }
  109. else
  110. return 0;
  111. }

在主函数中使用CAN通信

main.c

  1. #include "stm32f4xx.h"
  2. #include "usart.h"
  3. #include "delay.h"
  4. #include "stm32_can.h"
  5. extern CanRxMsg rxMessage;
  6. extern CanTxMsg txMessage;
  7. int main(void)
  8. {
  9. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  10. uint8_t txBuf[8];
  11. CanTransPort_Init();
  12. usart2_init(115200);
  13. delay_init(168);
  14. uint8_t i = 0;
  15. uint8_t cnt = 0;
  16. txBuf[0]=0x0e;
  17. txBuf[1]=0x1c;
  18. txBuf[2]=0xee;
  19. txBuf[3]=0xb0;
  20. txBuf[4]=0xe7;
  21. txBuf[5]=0xa1;
  22. txBuf[6]=0x99;
  23. txBuf[7]=0x35;
  24. USART2_printf("传输开始!\r\n");
  25. while(1)
  26. {
  27. // CanSendMsg(txBuf,8,0x00000000);
  28. sendMsgToCan(&txMessage,txBuf);
  29. txBuf[i]++;
  30. i++;
  31. if(i%8 == 0)
  32. {
  33. i = 0;
  34. cnt++;
  35. }
  36. if(cnt%4 == 0)
  37. {
  38. cnt = 0;
  39. for(i=0;i<8;i++)
  40. {
  41. txBuf[i]-=0x1F;
  42. }
  43. i=0;
  44. }
  45. delay_ms(2000);
  46. }
  47. }

三、实验设备:

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)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/512798
推荐阅读
相关标签
  

闽ICP备14008679号