STM32自学笔记-7-CAN总线通信

STM32F103有1个CAN控制器,可以配合逻辑分析仪来测试CAN和PC的通信。在此之前先学习一下CAN的基础知识。

CAN 控制器根据两根线上的电位差来判断总线电平。总线电平分为显性电平(0),CAN_H和 CAN_L之差为 2.5V左右;隐性电平(1),二者必居其一。而隐性电平对应逻辑 1 CAN_H和 CAN_L之差为 0V。发送方通过使总线电平发生变化,将消息发送给接收方。在总线上显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)

这里要注意,和常规理解不同,显性电平为0。
还有一点,CAN总线的起止端都有一个120欧的匹配电阻

除了正常工作模式外,还有3种测试模式:

  • 静默模式(接收自己发出去的数据和总线数据,不发送)
  • 环回模式(发送数据到总线,但不接收总线数据,只接收自己Tx到总线的那份数据)
  • 环回静默模式(不发送数据到总线,不接收总线数据,仅接收自己Tx的数据)

这里还有个很重要的知识点,就是CAN总线的波特率,计算方式比较复杂,结合CubeMX上的CAN设置来看
STM32自学笔记-7-CAN总线通信_第1张图片

有4个参数和波特率有关,PrescalerTQBS1TQBS2SJW
APB1的频率是36MHz,分频系数取9的话,则一个TQ为1(36/9) =250ns,之后*(TQBS1+TQBS2+SJW),则CAN的位时间为2000ns,相应的位波特率为500Kbps(记住这个值,后面很重要)

  1. Generate code之后,我们首先测试发送功能。
    CAN的发送比较简单,使用的是HAL_CAN_Start()HAL_CAN_AddTxMessage()这两个方法。还要利用CAN_TxHeaderTypeDef这个结构体。
  CAN_TxHeaderTypeDef   TxHeader;
  uint8_t               TxData[8]={0x10, 0x20, 0x30, 0x40, 0x54, 0x65, 0x66, 0x99};   //测试发送这8个字节
  uint32_t              TxMailbox = 0;
  TxHeader.StdId = 0x198;
  TxHeader.ExtId = 0x999;
  TxHeader.IDE = 0;
  TxHeader.RTR = 0;
  TxHeader.DLC = 8;

然后在进入while(1)循环前,开启CAN通道

HAL_CAN_Start(&hcan);  //F103ZET只有一个CAN,所以无需写序号

while循环中加入下列代码

 HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);   //LED1闪烁表示程序在正常运行
 HAL_Delay(500);
 HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox);

编译烧写后,将Saleae的USB Logic Analyzer的CH0连到开发板的CANL,并将分析仪的地线和开发板的某个GND相连,千万不能忘的是设置波特率为500Kbit/s。点击软件的Start后,可以看到捕获的波形
STM32自学笔记-7-CAN总线通信_第2张图片
放大右下角来看
STM32自学笔记-7-CAN总线通信_第3张图片
就是我们发送的数据以及CAN Identifier,测试通过!
2. 接收功能测试

CAN的接收比发送要复杂,CAN总线协议是有邮箱机制的,就是收到的报文是需要放到邮箱里,需要配置过滤器(Filter),关于过滤器的配置,可以在stm32f1xx_hal_can.h中找到CAN_FilterTypeDef结构体的各个成员定义,一般会在can.c中手动将这个结构体的各个成员进行初始化。

STM32自学笔记-7-CAN总线通信_第4张图片
CAN接收函数使用HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData),接收到的数据存到RxData中。
由于我手头上只有一块开发板,无法向CAN接收器发送数据,所以接收测试无法做,但可以使用测试模式回环即loopback来测试接收功能,即发数据不进入总线,直接接收回来。
3. 回环测试
can.c里将hcan.Init.Mode = CAN_MODE_NORMAL改为hcan.Init.Mode = CAN_MODE_LOOPBACK,即进入了回环模式。想法是通过串口将送回去的RxData打印出来
将过滤器初始化后,需要在原来的main.c代码中添加接收器结构体的初始化

  CAN_RxHeaderTypeDef	RxHeader;
  uint8_t				RxData[8];
  RxHeader.StdId = 0x234;
  RxHeader.ExtId = 0x234;
  RxHeader.IDE = 0;
  RxHeader.RTR = 0;
  RxHeader.DLC = 8;

while(1)循环中在原来的代码后加入以下

HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData);
printf("RX of the CAN data is: %02X %02X %02X %02X %02X %02X %02X %02X\r\n", RxData[0], RxData[1], RxData[2], RxData[3], RxData[4], RxData[5], RxData[6], RxData[7]);

这样在发送出去以后马上就能回到RxData中,打开串口调试助手可以看到
STM32自学笔记-7-CAN总线通信_第5张图片
证明发送出去的数据都可以通过串口打印出来,测试通过。
同时通过逻辑分析仪也还是能看到CAN模块的发送数据。

你可能感兴趣的:(stm32,单片机,arm,嵌入式硬件,mcu)