📄 pcm-rtx51.c
字号:
/********************************************/
/** 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 + -