STM32兴趣篇二:模拟汽车OBD接口处的CAN收发信号实验_obd车辆信号模拟串口_天亮继续睡的博客-程序员秘密

技术标签: STM32  keil mdk  STM32经典案例分享  嵌入式  CAN总线  单片机  

记录一下,方便以后翻阅~

CAN总线是汽车电子上不可缺少的技术,虽然现在有些造车新势力开始采用以太网来逐步取代CAN总线的地位,但是CAN总线先天的优势(成本低,安全性好,稳定性好),让其霸占汽车总线的巅峰,也必然有着其过人之处。个人比较看好未来是由CAN总线以太网两者互相并存的车载网络解决方案。
在这里插入图片描述
话题扯得有点远,只是想表个态度,即使现在才从零学习CAN总线,它也不是什么快要“没落”的技术,不仅仅在汽车领域上,在工业领域、医疗领域等都有CAN总线的一席之地。

今天分享一个简单的CAN通讯实验,用STM32F103C8T6工控板模拟汽车OBD发送CAN信号,再用另一款STM32F103ZET6开发板模拟汽车电子设备来接收CAN信号,主要实现两个功能:

1)STM32F103C8T6工控板上电后,会自动发送模拟转速信号,具体的:该转速信号的ID号为0x17c,其数据位的第三和第四位为转速数据。STM32F103ZET6开发板上电后,利用CAN中断服务函数不停的接收该转速信号(这一功能模拟汽车电子设备接收汽车OBD发送的CAN广播信号);
2)当按下STM32F103ZET6开发板的按键时,会主动发送一帧CAN信号至STM32F103C8T6工控板,STM32F103C8T6工控板接收到后,会发送一次汽车车速信号(这一功能模拟汽车电子设备接收汽车OBD发送的CAN收发信号)。

硬件部分
1. CAN的接线
下图是STM32F103C8T6工控板的芯片接线,PB8和PB9对应CAN_RX和CAN_TX;
在这里插入图片描述
下图是STM32F103ZET6开发板的新品接线,PA11和PA12对应CAN_RX和CAN_TX;
在这里插入图片描述
将STM32F103C8T6工控板的CAN_H和STM32F103ZET6开发板的CAN_H相连;
将STM32F103C8T6工控板的CAN_L和STM32F103ZET6开发板的CAN_L相连。

软件部分
1. STM32F103C8T6工控板的主要代码
前面也说了,STM32F103C8T6工控板用来模拟汽车OBD发送CAN信号,涉及广播发送CAN信号和收发模式下发送CAN信号。
1.1 main.c主函数
主函数主要包括系统初始化,while循环里主要包含了模拟CAN广播发送的代码,另外还包括转速和车速的变化代码,具体如下:

/************************************************
函数名称:int main()
函数功能:主函数入口
入口参数:无
返回参数:int
开发作者:闲人Ne
*************************************************/
#define CAN_500K 4
u16 can_rpm = 2800;                            // 广播用,模拟的转速, 初始化700rpm,那么700*4=2800
u8  can_v   =   10;                            // 收发用,模拟的车速,初始化10kph
u8  canbuf_broadcast[8] = {
    0,0,0,0,0,0,0,0};   // 广播用, 模拟接收到转速ID号里的8位数据,转速数据位于[3:4]位
u8  canbuf_rs[8]        = {
    0,0,0,0,0,0,0,0};   // 收发用,模拟接收到车速ID号里的8位数据,车速数据位于[3] 位
int main(void)
{
    
	u8 t=0;	
	u8 can_upper_rpm; 		   // can_rpm的高8位
	u8 can_lower_rpm;   	   // can_rpm的低8位 
	u8 res;                    // 错误号
	delay_init();              // 初始化延时函数    
	LED_Init();                // 初始化LED函数
	CAN_Mode_Init(CAN_500K);   // CAN初始化函数 
 	while(1)
	{
    
		can_lower_rpm = can_rpm;                           // can_lower取can_rpm低8位
		can_upper_rpm = can_rpm >> 8;                      // can_upper取can_rpm高8位
		canbuf_broadcast[3] = can_upper_rpm;               // 更新转速ID号里的第[3]位数据;
		canbuf_broadcast[4] = can_lower_rpm;			   // 更新转速ID号里的第[4]位数据;
		res=Can_Send_Msg_broadcast(canbuf_broadcast,8);    // 发送转速数据,模拟汽车CAN广播发送
		if(res)D2=0;            					       // 发送失败时,LED1灯亮
		canbuf_rs[3] = can_v;							   // 更新车速ID号里的第[3]位数据;
		can_rpm = can_rpm + 40;                           
		if(can_rpm > 16000)can_rpm =2800;	
	  	can_v = can_v + 10;
		if(can_v > 160)can_v =10;	
		t++;
		if(t==1)
		{
    
			D1=!D1;                                       //提示系统正在运行//	
			t=0;
		}	
		delay_ms(1000);		
	}
}
/****** Copyright (C)2020 闲人Ne. All Rights Reserved ****** END OF FILE *******/

1.2 stm32f10x_it.c里的中断服务函数
USB_LP_CAN1_RX0_IRQHandler()函数主要模拟接收到STM32F103ZET6开发板的CAN信号时,发送一帧CAN车速信号(模拟收发模式下发送CAN信号),具体代码如下:

/************************************************
函数名称:USB_LP_CAN1_RX0_IRQHandler()
函数功能:USB_LP_CAN1接收中断服务函数
入口参数:无
返回参数:无
开发作者:闲人Ne
*************************************************/
#define sr_stdid 0x7DF    // 这是从STM32F103ZET6开发板接收到的CAN信号里的ID号
extern u8 canbuf_rs[8];   // 收发用,模拟接收到车速ID号里的8位数据,车速数据位于[3] 位
void USB_LP_CAN1_RX0_IRQHandler(void)
{
    
	u8 err=0;
	u8 canbuf_v[8];            
 	CanRxMsg RxMessage; 
	int i=0;
	CAN_Receive(CAN1, 0, &RxMessage);
	if(sr_stdid == RxMessage.StdId)      				   // 判断接收到的CAN信号的ID号是否是0x7DF
		for(i=0;i<8;i++)canbuf_v[i]=RxMessage.Data[i];       
 		if(canbuf_v[0]==2&canbuf_v[1]==1&canbuf_v[2]==13)  // 判断接收到的CAN信号的数据第0,第1和第2位是否是0x21D
			err = Can_Send_Msg_rs(canbuf_rs,8);	           // 发送一帧CAN车速信号
		if(err)D2=0;            					                   
}
/****** Copyright (C)2020 闲人Ne. All Rights Reserved ****** END OF FILE *******/

1.3 CAN发送一帧信号函数
主要包括两个函数,分别模拟广播模式下发送CAN信号和收发模式下发送CAN信号,具体代码如下:

/********************************************************
函数名称:u8 Can_Send_Msg_broadcast(u8* msg,u8 len)
函数功能:广播用,CAN发送一组数据	
入口参数:u8* msg,数据指针,最大为8个字节; u8 len 数据长度
返回参数:0,成功;1,失败
开发作者:闲人Ne
*********************************************************/
u8 Can_Send_Msg_broadcast(u8* msg,u8 len)
{
    	
	u8 mbox;
	u16 i=0;
	CanTxMsg TxMessage_b;
	TxMessage_b.StdId=0x17C;			  // 标准标识符
	TxMessage_b.ExtId=0x18DB33F1;	      // 扩展标示符
	TxMessage_b.IDE=CAN_Id_Standard; 	  // 标准帧
	TxMessage_b.RTR=CAN_RTR_Data;		  // 数据帧
	TxMessage_b.DLC=len;				  // 数据长度
	for(i=0;i<len;i++)
		TxMessage_b.Data[i]=msg[i];			          
	mbox= CAN_Transmit(CAN1, &TxMessage_b);   
	i=0; 
	while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	
	if(i>=0XFFF)return 1;
	return 0;	 
}
/********************************************************
函数名称:u8 Can_Send_Msg_rs(u8* msg,u8 len)
函数功能:收发用,CAN发送一组数据	
入口参数:u8* msg,数据指针,最大为8个字节; u8 len 数据长度
返回参数:0,成功;1,失败
开发作者:闲人Ne
*********************************************************/
u8 Can_Send_Msg_rs(u8* msg,u8 len)
{
    	
	u8 mbox;
	u16 i=0;
	CanTxMsg TxMessage_r;
	TxMessage_r.StdId=0x7E8;			  // 标准标识符
	TxMessage_r.ExtId=0x18DB33F1;		  // 扩展标示符
	TxMessage_r.IDE=CAN_Id_Standard; 	  // 标准帧
	TxMessage_r.RTR=CAN_RTR_Data;		  // 数据帧
	TxMessage_r.DLC=len;				  // 数据长度
	for(i=0;i<len;i++)
		TxMessage_r.Data[i]=msg[i];			          
	mbox= CAN_Transmit(CAN1, &TxMessage_r);   
	i=0; 
	while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	
	if(i>=0XFFF)return 1;
	return 0;	 
}

2. STM32F103ZET6开发板的主要代码
前面也说了,STM32F103ZET6开发板用来模拟汽车电子设备接收汽车OBD发送的CAN信号。
2.1 main.c主函数
主函数主要包括系统初始化,while循环里主要包含了按键按下时,发送CAN请求信号,具体如下:

/************************************************
函数名称:int main()
函数功能:主函数
入口参数:无
返回参数:int
开发作者:闲人Ne
*************************************************/
int main(void)
{
    	 
	u8 canbuf_v[8]={
    2,1,13,0,0,0,0,0};                 // 0x 21D0 0000
	u8 key;
	u8 i=0,t=0;
	u8 res;
	u8 mode=CAN_Mode_Normal;                           //CAN工作模式;CAN_Mode_Normal(0):普通模式,CAN_Mode_LoopBack(1):环回模式
	delay_init();	    	                           //延时函数初始化  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    //设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	                           //串口初始化为115200
	LED_Init();		  		                           //初始化与LED连接的硬件接口
	KEY_Init();				                           //按键初始化	 	
	CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_Normal);  //CAN初始化环回模式,波特率500Kbps   	
 	while(1)
	{
    
		key=KEY_Scan(0);
		if(key==KEY0_PRES)                          
		{
    
			printf("\n发送CAN数据为:");
			for(i=0;i<8;i++)
				printf("\n[%x]",canbuf_v[i]);
			printf("\r\n");
			res=Can_Send_Msg(canbuf_v,8);              // 发送CAN请求信号                          
			if(res)printf("\n发送失败!\r\n");		
		}
		t++; 
		delay_ms(10);
		if(t==20)
		{
    
			LED0=!LED0;                                                  	
			t=0;
		}		   
	}
}
/****** Copyright (C)2020 闲人Ne. All Rights Reserved ****** END OF FILE *******/

2.2 stm32f10x_it.c里的中断服务函数
USB_LP_CAN1_RX0_IRQHandler()函数主要模拟接收到STM32F103C8T6开发板的CAN信号,并根据ID号判断是接收了广播模式下的转速信号还是收发模式下的车速信号,具体代码如下:

u8 canbuf[8];	    
#define stdid_broad 0x17C
#define stdid_rs 	 0x7E8
void USB_LP_CAN1_RX0_IRQHandler(void)
{
    
	u16 rpm;
	u8 v;
  	CanRxMsg RxMessage; 
	int i=0;
  	CAN_Receive(CAN1, 0, &RxMessage);
	if(RxMessage.StdId == stdid_broad)                // 判断接收到的CAN信号的ID号是否为 0x17C
	{
    
		for(i=0;i<8;i++)canbuf[i]=RxMessage.Data[i];
		rpm = (canbuf[3]<<8|canbuf[4])/4;
		printf("\n接收到的汽车转速为:%d rpm \r\n",rpm);
	}
	else 
		if(RxMessage.StdId == stdid_rs)              // 判断接收到的CAN信号的ID号是否为 0x7E8
		{
    
			for(i=0;i<8;i++)canbuf[i]=RxMessage.Data[i];
			v = canbuf[3];
			printf("\n接收到的汽车车速为:%d kph \r\n",v);	
		}			
}

2.3 STM32F103ZET6开发板还包含了串口通讯函数,主要用来与电脑通讯,显示运行结果。这些知识可以参考我以前写的文章。

实验结果
实验结果如下图所示,系统运行后,将STM32F103ZET6开发板的串口接到电脑上,可实时看到从STM32F103C8T6工控板传来的转速信号,当按下STM32F103ZET6开发板的按键时,可从STM32F103C8T6工控板接收到一次车速信号。
在这里插入图片描述
备注:
1)对于CAN的基础知识可以参考之前我写的文章;
2)汽车CAN总线知识参考ISO 15765-4,ISO 15031-5,SAE J1939这些标准。

最后,感兴趣的朋友可以私聊我。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Leisure_ksj/article/details/111759705

智能推荐

清北学霸的笔记方法_清华北大学神的纸质和电子笔记如何做的_notecoder的博客-程序员秘密

现在才知道什么叫笔记这些有逻辑的笔记法一、康奈尔笔记法二、麦肯锡笔记法善用工具让你的笔记更好看转载自网络,如有版权请联系博主。你会不会时常在想:为什么你下载了那么多笔记应用,仍然做不好笔记。如果你的笔记毫无重点、没有结论,只是流水账式的记录发生的事或者知识点。如果你想找回某一个关键笔记,但是却一直翻不到。如果你重新看回一个星期或者一个月之前的笔记,但是毫无印象,甚至脑海里很难再现当时的内容。...

Tensorflow Win10 stage.1_Ice星空的博客-程序员秘密

安装Tensorflow两种版本的TensorflowTensorflow有两种版本,根据显卡(如果你是使用Nvida的显卡的话)可以安装GPU版本,以及CPU版本。我们将安装CPU版本(本机 是AMD显卡)安装GPU版本的话可以参考这篇博客AnacondaAnaconda是由Python提供支持的领先的开放数据科学平台。 Anaconda的开源版本是Python和R的高性能分发版本,...

andriod zipalign 支持apk 2G 以上的对齐_黑塞123的博客-程序员秘密

该工具用python 实现 zipalign 兼容2G以上的apk 包括(64位)项目地址:本篇博客 只讲解 zip 32, 64的结构.也就是 zipalign 的实现原理:首先看下zip 的结构吧: 4.3.6 Overall .ZIP file format: [local file header 1] [encryption header 1] [file data 1] [data descriptor 1] . . . [local file hea

6-4 使用函数求素数和 (20 分)_6-4 使用函数求素数和python_bdtrdtbrtb的博客-程序员秘密

本题要求实现一个判断素数的简单函数、以及利用该函数计算给定区间内素数和的函数。素数就是只能被1和自身整除的正整数。注意:1不是素数,2是素数。函数接口定义:int prime( int p );int PrimeSum( int m, int n );其中函数prime当用户传入参数p为素数时返回1,否则返回0;函数PrimeSum返回区间[m,n]内所有素数的和。题目保证用户传入的参数m≤n。裁判测试程序样例:#include &lt;stdio.h&gt;#includ.

matlab用于系统框图建模的函数,MATLAB产品家族中文_吴域的博客-程序员秘密

MATLABMATLAB 是一种用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境。使用 MATLAB,您可以较使用传统的编程语言(如 C、C++ 和 Fortran)更快地解决技术计算问题。MATLAB 的应用范围非常广,包括信号和图像处理、通讯、控制系统设计、测试和测量、财务建模和分析以及计算生物学等众多应用领域。附加的工具箱(单独提供的专用 MATLAB 函数集)扩...

开源机器人技术工具包_geng_ch的博客-程序员秘密

http://www.robotsky.com  来源:IBM   时间:2007-06-27   评论 0 条  (访问论坛) RobotSky恭候您的投稿>> 传统机器人的类型有很多,形式也各式各样,但是随着软件代理(虚拟机器人)的出现,这些变种又大大扩充了。虚拟机器人借鉴了物理机器人的

随便推点

【华为OD机试真题 Python】找车位_机考找车位_steven_moyu的博客-程序员秘密

停车场有一横排车位,0代表没有停车,1代表有车。至少停了一辆车在车位上,也至少有一个空位没有停车。为防止刮蹭,需为停车人找到一个车位,使得停车人的车最近的车辆的距离是最大的,返回此时的最大距离。输出一个整数记录最大距离。

【Windows Server 2019】组策略的配置与管理——配置基于本地的组策略_本地组策略_NOWSHUT的博客-程序员秘密

博文介绍了如何配置基于本地的组策略。基于本地的组策略只作用于本计算机及其上的用户,对其他计算机和用户不生效。通过5个子任务实例来验证本地组策略设置对本地工作环境的影响。分别是:- (1)禁止本机用户编辑注册表。- (2)禁用Windows Server 2019服务器的【关闭事件追踪程序】。- (3)禁用互联网属性对话框中的【安全】选项卡。- (4)禁止本机用户使用命令提示符。- (5)对可移动磁盘进行权限设置。

2021-05-08_debuk的博客-程序员秘密

33岁,男,面试项目经理,程序员出身,今天被一个经理说,对中年危机是怎么看的,最后套出来话,感觉我说话比较稳,话中没有激情,不是他感觉的那种有杀伤力的项目经理。看来性格也要适应像变色龙一样,能调节才好?同志们33正是黄金年龄,我认为项目经理应该是性格上成熟稳重,处事不惊,抗压。你们遇到过什么奇葩问题嘛?...

Eclipse中Java做网络爬虫基本方法_eclipse怎么添加爬虫_Sean_SJTU的博客-程序员秘密

基本方法分为两大步,第一步即利用HttpClient建立网络连接并发送请求,第二步即利用HtmlParser解析网页。1.利用HttpClient建立网络连接,首先,我们必须安装好 HttpClient。HttpClient 可以在http://jakarta.apache.org/commons/httpclient/downloads.html下载HttpCli

普通的css普通的描边字_banyiji3580的博客-程序员秘密

当我们在切图的时候,经常会碰见这样的 普通 的描边字,如果我们都切成图片将造成大量的图片素材,工作量大,加载速度慢,难维护。经过反复实验,发现使用text-shadow的多重属性即可实现,多重属性主要用,(逗号)来分隔,给元素可以设置多个不同参数的属性。.text-shadow { color: #FFE339; text-shadow: 1p...

推荐文章

热门文章

相关标签