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

📄 pcm-rtx51.c

📁 《单片机应用系统设计与产品开发》配套源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************/
/**              PCM-ZXDU1500			**/
/**            操作系统 RTX51-TINY		**/
/*******************************************/

#include "rtx51tny.h"
#include "reg52.h"
#include "intrins.h"
#include "absacc.h"

#define uchar unsigned char
#define uint  unsigned int

#define MAX_NUM_COM1		   100		//定义COM1接收缓冲区长度

#define COM1_RXD_En()	  	   P1_1 = 0
#define COM1_TXD_En()		   P1_1 = 1


/********************************************/
/**              任务编号声明              **/
/********************************************/
#define TASK_INIT 			   0				//初始化任务
#define TASK_COM1 			   1			//与上位机通信任务
#define TASK_COM2 			   2			//与设备通信任务
#define TASK_DATA			   3				//数据处理任务
#define TASK_CMD			   4				//命令处理任务
#define TASK_LEDWDT			   5			//状态灯及看门狗

/********************************************/
/**           GM16C550寄存器声明           **/
/********************************************/
#define RBR         		   XBYTE[0x8000]
#define THR          		   XBYTE[0x8000]
#define DLL          		   XBYTE[0x8000]
#define DLM          		   XBYTE[0x8001]
#define IER          		   XBYTE[0x8001]
#define FCR           		   XBYTE[0x8002]
#define IIR           		   XBYTE[0x8002]
#define LCR           		   XBYTE[0x8003]
#define MCR           		   XBYTE[0x8004]
#define LSR           		   XBYTE[0x8005]
#define MSR           	       XBYTE[0x8006]
#define SCR                    XBYTE[0x8007]


/********************************************/
/**             控制引脚说明	           **/
/********************************************/
//串口1(16C550) RS485方式收发使能,0为接收,1为发送
sbit P1_1 = P1^1;							
sbit P1_2 = P1^2;							//串口1(16C550)复位信号输出
sbit P1_3 = P1^3;							//看门狗清零输出
sbit P3_5 = P3^5;							//运行状态灯输出


void CPU_Init(void);							//系统初始化
void COM1_Init(void);
void COM2_Init(void);

void Get_PcmAddr(void);						//读取PCM地址
void Hex2Ascii(uchar,uchar*);
void Int2Ascii(uint,uchar*);
uchar Ascii2Hex(uchar *);
bit Chk_Sum(uchar*);

uchar code ZXDUCMD[2][25]={
{0x10, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0x97, 0x5D, 0x01, 0x12}, 							//取实时数据
{0x10, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x74, 0x00, 0x12}, 							//取参数
};

uchar code ZXDUSET[] = {0x10, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};  								//设置命令的前面字节
uchar AlarmParaChar[35];									//ZXDU3000告警参数段
uchar xdata BuffCOM1[MAX_NUM_COM1];							//COM1接收缓存
uchar xdata BuffCOM2[1024];									//COM2接收缓存
uchar xdata BuffCmdSet[100];								//一条设置命令
uchar xdata BuffDvcReal[1024];								//设备实时数据
uchar xdata BuffDvcPara[1024];								//设备参数


uchar PcmAddr[2];											//按ASCII存放PCM地址
uchar RXDTimeOut = 0;										//超时计时
uchar TXDTimeOut = 0;

uchar xdata *data PtrCOM1RXD;								//串口收发指针
uchar xdata *data PtrCOM1TXD;
uchar xdata *data PtrCOM2RXD;
uchar 		*data PtrCOM2TXD;

bit FlagCOM1AllOut = 1;										//COM1发送完成标志
bit FlagCOM2AllOut = 1;										//COM2发送完成标志
bit FlagCmdStart   = 0;										//接收命令开始标志
bit FlagCmdSet     = 0;										//收到一条设置命令
bit FlagDataStored = 1;										//数据存储完成标志

bit CmdCnt = 0;												//读数据或参数的命令记数,只有两条,所以用bit

/********************************************/
/**             系统初始化任务	           **/
/**			初始化外设并建立其它任务       **/
/********************************************/
void Task_Init(void) _task_ TASK_INIT
{
	COM1_RXD_En();											//首先释放485线
	COM2_Init();
	COM1_Init();
	CPU_Init();
	Get_PcmAddr();
	os_create_task(TASK_COM1);
	os_create_task(TASK_COM2);
	os_create_task(TASK_DATA);
	os_create_task(TASK_CMD);
	os_create_task(TASK_LEDWDT);
	os_delete_task(TASK_INIT);
}

/********************************************/
/**               串口1任务 	           **/
/**			处理接收到的命令,发送数据      **/
/********************************************/
void Task_COM1(void) _task_ TASK_COM1
{
	uchar CmdTyp;											//命令类型
	while(1)
	{
		os_wait(K_SIG,0,0);									//等待接收到命令的信号
		CmdTyp = BuffCOM1[8];								//取命令类型
		switch(CmdTyp)										//根据命令类型作相应处理
		{
			case 0x31:										//命令类型: 41,取实时数
			{
				COM1_TXD_En();								//充许发送
				PtrCOM1TXD = BuffDvcReal;
				FlagCOM1AllOut = 0;
				THR = *PtrCOM1TXD++;
				break;
			}//41
			
			case 0x36:										//命令类型: 46,取参数
			{
				COM1_TXD_En();								//充许发送
				PtrCOM1TXD = BuffDvcPara;
				FlagCOM1AllOut = 0;
				THR = *PtrCOM1TXD++;				
				break;
			}//46

			case 0x35:										//命令类型: 45,遥调
			{
				os_send_signal(TASK_CMD);					//通知CMD任务进行命令转换
				break;
			}//45
		}
		os_switch_task();
	}
}

/********************************************/
/**               串口2任务 	           **/
/**			 定时发送命令到设备		       **/
/********************************************/
void Task_COM2(void) _task_ TASK_COM2
{
	while(1)
	{
		os_wait(K_TMO,200,0);								//等待时间标志,此段时间,从设备接收数据并存储完成
		os_wait(K_TMO,200,0);
		while(!FlagDataStored);								//等待数据存储完成,否则接收过程复盖原收到数据
	
		if(FlagCmdSet)										//收到上位机下发设置命令
		{
			PtrCOM2TXD = BuffCmdSet;							//指向设置命令
			FlagCmdSet = 0;
		}
		else
		{
			PtrCOM2TXD = ZXDUCMD[CmdCnt];					//指向读数据或参数命令
			CmdCnt = !CmdCnt;
		}
		FlagCOM2AllOut = 0;									//COM2启动发送
		TI = 1;
		os_switch_task();
	}
}


/********************************************/
/**              数据处理任务              **/
/********************************************/
void Task_Data(void) _task_ TASK_DATA
{
	uchar xdata *data PtrS;
	uchar xdata *data PtrD;
	uchar i;
	uchar SMR_NUM;											//整流模块数目
	uint SUM;												//校验和
	union
	{
		uint i;
		uchar c[2];
	}a_int;
	union
	{
		float f;
		uchar c[4];
	}a_float;
	while(1)
	{

		BuffDvcReal[0] = 0x7E;								//存放起始数据
		BuffDvcPara[0] = 0x7E;
		BuffDvcReal[1] = 0x32;
		BuffDvcPara[1] = 0x32;
		BuffDvcReal[2] = 0x30;
		BuffDvcPara[2] = 0x30;
		BuffDvcReal[3] = 0x46;
		BuffDvcPara[3] = 0x46;
		BuffDvcReal[4] = PcmAddr[1];
		BuffDvcPara[4] = PcmAddr[1];
		BuffDvcReal[5] = 0x44;
		BuffDvcPara[5] = 0x44;
		BuffDvcReal[6] = 0x30;
		BuffDvcPara[6] = 0x30;
		BuffDvcReal[7] = 0x30;
		BuffDvcPara[7] = 0x30;
		BuffDvcReal[8] = 0x30;
		BuffDvcPara[8] = 0x30;

		BuffDvcReal[9]  = 0x44;								//实时数据LENGTH 288(10) 120(16)
		BuffDvcReal[10] = 0x31;								//D120
		BuffDvcReal[11] = 0x32;
		BuffDvcReal[12] = 0x30;
		BuffDvcReal[13] = 0x34;								//CID2
		BuffDvcReal[14] = 0x31;

		BuffDvcPara[9]  = 0x35;								//参数LENGTH  86
		BuffDvcPara[10] = 0x30;								//5056
		BuffDvcPara[11] = 0x35;		
		BuffDvcPara[12] = 0x36;
		BuffDvcPara[13] = 0x34;								//CID2
		BuffDvcPara[14] = 0x36;

		BuffDvcReal[15] = 0x30;								//协议转换器状态
		BuffDvcReal[16] = 0x30;
		BuffDvcPara[15] = 0x30;
		BuffDvcPara[16] = 0x30;

		BuffDvcReal[17] = 0x30;								//设备信息
		BuffDvcReal[18] = 0x30;
		BuffDvcReal[19] = 0x30;								
		BuffDvcReal[20] = 0x30;
		BuffDvcPara[17] = 0x30;
		BuffDvcPara[18] = 0x30;
		BuffDvcPara[19] = 0x30;
		BuffDvcPara[20] = 0x30;

		os_wait(K_SIG,0,0);									//等待收到数据信号
		while(!FlagCOM1AllOut);								//等待数据上传完成,否则上传过程中更改数据
		FlagDataStored = 0;
		switch(BuffCOM2[7])									//根据数据类型作相应处理
		{
			case 'R':										//实时数据
			{
				PtrS = BuffCOM2 + 17;						//指向交流A相电压
				PtrD = BuffDvcReal + 95;					//指向实时数据段
				
				for(i = 0; i < 4; i++)						//转换相电压电流,int型转float型
				{
					a_int.c[1] = *PtrS++;
					a_int.c[0] = *PtrS++;
					a_float.f = (float)(a_int.i);
					Hex2Ascii(a_float.c[3],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[2],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[1],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[0],PtrD);
					PtrD += 2;
				}

				PtrS += 12;									//跳过12个保留字节
				for(i = 0; i < 5; i++)						//0: 市电一,1:市电二 1
 			    {											//直流总输出电压 4
					Hex2Ascii(*PtrS,PtrD);					
					PtrS++;									
					PtrD += 2;								
				}
				
		
				a_int.c[1] = *PtrS++;					//直流总输出电流 2
				a_int.c[0] = *PtrS++;
				a_float.f = (float)(a_int.i);
				Hex2Ascii(a_float.c[3],PtrD);
				PtrD += 2;
				Hex2Ascii(a_float.c[2],PtrD);
				PtrD += 2;
				Hex2Ascii(a_float.c[1],PtrD);
				PtrD += 2;
				Hex2Ascii(a_float.c[0],PtrD);
				PtrD += 2;
									
				for(i = 0; i < 5; i++)						//环境温度 1
 			    {											//环境湿度 4
					Hex2Ascii(*PtrS,PtrD);					
					PtrS++;									
					PtrD += 2;								
				}											
															
				PtrS += 16;									//跳过16个保留字节				
				for(i = 0; i < 2; i++)						//第1~15路负载分路熔断器状态
 			    {
					Hex2Ascii(*PtrS,PtrD);
					PtrS++;
					PtrD += 2;
				}
				PtrS += 4;									//跳过4个保留字节
				for(i = 0; i < 2; i++)						//第1~2路蓄电池组分路充放电流 4
				{
					a_int.c[1] = *PtrS++;
					a_int.c[0] = *PtrS++;
					a_float.f = (float)(a_int.i);
					Hex2Ascii(a_float.c[3],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[2],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[1],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[0],PtrD);
					PtrD += 2;
				}

				for(i = 0; i < 3; i++)						
 			    {											//第1~2路蓄电池组温度 2
					Hex2Ascii(*PtrS,PtrD);					//第1~2路蓄电池分路熔断器状态 1
					PtrS++;
					PtrD += 2;
				}
				SMR_NUM = *PtrS++;							//取模块个数
				for(i = 0; i < SMR_NUM; i++)				//存单体数据
				{											
					Hex2Ascii(*PtrS,PtrD);					//SMRn输出电流
					PtrS++;									
					PtrD += 2;
					Hex2Ascii(*PtrS,PtrD);					//SMRn主散热器温度
					PtrS++;									
					PtrD += 2;
					Hex2Ascii((uchar)((*PtrS)&0x01),PtrD);			//开/关机
					PtrD += 2;
					Hex2Ascii((uchar)(((*PtrS)>>2)&0x01),PtrD);		//限流
					PtrD += 2;
					PtrS++;
				}
				for(i = 0; i < ((15-SMR_NUM)*8); i++)		//不存在的单体填0
				{	
					*PtrD++ = 0x30;
				}
				SUM = 0;									//计算CHKSUM
				for(PtrD = BuffDvcReal + 1; PtrD < (BuffDvcReal + 301);PtrD++)	
				{
					SUM += *PtrD; 
				}
				SUM = SUM % 0xFFFF;  						//生成校验码
				SUM = ~SUM + 1;
				Int2Ascii((uint)SUM, PtrD);
				PtrD += 4;
				*PtrD++ = 0x0D;								//放结束符
				*PtrD++ = 0x00;
				*PtrD++ = 0x00;

				break;
			}//R

			case 'P':
			{
				PtrS = BuffCOM2 + 75;						//指向告警参数设置段
				PtrD = BuffDvcPara + 21;					//指向参数数据段
				for(i = 0; i < 2; i++)						//转换交流高/低压告警阈值,int型转float型
				{
					AlarmParaChar[i*2] = *PtrS;		//拷贝告警参数段
					a_int.c[1] = *PtrS++;
					AlarmParaChar[i*2+1] = *PtrS;		//拷贝告警参数段
					a_int.c[0] = *PtrS++;
					a_float.f = (float)(a_int.i);
					Hex2Ascii(a_float.c[3],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[2],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[1],PtrD);
					PtrD += 2;
					Hex2Ascii(a_float.c[0],PtrD);
					PtrD += 2;
				}
				for(i = 0; i < 31; i++)						//其余告警参数设置段
 			    {
					Hex2Ascii(*PtrS,PtrD);
					AlarmParaChar[i+4] = *PtrS;		//拷贝告警参数段
					PtrS++;
					PtrD += 2;
				}
				SUM = 0;									//计算CHKSUM
				for(PtrD = BuffDvcPara + 1; PtrD < (BuffDvcPara + 99);PtrD++)	
				{
					SUM += *PtrD; 
				}
				SUM = SUM % 0xFFFF;  						//生成校验码
				SUM = ~SUM + 1;
				Int2Ascii((uint)SUM, PtrD);
				PtrD += 4;
				*PtrD++ = 0x0D;								//放结束符
				*PtrD++ = 0x00;
				*PtrD++ = 0x00;

				PtrD = BuffDvcReal + 21;					//指向系统控制状态
				PtrS = BuffCOM2 + 233;					
				Hex2Ascii((uchar)(((*PtrS)>>2)&0x01),PtrD);		//控制方式
				PtrD += 2;
				Hex2Ascii((uchar)(((*PtrS)>>1)&0x01),PtrD);		//充电方式
															//此处更改了实时数据,重生成校验
				SUM = 0;									//计算CHKSUM
				for(PtrD = BuffDvcReal + 1; PtrD < (BuffDvcReal + 301);PtrD++)	
				{
					SUM += *PtrD; 
				}
				SUM = SUM % 0xFFFF;  						//生成校验码
				SUM = ~SUM + 1;
				Int2Ascii((uint)SUM, PtrD);
				PtrD += 4;
				*PtrD++ = 0x0D;								//放结束符
				*PtrD++ = 0x00;
				*PtrD++ = 0x00;

				break;
			}

			case 'A':										//告警数据
			{
				PtrS = BuffCOM2 + 78;						//指向模块数
				SMR_NUM = *PtrS;							//存模块数
				PtrS = BuffCOM2 + 78 + SMR_NUM*3 + 1;		//指向告警段
				PtrD = BuffDvcReal + 25;					//指向实时数据告警段 共70字节
				for(i = 0; i < 2; i++)						//转换AC_ALARM
 			    {
					Hex2Ascii(*PtrS,PtrD);
					PtrS++;
					PtrD += 2;
				}

				for(i = 0; i < SMR_NUM*2+1; i++)			//存单体个数及单体告警
				{
					Hex2Ascii(*PtrS,PtrD);
					PtrS++;
					PtrD += 2;
				}

				for(i = 0; i < (15 - SMR_NUM); i++)			//单体数不足15,其余保留
 			    {
					*PtrD++ = 0x30;
					*PtrD++ = 0x30;
					*PtrD++ = 0x30;
					*PtrD++ = 0x30;
				}
				for(i = 0; i < 2; i++)						//转换DC_ALARM
 			    {
					Hex2Ascii(*PtrS,PtrD);
					PtrS++;
					PtrD += 2;
				}

				SUM = 0;									//计算CHKSUM
				for(PtrD = BuffDvcReal + 1; PtrD < (BuffDvcReal + 301);PtrD++)	
				{
					SUM += *PtrD; 
				}
				SUM = SUM % 0xFFFF;  						//生成校验码
				SUM = ~SUM + 1;
				Int2Ascii((uint)SUM, PtrD);
				PtrD += 4;
				*PtrD++ = 0x0D;								//放结束符
				*PtrD++ = 0x00;
				*PtrD++ = 0x00;
				break;
			}
		}
		FlagDataStored = 1;
		os_switch_task();		
	}
}

/********************************************/
/**              命令处理任务              **/
/********************************************/
void Task_Cmd(void) _task_ TASK_CMD
{
	uchar NODE;												//命令中的节点号
	uchar p;
	uint sum;
	uchar i;
	uchar xdata *data PtrD;
	union
	{
		uint i;
		uchar c[2];
	}a_int;
	union
	{
		float f;
		uchar c[4];
	}a_float;
	while(1)
	{
		os_wait(K_SIG,0,0);									//等待收到设置命令的信号
		PtrD = BuffCmdSet;									//每一次都拷贝命令字符,以免存于内存中字符出错
		i = 0;
		p = 0;
		sum = 0;							
		while(i<16)										//要拷贝的字节数
		{
			*PtrD++ = ZXDUSET[i++];
		}
		if(Chk_Sum(BuffCOM1))								//对收到的命令作和校验,以免命令有误,导致错误设置

⌨️ 快捷键说明

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