STM32 子设备通过CAN发送数据到主设备

news2025/3/12 19:14:57

采集ADC、GPS经纬坐标、温湿度数据、大气压数据通过CAN方式发送给主设备端,帧ID按照如下定义:

我尼玛一个标准帧ID位数据是11位,扩展帧才是11+18=29位,它说最开头的是四位是真类型,并给我如下解释:

它把帧的定义当成了字节2和字节3的拼接了(整体的报文识别码),对于STM32帧ID设置是直接赋值,也就是它给我的帧ID需要左移5位才是实际帧ID。不多说直接上代码!波特率500kbs!

初始化部分:

void Can_Btl(u32 btl)
{
	switch(btl)
	{                
		case btl_5k	  	:CAN_Mode_Init(CAN_SJW_2tq,CAN_BS1_6tq,CAN_BS2_4tq,600,CAN_Mode_Normal);break;
		case btl_10k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_5tq,CAN_BS2_3tq,400,CAN_Mode_Normal);break;
		case btl_20k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,300,CAN_Mode_Normal);break;
		case btl_25k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,240,CAN_Mode_Normal);break;
		case btl_40k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,150,CAN_Mode_Normal);break;
		case btl_50k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,120,CAN_Mode_Normal);break;
		case btl_62_5k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,96,CAN_Mode_Normal);break;
		case btl_80k	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,75,CAN_Mode_Normal);break;
		case btl_100k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,60,CAN_Mode_Normal);break;
		case btl_125k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,48,CAN_Mode_Normal);break;
		case btl_200k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,30,CAN_Mode_Normal);break;
		case btl_250k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,24,CAN_Mode_Normal);break;
		case btl_400k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_5tq,CAN_BS2_3tq,10,CAN_Mode_Normal);break;
		case btl_500k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,12,CAN_Mode_Normal);break;
		case btl_666k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_4tq,CAN_BS2_4tq,6,CAN_Mode_Normal);break;
		case btl_800k 	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_5tq,CAN_BS2_3tq,5,CAN_Mode_Normal);break;
		case btl_1M	  	:CAN_Mode_Init(CAN_SJW_1tq,CAN_BS1_3tq,CAN_BS2_2tq,6,CAN_Mode_Normal);break;
	}
}
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
	 GPIO_InitTypeDef GPIO_InitStructure; 
	 CAN_InitTypeDef        CAN_InitStructure;
 	 CAN_FilterInitTypeDef  CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);//ʹÄÜPORTAʱÖÓ	                   											 
  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//ʹÄÜCAN1ʱÖÓ	
	  GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
	
    GPIO_InitStructure.GPIO_Pin = CAN_HIGH;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//¸´ÓÃÍÆÍì
    GPIO_Init(CAN_GPIO, &GPIO_InitStructure);		//³õʼ»¯IO
   
    GPIO_InitStructure.GPIO_Pin = CAN_LOW;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//ÉÏÀ­ÊäÈë
    GPIO_Init(CAN_GPIO, &GPIO_InitStructure);//³õʼ»¯IO
	  
 	//CANµ¥ÔªÉèÖÃ
 	CAN_InitStructure.CAN_TTCM=DISABLE;						 //·Çʱ¼ä´¥·¢Í¨ÐÅģʽ  //
 	CAN_InitStructure.CAN_ABOM=ENABLE;						 //Èí¼þ×Ô¶¯ÀëÏß¹ÜÀí	 //
  	CAN_InitStructure.CAN_AWUM=DISABLE;						 //˯Ãßģʽͨ¹ýÈí¼þ»½ÐÑ(Çå³ýCAN->MCRµÄSLEEPλ)//
  	CAN_InitStructure.CAN_NART=ENABLE;						 	//½ûÖ¹±¨ÎÄ×Ô¶¯´«ËÍ //
  	CAN_InitStructure.CAN_RFLM=DISABLE;						 //±¨ÎIJ»Ëø¶¨,еĸ²¸Ç¾ÉµÄ // 
  	CAN_InitStructure.CAN_TXFP=DISABLE;						 //ÓÅÏȼ¶Óɱ¨Îıêʶ·û¾ö¶¨ //
  	CAN_InitStructure.CAN_Mode= mode;	         //ģʽÉèÖ㺠mode:0,ÆÕͨģʽ;1,»Ø»·Ä£Ê½; //
  	//ÉèÖò¨ÌØÂÊ
  	CAN_InitStructure.CAN_SJW=tsjw;				//ÖØÐÂͬ²½ÌøÔ¾¿í¶È(Tsjw)Ϊtsjw+1¸öʱ¼äµ¥Î»  CAN_SJW_1tq	 CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
  	CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1¸öʱ¼äµ¥Î»CAN_BS1_1tq ~CAN_BS1_16tq
  	CAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1¸öʱ¼äµ¥Î»CAN_BS2_1tq ~	CAN_BS2_8tq
  	CAN_InitStructure.CAN_Prescaler=brp;            //·ÖƵϵÊý(Fdiv)Ϊbrp+1	//
  	CAN_Init(CAN1, &CAN_InitStructure);            // ³õʼ»¯CAN1 

 	CAN_FilterInitStructure.CAN_FilterNumber=0;	  //¹ýÂËÆ÷0
   	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32λ 
  	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32λID
  	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32λMASK
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//¹ýÂËÆ÷0¹ØÁªµ½FIFO0
 	  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //¼¤»î¹ýÂËÆ÷0

  	CAN_FilterInit(&CAN_FilterInitStructure);//Â˲¨Æ÷³õʼ»¯
#if CAN_RX0_INT_ENABLE
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0ÏûÏ¢¹ÒºÅÖжÏÔÊÐí.		    
  
  	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // Ö÷ÓÅÏȼ¶Îª1
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // ´ÎÓÅÏȼ¶Îª0
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
#endif
	return 0;
}

采集及发送部分:

#define STD_ID_PID		(0x1020>>5)//0x0081
#define STD_ID_BASE		(0x2020>>5)//0x0101
#define STD_ID_LONG		(0x4020>>5)//0x0201
#define STD_ID_LAT		(0x8020>>5)//0x0401
while(1)
	{
		if(sys_timer._1s_beat){//todo 1s freq things
			bme280GetData(&rel_data.bmp280_press,&bmp280_temper,&bmp280_humidity,&bmp280_asl);
			Analysis_GPS();
			SHT30_Read_Humiture(&sht30_temp,&sht30_humidity);
			rel_data.area_temper = sht30_temp*1.0f/10;
			rel_data.area_humi = sht30_humidity*1.0f/10;
			//»ù±¾ÐÅÏ¢·¢ËÍ
			can_buff[0] = ((STD_ID_BASE&0xff00)>>8);
			can_buff[1] = ((STD_ID_BASE&0x00ff)>>0);
			can_buff[2] = (sht30_temp&0xff00)>>8;//ζÈ
			can_buff[3] = (sht30_temp&0x00ff)>>0;
			can_buff[4] = (sht30_humidity&0xff00)>>8;//ʪ¶È
			can_buff[5] = (sht30_humidity&0x00ff)>>0;
			can_buff[6] = ((u16)rel_data.bmp280_press&0xff00)>>8;//´óÆøѹ
			can_buff[7] = ((u16)rel_data.bmp280_press&0x00ff)>>0;
			can_buff[8] = 0x00;
			can_buff[9] = 0x00;
			Can_Send_Msg(can_buff,sizeof(can_buff));
			//¾­¶ÈÐÅÏ¢·¢ËÍ
			can_buff[0] = ((STD_ID_LONG&0xff00)>>8);
			can_buff[1] = ((STD_ID_LONG&0x00ff)>>0);
			memcpy(&can_buff[2],(void *)&rel_data.longitude,sizeof(double));
			Can_Send_Msg(can_buff,sizeof(can_buff));
			//γ¶ÈÐÅÏ¢·¢ËÍ
			can_buff[0] = ((STD_ID_LAT&0xff00)>>8);
			can_buff[1] = ((STD_ID_LAT&0x00ff)>>0);
			memcpy(&can_buff[2],(void *)&rel_data.latitude,sizeof(double));
			Can_Send_Msg(can_buff,sizeof(can_buff));			
			sys_timer._1s_beat = false;
		}
		if(sys_timer._500ms_beat){//todo 500ms freq things
			sys_timer._500ms_beat = false;
		}
		if(sys_timer._50ms_beat){
			Get_Adc_Num();
			adc_buf[adc_cnt++] = rel_data.adc_val;
			if(adc_cnt==4){//Íê³ÉÒ»°ü£¬´ò°ü·¢×ß-ͳһ°´ÕÕ´ó¶ËÐò
				can_buff[0] = ((STD_ID_PID&0xff00)>>8);
				can_buff[1] = ((STD_ID_PID&0x00ff)>>0);
				can_buff[2] = (adc_buf[0]&0xff00)>>8;
				can_buff[3] = (adc_buf[0]&0x00ff)>>0;
				can_buff[4] = (adc_buf[1]&0xff00)>>8;
				can_buff[5] = (adc_buf[1]&0x00ff)>>0;
				can_buff[6] = (adc_buf[2]&0xff00)>>8;
				can_buff[7] = (adc_buf[2]&0x00ff)>>0;
				can_buff[8] = (adc_buf[3]&0xff00)>>8;
				can_buff[9] = (adc_buf[3]&0x00ff)>>0;
				Can_Send_Msg(can_buff,sizeof(can_buff));
				adc_cnt = 0;
			}
			sys_timer._50ms_beat = 0;
		}
	}	 
u8 Can_Send_Msg(u8* msg,u8 len)
{	
	u8 mbox;
	u16 i=0;
	CanTxMsg TxMessage;
	TxMessage.StdId=msg[0]<<8|msg[1];	// ±ê×¼±êʶ·û 11λ
	TxMessage.ExtId=1;				   // ÉèÖÃÀ©Õ¹±êʾ·û 
	TxMessage.IDE=CAN_Id_Standard; // ±ê×¼Ö¡
	TxMessage.RTR=CAN_RTR_Data;		 // Êý¾ÝÖ¡
	TxMessage.DLC=8;						// Òª·¢Ë͵ÄÊý¾Ý³¤¶È
	for(i=0;i<8;i++)
		TxMessage.Data[i]=msg[i+2];			          
	mbox= CAN_Transmit(CAN1, &TxMessage);   
	i=0;
	while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//µÈ´ý·¢ËͽáÊø
	if(i>=0XFF)
		return 1;
	return 0;
}

接收中断处理部分,此处没做帧ID过滤设置,没做接收数据处理设置:

CanRxMsg RxMessage;
void USB_LP_CAN1_RX0_IRQHandler(void)
{
	uint8_t i;
	CAN_Receive(CAN1, 0, &RxMessage);

	if(RxMessage.StdId>>8==0x01){
		paramx_can.Rev_ID = RxMessage.StdId & 0xFF;
		switch(RxMessage.Data[0]){
			default:break;
		}
	}
}

运行效果如下:

AD数据帧,1s发送5次,间隔200ms,一包包含4个数据,正好是50ms采集一次

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2311618.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HCIA-IP路由动态-RIP

一、概念 动态路由是指路由器通过运行动态路由协议&#xff08;RIP、OSPF等&#xff09;&#xff0c;自动学习和发现网络中的路由信息。路由器之间通过交换路由协议数据包&#xff0c;互相通告自己所知道的网络信息&#xff0c;从而构建和更新路由表。 二、RIP(路由信息协议)…

CentOS7离线部署安装docker和docker-compose

CentOS7离线部署安装docker和docker-compose 安装包准备 docker下载地址、docker-compose下载地址 docker和docker-compose版本对应关系 注&#xff1a;本次安装部署选择的版本是 docker&#xff1a;docker-28.0.1.tgzdocker-compose&#xff1a;docker-compose-linux-x86_6…

Core Speech Kit(基础语音服务)

文章目录 一、Core Speech Kit简介场景介绍约束与限制二、文本转语音1. 场景介绍2. 约束与限制3. 开发步骤4. 设置播报策略设置数字播报策略插入静音停顿指定汉字发音5. 开发实例三、语音识别约束与限制开发步骤开发实例一、Core Speech Kit简介 Core Speech Kit(基础语音服务…

配置 Thunderbird 以使用 QQ 邮箱

配置 Thunderbird 以使用 QQ 邮箱 本片文章的操作系统为 windws 10 &#xff0c;thunder bird 客户端版本为 128.7.1esr(64位)。注意到其他文章的图片中 thunder bird 的 ui 界面和我这个不一样&#xff0c;导致看起来不太方便&#xff0c;所以这里写一篇博客。不同版本的 thu…

如何使用MyBatis进行多表查询

前言 在实际开发中&#xff0c;对数据库的操作通常会涉及多张表&#xff0c;MyBatis提供了关联映射&#xff0c;这些关联映射可以很好地处理表与表&#xff0c;对象与对象之间的的关联关系。 一对一查询 步骤&#xff1a; 先确定表的一对一关系确定好实体类&#xff0c;添加关…

第六课:数据存储三剑客:CSV/JSON/MySQL

在Python的数据存储与处理领域&#xff0c;CSV、JSON和MySQL被广大开发者誉为“数据存储三剑客”。它们各自在不同的场景下发挥着重要作用&#xff0c;无论是简单的数据交换、轻量级的数据存储&#xff0c;还是复杂的关系型数据库管理&#xff0c;都能找到它们的身影。本文将详…

Python通过SSH隧道访问数据库

本文介绍通过sshtunnel类库建立SSH隧道&#xff0c;使用paramiko通过SSH来访问数据库。 实现了两种建立SSH方式&#xff1a;公私钥验证、密码验证。 公私钥可读本地&#xff0c;也可读取Aws S3上的私钥文件。 本质上就是在本机建立SSH隧道&#xff0c;然后将访问DB转发到本地SS…

Aws batch task 无法拉取ECR 镜像unable to pull secrets or registry auth 问题排查

AWS batch task使用了自定义镜像&#xff0c;在提作业后出现错误 具体错误是ResourceInitializationError: unable to pull secrets or registry auth: The task cannot pull registry auth from Amazon ECR: There is a connection issue between the task and Amazon ECR. C…

立即释放 Mac 空间!Duplicate File Finder 8 重复文件高速清理工具

Duplicate File Finder 专业的 Mac 重复文件清理工具。查找并删除重复的文件、文件夹&#xff0c;甚至相似的照片。 不要让无用的文件占用磁盘上的宝贵空间。 整理你的 Mac。用最好的重复文件查找器来管理你的文件集合。 扫描任何磁盘或文件夹 主文件夹、照片/音乐库、外部磁…

快速掌握EasyOCR应用实战指南

EasyOCR 是一个开源的、支持多语言&#xff08;28种&#xff09;和多文档格式&#xff08;PDF/PNG/JPG/TIFF等&#xff09;的 OCR&#xff08;光学字符识别&#xff09;工具库&#xff0c;由 Hugging Face 团队维护。其目标是简化 OCR 的开发流程&#xff0c;提供易用、高性能的…

ubuntu22.04本地部署OpenWebUI

一、简介 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台&#xff0c;旨在完全离线运行。它支持各种 LLM 运行器&#xff0c;如 Ollama 和 OpenAI 兼容的 API&#xff0c;并内置了 RAG 推理引擎&#xff0c;使其成为强大的 AI 部署解决方案。 二、安装 方法 …

JavaScript(最后一个元素的索引就是数组的长度减 1)array.length - 1

在不同的编程语言中&#xff0c;表示数组中最后一个元素的方法略有不同&#xff0c;但基本思路都是利用数组的长度或索引来实现。 以下是一些常见编程语言中获取数组最后一个元素的方法&#xff1a; 1. JavaScript: 使用 array.length - 1 索引: 这是最常见和传统的方法。Java…

【Linux系统编程】初识系统编程

目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理&#xff08;Process Management&#xff09;2. 内存管理&#xff08;Memory Management&#xff09;3. 文…

Python-列表和元组

列表 列表是什么, 元组是什么 编程中, 经常需要使用变量, 来保存/表示数据. 如果代码中需要表示的数据个数比较少, 我们直接创建多个变量即可. 但是有的时候, 代码中需要表示的数据特别多, 甚至也不知道要表示多少个数据. 这个时候, 就需要用到列表. 列表是一种让程序猿在代…

ISA-95(S95)标准详解

目录 1. 什么是ISA-95&#xff1f; 2. 为什么需要ISA-95&#xff1f; 3. ISA-95模型结构 3.1 功能层次&#xff08;Purdue CIM模型&#xff09; 3.2 信息流模型 3.3 控制功能模型 3.4 生产活动定义&#xff08;Part 3&#xff09; 4. ISA-95与ISA-88&#xff08;S88&am…

透视京东物流财报:一个长期主义的产业样本

“企业的使命不是预测未来&#xff0c;而是创造未来。但创造的前提是理解什么值得坚守百年。” 从某种角度来说&#xff0c;京东物流恰在成为当下国内研究长期主义的一个样本。这些亮眼的财报数据背后&#xff0c;对应的不仅是向上的业务增长本身&#xff0c;其中更需要被看见…

时序数据库 TDengine 化工新签约:存储降本一半,查询提速十倍

化工行业在数字化转型过程中面临数据接入复杂、实时性要求高、系统集成难度大等诸多挑战。福州力川数码科技有限公司科技依托深厚的行业积累&#xff0c;精准聚焦行业痛点&#xff0c;并携手 TDengine 提供高效解决方案。通过应用 TDengine&#xff0c;力川科技助力化工企业实现…

Networking Based ISAC Hardware Testbed and Performance Evaluation

文章目录 Applications and Challenges of Networked SensingCooperation Mechanism in Networked SensingChallenges and Key Enabling Technologies 5G NR Frame Structure Based ISAC ApproachSignals Available for Radio SensingMulti-Dimensiona Resource Optimization S…

【音视频】ffplay简单过滤器

一、ffplay简单过滤器 视频旋转&#xff1a;借助transpose滤镜 ffplay -i 1.mp4 -vf transpose1这里选择不同的数字是不同的方向&#xff1a; 视频翻转&#xff1a;借助hflip/vflip实现水平和垂直翻转&#xff1a; 水平翻转 ffplay 1.mp4 -vf hflip垂直翻转 ffplay 1.mp4 …

力扣HOT100之哈希:1. 两数之和

这道题之前刷代码随想录的时候已经刷过好几遍了&#xff0c;看到就直接秒了。这道题主要是通过unordered_map<int, int>来建立哈希表&#xff0c;其中键用来保存向量中的元素&#xff0c;而对应的值则为元素的下标。遍历整个向量&#xff0c;当遍历到nums[i]时&#xff0…