技术标签: 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这些标准。
最后,感兴趣的朋友可以私聊我。
现在才知道什么叫笔记这些有逻辑的笔记法一、康奈尔笔记法二、麦肯锡笔记法善用工具让你的笔记更好看转载自网络,如有版权请联系博主。你会不会时常在想:为什么你下载了那么多笔记应用,仍然做不好笔记。如果你的笔记毫无重点、没有结论,只是流水账式的记录发生的事或者知识点。如果你想找回某一个关键笔记,但是却一直翻不到。如果你重新看回一个星期或者一个月之前的笔记,但是毫无印象,甚至脑海里很难再现当时的内容。...
安装Tensorflow两种版本的TensorflowTensorflow有两种版本,根据显卡(如果你是使用Nvida的显卡的话)可以安装GPU版本,以及CPU版本。我们将安装CPU版本(本机 是AMD显卡)安装GPU版本的话可以参考这篇博客AnacondaAnaconda是由Python提供支持的领先的开放数据科学平台。 Anaconda的开源版本是Python和R的高性能分发版本,...
该工具用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
本题要求实现一个判断素数的简单函数、以及利用该函数计算给定区间内素数和的函数。素数就是只能被1和自身整除的正整数。注意:1不是素数,2是素数。函数接口定义:int prime( int p );int PrimeSum( int m, int n );其中函数prime当用户传入参数p为素数时返回1,否则返回0;函数PrimeSum返回区间[m,n]内所有素数的和。题目保证用户传入的参数m≤n。裁判测试程序样例:#include <stdio.h>#includ.
MATLABMATLAB 是一种用于算法开发、数据可视化、数据分析以及数值计算的高级技术计算语言和交互式环境。使用 MATLAB,您可以较使用传统的编程语言(如 C、C++ 和 Fortran)更快地解决技术计算问题。MATLAB 的应用范围非常广,包括信号和图像处理、通讯、控制系统设计、测试和测量、财务建模和分析以及计算生物学等众多应用领域。附加的工具箱(单独提供的专用 MATLAB 函数集)扩...
http://www.robotsky.com 来源:IBM 时间:2007-06-27 评论 0 条 (访问论坛) RobotSky恭候您的投稿>> 传统机器人的类型有很多,形式也各式各样,但是随着软件代理(虚拟机器人)的出现,这些变种又大大扩充了。虚拟机器人借鉴了物理机器人的
停车场有一横排车位,0代表没有停车,1代表有车。至少停了一辆车在车位上,也至少有一个空位没有停车。为防止刮蹭,需为停车人找到一个车位,使得停车人的车最近的车辆的距离是最大的,返回此时的最大距离。输出一个整数记录最大距离。
博文介绍了如何配置基于本地的组策略。基于本地的组策略只作用于本计算机及其上的用户,对其他计算机和用户不生效。通过5个子任务实例来验证本地组策略设置对本地工作环境的影响。分别是:- (1)禁止本机用户编辑注册表。- (2)禁用Windows Server 2019服务器的【关闭事件追踪程序】。- (3)禁用互联网属性对话框中的【安全】选项卡。- (4)禁止本机用户使用命令提示符。- (5)对可移动磁盘进行权限设置。
坚持写技术博客,经历和规划
33岁,男,面试项目经理,程序员出身,今天被一个经理说,对中年危机是怎么看的,最后套出来话,感觉我说话比较稳,话中没有激情,不是他感觉的那种有杀伤力的项目经理。看来性格也要适应像变色龙一样,能调节才好?同志们33正是黄金年龄,我认为项目经理应该是性格上成熟稳重,处事不惊,抗压。你们遇到过什么奇葩问题嘛?...
基本方法分为两大步,第一步即利用HttpClient建立网络连接并发送请求,第二步即利用HtmlParser解析网页。1.利用HttpClient建立网络连接,首先,我们必须安装好 HttpClient。HttpClient 可以在http://jakarta.apache.org/commons/httpclient/downloads.html下载HttpCli
当我们在切图的时候,经常会碰见这样的 普通 的描边字,如果我们都切成图片将造成大量的图片素材,工作量大,加载速度慢,难维护。经过反复实验,发现使用text-shadow的多重属性即可实现,多重属性主要用,(逗号)来分隔,给元素可以设置多个不同参数的属性。.text-shadow { color: #FFE339; text-shadow: 1p...