当前位置: 首页 > news >正文

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

采集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采集一次

相关文章:

  • git 添加额外的远程仓库 URL
  • 【每日学点HarmonyOS Next知识】Web跨域资源、Web长按菜单、Web拦截请求、禁止录屏、Base64图片宽高
  • WHAT - 前端阻塞场景梳理
  • Hive-优化(语法优化篇)
  • 【Unity】 HTFramework框架(六十一)Project窗口文件夹锁定器
  • Vue 系列之:Vuex 和 Pinia
  • 直播流程管理 AI 应用的开发思路和功能实现
  • 从零开始玩转 Docker:用 Node.js 打印“Hello World”
  • IOC 篇
  • 机器学习数学基础:38.统计学模型变量
  • Android中的AsyncTask。
  • Redis--Hash类型
  • SQL 注入 (C++向)
  • 【Linux】初识make
  • 78.StringBuilder简单示例 C#例子 WPF例子
  • GPT 4.5 可能是戳破 AI 泡沫的模型
  • C++二叉搜索树代码
  • 西安交大DeepSeek—电力人工智能多模态大模型创新技术应用
  • Leetcode 刷题记录 04 —— 子串
  • 【Linux】多线程(1)
  • 黄石做网站的/网络新闻发布平台
  • 怎么做电影引流网站/品牌推广与传播怎么写
  • 做网站一年要多少钱/宁波网络推广软件
  • 网站建设域名怎么用/武汉刚刚发生的新闻
  • 四川华远建设工程有限公司网站/网络营销推广公司名称
  • wordpress全自动赚钱/长沙网络优化产品