[STM32L5] 怎样用STM32CAN总线接口发送和接收数据

[复制链接]
5044|90
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:07 | 显示全部楼层
通过配置位时序寄存器CAN_BTR的TS1[3:0]及TS2[2:0]寄存器位设定BS1及BS2段的长度后,就可以确定每个CAN数据位的时间:
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:08 | 显示全部楼层
BS1段时间:
T S1 =Tq x (TS1[3:0] + 1),
BS2段时间:
T S2 = Tq x (TS2[2:0] + 1),
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:15 | 显示全部楼层
一个数据位的时间:
T 1bit =1Tq+T S1 +T S2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)= N Tq
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:15 | 显示全部楼层
其中单个时间片的长度Tq与CAN外设的所挂载的时钟总线及分频器配置有关,CAN1和CAN2外设都是挂载在APB1总线上的,而位时序寄存器CAN_BTR中的BRP[9:0]寄存器位可以设置CAN外设时钟的分频值 ,所以:
Tq = (BRP[9:0]+1) x T PCLK
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:18 | 显示全部楼层
其中的PCLK指APB1时钟,默认值为36MHz。最终可以计算出CAN通讯的波特率:
BaudRate = 1/N Tq
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:18 | 显示全部楼层
程序设计要点中强调的三个重要参数,其实是can总线物理层中所要求的位时序。共三个阶段,分别为SJW,BS1和BS2阶段,这三个阶段的时间长度都是以长度为tq的时间单元为单位的。这样可以逐步计算出CAN总线的波特率。因此要点提示中所要求的参数,实际上将CAN的波特率设置为450kdps。
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:19 | 显示全部楼层
过滤器的设置

can总线没有所谓地址的概念。总线上的每个报文都可以被各个节点接收。这是一种典型的广播式网络。在实际应用中。某个节点往往只希望接收到特定类型的数据, 这就要借助过滤器来实现。顾名思义,过滤器的作用就是把节点不希望接收到的数据过滤掉。只将希望接收到的数据给予通行。stm32的CAN控制器,提供14个过滤器。可以设置为屏蔽模式和列表模式对can总线上的报文进行过滤。当节点希望接收到一种报文时。可以用屏蔽位模式对can总线上的报文进行过滤。反之,当节点希望接受到单一类型报文时。则应该配置为列表模式。本机程序中使用了32位的屏蔽位模式。下面仅对这种模式进行解析。can控制器的每个过滤器都具备一个寄存器。称为屏蔽寄存器。其中标识符寄存器的每一位都有屏蔽寄存器的每一位所对应。事实上,这也对应着can数据。事实上,这也对应着看标准数据帧中的标识符段。如下图所示。
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:20 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:20 | 显示全部楼层
此处重点在于屏蔽寄存器的作用。通过查阅stm32微控制器参考文档可以知道。当过滤器工作在屏蔽模式下时。屏蔽寄存器被置为1的每一位都要求can接收到的数据帧标识符段必须和对应的接收缓冲区标识位相同。否则予以滤除。以本程序为例。要点中要求将节点接收缓冲标识符配置为0x00AA0000。过滤器屏蔽标识符为0x00FF0000。
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:21 | 显示全部楼层
该节点接收到的数据帧的标识符段的位[23:16],必须和接收缓冲区标识符中的[23:16]匹配。否则予以滤除。但若满足了这一条件而即便如下的位不匹配。则该数据帧仍不会被滤除。正如本程序而言。即can接口仅仅接收标识符段的位[23:16]为0xAA的数据帧.

 楼主| 花间一壶酒sd 发表于 2021-10-26 22:22 | 显示全部楼层
根据can总线物理层的要求。can总线的波特率和传输距离成反比关系。传输距离变化时,要根据位时序来调整can总线的波特率。
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:24 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-10-26 22:27 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-10-26 23:05 | 显示全部楼层
程序代码如下:
  1. void RCC_Config(void)
  2. {
  3.        
  4.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE)

  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE)

  6. }
  7. void GPIO_for_can_and_uart_Config(void)
  8. {               
  9.                 /*定义一个GPIO_InitTypeDef类型的结构体*/
  10.                 GPIO_InitTypeDef GPIO_InitStructure;

  11.                
  12.                 /*设置can的RX--pa.11引脚*/
  13.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;       
  14.                
  15.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   
  16.                
  17.                 GPIO_Init(GPIOA, &GPIO_InitStructure);       
  18.                
  19.                 /*设置can的TX--pa.12引脚*/
  20.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  21.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  22.                 GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
  23.                 GPIO_Init(GPIOA, &GPIO_InitStructure);
  24.                 /*设置usart1 的RX 脚 -PA.10为父浮空输入脚*/
  25.                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;       
  26.                
  27.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
  28.                
  29.                 GPIO_Init(GPIOA, &GPIO_InitStructure);

  30.                
  31.                
  32.                
  33. }

  34. void Can_Config(void)
  35. {
  36.         CAN_InitTypeDef          CAN_InitStructure;
  37.         CAN_FilterInitTypeDef         CAN_FilterInitStructure;

  38.         CAN_DeInit(CAN1);

  39.         CAN_StructInit(&CAN_InitStructure);
  40.         CAN_InitStructure.CAN_TTCM=DISABLE;
  41.         CAN_InitStructure.CAN_ABOM=DISABLE;
  42.         CAN_InitStructure.CAN_AWUM=DISABLE;
  43.         CAN_InitStructure.CAN_NART=DISABLE;
  44.         CAN_InitStructure.CAN_RFIM=DISABLE;
  45.         CAN_InitStructure.CAN_TXFP=DISABLE;

  46.         CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;
  47.         CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  48.         CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
  49.         CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;

  50.         CAN_InitStructure.CAN_Prescaler=5;
  51.         CAN_Init(CAN1,&CAN_InitStructure);

  52.         CAN_FilterInitStructure.CAN_FilterNumber=0;
  53.         CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  54.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
  55.         CAN_FilterInitStructure.CAN_FilterIdHigh=0x00AA<<3;
  56.         CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  57.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x00FF<<3;
  58.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  59.         CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;
  60.         CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  61.         CAN_FilterInit(&CAN_FilterInitStructure);

  62. }

  63. void main(void)
  64. {
  65.         u8 TransmitMailbox=0;
  66.         CanTxMsg   TxMessage;
  67.         CanRxMsg   RxMessage;
  68.         RCC_Config();
  69.         GPIO_for_can_and_uart_Config();
  70.         USART_Config();
  71.         Can_Config();

  72.         TxMessage.ExtId=0x00aa0000;
  73.         TxMessage.RTR=CAN_RTR_Data;
  74.         TxMessage.IDE=CAN_ID_EXT;
  75.         TxMessage.DLC=8;
  76.         TxMessage.Data[0]=0x00;
  77.         TxMessage.Data[1]=0x12;
  78.         TxMessage.Data[2]=0x34;
  79.         TxMessage.Data[3]=0x56;
  80.         TxMessage.Data[4]=0x78;
  81.         TxMessage.Data[5]=0xab;
  82.         TxMessage.Data[6]=0xcd;
  83.         TxMessage.Data[7]=0xef;

  84.         TransmitMailbox=CAN_Transmit(CAN1,&TxMessage);
  85.         while((CAN_TransmitStatus(CAN1,TransmitMailbox))!=CANTXOK);
  86.         printf("\r\nThe CAN has send data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,\r\n",
  87.                 TxMessage.Data[0],TxMessage.Data[1],TxMessage.Data[2],TxMessage.Data[3],
  88.                 TxMessage.Data[4],TxMessage.Data[5],TxMessage.Data[6],TxMessage.Data[7],);

  89.         while((CAN_MessagePending(CAN1,CAN_FIFO0)==0));
  90.        
  91.         RxMessage.StdId=0x00;
  92.         RxMessage.IDE=CAN_ID_EXT;
  93.         RxMessage.DLC=0;
  94.         RxMessage.Data[0]=0x00;
  95.         RxMessage.Data[1]=0x12;
  96.         RxMessage.Data[2]=0x34;
  97.         RxMessage.Data[3]=0x56;
  98.         RxMessage.Data[4]=0x78;
  99.         RxMessage.Data[5]=0xab;
  100.         RxMessage.Data[6]=0xcd;
  101.         RxMessage.Data[7]=0xef;

  102.         CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);
  103.         printf("\r\nThe CAN has received data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,\r\n",
  104.                 RxMessage.Data[0],RxMessage.Data[1],RxMessage.Data[2],RxMessage.Data[3],
  105.                 RxMessage.Data[4],RxMessage.Data[5],RxMessage.Data[6],RxMessage.Data[7],);
  106.         while(1);


  107. }
wiba 发表于 2021-11-8 13:12 | 显示全部楼层
我都是外挂一片can芯片
zljiu 发表于 2021-11-8 14:30 | 显示全部楼层
出现总线错误会报错 吗
tfqi 发表于 2021-11-8 14:44 | 显示全部楼层
节点数增加 功率就需要增加吧
qcliu 发表于 2021-11-8 15:02 | 显示全部楼层
主要就是调试的过程很坎坷
nawu 发表于 2021-11-8 15:05 | 显示全部楼层
替代远程请求位的作用是什么呢
dongnanxibei 发表于 2022-6-27 13:15 | 显示全部楼层
当CAN节点需要发送数据时,控制器把要发送的二进制编码通过CAN_Tx线发送到收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部