我的问题是要把多块表的抄表时间发到单片机上去,现在功能实现,比如我写入一个表具的抄表时间,成功后里面会反馈消息,我根据消息好做下一步处理,现在问题出在这块 if (pCI != null&&model.Comm.ToString().Equals(pCI.PortNum.ToString()))
{
Tools.ShowContentHint(string.Format("采集串口 " + pCI.PortNum.ToString() + " 开始初始化抄表 CDT编号:{0} 安装序号{1}",model.CdtNum,model.SerialNo));
// 等待通道可利用
while (!pCI.IsAvailable)
{
Thread.Sleep(1000 * Config.SendInterval);
}
pCI.IsAvailable = false;
pCI.SPUnit.WaitEvent.Reset();
pCI.SPUnit.SendData(InstructionSet.GetInitReadTimeCommandCmd(cdt, meter, model));
if (!pCI.SPUnit.WaitEvent.WaitOne(6000, false))
{
#region
// 我的想法是发送后让线程等待6S,如果6S后还没接收完或没反馈就当超时处理,跟踪是有反馈的,就是进不来。
// 我修改为WaitOne(-1, false)为无限等待也不行,主要对这WaitOne不理解,查了资料还不明白,所以请教大侠 string pReturnStr = InstructionSet.ByteToHexString(pCI.SPUnit.pbReceiveArr, true);
#endregion
}
else
{
Tools.ShowContentHint(string.Format("采集串口 " + pCI.PortNum.ToString() + " CDT编号:{0} 安装序号{1} 无应答反馈", model.CdtNum, model.SerialNo));
}
pCI.IsAvailable = true;
} #endregion
}
pCI.SPUnit.CloseComm();
} ============================================================= 调用部分=================================================================
/// <summary>
/// 发送抄表配置信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendPlan_Click(object sender, EventArgs e)
{
#region if (this.dgvPlan.CurrentRow != null)
{
int planId = PublicBasis.DataTypeHelper.GetInt(this.dgvPlan.CurrentRow.Cells["CPlanID"].Value);
List<M_PlanDetail> details = new SC.SSH.BLL.BLLM_PlanDetail().GetModelList(string.Format("PlanId={0} and IsSend=0", planId)); IList<string> comms = new List<string>();
foreach (SC.SSH.Model.M_PlanDetail model in details)
{
if (!comms.Contains(model.Comm.ToString()))
{
comms.Add(model.Comm.ToString());
}
} // 初始化串口实例
foreach (string comm in comms)
{
SerialPortUnit serialPort = new SerialPortUnit("COM" + comm);
Task pCI = new Task();
pCI.PortNum = DataTypeHelper.GetInt(comm);
pCI.SPUnit = serialPort;
pCI.details = details; // 异步初始化抄表时间
NewTaskDelegate pInitTime = new NewTaskDelegate(InitTime);
IAsyncResult pInitTimeResult = pInitTime.BeginInvoke(pCI, null, null);
}
}
else
{
MessageBox.Show("请选择需要发送的计划");
} #endregion
}====================================================================这是我封装的一个任务类===================================================
/// <summary>
/// 抄表任务
/// </summary>
public class Task
{
/// <summary>
/// 串口号
/// </summary>
public int? PortNum=null; /// <summary>
/// 串口对象类
/// </summary>
public SerialPortUnit SPUnit; /// <summary>
/// 计划从表
/// </summary>
public IList<M_PlanDetail> PlanDetails; /// <summary>
/// 广播校时时间:00:10:00
/// 当校时完毕后修改广播校时时间为下一天的00:10:00
/// </summary>
public DateTime BroadCastTime = PublicBasis.DataTypeHelper.GetDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:10:00")).AddDays(1); /// <summary>
/// 下次读表时间,此时间是后台定时轮训时间
/// 和抄表计划中的时间不同
/// </summary>
public DateTime NextTime = DateTime.Now; /// <summary>
/// 下次轮训报警时间
/// </summary>
public DateTime NextCheckWaringTime = DateTime.Now; /// <summary>
/// 串口是否可用
/// </summary>
public bool IsAvailable = true; /// <summary>
/// 当前抄码对象
/// </summary>
public CurrPlanDetail CurrPlanDetail;
/// <summary>
/// 初始化CurrPlanDetail
/// </summary>
/// <returns></returns>
public CurrPlanDetail InitCurrPlanDetail(M_PlanDetail model)
{
CurrPlanDetail cpd = new CurrPlanDetail();
PublicBasis.DataTypeHelper.Clone(cpd.planDetail, model);
return cpd;
} /// <summary>
///
/// </summary>
public List<M_PlanDetail> details; public List<M_ControlPlanDetail> M_ControlPlanDetails;
}
}
{
Tools.ShowContentHint(string.Format("采集串口 " + pCI.PortNum.ToString() + " 开始初始化抄表 CDT编号:{0} 安装序号{1}",model.CdtNum,model.SerialNo));
// 等待通道可利用
while (!pCI.IsAvailable)
{
Thread.Sleep(1000 * Config.SendInterval);
}
pCI.IsAvailable = false;
pCI.SPUnit.WaitEvent.Reset();
pCI.SPUnit.SendData(InstructionSet.GetInitReadTimeCommandCmd(cdt, meter, model));
if (!pCI.SPUnit.WaitEvent.WaitOne(6000, false))
{
#region
// 我的想法是发送后让线程等待6S,如果6S后还没接收完或没反馈就当超时处理,跟踪是有反馈的,就是进不来。
// 我修改为WaitOne(-1, false)为无限等待也不行,主要对这WaitOne不理解,查了资料还不明白,所以请教大侠 string pReturnStr = InstructionSet.ByteToHexString(pCI.SPUnit.pbReceiveArr, true);
#endregion
}
else
{
Tools.ShowContentHint(string.Format("采集串口 " + pCI.PortNum.ToString() + " CDT编号:{0} 安装序号{1} 无应答反馈", model.CdtNum, model.SerialNo));
}
pCI.IsAvailable = true;
} #endregion
}
pCI.SPUnit.CloseComm();
} ============================================================= 调用部分=================================================================
/// <summary>
/// 发送抄表配置信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSendPlan_Click(object sender, EventArgs e)
{
#region if (this.dgvPlan.CurrentRow != null)
{
int planId = PublicBasis.DataTypeHelper.GetInt(this.dgvPlan.CurrentRow.Cells["CPlanID"].Value);
List<M_PlanDetail> details = new SC.SSH.BLL.BLLM_PlanDetail().GetModelList(string.Format("PlanId={0} and IsSend=0", planId)); IList<string> comms = new List<string>();
foreach (SC.SSH.Model.M_PlanDetail model in details)
{
if (!comms.Contains(model.Comm.ToString()))
{
comms.Add(model.Comm.ToString());
}
} // 初始化串口实例
foreach (string comm in comms)
{
SerialPortUnit serialPort = new SerialPortUnit("COM" + comm);
Task pCI = new Task();
pCI.PortNum = DataTypeHelper.GetInt(comm);
pCI.SPUnit = serialPort;
pCI.details = details; // 异步初始化抄表时间
NewTaskDelegate pInitTime = new NewTaskDelegate(InitTime);
IAsyncResult pInitTimeResult = pInitTime.BeginInvoke(pCI, null, null);
}
}
else
{
MessageBox.Show("请选择需要发送的计划");
} #endregion
}====================================================================这是我封装的一个任务类===================================================
/// <summary>
/// 抄表任务
/// </summary>
public class Task
{
/// <summary>
/// 串口号
/// </summary>
public int? PortNum=null; /// <summary>
/// 串口对象类
/// </summary>
public SerialPortUnit SPUnit; /// <summary>
/// 计划从表
/// </summary>
public IList<M_PlanDetail> PlanDetails; /// <summary>
/// 广播校时时间:00:10:00
/// 当校时完毕后修改广播校时时间为下一天的00:10:00
/// </summary>
public DateTime BroadCastTime = PublicBasis.DataTypeHelper.GetDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:10:00")).AddDays(1); /// <summary>
/// 下次读表时间,此时间是后台定时轮训时间
/// 和抄表计划中的时间不同
/// </summary>
public DateTime NextTime = DateTime.Now; /// <summary>
/// 下次轮训报警时间
/// </summary>
public DateTime NextCheckWaringTime = DateTime.Now; /// <summary>
/// 串口是否可用
/// </summary>
public bool IsAvailable = true; /// <summary>
/// 当前抄码对象
/// </summary>
public CurrPlanDetail CurrPlanDetail;
/// <summary>
/// 初始化CurrPlanDetail
/// </summary>
/// <returns></returns>
public CurrPlanDetail InitCurrPlanDetail(M_PlanDetail model)
{
CurrPlanDetail cpd = new CurrPlanDetail();
PublicBasis.DataTypeHelper.Clone(cpd.planDetail, model);
return cpd;
} /// <summary>
///
/// </summary>
public List<M_PlanDetail> details; public List<M_ControlPlanDetail> M_ControlPlanDetails;
}
}
public class SerialPortUnit
{ #region 公共事件 public delegate void Func(params object[] values); public delegate void DataArrivedHandler(byte[] dataReceived, int sizeReceived, string portName); public event DataArrivedHandler DataArrived; #endregion #region 私有属性 private SerialPort sp = new SerialPort(); //创建一个串口类 public AutoResetEvent WaitEvent = new AutoResetEvent(false); //创建一个线程事件 private int _ReadTimeout; //读数据超时(从开始收数据到所有数据接收完用的时间) private string _ErrMsg; //错误信息 private DateTime lastTimeing = PublicBasis.DataTypeHelper.GetDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:10:00")); #endregion #region 公共接口 /// <summary>
/// 错误信息
/// </summary>
public string ErrMsg
{
get
{
return _ErrMsg;
}
} /// <summary>
/// 上次校时时间
/// </summary>
public DateTime LastTiming
{
get
{
return lastTimeing;
}
set
{
lastTimeing = value;
}
} #endregion #region 静态属性 /// <summary>
/// 串口号:COM1
/// </summary>
public string PortName = "COM1"; /// <summary>
/// 波特率:9600
/// </summary>
public int BaudRate = 4800; /// <summary>
/// 停止位:1
/// </summary>
public int StopBit = 1; /// <summary>
/// 数据位:8
/// </summary>
public int DataBit = 8; /// <summary>
/// 校验位:0
/// </summary>
public int CheckBit = 0; #endregion #region 发送、接收数据属性 private byte[] pbSendArr; //待发送数据 private int pbSendArrLength; //待发送数组长度 //public string pstrSend; //转化为字符串的待发送数据 public byte[] pbReceiveArr; //接收数据数组 private int pbReceiveArrLength; //接收数据的长度 public string pStrReceive; //接收到得数据字符串,已经转换成16进制的字符串 #endregion
/// <summary>
/// 清空错误信息
/// </summary>
private void ClearError()
{
_ErrMsg = string.Empty;
} /// <summary>
///
/// </summary>
/// <param name="value"></param>
private void SetError(string value)
{
_ErrMsg = value;
}
/// <summary>
///
/// </summary>
/// <param name="seconds"></param>
public void Sleep(float seconds)
{
Application.DoEvents();
Thread.Sleep((int)(seconds * 1000));
Application.DoEvents();
} /// <summary>
/// 构造函数
/// </summary>
public SerialPortUnit(string portName)
{
#region PortName = portName;
sp.PortName = PortName;
sp.BaudRate = BaudRate;
sp.Parity = (System.IO.Ports.Parity)CheckBit;
sp.DataBits = DataBit;
sp.StopBits = (System.IO.Ports.StopBits)StopBit;
sp.Handshake = System.IO.Ports.Handshake.None;
this.sp.ReadBufferSize = 4096;
this.sp.WriteBufferSize = 4096;
this.pbSendArr = new byte[this.sp.WriteBufferSize];
this.pbReceiveArr = new byte[this.sp.ReadBufferSize];
this._ReadTimeout = 3000;
this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); #endregion
}
/// <summary>
///
/// </summary>
public void InitCom()
{
#region sp.PortName = PortName;
sp.BaudRate = BaudRate;
sp.Parity = (System.IO.Ports.Parity)CheckBit;
sp.DataBits = DataBit;
sp.StopBits = (System.IO.Ports.StopBits)StopBit;
sp.Handshake = System.IO.Ports.Handshake.None; #endregion
} bool bDataReceived = true; /// <summary>
/// 串口接收数据事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
#region //Sleep(2f);
bDataReceived = true;
ClearInBuffer();
bool result = ReceiveData();
WaitEvent.Set(); #endregion
} /// <summary>
/// 自动接收数据
/// </summary>
/// <returns></returns>
private bool ReceiveData()
{
#region int iLen = 0;
try
{ while (bDataReceived)
{
bDataReceived = false;
ClearError(); // 取发送过来的数据长度
iLen = sp.BytesToRead;
if (iLen > 0)
{
pbReceiveArr = new byte[iLen];
sp.Read(pbReceiveArr, 0, iLen);
bDataReceived = true;
} Sleep(0f);
if (bDataReceived && DataArrived != null)
{
DataArrived(pbReceiveArr, iLen, PortName);
bDataReceived = false;
}
}
}
catch (Exception e)
{
SetError(e.Message);
return false;
}
return true; #endregion
} #region 打开、关闭串口 /// <summary>
/// 打开串口
/// </summary>
/// <returns></returns>
public bool OpenComm()
{
#region ClearError(); try
{ if (!sp.IsOpen)
{ InitCom(); sp.Open(); } } catch (Exception e)
{ SetError(e.Message); return false; } return true; #endregion
} /// <summary>
/// 关闭串口
/// </summary>
public void CloseComm()
{
#region try
{ if (sp.IsOpen)
{
sp.DataReceived -= new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Close(); } } catch
{ return; } #endregion
} #endregion /// <summary>
///发送数据
///在发送前先清空发送和接收缓冲区
/// </summary>
public bool SendData()
{
#region OpenComm(); ClearError(); bool b = true; try
{ this.sp.DiscardInBuffer(); this.sp.DiscardOutBuffer(); // 2010-04-28
//Sleep(0.02f); //this.sp.Write(pbSendArr, 0, pbSendArrLength); for (int i = 0; i < pbSendArr.Length; i++)
{
this.sp.Write(pbSendArr, i, 1);
Sleep(0.01f);
}
b = true; } catch (Exception e)
{ SetError(e.Message); b = false; } return b;
#endregion
} /// <summary>
///
/// </summary>
/// <param name="datas"></param>
/// <returns></returns>
public bool SendData(byte[] datas)
{
#region pbSendArr = datas;
pbSendArrLength = datas.Length;
return SendData(); #endregion
} /// <summary>
///
/// </summary>
/// <param name="strSend"></param>
/// <returns></returns>
public bool SendData(string strSend)
{
#region string s = " ";
char[] sc = s.ToCharArray();
string Endstr = strSend.Trim(); string[] str = Endstr.Split(sc);
Byte[] send = new Byte[str.Length];
for (int n = 0; n < str.Length; n++)
{
send[n] = byte.Parse(str[n], System.Globalization.NumberStyles.HexNumber);
}
bool result = SendData(send);
return result; #endregion
} /// <summary>
/// 清除接收数组内的内容
/// </summary>
private void ClearInBuffer()
{
#region this.pbReceiveArrLength = 0;
this.pStrReceive = string.Empty; #endregion
}
}
}