STM32 CAN 发送接收的简单测试
can接口相对是一种常用的串行接口,但是不像spi、i2c、uart等接口都有主从的关系,can可以任何一个节点主动发送数据,并且假如出现总线冲突会有硬件来处理。
can和rs485又有些类似,都是把ttl信号转换成了差分信号。所以在stm32 使用can的时候会有一个can收发器。
STM32 CAN 发送的简单测试
从电路上看起来也很简单,stm32也是通过can tx、rx两根线和收发器相连。所以假如我们要测试can的发送,是不是只接can tx脚就可以了?
我最开始也以为这样就可以,但是深究can的总线冲突检测原理就会发现这样行不通的。因为can 在发送数据的时候也会同时接收发送的数据,通过把接收的数据和内部发送寄存器的数据做对比,是不是一致就知道总线有没有冲突。所以在正常情况(这里意味着非正常情况下也可以)下can rx不接就到这发送出去的数据无法收到从而硬件自动判断为发送失败。
所以要保证发送数据成功,can tx脚和can rx脚要都接上,并且确保can收发器供电正常。
硬件上就这些主要注意点,接下来就主要是软件的配置了。
一般stm32 配置can有以下几大步骤:
can的初始化(cubemx直接可以生成代码)
can的启动
can滤波器的设置(用来接收的,发送的时候可以不用配置它)
can执行发送数据请求
我们只测试can的发送,所以就只用关系1、2、4步骤就可以了。
第一步,配置stm32cubemx
STM32 CAN 发送的简单测试
如上图所示,最关键主要配置如下三个参数,分频数我这里配置48,下面的time Quantum值就会自动计算出来。因为can时钟是48mhz经过48分频后,一个单位时间就是1us=1000ns。
因为我想要100k波特率,然后填写下面的Time segment1(简称 Tbs1 )和Time segment2 (简称 Tbs2) 为5和4。那么具体波特率该怎么计算还是要看看官方手册的描述:
STM32 CAN 发送的简单测试
根据如上描述,能决定波特率的也就是三个参数:分频值、Tbs1、Tbs2。需要注意的是,这个SYNC_SEG的1tq是固定值。和stm32cubemx中的jump width不要弄混淆了。jump width这个时间参数是作为补偿时间的上线,当时间有偏差的时候,就会自动补偿,最长时间不能超过该参数设定值。
第一步,stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。
typedef struct
{
uint32_t mailbox;
CAN_TxHeaderTypeDef hdr;
uint8_t payload[8];
}CAN_TxPacketTypeDef;
typedef struct
{
CAN_RxHeaderTypeDef hdr;
uint8_t payload[8];
}CAN_RxPacketTypeDef;
/// CAN过滤器寄存器位宽类型定义
typedef union
{
__IO uint32_t value;
struct
{
uint8_t REV : 1; ///< [0] :未使用
uint8_t RTR : 1; ///< [1] : RTR(数据帧或远程帧标志位)
uint8_t IDE : 1; ///< [2] : IDE(标准帧或扩展帧标志位)
uint32_t EXID : 18; ///< [21:3] : 存放扩展帧ID
uint16_t STID : 11; ///< [31:22]: 存放标准帧ID
} Sub;
} CAN_FilterRegTypeDef;
#define CAN_BASE_ID 0 ///< CAN标准ID,最大11位,也就是0x7FF
#define CAN_FILTER_MODE_MASK_ENABLE 1 ///< CAN过滤器模式选择:=0:列表模式 =1:屏蔽模式
#define CAN_ID_TYPE_STD_ENABLE 1 ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID
void CAN_Filter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
CAN_FilterRegTypeDef IDH = {0};
CAN_FilterRegTypeDef IDL = {0};
#if CAN_ID_TYPE_STD_ENABLE
IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF; // 标准ID高16位
IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF); // 标准ID低16位
#else
IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF; // 扩展ID高16位
IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF); // 扩展ID低16位
IDL.Sub.IDE = 1; // 扩展帧标志位置位
#endif
sFilterConfig.FilterBank = 0; // 设置过滤器组编号
#if CAN_FILTER_MODE_MASK_ENABLE
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 屏蔽位模式
#else
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; // 列表模式
#endif
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位宽
sFilterConfig.FilterIdHigh = IDH.value; // 标识符寄存器一ID高十六位,放入扩展帧位
sFilterConfig.FilterIdLow = IDL.value; // 标识符寄存器一ID低十六位,放入扩展帧位
sFilterConfig.FilterMaskIdHigh = IDH.value; // 标识符寄存器二ID高十六位,放入扩展帧位
sFilterConfig.FilterMaskIdLow = IDL.value; // 标识符寄存器二ID低十六位,放入扩展帧位
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 过滤器组关联到FIFO0
sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
sFilterConfig.SlaveStartFilterBank = 14; // 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
}
uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
{
if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
return 1;
return 0;
}
void CAN_Init(void)
{
MX_CAN_Init();
CAN_Filter_Config();
HAL_CAN_Start(&hcan);
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING); // 使能CAN接收中断
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
{
static CAN_RxPacketTypeDef packet;
// CAN数据接收
if (canHandle->Instance == hcan.Instance)
{
if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK) // 获得接收到的数据头和数据
{
printf("\r\n\r\n\r\n################### CAN RECV ###################\r\n");
printf("STID:0x%X\r\n",packet.hdr.StdId);
printf("EXID:0x%X\r\n",packet.hdr.ExtId);
printf("DLC :%d\r\n", packet.hdr.DLC);
printf("DATA:");
for(int i = 0; i < packet.hdr.DLC; i++)
{
printf("0x%02X ", packet.payload[i]);
}
HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING); // 再次使能FIFO0接收中断
}
}
}
CAN_TxPacketTypeDef g_CanTxPacket;
void CAN_SetTxPacket(void)
{
g_CanTxPacket.hdr.StdId = 0x321; // 标准ID
// g_CanTxPacket.hdr.ExtId = 0x10F01234; // 扩展ID
g_CanTxPacket.hdr.IDE = CAN_ID_STD; // 标准ID类型
// g_CanTxPacket.hdr.IDE = CAN_ID_EXT; // 扩展ID类型
g_CanTxPacket.hdr.DLC = 8; // 数据长度
g_CanTxPacket.hdr.RTR = CAN_RTR_DATA; // 数据帧
// g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE; // 远程帧
g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
for(int i = 0; i < 8; i++)
{
g_CanTxPacket.payload[i] = i;
}
}
int main()
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
CAN_Init();
printf("----------------------------------------\r\n");
CAN_SetTxPacket();
while(1)
{
if(CAN_Transmit(&g_CanTxPacket) != 0)
printf("failed\r\n");
HAL_Delay(1000);
}
}
原文地址:https://www.cnblogs.com/mengydz/p/12965125.html
- android获得ImageView图片的等级
- SqlServer:此数据库处于单用户模式,导致数据库无法删除的处理
- jQuery中排除指定元素,同时选择剩下的所有元素
- windows客户机连接gerrit的一个报错处理
- 装箱与值类型虽然很容易理解,但是在实际使用中,并不总是能100%用对
- Jexus 配置ssl
- 局部打印插件 jquery.PrintArea.js
- FluorineFx应用中“页面长时间不动”导致无法连接的解决办法
- Mysql主从同步(1)-主从/主主环境部署梳理
- mysql主从同步(3)-percona-toolkit工具(数据一致性监测、延迟监控)使用梳理
- 网站压力测试软件WebBench以及压测Jexus
- Gershon Dublon & Nan Zhao:用传感器网络感知世界
- 即日起珠海可用微信乘公交,腾讯乘车码助力智慧城市建设
- 利用mk-table-checksum监测Mysql主从数据一致性操作记录
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法