IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> HAL库进行CAN通讯的程序编写3 -> 正文阅读

[嵌入式]HAL库进行CAN通讯的程序编写3

1、STM32Cube MX中CAN的设置

  • 时钟的设置
    在这里插入图片描述
    我所使用的芯片是STM32F103R系列的,CAN通讯采用的时钟是PCLK1,APB1 peripheral clocks的时钟。
  • CAN的设置
    在这里插入图片描述
    我们在很多资料中显示,CAN通讯的波特率是(SS+PTS+PBS1+PBS2+SJW)个Tq,在STM32Cube MX中我们可以通过预分频系数,PBS2段长度和PBS2段长度,这几个参数来设定波特率,并且根据设置会自动计算出所设定的波特率,对新手很友好。
    STM32F103这款芯片CAN模式只能设置为Master Mode。
  • CAN配置设置
    等STM32Cube MX设置完成后产生代码。我们还需要进行CAN通讯的配置部分。这一部分主要是为了设置滤波器参数,也就是报文过滤配置。
#define CAN_BASE_ID   0//0x321						///< 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)//只针对32位宽的列表或掩码模式
{
    CAN_FilterTypeDef sFilterConfig;
    CAN_FilterRegTypeDef IDH = {0};
    CAN_FilterRegTypeDef IDL = {0};

#if CAN_ID_TYPE_STD_ENABLE
    IDH.Sub.STID = CAN_BASE_ID & 0x7fff;//(CAN_BASE_ID << 5) & 0xFFFF;		// CAN_FxR1高16位
    IDL.Sub.STID = CAN_BASE_ID & 0x7fff;//(CAN_BASE_ID & 0xFFFF);				// CAN_FxR2高16位
//    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  0x3FFFF;		// 扩展ID高16位
    IDL.Sub.EXID = CAN_BASE_ID & 0x3FFFF;				// 扩展ID低16位
//    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 & 0xFFFF0000) >> 16;//IDH.value;					//(0x321 << 5);//					// 标识符寄存器一ID高十六位,放入扩展帧位
    sFilterConfig.FilterIdLow          = IDH.value & 0x0000FFFF;// IDL.value;										// 标识符寄存器一ID低十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdHigh     = (IDL.value & 0xFFFF0000) >> 16;//IDH.value;										// 标识符寄存器二ID高十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdLow      = IDL.value & 0x0000FFFF;//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();
    }
	/* Start the CAN peripheral */
	if (HAL_CAN_Start(&hcan) != HAL_OK)
	{
		/* Start Error */
		Error_Handler();
	}

	/* Activate CAN RX notification */
	if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
	{
		/* Notification Error */
		Error_Handler();
	}
}

上面的这部分代码适用于接收所有标准ID的报文信息,由于我们CAN_BASE_ID设置为0,其他的不同设置都可以进行修改,只要注意我上一篇讲的过滤器部分的设置就行,有些ID写入时需要进行移位。

  • CAN发送数据帧和远程帧
CAN_TxPacketTypeDef g_CanTxPacket;
void CAN_SetTxPacket(uint16_t u16stdId, uint32_t u32CANRTR, uint8_t len)
{
	g_CanTxPacket.hdr.StdId = u16stdId;//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 = len;					// 数据长度
	g_CanTxPacket.hdr.RTR = u32CANRTR;//CAN_RTR_DATA;		// 数据帧
//	g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;		// 远程帧
	g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
}

发送前我们需要设置我们本身的ID,字长和发送类型。等设置好后,我们就可以进行发送操作了。

uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
{
	uint16_t k = 5000;
	while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)==0)
	{
	}
	if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
	{
		while((hcan.Instance->TSR & CAN_TSR_TME0) == 0U)
		{
			delay_us(10);
			k--;
			if(k == 0) return 0;
		}
		return 1;
	}
	else
	{
		Error_Handler();
	}
//	return 0;
}

这里需要进行说明的点有

  1. 关于远程帧,我们在定义CAN_TxPacketTypeDef g_CanTxPacket时,里面有一项就是关于发送数据内容,对于数据帧和远程帧,我们所用的函数都是一样的,除了在设置CAN_SetTxPacket这个函数时注明下一步我们要发的是远程帧还是数据帧外没有区别,只是远程帧发送时不会发送数据段,而数据帧发送时会把CAN_TxPacketTypeDef里的payload部分进行发送。
  2. 关于数据段部分,每一次只能最多发送8个字节,当我们要发送多于8个字节的数据内容时我们就需要进行多次发送,少于8个字节就按实际字节进行填写即可。
  3. 当我们在连续发送多余3帧的数据帧时,我们必须加上while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)==0) { }否则会出现数据丢失的现象。
  • CAN的接收
    由于我们设的是所有ID报文信息都接收,因此对于具体实际应用过程中我们可以再进行多一次的筛选,当然这需要我们在自己定义协议过程中进行设置。
    CAN通讯的接收函数是
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle)
{
	uint16_t j;
	header = NULL;
  /* Get RX message */
  if (HAL_CAN_GetRxMessage(CanHandle, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
  {
    /* Reception Error */
    Error_Handler();
  }

	if ((RxHeader.StdId == BOX_ID) && (RxHeader.IDE == CAN_ID_STD))
	{
		//所需要进行的操作
	}
}
注:对于HAL_CAN_RxFifo0MsgPendingCallback这个接收函数是由于我们在配置CAN过滤器的时候我们以下的配置:
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;									// 过滤器组关联到FIFO0

简单的一个CAN发送和接收就完成了!

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:54:31  更:2021-12-23 15:55:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 23:22:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码