19. STM32-CAN-BUS (下)

结构体介绍

  • CAN_FilterTypeDef
typedef struct
{
  uint32_t FilterIdHigh;        
  uint32_t FilterIdLow;          
  uint32_t FilterMaskIdHigh;      
  uint32_t FilterMaskIdLow;      
  uint32_t FilterFIFOAssignment;  
  uint32_t FilterBank;           
  uint32_t FilterMode;           
  uint32_t FilterScale;          
  uint32_t FilterActivation;     
  uint32_t SlaveStartFilterBank;  
} CAN_FilterTypeDef;

FilterIdHigh : 16bit 用来放STDID

FilterIdLow : 16 bit 用来放EXTID

FilterMaskIdHigh : 依模式选择 Mask 1 需比对 0不比对 LIST模式下设置第二组ID

FilterMaskIdLow : 依模式选择 Mask 1 需比对 0不比对 LIST模式下设置第二组ID

FilterFIFOAssignment : 选择相关联的FIFO编号 假设使用RX0 就填入 CAN_RX_FIFO0

FilterBank : 滤波器编组 根据板子不同可分为 0-13 or 0-27 (我这块板子只有14个也就是0-13)

FilterMode : Filter模式选择 有两种 LIST 跟MASK

FilterScale : 选择Filter位宽 分为16与32bit (CAN_FILTERSCALE_32BIT , CAN_FILTERSCALE_16BIT)

FilterActivation : 启用Filter (CAN_FILTER_ENABLE)

SlaveStartFilterBank : 只有在双CAN的板子上有用

  • CAN_TxHeaderTypeDef
typedef struct
{
  uint32_t StdId;    
  uint32_t ExtId;    
  uint32_t IDE;      
  uint32_t RTR;      
  uint32_t DLC;     
  FunctionalState TransmitGlobalTime;
} CAN_TxHeaderTypeDef;

StdId : 标准模式ID (11 bit)

ExtId : 扩展模式ID (32 bit)

IDE : 表示是扩展还标准(CAN_ID_STD , CAN_ID_EXT)

RTR : 表示是资料讯息还是远端请求 (CAN_RTR_DATA , CAN_RTR_REMOTE)

DLC : 表示传送资料长度 0-8 bytes

TransmitGlobalTime : 指定是否在传输开始时捕获时间戳计数器当中的值,透过DATA6 和 DATA7发送,也就是会替换 pData[6] 和 pData[7]。(ENABLE , DISABLE) 需要开启时间捕获模式

  • CAN_RxHeaderTypeDef
typedef struct
{
  uint32_t StdId;   
  uint32_t ExtId;   
  uint32_t IDE;    
  uint32_t RTR;      
  uint32_t DLC;      
  uint32_t Timestamp; 
  uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;

StdId : 标准模式ID (11 bit)

ExtId : 扩展模式ID (32 bit)

IDE : 表示是扩展还标准(CAN_ID_STD , CAN_ID_EXT)

RTR : 表示是资料讯息还是远端请求 (CAN_RTR_DATA , CAN_RTR_REMOTE)

DLC : 表示传送资料长度 0-8 bytes

Timestamp : 指定在讯息接收开始时捕获的时间戳计数器当中的值。 需要开启时间捕获模式

FilterMatchIndex : 指定配对哪一个Filter元素的Index


Filter设定说明

只有在CAN接收时会需要设置到Filter

接着来看看手册当中的Filter说明
https://ithelp.ithome.com.tw/upload/images/20220327/20146325HKl44iHRqy.png
这一段说明的其实就是CAN2.0A与CAN2.0B的Arbitration Field

  • 一个32bit的Filter,可以看到在CAN2.0B当中STDID的确有10个bit,EXTID有17个bit而剩余的就是IDE与RTR共 32bit,所以32位元的可以实现对标准与扩展的讯息过滤
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325zKyc47Vb0o.png
  • 两个16bit的Filter,包含了CAN2.0A当中的11个STDID、1个IDE、1个RTR与3个EXTID,只能实现对标准模式的讯息过滤。
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325CtOtqSEOxz.png

Filter模式

  • IDMASK : 当设置为1则会去比对所接收到的ID与Register当中的ID相不相符,0则不比对。像下方这张图来说红色的部分就是会比对的ID位置必须与暂存器当中相同才可以通过。
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325UB39qM9Dvu.png
    以32bit来看最多只能写入一组ID去过滤而已
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325qLtlsPXpHw.png
    以16bit来看最多可写入两组ID,但只能识别标准模式下的ID
    https://ithelp.ithome.com.tw/upload/images/20220327/2014632523jjYgbMy7.png
  • IDLIST : 所接收到的讯息当中ID必须与Filter Register当中所有的bit相同才会接收,只要有任何一个不相同则不接收
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325eyPkKBvCr2.png
    以32位元来看因为是IDLIST模式,可以设置两种ID来进行过滤
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325iT2AL6FvNN.png
    以16位元来看最多可设置四种ID来进行过滤
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325qIouE0rlDA.png

程序码范例

全域变数宣告

uint8_t send_data[8] = {0,1,2,3,4,5,6,7}; //传送的资料
uint8_t rece_data[8]; //接收的Buffer 
CAN_TxHeaderTypeDef TxHeader; 
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox;

使用RX中断去接收讯息

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, rece_data);
}
  • CAN2.0A 标准模式且Filter选为Mask
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
	TxHeader.DLC =8;
  TxHeader.ExtId = 0;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.StdId = 0x105;
  TxHeader.TransmitGlobalTime = DISABLE;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = 0x105<<5;
	CAN1Filter.FilterIdLow = 0x0000;
	CAN1Filter.FilterMaskIdHigh = 0x1111;
	CAN1Filter.FilterMaskIdLow = 0x1111;
	CAN1Filter.SlaveStartFilterBank = 0;

	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325jag8SQOFoD.png
经过逻辑分析仪後测试ID为105,这边是将Filter设定为Mask模式,且将MASKID都设置为1需要检验所接收到了ID是否与暂存器中ID相同。

  • CAN2.0A 标准模式且Filter选为IDLIST
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<2 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0;
	  TxHeader.IDE = CAN_ID_STD;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.StdId = 0x103+x;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = 0x103<<5;  //第一组可通过的ID
	CAN1Filter.FilterIdLow = 0x0000;
	CAN1Filter.FilterMaskIdHigh = 0x104<<5; //第二组可通过的ID
	CAN1Filter.FilterMaskIdLow = 0x0000;
	CAN1Filter.SlaveStartFilterBank = 0;
}

https://ithelp.ithome.com.tw/upload/images/20220327/201463251VTKYoBRu3.png
可以看到使用逻辑分析仪後的测试结果,在ID为103与104时可通过Filter成功接收回来。

上方左移五位的原因是为了对齐32bit的高位,STDID为11位需要左移才能对齐。

  • CAN2.0B 扩展模式且Filter选为Mask
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  TxHeader.DLC =8;
  TxHeader.IDE = CAN_ID_EXT;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.ExtId = 0x1234ABCD;
  TxHeader.TransmitGlobalTime = DISABLE;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterMaskIdHigh = 0;
	CAN1Filter.FilterMaskIdLow = 0;
	CAN1Filter.SlaveStartFilterBank = 0;
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325brNZ10mZVl.png

  • CAN2.0B 扩展模式且Filter选为IDLIST
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<2 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0x1234ABCD+x;
	  TxHeader.IDE = CAN_ID_EXT;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCE<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.SlaveStartFilterBank = 0;
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325GJWwubqh7Y.png
上图可以看到对应的ID为0x1234ABCD与0x1234ABCE,Filter为LIST模式而32位宽的Filter当中可以设置两组EXTID来过滤。

  • 当有好几组需要通过Filter时
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<4 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0x1234ABCD+x;
	  TxHeader.IDE = CAN_ID_EXT;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCE<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.SlaveStartFilterBank = 0;

	CAN_FilterTypeDef CAN1Filter1;
	CAN1Filter1.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter1.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter1.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter1.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter1.FilterBank = 1;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCF<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABD0<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter1.SlaveStartFilterBank = 0;

	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter1);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325V9gQop4fTn.png
当有好几组需要设置的时候,这时候就可以使用编组来设置其余的过滤器ID,这边设置了编组0与编组1的ID。


<<:  Organizing Data

>>:  CLI名词解释

D3 - 今天点个 String Methods 套餐

前言 今天来讲讲 String Methods,你知道其实除了length 以外,String 还内...

[Day 30] 使用ChromeDriver来做单元测试(三)

同时开启多个浏览器 有时候可能需要多个浏览器来进行测试, 譬如说用多个浏览器来测试WebSocket...

Batch Processing (1) - Batch Processing with Unix Tools

Batch Processing 从去年开始写 本系列文 开始到现在,我们着墨的都是现代系统的样子,...

Day 09:一起了解 Angular 应用程序的启动流程(一)

启动 Angular 开发服务器 我们先打开 VS Code 的终端机面版,输入 npm start...

夜间模式真的对眼睛比较好吗? 详细整理(上)

重点摘要: 可靠的研究中,没有白底黑底对眼健康的直接支持或反对 蓝光已知影响睡眠周期 对眼睛好要: ...