⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppia.h

📁 西门子PPI协议源码
💻 H
📖 第 1 页 / 共 3 页
字号:
//PPI通讯协议如下:
//主发写命令,从返回E5(准备就绪命令),主收到后发确认命令(10 SLAVER,MASTER,5C,ADD,16),从发(68 12 12 68 。。。)完毕
//主发读命令,从返回E5(准备就绪命令),主收到后发确认命令(10 SLAVER,MASTER,5C,ADD,16),从发(68 xx xx 68 。。。)完毕

//****************************************************************************
//**Purpose: 当PPI本机为从时,接受到了主的命令,命令有两种,申请和确认
//**  uc_rec_len是长度,不是下标。先效验 返回为发送串长(下标),返回0xff为不发送
UCHAR ppi_reqframe_anlys_slaver(UCHAR uc_ch,UCHAR *puc_rec_buf,UCHAR uc_rec_len,UCHAR *puc_send_buf,uchar me_address)
{   
	static uchar st_uc_ppi_var_type[MCU_UART_NUM] = {2,2};//传输的数据类型
	static uchar st_uc_ppi_var_num[MCU_UART_NUM];//传输的数据个数
	static uint  st_ui_ppi_me_var_add[MCU_UART_NUM];
	static uchar st_uc_ppi_connect_type[MCU_UART_NUM]={0,0};
	
	UCHAR ucp_send_count,uc_count; 
	UINT  u16;
	UCHAR uc_mid1,uc_mid2,uc_mid3;
	
	
	if((*puc_rec_buf) == 0x10)//确认命令
	{
		if((uc_rec_len != 6) || (*(puc_rec_buf+5)!=0x16))//长度不对,或者结束符号不对
		{
			return(0xfe);
		}
		
		if(*(puc_rec_buf + 1) != me_address)
		{
			return(0xfe);
		}
		
		if(uc_ppi_addtest(puc_rec_buf+1, uc_rec_len-3) != *(puc_rec_buf + uc_rec_len - 2))//效验
		{
			return(0xfe);   
		}
		//10 03 02 5c 61 16
		//if(st_uc_ppi_connect_type[uc_ch] == 0)//还没连接
		//{
		//	return(0xfe);
		//}
		//以上是2008.6.24修改,因为如果上电或其他因素
		//首发DC命令,再发49命令,以上导致对49命令无响应(因为无连接),而PLC死循环
		
		ucp_send_count = 0;
		
		if(*(puc_rec_buf + 3) != 0x49)  //最多出现的是5C,而7C也见过
		{
			
			uc_count = st_uc_ppi_var_num[uc_ch];  //此后的计算结果,uc_count将成为字节数
			
			uc_mid1 = st_uc_ppi_var_type[uc_ch];
			if(uc_mid1 == 4)//如果是字
			{uc_count *=2;}
			else if(uc_mid1 == 6)//如果是双字
			{uc_count *=4;}
			else if(uc_mid1 == 1)//位
			{return(0xfe);}
			
			if((uc_count+26) >= comm_array_max_xb)
			{return(0xfe);}
			
			if(st_uc_ppi_connect_type[uc_ch] == 1)//连接的性质,主PLC读本机
			{
				uc_mid1 = 0x15 + uc_count;
				uc_mid2 = 4 + uc_count;
				uc_mid3 = 0x04;
			}
			else
			{
				uc_mid1 = 0x12;
				uc_mid2 = 0x01;
				uc_mid3 = 0x05;
			}
			
			*(puc_send_buf + ucp_send_count++) = 0x68;
			*(puc_send_buf + ucp_send_count++) = uc_mid1;
			*(puc_send_buf + ucp_send_count++) = uc_mid1;
			*(puc_send_buf + ucp_send_count++) = 0x68;
			*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + 2);//对方地址
			*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + 1);//本机地址
			*(puc_send_buf + ucp_send_count++) = 0x08;
			*(puc_send_buf + ucp_send_count++) = 0x32;
			*(puc_send_buf + ucp_send_count++) = 0x03;
			*(puc_send_buf + ucp_send_count++) = 0x00;	  
			*(puc_send_buf + ucp_send_count++) = 0x00;
			*(puc_send_buf + ucp_send_count++) = uc_ppi_comm_count[uc_ch];  //通讯次数
			*(puc_send_buf + ucp_send_count++) = uc_ppi_comm_count[uc_ch];  //主机来是多少,返回就是多少
			*(puc_send_buf + ucp_send_count++) = 0x00;
			*(puc_send_buf + ucp_send_count++) = 0x02;  //不管是字还是字节,固定为2	  
			*(puc_send_buf + ucp_send_count++) = 0x00; 
			*(puc_send_buf + ucp_send_count++) = uc_mid2;
			*(puc_send_buf + ucp_send_count++) = 0x00;    
			*(puc_send_buf + ucp_send_count++) = 0x00;
			*(puc_send_buf + ucp_send_count++) = uc_mid3;
			*(puc_send_buf + ucp_send_count++) = 0x01;   
			*(puc_send_buf + ucp_send_count++) = 0xff;
			
			if(st_uc_ppi_connect_type[uc_ch] == 1)//连接的性质,主PLC读本机
			{
				*(puc_send_buf + ucp_send_count++) = 0x04;
				
				u16  = uc_count;
				u16 *= 8;
				*(puc_send_buf + ucp_send_count++) = HI_UINT(u16);	  	  
				*(puc_send_buf + ucp_send_count++) = LO_UINT(u16);
				
				for(uc_mid1 = 0;uc_mid1<uc_count;uc_mid1++)
				{
					*(puc_send_buf + ucp_send_count++) = uc_PPI_ret_Word(st_ui_ppi_me_var_add[uc_ch] + uc_mid1);
				}
			}
			//从4开始,就是从地址开始,-4是个数 
			uc_mid1 = uc_ppi_addtest(puc_send_buf + 4,ucp_send_count-4);
			*(puc_send_buf + ucp_send_count++) = uc_mid1;
			*(puc_send_buf + ucp_send_count) = 0x16;
			return(ucp_send_count);  //返回的是下标
		}
		else //if((*puc_rec_buf + 3) == 0x49) )似乎主机在问本机是不是也是主机,回答不是
		{
			*(puc_send_buf + ucp_send_count++) = 0x10;
			*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + 2);//对方地址
			*(puc_send_buf + ucp_send_count++) = *(puc_rec_buf + 1);//本机地址
			*(puc_send_buf + ucp_send_count++) = 0;                 //告诉主机
			*(puc_send_buf + ucp_send_count++) = uc_ppi_addtest(puc_send_buf+1,3);
			*(puc_send_buf + ucp_send_count) = 0x16;
			return(5);  //返回的是下标
		}//if((*puc_rec_buf + 3) == 0x5c))
		
	}//确认命令至此完成了
	/////////////////////////////////////////////////////////////////////////////////////////////////////
	//热烈祝贺确认类型命令完成了,下面是申请命令,地址和效验都要重新做
	/////////////////////////////////////////////////////////////////////////////////////////////////////
	else if(((*puc_rec_buf) == 0xdc) || ((*puc_rec_buf) == 0x68))  //可能是呼叫申请,也可能是其他PPI的数据
	{
		if((uc_rec_len < 33) || (*(puc_rec_buf + uc_rec_len - 1) != 0x16))//长度不对,或者结束符号不对
		{
			return(0xfe);
		}
		
		if((*puc_rec_buf) == 0xdc)
		{
			puc_rec_buf += 3;
			uc_rec_len -= 3;
			if((*puc_rec_buf) != 0x68){return(0xfe);}
		}
		
		if(*(puc_rec_buf + 4) != me_address){return(0xfe);}   //地址效验
		puc_rec_buf += 3;  //从第二个68开始
		uc_rec_len -= 3;   //长度跟着调整
		
		if(uc_ppi_addtest(puc_rec_buf+1,uc_rec_len-3) != *(puc_rec_buf + uc_rec_len - 2))  //和效验
		{
			//st_uc_ppi_connect_type[uc_ch] = 0;//地址对了,但是效验错了,取消连接?
			//2008.6.24 不取消连接
			return(0xfe);
		}
		//以下效验也对了
		
		st_uc_ppi_var_type[uc_ch] = *(puc_rec_buf + 19);
		st_uc_ppi_var_num[uc_ch]  = *(puc_rec_buf + 21);         
		uc_ppi_comm_count[uc_ch]  = *(puc_rec_buf + 8);
		st_ui_ppi_me_var_add[uc_ch] = MAKE_UINT(*(puc_rec_buf + 26),*(puc_rec_buf + 27)) / 8;
		
		if(*(puc_rec_buf - 1) == 0x1b)//st_uc_ppi_connect_type[uc_ch]=1是读,2是写
		{
			st_uc_ppi_connect_type[uc_ch] = 1;  //主PLC要从本机读数据
			*(puc_send_buf) =0xe5;
			return(0);  //返回的是下标,却只发一个字节
		}
		//PLC写入功能不用包含在只读的采集模块仪表中
		else  if(*(puc_rec_buf - 1) >= 0x20)//是写入命令,主PLC写入信息
		{
			st_uc_ppi_connect_type[uc_ch] = 2;
			
			uc_count = st_uc_ppi_var_num[uc_ch];  //此后的计算结果,uc_count将成为字节数
			
			uc_mid1 = st_uc_ppi_var_type[uc_ch];
			if(uc_mid1 == 4)//如果是字
			{uc_count *=2;}
			else if(uc_mid1 == 6)//如果是双字
			{uc_count *=4;}
			else if(uc_mid1 == 1)//位
			{return(0xfe);}
			
			for(uc_mid1 = 0;uc_mid1<uc_count;uc_mid1++)
			{
				PPI_write_singleReg(st_ui_ppi_me_var_add[uc_ch] + uc_mid1, *(puc_rec_buf + 32 + uc_mid1));
				//开始地址+字节指针            从32(35从第一个68开始)
			}
			*(puc_send_buf) =0xe5;//发E5
			return(0);  //返回的是下标,却只发一个字节
		}
		else  //不是读,也不是写,不认识
		{
			//st_uc_ppi_connect_type[uc_ch] = 0;
			//2008.6.24不取消连接
			return(0xfe);
		}
		
	}//else if(((*puc_rec_buf) == 0xdc) || ((*puc_rec_buf) == 0x68))
	
    return(0xfe);	
}

//*****************************************************************************************
//*****************************************************************************************
UCHAR ppi_send_command_10(UCHAR *puc_send_buf,UCHAR me_address,UCHAR uc_plc_address,UCHAR uc_command)
{
	UCHAR uc_mid,uc_loop;
	UCHAR ucp_send_count = 0;
	
	*(puc_send_buf + ucp_send_count++) = 0x10;
	*(puc_send_buf + ucp_send_count++) = uc_plc_address;
	*(puc_send_buf + ucp_send_count++) = me_address;
	*(puc_send_buf + ucp_send_count++) = uc_command;
	
	uc_mid = 0;
	for(uc_loop =1; uc_loop < ucp_send_count;uc_loop++)
	{
		uc_mid += *(puc_send_buf + uc_loop);
	}
	*(puc_send_buf + ucp_send_count++) = uc_mid;
	*(puc_send_buf + ucp_send_count)   = 0x16;
	
	return(ucp_send_count);
}
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//*****************************************************************************************
//业务流程有必要写一下
//主发写命令,从返回E5(准备就绪命令),主收到后发确认命令(10 SLAVER,MASTER,5C,ADD,16),从发(68 12 12 68 。。。)完毕
//主发读命令,从返回E5(准备就绪命令),主收到后发确认命令(10 SLAVER,MASTER,5C,ADD,16),从发(68 xx xx 68 。。。)完毕
//接受部分和MODBUS基本相同:
//在接受中断中,重置了3.5字节的接受完毕,并且将发送的计数器g_uc_ppi_main_send_count=-1,就是最大值,这样,就会先进入接收程序,而不会由定时器导致发送
//而在主程序中,要对g_uc_ppi_main_send_count每ms--,到0后发出is_ppi_master_need_send消息
//而主接收函数ppi_reqframe_anlys_master 和主发送函数ppi_master_send都可能会组成发送串,并且会重写g_uc_ppi_main_send_count(函数内叫next_send_ms_count)
//当g_uc_ppi_main_send_count(next_send_ms_count)到时间后叫“超时”,将导致发送,用STEP同步
//
//#define PPI_F_MASTER_REQUIRED 0
//#define PPI_F_MASTER_ENTERED  1
//#define PPI_F_MASTER_SEND_DC  2
//#define PPI_F_MASTER_ANSW_DC  3 //这是接收函数发的DC ME ME 指令,发完后定时,再有主程序引发主发函数工作
//#define PPI_F_MASTER_E5AGAIN  4

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -