C 面向对象编程 --- 一模块的串口协议解析

摘要:
//任务目的//分析串行端口接收的54个字节。这54个字节包含8个通道的5个信息和检查信息//它实现了对每个通道包含哪些信息的查询#include<标准。小时>#包括<马洛克。小时>#包括<明确肯定h>类型分解危害池;类型定义代码8;类型定义

// 任务目的
// 解析串口收到的54个字节。这54个字节包含了8个车道的5大信息以及校验信息。
// 实现了查询每条车道包含了哪些信息。

C 面向对象编程 --- 一模块的串口协议解析第1张

#include <stdio.h>
#include <malloc.h>
#include <assert.h>

typedef unsigned char mybool; 
typedef unsigned char u8; 
typedef unsigned short u16; 
typedef unsigned int u32;

mybool SumCheck(const u8* pScrData);

typedef enum{
RoadID1=1, // 距离雷达最远的那条车道, 一个绿化带也算一条车道。
RoadID2,
RoadID3,
RoadID4,
RoadID5,
RoadID6,
RoadID7,
RoadID8,
RoadIDNull
}RoadID_;


typedef enum{    
T_LongCarCnt=1,
T_CarCnt, 
T_SmallCarCnt,
T_Occupancy,
T_AveSpeed,
T_AskNull
}T_ask_;


struct CertainRoad_; // 下面定义函数指针时,形参有这个结构体的指针, 所以,这里的结构体一定要先声明。

typedef struct CertainRoad_{
RoadID_ RoadID;

// 成员函数的使用方法示例: pRoad->pGetUpdated_LongCarCnt(pRoad, FakeData); 
// 第一个pRoad是CertainRoad类的一个对象的指针,作用不言而喻。 
// 第二个pRoad起到类似this指针的作用。目的是可供调用对象的其他成员(对象的其他属性或者行为。)
// C++的类内的成员函数的定义内可以直接使用this指针,但是C语言不支持这样,所以要通过形参再次传入对象指针。

//u8(*pGetUpdated_LongCarCnt) ( struct CertainRoad_ *pRoad,  const u8 *pScrData);         // 所以说,形参命名为pRoad,还不能体现是和C++映衬的最佳的理解。

u8(*pGetUpdated_LongCarCnt) ( struct CertainRoad_ *this,                  const u8 *pScrData); // 第二个参数是54字节的数据哦 
u8(*pGetUpdated_CarCnt) ( struct CertainRoad_ *this,                          const u8 *pScrData);
u8(*pGetUpdated_SmallCarCnt)( struct CertainRoad_ *this,                  const u8 *pScrData);
u8(*pGetUpdated_Occupancy) ( struct CertainRoad_ *this,                   const u8 *pScrData);
u8(*pGetUpdated_AveSpeed) ( struct CertainRoad_ *this,                    const u8 *pScrData);

void(*pGetUpdatedAllresults)( struct CertainRoad_ *this,      const u8 *pScrData, u8 *result);

}CertainRoad; // Certain是某的意思。CertainRoad:某条车道。


// 根据车道号获取该时间段内的长车的流量
// 规律:长车的流量 = pScrData[pRoad->RoadID+2];
u8 GetUpdated_LongCarCnt(CertainRoad* pRoad, const u8* pScrData)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);
return pScrData[pRoad->RoadID+2];
}

u8 GetUpdated_CarCnt(CertainRoad* pRoad, const u8* pScrData)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);
return pScrData[pRoad->RoadID+15];
}

u8 GetUpdated_SmallCarCnt(CertainRoad* pRoad, const u8* pScrData)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);
return GetUpdated_CarCnt(pRoad,pScrData) - GetUpdated_LongCarCnt(pRoad, pScrData);
}

u8 GetUpdated_Occupancy(CertainRoad* pRoad, const u8* pScrData)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);
return pScrData[pRoad->RoadID+28];
}

u8 GetUpdated_AveSpeed(CertainRoad* pRoad, const u8* pScrData)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);
return pScrData[pRoad->RoadID+41];
}

void GetUpdatedAllresults(CertainRoad* pRoad, const u8* pScrData, u8* result)
{
if( !(pRoad->RoadID >= RoadID1)&&(pRoad->RoadID <= RoadID8) )
assert(0);

result[0] = pRoad->pGetUpdated_LongCarCnt (pRoad, pScrData); 
result[1] = pRoad->pGetUpdated_CarCnt (pRoad, pScrData); 
result[2] = pRoad->pGetUpdated_SmallCarCnt(pRoad, pScrData); 
result[3] = pRoad->pGetUpdated_Occupancy (pRoad, pScrData); 
result[4] = pRoad->pGetUpdated_AveSpeed (pRoad, pScrData); 
}


CertainRoad* CreatNewRoad(RoadID_ RoadID)
{
CertainRoad* pNewRoadObj = (CertainRoad*)malloc(sizeof(CertainRoad)); 

pNewRoadObj->RoadID = RoadID;

pNewRoadObj->pGetUpdated_LongCarCnt = GetUpdated_LongCarCnt;
pNewRoadObj->pGetUpdated_CarCnt = GetUpdated_CarCnt;
pNewRoadObj->pGetUpdated_SmallCarCnt= GetUpdated_SmallCarCnt;
pNewRoadObj->pGetUpdated_Occupancy = GetUpdated_Occupancy;
pNewRoadObj->pGetUpdated_AveSpeed = GetUpdated_AveSpeed;

// 对上面的5个再次封装,提供统一接口
pNewRoadObj->pGetUpdatedAllresults = GetUpdatedAllresults;

return pNewRoadObj;
}


//串口底层收到数据,先进性简单逻辑判断,
//判断依据:0xff是第一个数据,之后的是0x1b 0x10 0x11 0x12四者之一。
//不符合上述依据,丢弃数据。
//符合上述依据,开始计数(要算上之前的2个),一共计数到54字节,发送一个信号量给相应的处理任务进行解析。
//处理任务进行: 和校验 、 原始数据的格式封装与转换。
int main(void)
{ 
// 车道1 2 3 4 5 6 7 车道8 // 这里模拟一下原始数据
u8 FakeData[54]={0xFF, 0x1B, 0x09, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x76, 0x94, // T_LongCarCnt:这一行都是长车流量 
0xFF, 0x10, 0x09, 0xf5, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x01, 0x12, // T_CarCnt 总车流量
0xFF, 0x11, 0x09, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x03, 0x3f, // T_Occupancy 占有率
0xFF, 0x12, 0x0B, 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x00, 0x30, 0xD4};// T_AveSpeed 平均速度

// 感觉这样写得很丑,其实输入就应该是一个车道的ID,u8类型的数据即可,而不是这样填写枚举值。
// 改进方法:在CreatNewRoad函数内增加断言,利用switch case,将u8的ID值转为枚举值。并assert断言,防止输入参数大于8。
// 暂不改进
CertainRoad* pRoad1 = CreatNewRoad(RoadID1); // 每条车道是一个对象    
CertainRoad* pRoad2 = CreatNewRoad(RoadID2); 
CertainRoad* pRoad3 = CreatNewRoad(RoadID3);
CertainRoad* pRoad4 = CreatNewRoad(RoadID4);
CertainRoad* pRoad5 = CreatNewRoad(RoadID5);
CertainRoad* pRoad6 = CreatNewRoad(RoadID6);
CertainRoad* pRoad7 = CreatNewRoad(RoadID7);
CertainRoad* pRoad8 = CreatNewRoad(RoadID8);
// 注:当前VS是C89标准
printf(" Main Begin 

");

if(SumCheck(FakeData))
{
u8 LongCarCnt=0;
u8 CarCnt=0;
u8 SmallCarCnt=0;
u8 Occupancy=0;
u8 AveSpeed=0;

u8 Result[5] = {0};
u8 i=0, j=0;
CertainRoad*pRoad = (CertainRoad*)0; // NULL

for(i=1; i<=8; i++)
{    
switch(i)
{
case 1:
pRoad = pRoad1;break;
case 2:
pRoad = pRoad2;break;
case 3:
pRoad = pRoad3;break;
case 4:
pRoad = pRoad4;break;
case 5:
pRoad = pRoad5;break;
case 6:
pRoad = pRoad6;break;
case 7:
pRoad = pRoad7;break;
case 8:
pRoad = pRoad8;break;
}

//本接口的使用方式一: 让用户一个一个调用
LongCarCnt = pRoad->pGetUpdated_LongCarCnt(pRoad, FakeData); 
printf("pRoad%d: LongCarCnt = %d 
",i, LongCarCnt);

CarCnt = pRoad->pGetUpdated_CarCnt(pRoad, FakeData); 
printf("pRoad%d: CarCnt = %d 
", i, CarCnt);

SmallCarCnt = pRoad->pGetUpdated_SmallCarCnt(pRoad, FakeData); 
printf("pRoad%d: SmallCarCnt = %d 
", i, SmallCarCnt);

Occupancy = pRoad->pGetUpdated_Occupancy(pRoad, FakeData); 
printf("pRoad%d: Occupancy = %d 
", i, Occupancy);

AveSpeed = pRoad->pGetUpdated_AveSpeed(pRoad, FakeData); 
printf("pRoad%d: AveSpeed = %d 
", i, AveSpeed);

//本接口的使用方式二:让用户一个一个调用太麻烦了,再封装一层,直接返回5个有物理意义的字节作为结果。
pRoad->pGetUpdatedAllresults(pRoad, FakeData, Result);

for(j=0; j<5; j++)
{
printf(" Result[%d] = %d 
", j, Result[j]);
}
printf(" -----pRoad%d ---OVER---

", i); 
}
}
printf(" 

");
return 0;
}


//和校验,这是一个独立使用的函数
mybool SumCheck(const u8* pScrData)
{
mybool ret = 0;
u8 i = 0;
u16 CheckSUM1=0, CheckSUM2=0, CheckSUM3=0, CheckSUM4=0;

for(i=3; i<=11; i++)
{
CheckSUM1 += pScrData[i];
}    
CheckSUM1 = CheckSUM1%256;

for(i=16; i<=24; i++)
{
CheckSUM2 += pScrData[i];
}
CheckSUM2 = CheckSUM2%256;

for(i=29; i<=37; i++)
{
CheckSUM3 += pScrData[i];
}
CheckSUM3 = CheckSUM3%256;

for(i=42; i<=52; i++)
{
CheckSUM4 += pScrData[i];
}
CheckSUM4 = CheckSUM4%256;

if( ( (u8)CheckSUM1 == pScrData[12]) && ((u8)CheckSUM2 == pScrData[25]) 
&& ((u8)CheckSUM3 == pScrData[38]) && ((u8)CheckSUM4 == pScrData[53]) )
{
ret = 1;
printf(" 本次串口收到的54字节 和检验 OK 

");
}
return ret;
}

.

免责声明:文章转载自《C 面向对象编程 --- 一模块的串口协议解析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Java:程序开机自启动shiro拦截器处理链执行顺序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

编一程序,将两个字符串连接起来,不要用strcat函数

编一程序,将两个字符串连接起来,不要用strcat函数 【答案解析】 直接将s2中的字符逐个拷贝到s1的末尾即可,用户需要保证s1中能存的下s2中的字符 获取s1末尾的位置 将s2中的字符逐个拷贝到s1中 【代码实现】 #include<stdio.h> int main() { char s1[100] = {0}; char s2...

skynet源码分析之热更新

skynet有两种方法支持热更新lua代码:clearcache和inject,在介绍skynet热更新机制之前,先介绍skynet控制台,参考官方wikihttps://github.com/cloudwu/skynet/wiki/DebugConsole 1. skynet控制台 想要使用skynet控制台,需启动debug_console服务skyn...

openssl多线程实例

本示例用多线程实现了一个ssl服务端和一个客户端。 服务端代码如下: #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #ifndef _WIN32 #include <sys/types.h>...

文件系统FatFsR0.09a翻译(三):ff.h

//本译文只供学习使用,未经作者许可,不得用于其它任何用途 //译者:xiaofeng //修改日期:2013/03/19 //版本:V1.0 //版权所有,盗版必究。 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...

算法训练 删除数组零元素

算法训练 删除数组零元素   时间限制:1.0s   内存限制:512.0MB     从键盘读入n个整数放入数组中,编写函数CompactIntegers,删除数组中所有值为0的元素,其后元素向数组首端移动。注意,CompactIntegers函数需要接受数组及其元素个数作为参数,函数返回值应为删除操作执行后数组的新元素个数。输出删除后数组中...

sz/rz实现及cat binary文件时乱码问题

一、嵌入式系统中文件传输这个工具之前还的确是没有使用到过,可能的原因是因为之前一直使用桌面系统fedora core发行版本,开发主要使用busybox文件系统,而这两种版本中都没有自带sz/rz工具。它们的作用是通过串口来发送和接收文件,虽然说是串口,所有的支持串口协议的软件或者链路都可以,例如使用telnet/ssh之类的远程链接工具,主机之间的通讯使...