📄 scomservice.c
字号:
#endif
break;
default: //默认情况当作无参数命令处理
UartRecBuf[nCount++]=_F_EXTRA_LEN; //表示数据长度0一个序号和Crc常数
UartRecBuf[nCount++]=_F_SINGLE_NUM; //It's a single frame
break;
}
//SendFrame(UartRecBuf,UartRecBuf[_F_LENGTH_POS]+_F_SEND_ADD);
SendFrame(UartRecBuf,nCount);
OpenScom();
}
//##################################################
//#Function: ProcessFrameTask(void)
//#Description:51串行口数据帧处理服务函数
//#Input: 无
//#Output: 无
//#Return: 返回相关的帧命令
//#Others: 文件级公共函数
//##################################################
uchar ProcessFrameTask(void)
{
uchar cmd;
#if(_SCOM_TEST>0)
uchar i;
#endif
/*进行Crc校验4是(addr cmd len fh fl crh crl)此处应放置主机地址核对程序
经过验证是有一个合法帧收到了
*/
if (RecReady)
{
RecReady=0;
CloseScom();
if(CRCverify(UartRecBuf,UartRecBuf[3]+_F_RECV_ADD)==0)
{
#if(_SCOM_TEST>0)
for(i=0;i<DataBlockCount;i++) //DataBlockCount
SendByte(UartRecBuf[i]);
#endif
SystemState=_CMD_CTRL_RUN; //表示收到一个命令进入命令响应模式
cmd= UartRecBuf[2];
/*此处放置实际的数据帧响应代码*/
switch(cmd)
{
case _CMD_END:
SystemState=_CMD_NORMAL_RUN; //返回正常的温湿度显示模式
break;
case _CMD_LOG_IN:
CallMaster(_CMD_LOG_IN);
WorkMode=_NET_MODE;
break;
case _CMD_LOG_OUT:
CallMaster(_CMD_LOG_OUT);
WorkMode=_SITE_MODE;
break;
case _CMD_ACK: //不动作
//CallMaster(_CMD_ACK);
WorkMode=_NET_MODE;
break;
case _CMD_ERROR: //不动作
//CallMaster(_CMD_ERROR);
LcmMode=_ERROR_RUN;
break;
case _CMD_REAL_GET:
#if _DETECT_TASK>0
SensorTaskRun();
#endif
#if _CLOCK_TASK >0
ReadClock(ClkLcmBuf); //获取当前时钟
#endif
CloseScom();
UartRecBuf[0]=SlaveAddr;
UartRecBuf[1]=MasterAddr;
UartRecBuf[2]=_CMD_WR_RECORD;
UartRecBuf[3]=10+_F_EXTRA_LEN;
UartRecBuf[4]=TempInteger;
UartRecBuf[5]=TempDecimal;
UartRecBuf[6]=HumiInteger;
UartRecBuf[7]=HumiDecimal;
UartRecBuf[8]=ClkLcmBuf[_ID_YEAR];
UartRecBuf[9]=ClkLcmBuf[_ID_MONTH];
UartRecBuf[10]=ClkLcmBuf[_ID_DAY];
UartRecBuf[11]=ClkLcmBuf[_ID_HOUR];
UartRecBuf[12]=ClkLcmBuf[_ID_MINUTE];
UartRecBuf[13]=ClkLcmBuf[_ID_SECOND];
UartRecBuf[14]=_F_SINGLE_NUM; //It's a single frame
SendFrame(UartRecBuf,15);
OpenScom();
break;
case _CMD_RD_TEMP:
CallMaster(_CMD_WR_TEMP);
break;
case _CMD_RD_HUMI:
CallMaster(_CMD_WR_HUMI);
break;
case _CMD_RD_TIME:
CallMaster(_CMD_WR_TIME);
break;
case _CMD_RD_ALARM: //保留的命令
//CallMaster(_CMD_WR_ALARM);
break;
case _CMD_RD_DATE:
CallMaster(_CMD_WR_DATE);
break;
case _CMD_RD_WEEK:
CallMaster(_CMD_WR_WEEK);
break;
case _CMD_RD_RECORD:
CallMaster(_CMD_WR_RECORD);
break;
case _CMD_RD_RECNUM:
_CallMaster(_CMD_WR_RECNUM);
break;
case _CMD_RD_MCUID:
CallMaster(_CMD_WR_MCUID);
break;
case _CMD_RD_PCID: //保留的命令
CallMaster(_CMD_WR_PCID);
break;
case _CMD_RD_PCUSER: //保留的命令
CallMaster(_CMD_WR_PCUSER);
break;
/*--------以下开始为带参数命令----------*/
//case _CMD_SITE_INIT:
//系统状态初始化
// break;
case _CMD_WR_PCUSER: //保留的命令
//MasterUser=UartRecBuf[4];
//WriteOneChar(_REMOTE_USER,MasterUser);
break;
case _CMD_WR_PCID:
#if ((_DETECT_TASK>0)&&(_E2PROM_TASK>0))
MasterAddr=UartRecBuf[4];
WriteOneChar(_REMOTE_ID,MasterAddr);
#endif
break;
case _CMD_WR_MCUID:
#if ((_DETECT_TASK>0)&&(_E2PROM_TASK>0))
SlaveAddr=UartRecBuf[4];
WriteOneChar(_LOCAL_ID,SlaveAddr);
#endif
break;
case _CMD_WR_RECNUM:
CurRecNum=UartRecBuf[4];
WriteOneChar(_CUR_REC_ADDR,CurRecNum);
break;
case _CMD_WR_DATE:
#if _CLOCK_TASK>0
ReadClock(ClkLcmBuf);
ClkLcmBuf[_ID_YEAR] =UartRecBuf[4];
ClkLcmBuf[_ID_MONTH]=UartRecBuf[5];
ClkLcmBuf[_ID_DAY] =UartRecBuf[6];
ClockInitialize(ClkLcmBuf);
LcmMode=_DATE_RUN;
#endif
break;
case _CMD_WR_TIME:
#if _CLOCK_TASK>0
ReadClock(ClkLcmBuf);
ClkLcmBuf[_ID_HOUR] =UartRecBuf[4];
ClkLcmBuf[_ID_MINUTE]=UartRecBuf[5];
ClkLcmBuf[_ID_SECOND] =UartRecBuf[6];
ClockInitialize(ClkLcmBuf);
LcmMode=_TIME_RUN;
#endif
break;
case _CMD_WR_ALARM: //保留的命令
//;
break;
case _CMD_WR_WEEK:
#if _CLOCK_TASK>0
ReadClock(ClkLcmBuf);
ClkLcmBuf[_ID_WEEKLY] =UartRecBuf[4];
ClockInitialize(ClkLcmBuf);
LcmMode=_WEEKLY_RUN;
#endif
break;
/*--------------------------------------*/
default:
break;
}
//CallMaster(_CMD_ACK);
}
else
{
cmd=0;
}
/*恢复通讯口的初始化状态*/
RecReady=0;
DataBlockCount=0;
RecUpFlg=0;
UartHead=0xeb;
//SystemState=_CMD_NORMAL_RUN;
//#if _SCOM_TEST>0
// SendByte(cmd);
//#endif
OpenScom();
}
return cmd;
}
//#if _CRC_EN>0
#define _GOLD_CRC 0 //1:采用gold的CRC
/*#######################################################################################//
Function: CRCverify()
Description: 计算CRC常数
Input: CrcLeng、 :有效数据个数
uchar *Ptr:校验数据缓冲
Output: Null
Return: uint 返回余码
Others: CRC16-CCITT 按字节方式计算
注:
1.将一组数据进行CRC16运算后得到的CrcResult放在该序列后组成
一个新组;接收方收到该组数据后在进行CRC16运算CrcResult=0表示
无错误否则有错误!移位链的长度与CRC常数的长度相同!两次异或值
还原;求得的CrcResult高字节在前低字节在后;
2.只要移位链最高位出现一个1就要进行一次异或运算而移位链的值
又来自序列所以要判断出序列中的1;
CRC 根据”权”(即多项表达式)的不同而相应的源代码也有稍有不同,
各种常用的权:
CRC8=X8+X5+X4+1 //0x0031=1 0011 0001
CRC-CCITT=X16+X12+X5+1 //0x1021=1 0001 0000 0010 0001
CRC16=X16+X15+X5+1 //0x8021=1 1000 0000 0010 0001
CRC12=X12+X11+X3+X2+1 //0x080D=1 1000 0000 1101
CRC32=X32+X26+X23+X22+X16+X12 //0x04C11DB7=1 0000 0100 1100
+X11+X10+X8+X7+X5+X4+X2+X1+1 //0001 0001 1101 1011 0111
r1<-----------r2<---------------------|<------DataIn
| |
◎------------------------------------◎
#########################################################################################*/
uint CRCverify( uchar *Ptr,uint CrcLeng ) //本函数采用的方式速度最慢
{
#if _GOLD_CRC >0 //这种实现方式需要为序列空余出两个字节空间 后填充0
uchar Crc_j; //循环计数用变量
uint Crc_i; //循环计数用变量
uchar r1,r2,r3,r4; //临时本地变量r3,r4;移位链r1,r2
uint CrcResult; //CRC计算结果存放单元
*(Ptr+CrcLeng)=0; //在序列最后添加两个单元为0
*(Ptr+CrcLeng+1)=0; //
r1=*Ptr; //将首两个数据复制到r1、r2
Ptr++; //CrcResult=(r1<<8)|r2
r2=*Ptr; //先将前两个数据放入移位链中
Ptr++;
for (Crc_i=0;Crc_i<CrcLeng;Crc_i++) //从最高位开始移位
{
r3=*Ptr; //取出序列中的一个数据进行运算
Ptr++;
for (Crc_j=0;Crc_j<8;Crc_j++) //r1(High),r2(Low)作为移位寄存器
{
r4=r1; //保存上一次的r1到r4
/*将16位移位链低字节r2移动一位到高字节r1中*/
r1=(r1<<1); //移掉最高为等待低位移入
if ((r2&0x80)!=0)
r1++;
/*把新数的最高位移入移位链低字节r2中*/
r2=(r2<<1); //移掉最高为等待低位移入
if ((r3&0x80)!=0)
r2++;
r3=(r3<<1);
/*移位操作完成等待判断是否进行异或运算*/
if ((r4&0x80)!=0) //如果上一次移位链最高位是1则异或
{
r1=r1^0x10; //CRCConstant=0x1021
r2=r2^0x21; //将移位链与CRC常数进行异或
}
}
}
CrcResult=r1;
CrcResult<<=8;
CrcResult|=r2;
return (CrcResult);
#else //采用另外一种实现方式:序列不需要进入移位链 先填充0
uchar i;
uint CrcResult=0;
while(CrcLeng--)
{
for(i=0x80; i!=0; i>>=1)
{
/* 只要移位链中最高位为1则移动一次再异或否则只移动*/
if((CrcResult&0x8000)!=0)
{
CrcResult<<=1;
CrcResult^=0x1021; //两次异或值还原;
} //1-1
else
CrcResult<<=1; //1-2
/* 只要序列中出现一个1就要进行一次异或运算
以下这句程序可以避免方法一中多余的两个字节 */
if((*Ptr&i)!=0)
CrcResult^=0x1021; //1-3
}
Ptr++;
}
return(CrcResult);
#endif
}
//#######################################################################################//
//#######################################################################################//
#endif //#ifdef _SCOM_TASK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -