CAN 总线数据收发驱动
目标:使用链表实现 CAN 总线数据的分帧发送和分帧数据的接收,同时将接收到的多帧数据合并成一个完整的数据包。
使用场合:当一个CAN总线网络上有多个端口对同一个端口发送分帧数据,且来自不同端口的分帧数据穿插接收,因此需要将不同端口的数据分别进行合并,形成完整的数据包
下面的代码使用纯C实现,方便移植。
CAN扩展帧标识如下:
typedef union
{
unsigned long extId;
struct
{
unsigned long sesId : 8;
unsigned long funId : 5;
unsigned long srcId : 8;
unsigned long desId : 8;
unsigned long _null : 3;
}atr;
}uextId_t;
八字节数据域,做如下处理:前两字节作为帧序号,后六字节为有效数据。
帧序号从零开始。帧序号为零时,表示信息帧,后面四字节保存数据总字节数;帧序号不为零时表示实际发送的数据帧数,每帧六字节数据。
实验环境:VS2012
实验过程:使用多个线程,每个线程将一个较大的数据包,按照帧格式拆成多帧数据,然后将帧数据全部保存到一个非常大的数组中,由于是多个线程 同时工作,所以对于每个数据包的帧来说都不是按顺序进入数组中的,而是多个数据包的帧穿插着存入数组,最后调用数据接收处理API函数,对数组中的帧一个个进行接收处理,最后输出帧合并后的数据包。
代码注释比较清晰,因此这里就不废话了,直接上代码。
驱动文件
CanDrv.c
#include <stdlib.h>
#include "CanDrv.h"
// Define NULL pointer value
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
// 需求:CAN端口可能会收到来自多个节点的分帧数据,在多个节点的分帧数据穿插接收进来后,根据帧标识将多个节点的分帧数据整理合并.
// 思路:建立一条单向链表,链表的一个节点代表CAN总线的一个端点的一个完整数据包,接收到一个分帧数据后将其存储在对应的链表节点中.
typedef union
{
unsigned long extId;
struct
{
unsigned long sesId : 8; // 会话ID,每发一个数据包,自增一次
unsigned long funId : 5; // 功能码
unsigned long srcId : 8; // 本地ID
unsigned long desId : 8; // 目标ID
unsigned long _null : 3; // 未使用bit
}atr;
}uextId_t;
typedef struct _sCanData_t
{
unsigned char desId; // 目标ID
unsigned char srcId; // 本地ID
unsigned char funId; // 功能码
unsigned char sesId; // 会话ID
unsigned char txLen; // 发送字节数
unsigned char Buf[8]; // 发送缓存区
}sCanData_t;
{
unsigned char desId; // 目标ID
unsigned char srcId; // 本地ID
unsigned char funId; // 功能码
unsigned char sesId; // 会话ID
unsigned char *pBuf; // 接收缓存
unsigned long rxLen; // 当前已经接收的字节数
unsigned long rxTotalLen; // 需要接收的总字节数
}sCanRecvData_t;
{
struct _sCanRecvData_t *pBuf;
struct _sCanRecvList_t *pNext;
}sCanRecvList_t;
#pragma pack(pop)
static sCanRecvList_t *sCanRecvListHandle = NULL; // 链表句柄
// 返回值:内存起始地址
static void *pMalloc(unsigned int size)
{
return malloc(size);
}
static void pFree(void *pmem)
{
free(pmem);
}
// 搜索对应的CAN节点在链表中的位置
// 返回值:若相应的CAN节点存在,则返回CAN节点在链表中的节点地址,否则返回NULL
static sCanRecvList_t *CanNodeSearch(const sCanRecvList_t *pHeadNode, sCanData_t *sCanData)
{
sCanRecvList_t *pNode = NULL;
{
return NULL;
}
{
if(pNode->pBuf->srcId == sCanData->srcId && pNode->pBuf->funId == sCanData->funId && pNode->pBuf->sesId == sCanData->sesId)
{
return pNode;
}
}
}
// 返回值:创建成功则返回头节点地址,否则返回NULL
static sCanRecvList_t *ListCreate(void)
{
sCanRecvList_t *head = NULL;
if(head == NULL)
{
return NULL;
}
head->pNext = NULL;
}
// 返回值:创建成功返回节点地址,否则返回NULL
static sCanRecvList_t *ListNodeCreate(sCanData_t *sCanData)
{
sCanRecvList_t *node = NULL;
{
return NULL; // 数据异常
}
{
return NULL; // 帧序号不为0,说明不是头帧
}
if(node == NULL)
{
return NULL;
}
node->pBuf = (sCanRecvData_t *)pMalloc(sizeof(sCanRecvData_t));
if(node->pBuf == NULL)
{
pFree(node);
node = NULL;
return NULL;
}
node->pBuf->desId = sCanData->desId;
node->pBuf->srcId = sCanData->srcId;
node->pBuf->funId = sCanData->funId;
node->pBuf->sesId = sCanData->sesId;
node->pBuf->rxTotalLen = (node->pBuf->rxTotalLen << 8) + sCanData->Buf[5];
node->pBuf->rxTotalLen = (node->pBuf->rxTotalLen << 8) + sCanData->Buf[4];
node->pBuf->rxTotalLen = (node->pBuf->rxTotalLen << 8) + sCanData->Buf[3];
node->pBuf->rxTotalLen = (node->pBuf->rxTotalLen << 8) + sCanData->Buf[2];
if(node->pBuf->pBuf == NULL)
{
pFree(node->pBuf);
node->pBuf = NULL;
pFree(node);
node = NULL;
return NULL;
}
}
// 返回值:链表尾节点地址,链表为空或者没有找到时返回NULL
static sCanRecvList_t *ListNodeSearch(const sCanRecvList_t *pHeadNode, const sCanRecvList_t *pSearchNode)
{
sCanRecvList_t *pNode = (sCanRecvList_t *)pHeadNode;
{
return NULL;
}
{
while(pNode->pNext != NULL)
{
pNode = pNode->pNext; // 搜索尾节点
}
}
else
{
while(pNode != pSearchNode)
{
pNode = pNode->pNext; // 搜索指定节点
if(pNode == NULL)
{
return NULL;
}
}
}
}
static void ListNodeInssert(const sCanRecvList_t *pHeadNode, sCanRecvList_t * const pNewNode)
{
sCanRecvList_t *pNode = NULL;
{
return;
}
if(pNode != NULL)
{
pNode->pNext = pNewNode; // 在链表末尾插入一个新节点
pNewNode->pNext = NULL;
}
}
static void ListNodeDelete(const sCanRecvList_t *pHeadNode, sCanRecvList_t *pDeleteNode)
{
sCanRecvList_t *pLastNode = (sCanRecvList_t *)pHeadNode;
{
return;
}
while(pLastNode->pNext != pDeleteNode)
{
pLastNode = pLastNode->pNext;
}
{
// 删除节点
pLastNode->pNext = pDeleteNode->pNext;
pFree(pDeleteNode->pBuf->pBuf);
pDeleteNode->pBuf->pBuf = NULL;
pDeleteNode->pBuf = NULL;
pDeleteNode->pNext = NULL;
pDeleteNode = NULL;
}
}
// p:RxMsg 数据域数据指针(RxMsg.Data)
// len:有效字节数(RxMsg.DLC)
// extId:扩展帧ID(RxMsg.ExtId)
// 返回值:0=succ,1=data error,2=memory error
unsigned char CanRecvDataProcess(const void *p, unsigned char len, unsigned long extId)
{
unsigned char i;
uextId_t uextId;
sCanData_t sCanData;
sCanRecvList_t *pNode = NULL;
static sCanRecvList_t *pHeadNode = NULL; // 创建一条双向链表
unsigned char *pBuf = (unsigned char *)p;
{
return 1; // 数据异常
}
uextId.extId = extId;
sCanData.desId = uextId.atr.desId;
sCanData.srcId = uextId.atr.srcId;
sCanData.funId = uextId.atr.funId;
sCanData.sesId = uextId.atr.sesId;
sCanData.txLen = len;
for(i = 0; i < sizeof(sCanData.Buf); i++)
{
sCanData.Buf[i] = pBuf[i];
}
if(pHeadNode == NULL)
{
pHeadNode = ListCreate(); // 链表为空就创建链表
if(pHeadNode == NULL)
{
return 2; // 链表创建失败的原因只有内存申请失败
}
sCanRecvListHandle = pHeadNode;
}
pNode = CanNodeSearch(pHeadNode, &sCanData);
if(pNode == NULL)
{
pNode = ListNodeCreate(&sCanData); // 创建一个新节点
if(pNode == NULL)
{
return 2;
}
}
else
{
// 帧数据合法性验证
unsigned int index = sCanData.Buf[1];
index = (index << 8) + sCanData.Buf[0];
if((index - 1) * 6 != pNode->pBuf->rxLen)
{
return 0; // 帧序号不正确,直接丢弃
}
for(i = 0; i < sCanData.txLen - 2; i++)
{
pNode->pBuf->pBuf[pNode->pBuf->rxLen++] = sCanData.Buf[i + 2];
}
if(pNode->pBuf->rxLen == pNode->pBuf->rxTotalLen)
{
CanRead(pNode->pBuf->pBuf, pNode->pBuf->rxLen);
ListNodeDelete(sCanRecvListHandle, pNode);
}
}
return 0;
}
// 发送区
//=========================================================================================================================================================
// 返回值:0=succ,1=data error,2=timeout
static unsigned char CanSendFrame(const void *p, unsigned char len)
{
uextId_t uextId;
sCanData_t *sCanData = (sCanData_t *)p;
{
return 1;
}
uextId.atr.desId = sCanData->desId;
uextId.atr.srcId = sCanData->srcId;
uextId.atr.funId = sCanData->funId;
uextId.atr.sesId = sCanData->sesId;
return CanWrite(sCanData->Buf, sCanData->txLen, uextId.extId);
}
// desId:目标ID
// srcId:本地ID
// funId:功能码
// sesId:会话ID,每次发送前自增1
// p:发送数据指针
// len:发送字节数(长度不限)
// 返回值:0=succ,1=error
unsigned char CanSendData(unsigned char desId, unsigned char srcId, unsigned char funId, unsigned char sesId, const void *p, unsigned int len)
{
sCanData_t sCanData;
unsigned int i = 0;
unsigned int FrameCount = 0;
unsigned char *pBuf = (unsigned char *)p;
{
return 1;
}
sCanData.srcId = srcId;
sCanData.funId = funId;
sCanData.sesId = sesId;
sCanData.Buf[0] = 0x00;
sCanData.Buf[1] = 0x00; // 帧序号
sCanData.Buf[3] = (unsigned char)(len >> 8);
sCanData.Buf[4] = (unsigned char)(len >> 16);
sCanData.Buf[5] = (unsigned char)(len >> 24); // 总长度
CanSendFrame(&sCanData, sizeof(sCanData));
FrameCount = len / 6;
for(i = 0; i < FrameCount; i++)
{
unsigned char k;
sCanData.Buf[0] = (unsigned char)(i + 1);
sCanData.Buf[1] = (unsigned char)((i + 1) >> 8);
for(k = 0; k < 6; k++)
{
sCanData.Buf[k + 2] = pBuf[i * 6 + k];
}
CanSendFrame(&sCanData, sizeof(sCanData));
}
if((len % 6) != 0)
{
// 帧序号
sCanData.Buf[0] = (unsigned char)(FrameCount + 1);
sCanData.Buf[1] = (unsigned char)((FrameCount + 1) >> 8);
for(i = 0; i < len % 6; i++)
{
sCanData.Buf[i + 2] = pBuf[FrameCount * 6 + i];
}
CanSendFrame(&sCanData, sizeof(sCanData));
}
}
#define __CAN_DRV_H
// p:RxMsg 数据域数据指针(RxMsg.Data)
// len:有效字节数(RxMsg.DLC)
// extId:扩展帧ID(RxMsg.ExtId)
// 返回值:0=succ,1=data error,2=memory error
unsigned char CanRecvDataProcess(const void *p, unsigned char len, unsigned long extId);
// 向 CAN 总线发送数据
// desId:目标ID
// srcId:本地ID
// funId:功能码
// sesId:会话ID,每次发送前自增1
// p:发送数据指针
// len:发送字节数(长度不限)
// 返回值:0=succ,1=error
unsigned char CanSendData(unsigned char desId, unsigned char srcId, unsigned char funId, unsigned char sesId, const void *p, unsigned int len);
//===============================================================================================================================================
// 需外部实现的函数
//===============================================================================================================================================
// p:数据指针
// len:接收字节数
extern void CanRead(const void *p, unsigned int len);
//void CanRead(const void *p, unsigned int len)
//{
// unsigned char *pbuf = (unsigned char *)p;
//
// if(!pbuf || len < 1)
// {
// return;
// }
//
// for(unsigned int i = 0; i < len; i++)
// {
// printf("%d ", pbuf[i]); // 打印 CAN 端口数据
// }
//}
// p:数据指针(数据域数据)
// len:发送字节数(数据域长度)
// extId:扩展帧ID
// 返回值:0=succ,1=data error,2=timeout
extern unsigned char CanWrite(const void *p, unsigned int len, unsigned long extId);
//unsigned char CanWrite(const void *p, unsigned int len, unsigned long extId)
//{
// unsigned short int retry = 0;
// unsigned char TransmitMailbox = 0;
// if(!pbuf || len < 1)
// {
// return 1;
// }
//
// CanTxMsg TxMsg; // 发送帧结构体
// TxMsg.StdId = 0x00; // 标准ID:0x00
// TxMsg.ExtId = extId; // 设置扩展标示符(29位)
// TxMsg.IDE = CAN_Id_Extended; // 使用扩展标识符
// TxMsg.RTR = CAN_RTR_Data; // 消息类型为数据帧
// TxMsg.DLC = len; // 数据长度
// memcpy(TxMsg.Data, p, len); // 拷贝数据
//
// // 数据发送至 CAN 网络
// TransmitMailbox = CAN_Transmit(CAN1, &TxMsg);
// while(CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) // 等待发送完成
// {
// if(++retry > 0xFFF)
// {
// return 2; // 数据发送超时
// }
// }
//
// return 0; // 数据发送成功
//}
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include "CanTest.h"
#include "CanDrv.h"
#pragma pack(push, 1)
typedef struct _sCanMsg_t
{
unsigned long ExtId; // 扩展ID
unsigned char DLC; // 发送字节数
unsigned char Data[8]; // 发送缓存区
}sCanMsg_t;
#pragma pack(pop)
unsigned int id = 0;
unsigned int BufLen = 0;
unsigned char buf[1000][sizeof(sCanMsg_t)] = {0};
CRITICAL_SECTION CriticalSection; // 临界区结构对象
#define PrintBytes(p, len) CanRead(p, len)
void CanRead(unsigned char *p, unsigned int len)
{
unsigned int i = 0;
for(i = 0; i < len; i++)
{
printf("%d ", p[i]);
}
printf("\r\n");
}
{
unsigned char i;
unsigned char *pbuf = NULL;
TxMsg.ExtId = extId;
memcpy(TxMsg.Data, p, len);
memcpy(buf[BufLen], pbuf, sizeof(sCanMsg_t));
// PrintBytes(buf[BufLen], len + 4);
Sleep(10);
return 0;
}
// 数据发送子线程
UINT WINAPI SendChildThread(void *arg)
{
unsigned int k = 0;
unsigned char buf[49] = {0};
for(k = 0; k < sizeof(buf); k++)
{
buf[k] = id + k;
}
}
void CanRecvTest(void)
{
unsigned int i;
sCanMsg_t *RxMsg;
HANDLE SendThread[16];
InitializeCriticalSection(&CriticalSection); // 初始化临界区变量
for(i = 0; i < sizeof(SendThread) / sizeof(SendThread[0]); i++)
{
SendThread[i] = (HANDLE)_beginthreadex(NULL, 0, SendChildThread, NULL, 0, NULL);
}
{
CloseHandle(SendThread[i]);
}
printf("\r\nData Frame Count:%d\r\n", BufLen);
for(i = 0; i < BufLen; i++)
{
// 模拟 CAN 端口数据格式
RxMsg = (sCanMsg_t *)buf[i];
CanRecvDataProcess(RxMsg->Data, RxMsg->DLC, RxMsg->ExtId);
}
BufLen = 0;
id = 0;
}
#define __CAN_TEST_H
void CanRecvTest(void);
13 46 160 193 6 0 0 49 0 0
3 36 96 192 6 0 0 49 0 0
4 37 128 192 6 0 0 49 0 0
5 38 160 192 6 0 0 49 0 0
6 39 192 192 6 0 0 49 0 0
7 40 224 192 6 0 0 49 0 0
8 41 0 193 6 0 0 49 0 0
9 42 32 193 6 0 0 49 0 0
10 43 64 193 6 0 0 49 0 0
11 44 96 193 6 0 0 49 0 0
12 45 128 193 6 0 0 49 0 0
2 35 64 192 6 0 0 49 0 0
14 47 192 193 6 0 0 49 0 0
15 48 224 193 6 0 0 49 0 0
16 49 0 194 6 0 0 49 0 0
14 47 192 193 8 1 0 14 15 16 17 18
16 49 0 194 8 1 0 16 17 18 19 20
12 45 128 193 8 1 0 12 13 14 15 16
10 43 64 193 8 1 0 10 11 12 13 14
9 42 32 193 8 1 0 9 10 11 12 13
15 48 224 193 8 1 0 15 16 17 18 19
4 37 128 192 8 1 0 4 5 6 7 8
7 40 224 192 8 1 0 7 8 9 10 11
3 36 96 192 8 1 0 3 4 5 6 7
2 35 64 192 8 1 0 2 3 4 5 6
8 41 0 193 8 1 0 8 9 10 11 12
11 44 96 193 8 1 0 11 12 13 14 15
5 38 160 192 8 1 0 5 6 7 8 9
6 39 192 192 8 1 0 6 7 8 9 10
1 34 32 192 8 1 0 1 2 3 4 5
16 49 0 194 8 2 0 22 23 24 25 26
10 43 64 193 8 2 0 16 17 18 19 20
13 46 160 193 8 1 0 13 14 15 16 17
12 45 128 193 8 2 0 18 19 20 21 22
14 47 192 193 8 2 0 20 21 22 23 24
7 40 224 192 8 2 0 13 14 15 16 17
15 48 224 193 8 2 0 21 22 23 24 25
4 37 128 192 8 2 0 10 11 12 13 14
9 42 32 193 8 2 0 15 16 17 18 19
6 39 192 192 8 2 0 12 13 14 15 16
1 34 32 192 8 2 0 7 8 9 10 11
5 38 160 192 8 2 0 11 12 13 14 15
2 35 64 192 8 2 0 8 9 10 11 12
3 36 96 192 8 2 0 9 10 11 12 13
11 44 96 193 8 2 0 17 18 19 20 21
8 41 0 193 8 2 0 14 15 16 17 18
16 49 0 194 8 3 0 28 29 30 31 32
7 40 224 192 8 3 0 19 20 21 22 23
14 47 192 193 8 3 0 26 27 28 29 30
12 45 128 193 8 3 0 24 25 26 27 28
10 43 64 193 8 3 0 22 23 24 25 26
13 46 160 193 8 2 0 19 20 21 22 23
9 42 32 193 8 3 0 21 22 23 24 25
16 49 0 194 8 4 0 34 35 36 37 38
8 41 0 193 8 3 0 20 21 22 23 24
3 36 96 192 8 3 0 15 16 17 18 19
2 35 64 192 8 3 0 14 15 16 17 18
5 38 160 192 8 3 0 17 18 19 20 21
7 40 224 192 8 4 0 25 26 27 28 29
4 37 128 192 8 3 0 16 17 18 19 20
6 39 192 192 8 3 0 18 19 20 21 22
15 48 224 193 8 3 0 27 28 29 30 31
1 34 32 192 8 3 0 13 14 15 16 17
11 44 96 193 8 3 0 23 24 25 26 27
12 45 128 193 8 4 0 30 31 32 33 34
10 43 64 193 8 4 0 28 29 30 31 32
14 47 192 193 8 4 0 32 33 34 35 36
9 42 32 193 8 4 0 27 28 29 30 31
13 46 160 193 8 3 0 25 26 27 28 29
16 49 0 194 8 5 0 40 41 42 43 44
3 36 96 192 8 4 0 21 22 23 24 25
8 41 0 193 8 4 0 26 27 28 29 30
7 40 224 192 8 5 0 31 32 33 34 35
2 35 64 192 8 4 0 20 21 22 23 24
5 38 160 192 8 4 0 23 24 25 26 27
6 39 192 192 8 4 0 24 25 26 27 28
4 37 128 192 8 4 0 22 23 24 25 26
15 48 224 193 8 4 0 33 34 35 36 37
11 44 96 193 8 4 0 29 30 31 32 33
1 34 32 192 8 4 0 19 20 21 22 23
10 43 64 193 8 5 0 34 35 36 37 38
13 46 160 193 8 4 0 31 32 33 34 35
12 45 128 193 8 5 0 36 37 38 39 40
9 42 32 193 8 5 0 33 34 35 36 37
14 47 192 193 8 5 0 38 39 40 41 42
7 40 224 192 8 6 0 37 38 39 40 41
16 49 0 194 8 6 0 46 47 48 49 50
3 36 96 192 8 5 0 27 28 29 30 31
8 41 0 193 8 5 0 32 33 34 35 36
2 35 64 192 8 5 0 26 27 28 29 30
4 37 128 192 8 5 0 28 29 30 31 32
15 48 224 193 8 5 0 39 40 41 42 43
6 39 192 192 8 5 0 30 31 32 33 34
5 38 160 192 8 5 0 29 30 31 32 33
14 47 192 193 8 6 0 44 45 46 47 48
9 42 32 193 8 6 0 39 40 41 42 43
12 45 128 193 8 6 0 42 43 44 45 46
10 43 64 193 8 6 0 40 41 42 43 44
13 46 160 193 8 5 0 37 38 39 40 41
1 34 32 192 8 5 0 25 26 27 28 29
11 44 96 193 8 5 0 35 36 37 38 39
2 35 64 192 8 6 0 32 33 34 35 36
4 37 128 192 8 6 0 34 35 36 37 38
16 49 0 194 8 7 0 52 53 54 55 56
7 40 224 192 8 7 0 43 44 45 46 47
3 36 96 192 8 6 0 33 34 35 36 37
8 41 0 193 8 6 0 38 39 40 41 42
15 48 224 193 8 6 0 45 46 47 48 49
6 39 192 192 8 6 0 36 37 38 39 40
9 42 32 193 8 7 0 45 46 47 48 49
14 47 192 193 8 7 0 50 51 52 53 54
5 38 160 192 8 6 0 35 36 37 38 39
12 45 128 193 8 7 0 48 49 50 51 52
1 34 32 192 8 6 0 31 32 33 34 35
13 46 160 193 8 6 0 43 44 45 46 47
10 43 64 193 8 7 0 46 47 48 49 50
16 49 0 194 8 8 0 58 59 60 61 62
11 44 96 193 8 6 0 41 42 43 44 45
2 35 64 192 8 7 0 38 39 40 41 42
4 37 128 192 8 7 0 40 41 42 43 44
7 40 224 192 8 8 0 49 50 51 52 53
3 36 96 192 8 7 0 39 40 41 42 43
15 48 224 193 8 7 0 51 52 53 54 55
6 39 192 192 8 7 0 42 43 44 45 46
8 41 0 193 8 7 0 44 45 46 47 48
14 47 192 193 8 8 0 56 57 58 59 60
5 38 160 192 8 7 0 41 42 43 44 45
9 42 32 193 8 8 0 51 52 53 54 55
12 45 128 193 8 8 0 54 55 56 57 58
10 43 64 193 8 8 0 52 53 54 55 56
11 44 96 193 8 7 0 47 48 49 50 51
1 34 32 192 8 7 0 37 38 39 40 41
13 46 160 193 8 7 0 49 50 51 52 53
16 49 0 194 3 9 0
7 40 224 192 3 9 0
3 36 96 192 8 8 0 45 46 47 48 49
4 37 128 192 8 8 0 46 47 48 49 50
15 48 224 193 8 8 0 57 58 59 60 61
6 39 192 192 8 8 0 48 49 50 51 52
2 35 64 192 8 8 0 44 45 46 47 48
10 43 64 193 3 9 0
12 45 128 193 3 9 0
14 47 192 193 3 9 0
9 42 32 193 3 9 0
5 38 160 192 8 8 0 47 48 49 50 51
8 41 0 193 8 8 0 50 51 52 53 54
3 36 96 192 3 9 0
13 46 160 193 8 8 0 55 56 57 58 59
1 34 32 192 8 8 0 43 44 45 46 47
11 44 96 193 8 8 0 53 54 55 56 57
4 37 128 192 3 9 0
6 39 192 192 3 9 0
15 48 224 193 3 9 0
2 35 64 192 3 9 0
1 34 32 192 3 9 0
13 46 160 193 3 9 0
8 41 0 193 3 9 0
5 38 160 192 3 9 0
11 44 96 193 3 9 0
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
CAN 总线数据收发驱动的更多相关文章
- Linux SPI总线和设备驱动架构之三:SPI控制器驱动
通过第一篇文章,我们已经知道,整个SPI驱动架构可以分为协议驱动.通用接口层和控制器驱动三大部分.其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:1. ...
- FPGA的GTP(aurora 协议)高速串行接口数据收发(转)
reference:https://blog.csdn.net/qq_40261818/article/details/83039829 PG046-Aurora 8B/10B Logicore I ...
- Linux SPI总线和设备驱动架构之四:SPI数据传输的队列化
我们知道,SPI数据传输可以有两种方式:同步方式和异步方式.所谓同步方式是指数据传输的发起者必须等待本次传输的结束,期间不能做其它事情,用代码来解释就是,调用传输的函数后,直到数据传输完成,函数才会返 ...
- STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发
这里我主要说一下如何做一个USB下位机,这里主要分3部分:1.建立工程:2.添加报文描述符:3.数据的传输.这里就不讲USB的理论知识了,有想要了解的自行百度一下就可以了. 建立工程:工程建立参考:h ...
- 转载 STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发
STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发 本文转载自 https://www.cnblogs.com/xingboy/p/9913963.html 这里我主要说一 ...
- Linux驱动之I2C总线设备以及驱动
[ 导读] 本文通过阅读内核代码,来梳理一下I2C子系统的整体视图.在开发I2C设备驱动程序时,往往缺乏对于系统整体的认识,导致没有一个清晰的思路.所以从高层级来分析一下I2C系统的设计思路,将有助于 ...
- HAL UART DMA 数据收发
UART使用DMA进行数据收发,实现功能,串口2发送指令到上位机,上位机返回数据给串口2,串口2收到数据后由串口1进行转发,该功能为实验功能 1.UART与DMA通道进行绑定 void HAL_UAR ...
- java网络编程——多线程数据收发并行
基本介绍与思路 收发并行 前一篇博客中,完成了客户端与服务端的简单TCP交互,但这种交互是触发式的:客户端发送一条消息,服务端收到后再回送一条.没有做到收发并行.收发并行的字面意思很容易理解,即数据的 ...
- Linux I2C核心、总线和设备驱动
目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...
随机推荐
- centos7安装python3x,使用virtualenv创建python3的隔离环境
centos7默认python程序是2x,如果要使用3x可以使用EPEL仓库安装.同时为了使用隔离的python环境可以安装virtualenv. 1.启用EPEL sudo yum install ...
- 树莓派设定笔记(Raspberry Pi 3 B+)
树莓派默认用户名密码 pi / raspberry 一.启用root用户 设置root用户密码 sudo passwd root 开启root账户 sudo passwd --unlock root ...
- CSS 分类 (Classification)
★★CSS 分类属性 (Classification)★★ ⑴CSS 分类属性允许你控制如何显示元素,设置图像显示于另一元素中的何处,相对于其正常位置来定位元素,使用绝对值来定位元素,以及元素的可见度 ...
- CSS3 阴影与圆角边框
㈠css3的新特性实际应用 ⑴文本阴影效果,用代码编写的方式实现 ⑵鼠标悬停的动态效果 左侧三幅图片,上面初始状态是没有说明文本的,但把鼠标放在上面的时候,这个图片上面就出现了说明文字 ⑶分栏 ...
- Spring实例化相关问题
1.当Controller或者Service使用new来实例化时,能不能正常调用使用Resource声明的变量 不能,使用new来实例化时,所有使用Resource声明的变量均为null
- Jmeter(二) Jmeter组件介绍
一.测试计划 测试的起点,同时也是其他所有组件的容器 二.线程(用户) Setup 线程组:一种特殊类型的线程,可用于执行预测试操作.即执行测试前进行定期线程组的执行 Teardown 线程组:一种特 ...
- Linux命令-文件管理(一)
Linux命令-文件管理(一) 1.命令:cat cat命令用于把档案串连接后传到基本输出(萤幕或加 > fileName 到另一个档案) 使用权限:所有使用者 语法格式:cat [-AbeEn ...
- Map循环/迭代/遍历效率、性能问题。
项目开发完毕,为了找点事打发一下时间,于是用findBugs插件对当前完工的项目进行扫描,发现了很多问题.其中有个关于性能的问题,在这里记录一下. 提示信息为:Inefficient use of k ...
- x-admin
https://blog.csdn.net/u014793102/article/details/80316335
- TL;DR
英文文章中,偶尔会出现TL;DR 的字符. TL;DR=>Too Long; Don’t Read=>太长了,读不下去=>长话短说 一般用于在文章开头先给出干货.