CAN编写完分帧发送, 分帧接收,J1939位域型结构体心得
关于由多个不同的C文件构成的工程,我采用以下方法
以为400Hz数字电源程序为例
假设工程由以下文件组成
DC_Comm.c 主要完成串口通讯部分
DC_Config.c 主要完成时钟,外设 中断初始化
DC_Control.c 主要完成电源数字化SPWM控制,以及串口接收中断的处理
DC_Memory.c 主要完成FM33256 的SPI时序的软件实现。故障记录与操作记录的写入与读取操作。
DC_Timing.h 主要完成与CPLD配合的一些时序。
响应的在include 中我还用到了一些头文件
DC_Comm.h 主要用来对DC_Comm.c中用到的数据类型进行声明,以及函数进行声明。这些函数都在DC_Comm.c中定义
DC_Control.h 主要用来对DC_Control.c中用到的数据类型进行声明,以及函数进行声明。这些函数在DC_Control.c 中定义
DC_Types.h 中宏定义了 一些Q格式常量 ,以及一些函数的声明。
总之:假设在DC_Comm.c中 定义了函数SCIRXProcess ()
则在DC_Comm.h中声明了 extern void SCIRXProcess ()
那么我在main.c 文件中调用 SCIRXProcess()的时候, 直接在main.c的前方将DC_Comm.h 包含进来就ok .
总结 就是 一个工程假设有A,B,C,main.c 4个文件组成, 假设在main.c 中定义了一些变量p,q,m 若A文件要使用p , 则需要在A文件的开头 用extern 关键字进行声明。
抛砖引玉:开始进入基于ican协议的CAN开发,该平台单片机采用STC89C52
该工程由两个文件组成SJA.C 和ican.c
SJA1000.h 中 定义了寄存器的硬件地址
基本地址 #define SJA_BaseAdr 0X7F00 由外部电路的硬件地址决定 单片机的那一个引脚连接在SJA1000的CS引脚上
内部控制寄存器 #define REG_CONTROL SJA_BaseAdr+0x00
命令寄存器 #define REG_COMMAND SJA_BaseAdr+0x01
状态此存器 #define REG_STATUS SJA_BaseAdr+0x02
…….
发送缓冲区寄存器
#define REG_TXBuffer1 SJA_BaseAdr+0x10 //发送缓冲区1
#define REG_TXBuffer2 SJA_BaseAdr+0x11 //
#define REG_TXBuffer3 SJA_BaseAdr+0x12 //
#define REG_TXBuffer4 SJA_BaseAdr+0x13 //
#define REG_TXBuffer5 SJA_BaseAdr+0x14 //
#define REG_TXBuffer6 SJA_BaseAdr+0x15 //
#define REG_TXBuffer7 SJA_BaseAdr+0x16 //
#define REG_TXBuffer8 SJA_BaseAdr+0x17 //
#define REG_TXBuffer9 SJA_BaseAdr+0x18 //
#define REG_TXBuffer10 SJA_BaseAdr+0x19 //
#define REG_TXBuffer11 SJA_BaseAdr+0x1A //
#define REG_TXBuffer12 SJA_BaseAdr+0x1B //
#define REG_TXBuffer13 SJA_BaseAdr+0x1C //发送缓冲区13
接收缓冲区寄存器
#define REG_RXBuffer1 SJA_BaseAdr+0x10 //接收缓冲区1
#define REG_RXBuffer2 SJA_BaseAdr+0x11 //
#define REG_RXBuffer3 SJA_BaseAdr+0x12 //
#define REG_RXBuffer4 SJA_BaseAdr+0x13 //
#define REG_RXBuffer5 SJA_BaseAdr+0x14 //
#define REG_RXBuffer6 SJA_BaseAdr+0x15 //
#define REG_RXBuffer7 SJA_BaseAdr+0x16 //
#define REG_RXBuffer8 SJA_BaseAdr+0x17 //
#define REG_RXBuffer9 SJA_BaseAdr+0x18 //
#define REG_RXBuffer10 SJA_BaseAdr+0x19 //
#define REG_RXBuffer11 SJA_BaseAdr+0x1A //
#define REG_RXBuffer12 SJA_BaseAdr+0x1B //
#define REG_RXBuffer13 SJA_BaseAdr+0x1C //接收缓冲区13
SJA1000.h中声明了若干函数 包括:
CAN总线发送数据的流程:
发送数据还有一种写法:
if ((ReadSJAReg(REG_CAN_SR) & (TBS_BIT|TCS_BIT)) != (TBS_BIT|TCS_BIT))
{ status = 0;}
查看SJA1000资料 有以下要点:
- SJA1000 的peilican模式的发送是单次发送
(2)与发送有关的状态寄存器的各位定义
位 |
符号 |
名称 |
值 |
功能 |
SR.5 |
Ts |
发送状态 注3 |
1 |
发送 sja1000 在传送信息 |
0 |
空闲 没有要发送的信息 |
|||
SR.3 |
Tcs |
发送完毕状态 注4 |
1 |
完毕 最近一次发送请求被成功处理 |
0 |
未完毕 当前发送请求未处理完毕 |
|||
SR.2 |
Tbs |
发送缓冲区状态 注5 |
1 |
释放:CPU可以向发送缓存器写数据 |
0 |
锁定:CPU不能访问发送缓冲器,有信息正在等待 发送或者正在发送 |
注3:如果接收状态位和发送状态位 都是0 ,则CAN总线是空闲的。
注4:无论何时发送请求位被置为1,发送完毕位(Tcs)都会被置为0,发送完毕位会一直保持到消息被成功发送。
注5:如果CPU在发送缓冲器状态为是0时(锁定)试图写发送缓冲器,则写入的字节被拒绝接收且会在无任何提示的情况下丢失。
与485通讯比较,485发送出去的数据 若接收方没有安装,主机依然显示发送成功,相比较CAN,CAN发送数据给另一个节点,则CAN节点在应答场会给主机CAN节点一个信号,表示主节点的CAN发送成功。
关于ican.c 中的应用
首先 我用结构体定义 iCANMSG 数据类型
在SJA.C 中定义了 icanmsg 数据类型的变量
iCANMSG message1 ;
iCANMSG * pcan ;
iCANMSG msg_readonly_s;
此外:对于ican协议我专门定义了指针 pcan 并用宏定义去进行处理,这样很方便的与29位ID号所对应的标识符号对应上。
然后在ican.c中因为 用到了这些变量 全部在前面加上 extern
在main.c 里 我用
至于为什么要在main () 文件 的开头 定义 msg_readonly_s
iCANMSG msg_readonly_s; //保存副本
是因为 如果出现如下情况 相当于是一个临时变量,
关于使用位阈型结构体的总结:
ICAN协议:
遵循原则 第 条我认为不一定对,因为在ican下 我infoID定义8位
但是ican下 我的低3位 是没有被定义的 undef
Ican 协议的格式定义如下:
帧结构信息
位 |
BIT7 |
BIT6 |
BIT5 |
BIT4 |
BIT3 |
BIT2 |
BIT1 |
BIT0 |
说明 |
FF |
RTR |
X |
X |
DLC.3 |
DLC.2 |
DLC.1 |
DLC.0 |
帧标识符信息
帧 标 识 符 |
ID28 |
ID27 |
ID26 |
ID25 |
ID24 |
ID23 |
ID22 |
ID21 |
|
00 |
SRCMACID(资源节点编号) |
||||||||
ID20 |
ID19 |
ID18 |
ID17 |
ID16 |
ID15 |
ID14 |
ID13 |
||
00 |
DestMACID(目标节点编号) |
||||||||
ID12 |
ID11 |
ID10 |
ID9 |
ID8 |
ID7 |
ID6 |
ID5 |
||
ACK |
FUNCID(功能码) |
SourceID(资源节点编号) |
|||||||
ID4 |
ID3 |
ID2 |
ID1 |
ID0 |
X |
X |
X |
||
SourceID(资源节点编号) |
未使用(忽略) |
我定义的方法如下:
但是 我在应用j1939协议的时候
J1939协议 所定义的帧信息ID结构如下 (29位扩展)
ID28 |
ID27 |
ID26 |
ID25 |
ID24 |
ID23 |
ID22 |
ID21 |
优先级 |
保留位 |
数据页 |
PDU格式 |
||||
ID20 |
ID19 |
ID18 |
ID17 |
ID16 |
ID15 |
ID14 |
ID13 |
PDU格式 |
特定PDU |
||||||
ID12 |
ID11 |
ID10 |
ID9 |
ID8 |
ID7 |
ID6 |
ID5 |
特定PDU |
源地址 |
||||||
ID4 |
ID3 |
ID2 |
ID1 |
ID0 |
X |
X |
X |
源地址 |
我的定义方法如下: 从低位到高位定义
假设 节点2 和节点3正在通讯,某一时刻节点1要设置节点3 。给节点3发数据,
节点1不用等到节点2和节点3不通讯了。节点1直接发送数据,节点1 的CAN硬件会自动控制给节点1发数据。不用人为控制,由CAN控制器的硬件来完成。
基于51单片机的CAN通讯试验:
方法: 51单片机程序中不断的往上位机(CANtest)发送数据 ,然后在某一任意时刻, 我用周立功的(CANtest)发送建立连接命令,看单片机是否可以正常响应。 并且记录示波器的波形图。
在CANTEST 上 点击 发送消息帧 如下图 第2个较短的时间间隔内的帧
该消息的ID号是 0x0023e4fe 数据场是 00 ee 0a
51单片机接收到消息以后,往上传送消息 该消息的数据场 00 01 02 03 04
如下图所示: 左侧第一个较短的帧 就是 51单片机上传的响应帧。数据场为00 01 02 03 04
响应场 的数据 (该数据我先不解析)
为了验证我用kavaser 捕捉以下时间间隔 。
看两个时间间隔
第一 就是上位机 发送建立连接命令 到收到51单片机 返回的响应帧的时间间隔
第二 就是51 单片机 返回响应帧 到 51单片机继续往上位机传送计数值的时间间隔
第三 测试 看一下 默认情况下 上位机不发送连接命令,51单片机上传数据的时间间隔
第一个时间 我用示波器测试是: 约为200ms
第二个时间 我用示波器测试是: 约为1.5ms
第三个时间 我用示波器测试是: 约为12.4ms
我用kavaser 在 20190423 的 9点32 和 9点33 分左右的时候分别用cantest 发送建立连接命令 接收的时间间隔是 6041-4021=2021
2021*百分之一毫秒 约等于 200ms 与示波器测试一致
接下来 我用kavaser 的logging 功能测试
时刻 9点32 的数据
9点33时刻的数据
接下来 我的想法是 你新找一个51单片机 ,然后替换 周立功上位机的功能,进行连接命令的发送
试验平台大家如下:
试验平台照片
实际上 CAN 网络是不分主机和从机的,不像485网络。这里我设计的主机的功能就是:
按下:靠4个数码管一侧的按键, 按一下 数码管的显示增加1 然后并发送一帧
发送的消息帧 为 ID号 0x0023e4fe 数据场是00 ee 20 (16进制的20代表十进制32
计数 32次,认为握手时间是32秒,超过32秒可以认为连接断开)
做这个事情的目的是:消息帧的发送我在用嵌入式编程的时候,用can_send_anylength()函数就可以搞定。这种情况使用于网络中一直有数据通讯存在的情况。
试验现象:
在时间10点24
我用主机(51单片机)的按键 发送消息帧 ID号0x0023e4fe 数据 00 ee 2 0
从机51单片机 在1秒以后 反馈给我响应帧 ID号0X3E034EE 数据是 00 01 02 03 04
在这个1秒的时间间隔内,CAN数据线上 还有一帧消息在传递 如下图所示:
若在32秒内,主机再次发送连接命令,。从机将给主机反馈 已经在连接中的提示消息
该消息 的ID号是 0X3E02FFE 00 03
在时间:10:30:10:7323 我又用主机发送了 建立连接的消息
ID号是 0x023e4fe 00 ee 20
此时在10:30:10:8433 时刻 从机就给主机回复了消息帧 在这个时间间隔内,无其他帧在传递。 如下图:
重要:与上面的那个中间有一帧的情况的截图进行对比:可以知道:从机在接收到主机的连接,命令后,会判断CAN线上是否空闲,如果当前有数据发送或接收 从机就等该数据发送完毕以后,在发送响应帧, 如果CAN线上空闲,则从机便可以直接发送给主机器响应帧。发送程序的时候 从机程序仅仅检测 是不是上一帧数据是不是发送完成,并不检测总线上空闲,这一块是CAN控制器硬件自动完成的,我暂且先这么认为。
在时间 10时30分 13秒 在32秒的计时时间内, 我再次发送建立连接命令,此时 从机
便会给我回复响应的消息帧 帧ID号 0x 3e02ffe 00 03 如下图所示:
Word 源文件在百度网盘
CAN编写完分帧发送, 分帧接收,J1939位域型结构体心得的更多相关文章
- I帧、P帧、B帧、GOP、IDR 和PTS, DTS之间的关系
一.视频传输原理 视频是利用人眼视觉暂留的原理,通过播放一系列的图片,使人眼产生运动的感觉.单纯传输视频画面,视频量非常大,对现有的网络和存储来说是不可接受的.为了能够使视频便于传输和存储,人们发现视 ...
- java socket传送一个结构体给用C++编写的服务器解析的问题
另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...
- CAN分帧发送程序说明
试验平台 仅仅 需要一台主机 一台 周立功 CAN 助手, 一个232 助手就OK ICAN 协议 资源节点地址 电脑 我认为是0x01 51单片机主机的地址 是 0x1f 建立连接的 功能码 是0x ...
- 构造并发送Beacon帧以伪造任意WiFi热点
请想象一下这样的情景:你可以任意伪造很多个WiFi热点, 这个技术只能在linux上使用,而且对无线网卡也有一定的挑剔,具体的下面会讲- 阶段一:基本原理 首先需要搞清楚的是,手机.电脑等支持WiFi ...
- 程序设计入门——C语言 第6周编程练习 2 完数(5分)
2 完数(5分) 题目内容: 一个正整数的因子是所有可以整除它的正整数.而一个数如果恰好等于除它本身外的因子之和,这个数就称为完数.例如6=1+2+3(6的因子是1,2,3). 现在,你要写一个程序, ...
- DIOCP数据包太大,请在业务层分拆发送
DIOCP数据包太大,请在业务层分拆发送 DIOCP日志记录异常:数据包太大,请在业务层分拆发送...... 跟踪发现,原因在下图:
- stm32+lwip(五):以太网帧发送测试
我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...
- CAN总线远程帧和错误帧
远程帧 通常,数据传输是由数据源节点(例如,传感器发出数据帧)自主完成的.但也可能存在目标节点向源节点请求发送数据的情况.要做到这一点,目标节点需发送一个远程帧,其中的标识符应与所需数据帧的标识符相匹 ...
- 图解 I帧,B帧以及P帧
I‑frame (Intra-coded picture): 即完整的一张图片 P‑frame (Predicted picture): 与前面一张图片的区别的区域 B‑frame (Bidirect ...
随机推荐
- 《SQL 进阶教程》 查找局部不一致的数据
-- 从下面这张商品表里找出价格相等的商品的组合 select * from products p1LEFT JOIN products p2on p1.price = p2.price and p1 ...
- git 常用命令记录 -- 快捷&备忘
1.安装 略2.git拉取远程分支 git config user.name git config user.email git config --global user.name xxxx git ...
- C#学习之time控件和timer_tick事件 -----转载
Timer控件:Timer控件只有绑定了Tick事件,和设置Enabled=True后才会自动计时,停止计时可以用Stop()控制,通过Stop()停止之后,如果想重新计时,可以用Start()方法来 ...
- mybatis动态参数查询
参考:https://blog.csdn.net/zbw18297786698/article/details/53727594
- 第2节 storm路由器项目开发:1 - 7、网络路由器项目
网安需求: 1:IFTTT:随着物联网的兴起,if this then that .如果出现这种情况,那么及时反映做出对应的操作. 判断手机号黑白名单,mac地址黑白名单.如果是碰到手机号或者mac地 ...
- Ajax--概述
1.Ajax(Asynchronous JavaScript and XML),允许浏览器与服务器通信而无需刷新当前页面的技术都被叫做Ajax; 2.XMLHttpRequest:该对象是对JavaS ...
- 45 孩子们的游戏(圆圈中最后剩下的数) + list操作总结+ for_each多记忆容易忘记
题目描述 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此.HF作为牛客的资深元老,自然也准备了一些小游戏.其中,有个游戏是这样的:首先,让小朋友们围成一个大圈.然后,他随机指 ...
- 「NOIP2015」斗地主
传送门 Luogu 解题思路 给你们一张搜索顺序图,然后就大力模拟就好. 细节注意事项 爆搜题,你们懂的... 参考代码 写的有点丑了,洛谷上只能过加强版的88分,会T六个点 #include < ...
- Redis散列表类型
散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其他的数据类型. 一个散列类型键可以包含至多2^32 -1个字段. 命令 赋值 HSE ...
- SSH框架系列:Spring配置多个数据源
分类: [java]2013-12-09 16:59 1247人阅读 评论(0) 收藏 举报 1.问题的引入 对于普通的SSH框架而言,一般配置一个数据源,一个SessionFactory,一个事务管 ...