今天内容:
1.配置CAN1和CAN2环回模式下接收数据;
2.配置CAN1和CAN2正常模式下进行相互通信
这里我不再给大家继续讲CAN通信基础原理了,直接上手教大家使用STM32CubeMX配置环回模式下的收发数据,以及配置STM32F405RGT6的CAN1和CAN相互通信;
一、配置CAN1和CAN2环回模式下下发送和接收数据
步骤1:配置时钟
步骤2:CAN基础配置(配置波特率500K),
这里讲解下如何计算传输比特率,首先确定自己的CAN所在总线最大频率,我使用的是STM32F405RGT6,总线原理图如下:
可以看到CAN0和CAN1是挂载到APB1上面的,主频是42MHz,那么配置传输波特率为(142/(4+2+1)/12 = 0.5Mhz)
这里工程配置基本结束
步骤3:开启CAN1和配置CAN过滤器(这里扩展ID和标准ID为0表示不过滤ID)
/开启CAN1
HAL_CAN_Start(&hcan1);
//配置CAN1过滤器
bsp_can1_filter_config();
//配置CAN过滤器
uint8_t bsp_can1_filter_config(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 0;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
//筛选标准ID高位
filter.FilterIdHigh = 0;
//筛选标准ID低位
filter.FilterIdLow = 0;
//标准ID掩码高位
filter.FilterMaskIdHigh = 0;
//标准ID掩码低位
filter.FilterMaskIdLow = 0;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDMASK;
//筛选器长度 32位
filter.FilterScale = CAN_FILTERSCALE_32BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan1, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
my_printf("CAN1 ConfigFilter Fail!!\r\n");
}
else
{
my_printf("CAN1 ConfigFilter SUCCESS!!\r\n");
}
return 1;
}
步骤4:编写发送和接收函数
这里需要说一下,环回模式是直接将数据发送到接收的FIFO里面,外部引脚没有任何物理连接作用。
//编写CAN发送函数
void bsp_can1_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len)
{
//初始化发送结构体
CAN_TxHeaderTypeDef send_msg_hdr = {0};
uint8_t index = 0;
uint32_t msg_box = 0;
uint8_t send_buf[8] = {0};
//标识符ID
send_msg_hdr.StdId = basic_id;
//扩展标识符ID
send_msg_hdr.ExtId = 0x1839f101;
//扩展标志
//send_msg_hdr.IDE = CAN_ID_EXT;
send_msg_hdr.IDE = CAN_ID_STD;
//远程控制标志
send_msg_hdr.RTR = CAN_RTR_DATA;
//有效数据位长度
send_msg_hdr.DLC = data_len;
//是否使能捕获时间戳计数器
send_msg_hdr.TransmitGlobalTime = DISABLE;
for(index = 0; index < data_len; index++)
{
send_buf[index] = data[index];
}
if((HAL_CAN_AddTxMessage(&hcan1,&send_msg_hdr,send_buf,&msg_box))!= HAL_OK)
{
my_printf("CAN1 Send data Err!!\r\n");
}
else
{
my_printf("CAN1 Send data Success!!\r\n");
}
}
//接收数据
void Can1RecvMsg()
{
//配置CAN过滤器
bsp_can1_filter_config();
//配置32位列表模式
//bsp_can1_filter_config_list();
//配置16位掩码模式
//bsp_can1_filter_config_16();
//16位列表模式
//bsp_can1_filter_config_16_list();
//初始话CAN接收结构体
CAN_RxHeaderTypeDef rceStu = {0};
uint8_t data[8] = {0};
//判断FIFO中是否有数据
if(HAL_CAN_GetRxFifoFillLevel(&hcan1,CAN_RX_FIFO0) != 0)
{
my_printf("CAN1 have data!!\r\n");
//接收CAN数据信息
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rceStu, data);
my_printf("rceStu.DLC: %d\r\n",rceStu.DLC);
my_printf("rceStu.ExtId: %d\r\n",rceStu.ExtId);
my_printf("rceStu.StdId: %x\r\n",rceStu.StdId);
my_printf("rceStu.Timestamp: %d\r\n",rceStu.Timestamp);
for(uint8_t i = 0;i<rceStu.DLC;i++)
{
my_printf(" %x",data[i]);
}
my_printf("\r\n");
}
else
{
my_printf("No CAN1 INFO!\r\n");
}
}
二、配置CAN1和CAN2正常模式下相互发送和接收数据
我是用的板子是STM32F405RGT6的,只有STM32F405RGT6自带的控制器,很遗憾没有集成收发器,所以需要额外准备两个CAN的收发器,
这里给大家看看我的板子:
然后我使用的是收发器是TJA1050
接线:需要将两个收发器的高-高、低-低,RX-RX,TX-TX,GND接地,需要注意的是一定要外接5V的电源,我的STM32F405RGT6板子很坑,上面标注的5V实际没有5V只有2.几V,所以导致我最开始用的时候一直找不到原因,一直无法收发数据(重新写了好几遍测试代码都没用,又重新查看数据手册看看CAN1和CAN2是不是有啥显示条件不能通信,最后实在没办法只能将所有可能因素全查找一遍,主要是STM32F405RGT6它3.3V的电源是正常的,就没怀疑过板子问题)。
接线图
工程配置:
can1配置:
can2配置:
还是不对ID进行过过滤(下期再给大家分享如何对16位和32位ID进行列表模式和掩码模式进行配置),这里我把我写的.c和.h分享给大家。
CANTest.c
#include "CanTest.h"
//标准CAN ID
uint16_t StdIdArray[10] ={0x7e0,0x7e1,0x7e2,0x7e3,0x7e4,
0x7e5,0x7e6,0x7e7,0x7e8,0x7e9};
//扩展ID
uint32_t ExtIdArray[10] = {0x1839f101,0x1839f102,0x1839f111,0x1839f107,0x1839f1f1,
0x183Af101,0x183Af102,0x183Af103,0x183Af104,0x183Af105};
/*CAN使用中断接收处理*/
//使能CAN中断
//HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint16_t i = 0;
uint8_t buf[8] = {0};
CAN_RxHeaderTypeDef rxHeader = {0};
if(hcan->Instance == CAN1)
{
my_printf("Recv via STM32F429 Interrupt\r\n");
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);
my_printf("Recv Data: ");
for(i = 0; i < rxHeader.DLC; i++)
{
my_printf("%x ",buf[i]);
}
my_printf("\r\n");
}
}
//配置CAN过滤器
uint8_t bsp_can1_filter_config(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 0;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
//筛选标准ID高位
//filter.FilterIdHigh = 0x702 << 5;
filter.FilterIdHigh = 0;
//扩展ID高位
//filter.FilterIdHigh = (0x1839f101 >> 13) & 0xFFFF;
//筛选标准ID低位
filter.FilterIdLow = 0;
//扩展ID低位
//filter.FilterIdLow = ((0x1839f101 << 3)| CAN_ID_EXT) & 0xFFFF;
//筛选ID掩码高位 存放寄存器的高16位
//filter.FilterMaskIdHigh = 0xFFFFFFFF;
//计算掩码
//uint16_t msk = (0x701 ^ (~0x702));
//uint16_t msk = (0x1839f101 ^ (~0x1839f102));
//标准ID掩码高位
//filter.FilterMaskIdHigh = msk << 5;
filter.FilterMaskIdHigh = 0;
//扩展ID掩码低位
//filter.FilterMaskIdHigh = (msk >> 16) & 0xFFFF;
//标准ID掩码低位
filter.FilterMaskIdLow = 0;
//扩展ID掩码低位
//filter.FilterMaskIdLow = msk & 0xFFFF;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDMASK;
//筛选器长度 32位
filter.FilterScale = CAN_FILTERSCALE_32BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan1, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
my_printf("CAN1 ConfigFilter Fail!!\r\n");
}
else
{
my_printf("CAN1 ConfigFilter SUCCESS!!\r\n");
}
return 1;
}
//列表模式过滤器
uint8_t bsp_can1_filter_config_list(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 0;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
filter.FilterIdHigh = 0x723<<5;
filter.FilterIdLow = 0;
filter.FilterMaskIdHigh = 0x724<<5;
filter.FilterMaskIdLow = 0;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDLIST;
//筛选器长度 32位
filter.FilterScale = CAN_FILTERSCALE_32BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan1, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
my_printf("CAN1 ConfigFilter Fail!!\r\n");
}
return 1;
}
//16位掩码过滤器
uint8_t bsp_can1_filter_config_16(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 0;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
//ID组1
uint16_t msk = (0x721 ^ (~0x722));
//掩码
filter.FilterIdLow = (0x723 << 5) & 0xFFFF;
//ID
filter.FilterMaskIdLow = (msk << 5) & 0xFFFF;
//ID组2
uint16_t msk1 = (0x741 ^ (~0x742));
filter.FilterIdHigh = (0x741 << 5) & 0xFFFF;
filter.FilterMaskIdHigh = (msk1 << 5) & 0xFFFF;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDMASK;
//筛选器长度 16位
filter.FilterScale = CAN_FILTERSCALE_16BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan1, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
my_printf("CAN1 ConfigFilter Fail!!\r\n");
}
return 1;
}
uint8_t bsp_can1_filter_config_16_list(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 0;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
//ID1
filter.FilterIdLow = (0x729 << 5) & 0xFFFF;
//ID2
filter.FilterMaskIdLow = (0x741 << 5) & 0xFFFF;
//ID3
filter.FilterIdHigh = (0x755 << 5) & 0xFFFF;
//ID4
filter.FilterMaskIdHigh = (0x769 << 5) & 0xFFFF;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDLIST;
//筛选器长度 16位
filter.FilterScale = CAN_FILTERSCALE_16BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan1, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan1, &filter) != HAL_OK)
{
my_printf("CAN1 ConfigFilter Fail!!\r\n");
}
return 1;
}
//配置CAN过滤器
uint8_t bsp_can2_filter_config(void)
{
//初始化筛选器
CAN_FilterTypeDef filter = {0};
//筛选器编号
filter.FilterBank = 14;
//存储FIFO FIFO0
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
//筛选标准ID高位
//filter.FilterIdHigh = 0x702 << 5;
filter.FilterIdHigh = 0;
//扩展ID高位
//filter.FilterIdHigh = (0x1839f101 >> 13) & 0xFFFF;
//筛选标准ID低位
filter.FilterIdLow = 0;
//扩展ID低位
//filter.FilterIdLow = ((0x1839f101 << 3)| CAN_ID_EXT) & 0xFFFF;
//筛选ID掩码高位 存放寄存器的高16位
//filter.FilterMaskIdHigh = 0xFFFFFFFF;
//计算掩码
//uint16_t msk = (0x701 ^ (~0x702));
//uint16_t msk = (0x1839f101 ^ (~0x1839f102));
//标准ID掩码高位
//filter.FilterMaskIdHigh = msk << 5;
filter.FilterMaskIdHigh = 0;
//扩展ID掩码低位
//filter.FilterMaskIdHigh = (msk >> 16) & 0xFFFF;
//标准ID掩码低位
filter.FilterMaskIdLow = 0;
//扩展ID掩码低位
//filter.FilterMaskIdLow = msk & 0xFFFF;
//是否使能当前筛选器
filter.FilterActivation = ENABLE;
//筛选器模式 掩码模式
filter.FilterMode = CAN_FILTERMODE_IDMASK;
//筛选器长度 32位
filter.FilterScale = CAN_FILTERSCALE_32BIT;
//配置筛选器
HAL_CAN_ConfigFilter(&hcan2, &filter);
//过滤器配置失败
if(HAL_CAN_ConfigFilter(&hcan2, &filter) != HAL_OK)
{
my_printf("CAN2 ConfigFilter Fail!!\r\n");
}
return 1;
}
//编写CAN发送函数
void bsp_can1_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len)
{
//初始化发送结构体
CAN_TxHeaderTypeDef send_msg_hdr = {0};
uint8_t index = 0;
uint32_t msg_box = 0;
uint8_t send_buf[8] = {0};
//标识符ID
send_msg_hdr.StdId = basic_id;
//扩展标识符ID
send_msg_hdr.ExtId = 0x1839f101;
//扩展标志
//send_msg_hdr.IDE = CAN_ID_EXT;
send_msg_hdr.IDE = CAN_ID_STD;
//远程控制标志
send_msg_hdr.RTR = CAN_RTR_DATA;
//有效数据位长度
send_msg_hdr.DLC = data_len;
//是否使能捕获时间戳计数器
send_msg_hdr.TransmitGlobalTime = DISABLE;
for(index = 0; index < data_len; index++)
{
send_buf[index] = data[index];
}
if((HAL_CAN_AddTxMessage(&hcan1,&send_msg_hdr,send_buf,&msg_box))!= HAL_OK)
{
my_printf("CAN1 Send data Err!!\r\n");
}
else
{
my_printf("CAN1 Send data Success!!\r\n");
}
}
//编写CAN发送函数
void bsp_can2_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len)
{
//初始化发送结构体
CAN_TxHeaderTypeDef send_msg_hdr = {0};
uint8_t index = 0;
uint32_t msg_box = 1;
uint8_t send_buf[8] = {0};
//标识符ID
send_msg_hdr.StdId = basic_id;
//扩展标识符ID
send_msg_hdr.ExtId = 0x1839f101;
//扩展标志
//send_msg_hdr.IDE = CAN_ID_EXT;
send_msg_hdr.IDE = CAN_ID_STD;
//远程控制标志
send_msg_hdr.RTR = CAN_RTR_DATA;
//有效数据位长度
send_msg_hdr.DLC = data_len;
//是否使能捕获时间戳计数器
send_msg_hdr.TransmitGlobalTime = DISABLE;
for(index = 0; index < data_len; index++)
{
send_buf[index] = data[index] + 1;
}
if((HAL_CAN_AddTxMessage(&hcan2,&send_msg_hdr,send_buf,&msg_box))!= HAL_OK)
{
my_printf("CAN2 Send data Err!!\r\n");
}
else
{
my_printf("CAN2 Send data Success!!\r\n");
}
}
//接收数据
void Can1RecvMsg()
{
//配置CAN过滤器
bsp_can1_filter_config();
//配置32位列表模式
//bsp_can1_filter_config_list();
//配置16位掩码模式
//bsp_can1_filter_config_16();
//16位列表模式
//bsp_can1_filter_config_16_list();
//初始话CAN接收结构体
CAN_RxHeaderTypeDef rceStu = {0};
uint8_t data[8] = {0};
//判断FIFO中是否有数据
if(HAL_CAN_GetRxFifoFillLevel(&hcan1,CAN_RX_FIFO0) != 0)
{
my_printf("CAN1 have data!!\r\n");
//接收CAN数据信息
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rceStu, data);
my_printf("rceStu.DLC: %d\r\n",rceStu.DLC);
my_printf("rceStu.ExtId: %d\r\n",rceStu.ExtId);
my_printf("rceStu.StdId: %x\r\n",rceStu.StdId);
my_printf("rceStu.Timestamp: %d\r\n",rceStu.Timestamp);
for(uint8_t i = 0;i<rceStu.DLC;i++)
{
my_printf(" %x",data[i]);
}
my_printf("\r\n");
}
else
{
my_printf("No CAN1 INFO!\r\n");
}
}
//接收数据
void Can2RecvMsg()
{
//配置CAN过滤器
bsp_can2_filter_config();
//初始话CAN接收结构体
CAN_RxHeaderTypeDef rceStu = {0};
uint8_t data[8] = {0};
//判断FIFO中是否有数据
if(HAL_CAN_GetRxFifoFillLevel(&hcan2,CAN_RX_FIFO0) != 0)
{
my_printf("CAN2 have data!!\r\n");
//接收CAN数据信息
HAL_CAN_GetRxMessage(&hcan2, CAN_RX_FIFO0, &rceStu, data);
//打印有效数据长度
my_printf("rceStu.DLC: %d\r\n",rceStu.DLC);
//打印扩展ID
my_printf("rceStu.ExtId: %d\r\n",rceStu.ExtId);
//打印标准ID
my_printf("rceStu.StdId: %x\r\n",rceStu.StdId);
//打印接收时间
my_printf("rceStu.Timestamp: %d\r\n",rceStu.Timestamp);
for(uint8_t i = 0;i<rceStu.DLC;i++)
{
my_printf(" %x",data[i]);
}
my_printf("\r\n");
}
else
{
my_printf("No CAN2 INFO!\r\n");
}
}
//CAN1}CAN2通信测试
void Can1AndCan2CommunicationTest()
{
//CAN发送数据
uint8_t data[10] = {0x66,0x64,0x55,0x33,0x66,0x33,0x44,0x55};
//发送CAN数据信息
bsp_can1_send_msg(CAN_ID_STD,0x729,2,data,8);
//发送CAN数据信息
bsp_can2_send_msg(CAN_ID_STD,0x723,2,data,8);
//CAN1接收数据
Can1RecvMsg();
//CAN2接收数据
Can2RecvMsg();
}
CANTest.h
#ifndef CANTEST_H_
#define CANTEST_H_
#include "can.h"
#include "comm.h"
#define MY_CAN_ID 0x7B1
//32位掩码模式
uint8_t bsp_can1_filter_config(void);
//32位掩码模式
uint8_t bsp_can2_filter_config(void);
//32位列表模式
uint8_t bsp_can1_filter_config_list(void);
//16位掩码模式
uint8_t bsp_can1_filter_config_16(void);
//16位列表模式
uint8_t bsp_can1_filter_config_16_list(void);
void bsp_can1_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len);
void bsp_can2_send_msg(uint32_t id_type,uint32_t basic_id,uint32_t ex_id,uint8_t *data,uint32_t data_len);
void Can1RecvMsg();
void Can2RecvMsg();
void Can1AndCan2CommunicationTest();
#endif
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_CAN1_Init();
MX_CAN2_Init();
MX_TIM3_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
//开启CAN1
HAL_CAN_Start(&hcan1);
//开启CAN2
HAL_CAN_Start(&hcan2);
//配置CAN1过滤器
bsp_can1_filter_config();
//配置CAN2过滤器
bsp_can2_filter_config();
//Dht11重置处理
//Dht11InitHandle();
//OLED初始化
//OLED_Init();
//清屏操作
//OLED_FullyClear();
//固定位显示
//FixedDisplay();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//led显示模块
//LedModuleHandle();
//CAN1\CAN2通信测试
Can1AndCan2CommunicationTest();
//Dht11模块处理
//Dht11ModuleHandle();
//OLED模块处理
//TemperatureAndHumidityTest();
//延时2S
HAL_Delay(2000);
}
/* USER CODE END 3 */
}
下面展示串口打印接收的数据: