常规数据的收发实现其实也不是很难,主要是根据CAN盒提供的二次开发库(一般为dll文件)和一些帮助文档(主要是介绍函数的使用,CAN盒的初始化顺序)在上位机中按照正确的顺序初始化CAN盒并开启,最后在一个线程中不断的调用接口函数获取数据。
关于CAN盒的选择主要有两种,一种是通过USB接口和PC通信的,这类CAN盒收发的速率比较高,也比较稳定,不容易出现丢帧的现象;另一类是通过串口的方式和PC通信,这种CAN盒的特点是相对便宜,原理上就一个MCU利用内部的CAN控制器模块和串口模块。CAN模块提供对外接口,串口模块负责和PC端通信,在我之前的开发中有用过这类CAN盒,收发速度不能太快,发送实际测试应该有每秒500帧-600帧。本次设计中选用USB通信的CAN盒。
CAN盒选用的是某宝上200大洋左右的,实际使用中没遇到过丢帧的情况(测试环境是接收1百万帧的数据以每秒3千帧的速度)。根据其帮助文档,按顺序初始化设备。在我的设计中有两种开启设备方式,一种是在上位机开启时尝试初始化并开启。第二种是在上位机运行时通过菜单键手动设置,开启CAN盒。
实现收发功能,用到了两个线程,一个定时器,一个缓存显示收发数据的ringbuffer,datagridview等控件/资源。
线程1:用于CAN数据的接收,将接收到的数据放入ringbuffer中。
线程2:用于将收发数据加载到List中。
定时器:用于定时检测CAN盒的状态,计算收发速率。
RingBuffer:用于缓存要显示的收发数据。
Datagridview:用于显示收发的数据。
在这两个线程中都应该加入线程的sleep方法,避免CPU使用过高,另外sleep的时间不应过长,以防止数据接收不过来,实际中发现就算写成sleep(1),有时线程再切换回来已花费了十五左右毫秒,网上查找资料发现这是windows的问题,要解决这个问题得在sleep函数调用前后加上 void timeBeginPeriod(int t) 和 void timeEndPeriod(int t);参数t设置成1,此时线程切换就是1ms了,但不易过多的使用,因为会导致系统花费过多的资源在线程切换上。
计算收发速率时,本想着计算1秒钟内接收或发送的报文数量,但是由于定时器及其不稳,导致计算的速率错误。解决方法是应该测量这个定时器实际定时的时间,用这段时间内接收/发送的报文数量计算其收发速率。
用datagriidview显示数据时,在数据量较少时没什么问题,数据量大时会耗费大量的时间,通过调查发现主要原因是每次更新显示都是从新绑定List到datagridview,这会花费时间,另外由于我在每次更新时会将datagridview指向最后一行,虽说好看了些,但是这样消耗了一些时间。解决的方法是采用虚拟加载的方式,以及限定最大的收发显示数量,就是说当list的长度大于我设定的值时,当新增一个数据时,移除最前面的数据,这样在收发,查看数据时也不会发生卡顿的现象了。
测试10万帧数据的接收,时间戳做的不好应该用CAN盒的时间来表示每帧数据真实的接收时间点,但是由于不好和发送的时间做统一,故而统一采用PC端的时间了?,这点以后可以改进。。。
显示接收速率
数据发送
当窗口关闭时,把各个控件的属性值写入到XML文件中,加密保存,窗口打开时解密并解析xml,将各个控件的属性值初始化。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
using System.Text;
using System.Xml;
namespace XCAN
{
public partial class XCAN : Form
{
const int RT_MaxNumber = 8000;//最大显示行数
bool IsDisplayRate_Flag = false;//用于产生1S
UInt16 CAN_Rate = 0;//can 波特率
UInt16 OldCAN_Rate = 0;
public const UInt32 m_devtype = 4;//设备类型,USBCAN2
public const UInt32 m_devind = 0; //设备索引号,0
private const UInt32 canbffersize = 2000;//can buffer
ushort CAN_Status = 0; //can盒设备开启(bit0),初始化(bit1),通道开启状态(bit2)
ushort OldCAN_Status = 0x08;
//uint R_HistoryTicks = 0;//时间戳
//long T_HistoryTicks = 0;//时间戳
//long FristEnterT_ticks = 0;
//long FristEnterR_ticks = 0;
long FristEnterRT_ticks = 0;
//long LastTimeStamp = 0;
//bool FirstEnterRcevDeal_Pec_Flag = true;
//bool FirstEnterSendDeal_Pec_Flag = true;
//UInt16 WhoFristEnterRTBuffer = 0;//标记R/T那个先进入RT_buffer
bool Add_RT_DataToList_Flag = false;
bool Is_RT_IDLE_Flag = false;
public static bool Is_RT_ButtonTurnOn = true;
public static bool UDS_ENABLE = false; //UDS使能
public static UInt32 m_bOpen = 0; //设备启用
public static UInt32 m_canind = 0; //can 通道
UInt32 r_number = 0;//用于计算接收速率
UInt32 t_number = 0;//用于计算发送速率
public static UInt32 t_error_number = 0;//发送错误
UInt32 r_sequence_number = 0;//指示收数据的编号
public static UInt32 t_sequence_number = 0;//指示发数据的编号
UInt32 rt_sequence_number = 0;//指示收发数据的编号
VCI_CAN_OBJ[] m_recobj = new VCI_CAN_OBJ[canbffersize];
public static List
/*------------兼容ZLG的函数描述---------------------------------*/
[DllImport("controlcan.dll")]
static extern UInt32 VCI_OpenDevice(UInt32 DeviceType, UInt32 DeviceInd, UInt32 Reserved);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_CloseDevice(UInt32 DeviceType, UInt32 DeviceInd);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_InitCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_INIT_CONFIG pInitConfig);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_ReadBoardInfo(UInt32 DeviceType, UInt32 DeviceInd, ref VCI_BOARD_INFO pInfo);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_GetReceiveNum(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_ClearBuffer(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_StartCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_ResetCAN(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_Transmit(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pSend, UInt32 Len);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_Receive(UInt32 DeviceType, UInt32 DeviceInd, UInt32 CANInd, ref VCI_CAN_OBJ pReceive, UInt32 Len, Int32 WaitTime);
/*-------------------------------------------------------其他函数描述----------------------------------------*/
[DllImport("controlcan.dll")]
static extern UInt32 VCI_ConnectDevice(UInt32 DevType, UInt32 DevIndex);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_UsbDeviceReset(UInt32 DevType, UInt32 DevIndex, UInt32 Reserved);
[DllImport("controlcan.dll")]
static extern UInt32 VCI_FindUsbDevice(ref VCI_BOARD_INFO1 pInfo);
/*--------------------------------------------------------函数描述结束----------------------------------------*/
public XCAN()
{
InitializeComponent();
}
[DllImport("kernel32.dll")]
public extern static short QueryPerformanceCounter(ref long x);
[DllImport("kernel32.dll")]
public extern static short QueryPerformanceFrequency(ref long x);
private void Form1_Load(object sender, EventArgs e)
{
/* 初始化CAN配置参数显示 */
bool UseLocalParameter = false;
string XML_DecryptContent = null;
try
{
StreamReader sr = new StreamReader("Form1_Cfg.xml", Encoding.Default);
string XML_Content = sr.ReadToEnd();
sr.Close();
XML_DecryptContent = AES.AesDecrypt(XML_Content,"q1a2s3d4d5f6g7h8
}
catch
{
UseLocalParameter = true;
}
if (XML_DecryptContent == "")
{
UseLocalParameter = true;
}
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml(XML_DecryptContent);
}
catch
{
UseLocalParameter = true;
}
XmlNodeList CfgNodeList = null;
try
{
CfgNodeList = xmlDoc.SelectSingleNode("Form1_Cfg").ChildNodes;
}
catch
{
UseLocalParameter = true;
}
if (CfgNodeList != null)
{
foreach (XmlNode singleXmlNode in CfgNodeList)
{
switch (singleXmlNode.Name)
{
case "label_frame_type": { combobox_frame_type.SelectedIndex = (singleXmlNode.InnerText == "1") ? 1 : 0; } break;
case "label_frame_format": { combobox_frame_format.SelectedIndex = (singleXmlNode.InnerText == "1") ? 1 : 0; } break;
case "label_frame_id": { textBox_frame_iden.Text = singleXmlNode.InnerText; } break;
case "label_frame_data": { textBox_frame_data.Text = singleXmlNode.InnerText; } break;
default: break;
}
}
}
else
{
UseLocalParameter = true;
}
if(UseLocalParameter == true)
{
combobox_frame_format.SelectedIndex = 0;//默认为数据帧
combobox_frame_type.SelectedIndex = 0; //默认为标准帧
textBox_frame_iden.Text = "123"; //默认ID为0x123
textBox_frame_data.Text = "12 13 14 15 16 17 18 19"; //默认的发送数据
}
//设置列的宽度
dataGridView1.Columns[0].Width = 65;
dataGridView1.Columns[1].Width = 75;
dataGridView1.Columns[2].Width = 90;
dataGridView1.Columns[3].Width = 90;
dataGridView1.Columns[4].Width = 85;
dataGridView1.Columns[5].Width = 95;
dataGridView1.Columns[6].Width = 100;
dataGridView1.Columns[7].Width = 100;
dataGridView1.Columns[8].Width = dataGridView1.Width - 700;//972-700 = 272
/* 尝试打开设备,返回 1 ,0 ,-1 */
UInt32 tval = opendevice();
if(1== tval)//打开成功,清通道数据
{
VCI_INIT_CONFIG Tcan_confi;
CAN_Status = (ushort)(CAN_Status | (0x01));//标记设备已开启
Tcan_confi.AccCode = 0x80000000;//过滤验收码
Tcan_confi.AccMask = 0xFFFFFFFF;//过滤屏蔽码
Tcan_confi.Filter = 1;//接收所有
Tcan_confi.Mode = 0;//工作模式,正常
Tcan_confi.Reserved = 0;
Tcan_confi.Timing0 = 0x00;
Tcan_confi.Timing1 = 0x1c; //500k
CAN_Rate = 500;
setCAN_Praameter(Tcan_confi);
}
/* 创建一个接收线程 */
Thread rec_th = new Thread(new ThreadStart(rec_can_message_TH));
rec_th.Priority = ThreadPriority.AboveNormal;
rec_th.IsBackground = true;
rec_th.Start();
/* 创建一个更新收发数据显示的线程 */
Thread displayoriginaldata_th = new Thread(new ThreadStart(update_display_original_data_TH));
displayoriginaldata_th.Priority = ThreadPriority.BelowNormal;
displayoriginaldata_th.IsBackground = true;
displayoriginaldata_th.Start();
timer1_dispaly_500ms.Enabled = true;//开启定时显示,500ms
Control.CheckForIllegalCrossThreadCalls = false;//(不推荐)
}
///
/// 输出提示信息
///
///
private void MainWindows_Output_Reminder(string str)
{
label_mainwindow_reminder.Text = "提示:" + str + "!" + "(" + System.DateTime.Now.ToString("t") + ")";
}
/*
* 毫秒->秒毫秒
*/
private String Time_Frame_Conversion(long ms)
{
string conversion_value;
conversion_value = (ms/1000).ToString().PadLeft(4,'0')+":"+ (ms%1000).ToString().PadLeft(3, '0');
return conversion_value;
}
///
/// 没有数据时,睡眠1ms
///
private void update_display_original_data_TH()
{
long ticks_ms = 0;
rec_send_info t_info;
string T_rt = null;
string T_timestamp = null;
while (true)
{
if(true == rt_can_ringbuffer.ringbufferisempty())
{
timeBeginPeriod(1);
Thread.Sleep(1);//休眠1ms
timeEndPeriod(1);
}
else
{
RT_CANDATA_INFO Tdata = rt_can_ringbuffer.ringbuffergetone();
if (0xA5 == Tdata.RT_Index)//数据为发送
{
T_rt = "发送";
}
else if(0x5A == Tdata.RT_Index)//数据为接收
{
T_rt = "接收";
}
else
{
continue;
}
if (FristEnterRT_ticks > 0)
{
ticks_ms = ( DateTime.Now.Ticks - FristEnterRT_ticks) / 10000;
}
else
{
FristEnterRT_ticks = DateTime.Now.Ticks;
ticks_ms = 0;
}
T_timestamp = Time_Frame_Conversion(ticks_ms);
t_info.temp_can_id = "Ox" + System.Convert.ToString(Tdata.VCI_CAN_OBJ1.ID, 16).ToLower();
if (Tdata.VCI_CAN_OBJ1.RemoteFlag == 0)
{
t_info.tem_can_format = "数据帧 ";
}
else
{
t_info.tem_can_format = "远程帧 ";
}
if (Tdata.VCI_CAN_OBJ1.ExternFlag == 0)
{
t_info.tem_can_type = "标准帧 ";
}
else
{
t_info.tem_can_type = "扩展帧 ";
}
t_info.tem_rt_ch = "CH" + m_canind.ToString();
byte len = (byte)(Tdata.VCI_CAN_OBJ1.DataLen % 9);
t_info.tem_can_data = null;
unsafe
{
for (int i = 0; i < len; i++)
{
t_info.tem_can_data += "0x" + Tdata.VCI_CAN_OBJ1.Data[i].ToString("x2") + " ";
}
}
/* 当数据长度大于list指定的长度时,移除掉0号元素 */
if(tr_can_information.Count >= RT_MaxNumber)
{
tr_can_information.RemoveAt(0);
}
//if (tr_can_information.Count < 2)
//{
tr_can_information.Add(new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
//}
//else
//{
// if (LastTimeStamp > ticks_ms)
// {
// tr_can_information.Insert(tr_can_information.Count - 2, new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
// t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
// }
// else
// {
// tr_can_information.Add(new RT_Frame_Info(rt_sequence_number++, T_timestamp, T_rt, t_info.tem_rt_ch,
// t_info.temp_can_id, t_info.tem_can_format, t_info.tem_can_type, len, t_info.tem_can_data));
// }
//}
Add_RT_DataToList_Flag = true;//标记收发数据已更新到List
//LastTimeStamp = ticks_ms;
//System.Diagnostics.Debug.WriteLine("时间戳:{0}(毫秒)", ticks_ms); //总毫秒数
}
}
}
void setCAN_Praameter(VCI_INIT_CONFIG can_confi)
{
UInt32 val1 = VCI_InitCAN(m_devtype, m_devind, m_canind, ref can_confi);
if (1 == val1)
{
CAN_Status = (ushort)(CAN_Status | (0x02));//标记设备已初始化
UInt32 val2 = VCI_ClearBuffer(m_devtype, m_devind, m_canind);
if (1 == val2)
{
UInt32 val3 = VCI_StartCAN(m_devtype, m_devind, m_canind);
if (1 == val3)
{
CAN_Status = (ushort)(CAN_Status | (0x04));//置打开通道标记
MainWindows_Output_Reminder("CAN" + m_canind.ToString() + "已开启");
}
else
{
CAN_Status = (ushort)(CAN_Status & (0x03));//清初打开通道标记
MainWindows_Output_Reminder("打开CAN" + m_canind.ToString() + "失败");
}
}
else
{
MainWindows_Output_Reminder("清CAN" + m_canind.ToString() + "通道数据失败");
}
}
else
{
CAN_Status = (ushort)(CAN_Status & (0x05));//清初始化标记
MainWindows_Output_Reminder("初始化CAN" + m_canind.ToString() + "失败");
}
}
///
/// 设置can参数窗口
///
///
///
void updata_can_parameter(UInt32 can_ch, VCI_INIT_CONFIG can_config)
{
VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
opendevice();//开启设备
if (m_bOpen == 1)
{
m_canind = can_ch;
config = can_config;
CAN_Rate = (UInt16)config.Reserved;
setCAN_Praameter(config);
}
else
{
MainWindows_Output_Reminder("设备未开启");
}
}
///
/// CAN盒的接收线程,每隔5ms更新数据,并将数据添加到UDS缓存和原始数据缓存中
///
private void rec_can_message_TH()
{
while(true)
{
UInt32 res = new UInt32();
UInt32 i = 0;
res = VCI_Receive(m_devtype, m_devind, m_canind, ref m_recobj[0],100,0);
RT_CANDATA_INFO Tr_candata_info = new RT_CANDATA_INFO();
if ((res > 0) && (res <= canbffersize))
{
for (i = 0; i < res; i++)
{
if ((m_recobj[i].ID == Diag.Diag_CANparameters.Response_ID) && (Diag.Diag_CANparameters.Response_ID != 0x00))//uds报文
{
while (!(rec_uds_ringbuffer.ringbufferaddone(m_recobj[i])))//诊断报文必须接收
{
timeBeginPeriod(1);
Thread.Sleep(1);
timeEndPeriod(1);
}
}
/***将所有接收报文添加到缓存中****/
Tr_candata_info.RT_Index = (byte)0x5A;//标记此报文为接收报文
Tr_candata_info.VCI_CAN_OBJ1 = m_recobj[i];
if (false == (rt_can_ringbuffer.ringbufferputone2(Tr_candata_info)))//非诊断报文可以不接收
{
UInt16 j = 6;
bool val = false;
do
{
j--;
timeBeginPeriod(1);
Thread.Sleep(1);
timeEndPeriod(1);
val = rt_can_ringbuffer.ringbufferputone2(Tr_candata_info);
} while((val == false)&&(j>0));
}
}
r_sequence_number += res;//更新接收的帧数
}
else
{
Is_RT_IDLE_Flag = true;
}
timeBeginPeriod(1);
Thread.Sleep(1);//1ms
timeEndPeriod(1);
}
}
///
/// 返回1,打开成功,其它失败
///
///
private UInt32 opendevice()
{
UInt32 dwRel;
dwRel = VCI_OpenDevice(m_devtype, m_devind, 0);
if (dwRel == 1)
{
m_bOpen = 1;
CAN_Status = (ushort)(CAN_Status | (0x01));//标记设备已开启
MainWindows_Output_Reminder("设备开启");
}
else if (dwRel == 0)
{
MainWindows_Output_Reminder("设备开启操作失败");
}
else
{
MainWindows_Output_Reminder("设备不存在或USB掉线");
}
return dwRel;
}
///
/// 打开设备 usbcan2 ,索引 0
///
///
///
private void 打开设备ToolStripMenuItem_Click(object sender, EventArgs e)
{
opendevice();
}
///
/// 关闭设备,复位设备开启标志和初始化标志,关闭定时器timer_rec
///
///
///
private void 关闭设备ToolStripMenuItem1_Click(object sender, EventArgs e)
{
UInt32 dwRel;
dwRel = VCI_CloseDevice(m_devtype, m_devind);
if (dwRel == 1)
{
m_bOpen = 0;
CAN_Status = (ushort)(CAN_Status & (0x06));//清设备已开启标记
MainWindows_Output_Reminder("设备关闭");
}
else if (dwRel == 0)
{
MainWindows_Output_Reminder("设备关闭操作失败");
}
else
{
MainWindows_Output_Reminder("设备不存在或USB掉线");
}
}
///
/// 退出应用程序之前,先关闭设备
///
///
///
private void 退出设备ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (m_bOpen == 1)
{
VCI_CloseDevice(m_devtype, m_devind);
}
this.Close();
}
///
/// 应用程序关闭时,如果设备已打开,则关闭设备
///
///
///
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (m_bOpen == 1)
{
VCI_CloseDevice(m_devtype, m_devind);
}
timer1_dispaly_500ms.Enabled = false;
/* 保存窗口参数 */
if (File.Exists("Form1_Cfg.xml")) //如果文件存在,则删除对象
{
try
{
File.Delete("Form1_Cfg.xml");
}
catch
{
}
}
StreamWriter sr;
string XMLString = "\r\n";
XMLString += "
XMLString += "\t
+ "\t
+ "\t
+ "\t
XMLString += "\r\n";
XMLString = AES.AesEncrypt(XMLString, "q1a2s3d4d5f6g7h8
if(XMLString != "")
{
try
{
sr = File.CreateText("Form1_Cfg.xml");
sr.WriteLine(XMLString);
sr.Close();
}
catch
{
}
}
try
{
System.Environment.Exit(0);
}
catch
{
}
}
///
/// 发送一帧,数据内容在 VCI_CAN_OBJ
///
/// 驱动类型:4>
/// 驱动索引:0>
///
///
/// 一次发送的帧数:1>
///
//private static long oldtime = 0;
public static Boolean send_can_message(ref VCI_CAN_OBJ pSend)
{
//long nowtime = DateTime.Now.Ticks;
//System.Diagnostics.Debug.WriteLine("VCI_Transmit()函数调用时间差,{0}(毫秒)", (nowtime - oldtime) / 10000); 获取当前时间
//oldtime = nowtime;
///* 需要测试的代码 */
uint t = VCI_Transmit(m_devtype, m_devind, m_canind, ref pSend, 1);
//System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
//XCAN.watch.Stop(); //停止监视
//TimeSpan timespan = watch.Elapsed; //获取当前实例测量得出的总时间
//System.Diagnostics.Debug.WriteLine("VCI_Transmit()发送时间:{0}(毫秒)", timespan.TotalMilliseconds); //总毫秒数,发生时间:0.434(毫秒)
//watch.Start(); //开始监视代码运行时间
if ((t == 0)||(t > 1000))//发送一帧数据
{
t_error_number++;
return false;//返回实际发送的帧数, =-1表示USB-CAN设备不存在或USB掉线
}
else
{
RT_CANDATA_INFO Tt_candata_info = new RT_CANDATA_INFO();
Tt_candata_info.TimeStamp = DateTime.Now.Ticks;//获取当前时间
Tt_candata_info.VCI_CAN_OBJ1 = pSend;
Tt_candata_info.RT_Index = (byte)0xA5;//标记此报文为发送报文
//将此报文添加到收发buffer,若bufferyi满,则睡眠后再次尝试
if (false == (rt_can_ringbuffer.ringbufferputone1(Tt_candata_info)))
{
UInt16 j = 4;
bool addflag = false;
do
{
j--;
timeBeginPeriod(1);
Thread.Sleep(1);
timeEndPeriod(1);
addflag = rt_can_ringbuffer.ringbufferputone1(Tt_candata_info);
}while((addflag == false)&&(j>0));
}
t_sequence_number++;//更新发送帧数
return true;
}
}
///
/// 立即发送常规报文
///
///
///
private void button_immediate_send_Click(object sender, EventArgs e)
{
if (m_bOpen == 0)//未开启
{
MainWindows_Output_Reminder("设备未开启");
return;
}
VCI_CAN_OBJ sendobj = new VCI_CAN_OBJ();
unsafe
{
try
{
sendobj.RemoteFlag = (byte)combobox_frame_format.SelectedIndex;
sendobj.ExternFlag = (byte)combobox_frame_type.SelectedIndex;
sendobj.ID = System.Convert.ToUInt32("0x" + textBox_frame_iden.Text, 16);
if(0 == sendobj.ExternFlag)
{
if(sendobj.ID > 0x7ff)/* 标准帧ID范围 0 - 0x7FF */
{
MainWindows_Output_Reminder("ID超出范围");
return;
}
}
else
{
if (sendobj.ID > 0x1fffffff)/* 扩展帧ID范围 0 - 0x7FFFFFFF */
{
MainWindows_Output_Reminder("ID超出范围");
return;
}
}
int len = (textBox_frame_data.Text.Length + 1) / 3;
sendobj.DataLen = System.Convert.ToByte(len);
String strdata = textBox_frame_data.Text;
int i = -1;
if (i++ < len - 1)
sendobj.Data[0] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[1] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[2] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[3] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[4] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[5] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[6] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
if (i++ < len - 1)
sendobj.Data[7] = System.Convert.ToByte("0x" + strdata.Substring(i * 3, 2), 16);
}
catch
{
MainWindows_Output_Reminder("发送数据格式错误");
return;
}
bool returnvalue = send_can_message(ref sendobj);
if (true == returnvalue)
{
MainWindows_Output_Reminder("发送成功");
}
else
{
MainWindows_Output_Reminder("发送失败");
}
}
}
///
/// 清接收,发送计数器,清List
///
///
///
private void button_clear_data_Click(object sender, EventArgs e)
{
r_number = 0;
t_number = 0;
t_error_number = 0;
r_sequence_number = 0;
t_sequence_number = 0;
rt_sequence_number = 0;//清空RT数据
dataGridView1.RowCount = 0;
tr_can_information.Clear();
tr_can_information.TrimExcess();
FristEnterRT_ticks = 0;
label_rx.Text = "Rx:" + r_sequence_number.ToString();
label_tx.Text = "Tx:" + t_sequence_number.ToString();
label_Txerror.Text = "Tx_error:" + t_error_number.ToString();
}
///
/// 是否开启显示收发的数据
///
///
///
private void button_display_on_off_Click(object sender, EventArgs e)
{
Is_RT_ButtonTurnOn = !Is_RT_ButtonTurnOn;//将按钮状态取反
if (Is_RT_ButtonTurnOn)
{
button_display_on_off.BackgroundImage = Properties.Resources.stop; //是收发状态,显示暂停状态
}
else
{
button_display_on_off.BackgroundImage = Properties.Resources.play;//是暂停状态,显示收发状态
}
}
///
/// 诊断下载功能
///
///
///
public static bool show_diag_form = false;
private void 诊断测试ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!Diag.isopen_diag)
{
Diag diag_form3 = new Diag();
diag_form3.Show();
}
else
{
show_diag_form = true;
}
}
///
/// 诊断发送函数,发送通道为 m_canind
///
/// < VCI_CAN_OBJ类型 >
///
public static Boolean g_uint8_CAN0SetTxStdMsg(ref VCI_CAN_OBJ pSend)
{
Boolean Tvalue = send_can_message(ref pSend);
return Tvalue;
}
///
/// 根据接收和发送标志,定时更新原始报文的显示,用于计算接收或发送的速度,帧/S
///
///
///
long OldTimeValue = 0;
private void timer_dispaly_500ms_Tick(object sender, EventArgs e)
{
long NewTimeValue = 0;
long freq = 0;
IsDisplayRate_Flag = !IsDisplayRate_Flag;
if ((Is_RT_ButtonTurnOn) && (Add_RT_DataToList_Flag))
{
label_rx.Text = "Rx:" + r_sequence_number.ToString();
label_tx.Text = "Tx:" + t_sequence_number.ToString();
label_Txerror.Text = "Tx_error:" + t_error_number.ToString();
dataGridView1.RowCount = tr_can_information.Count;
if (Is_RT_IDLE_Flag)
{
if (dataGridView1.Rows.Count > 0)//将光标指到最后一行数据,数据量大时,耗时较长
{
dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Index;
}
Is_RT_IDLE_Flag = false;
}
Add_RT_DataToList_Flag = false;
}
if (true == IsDisplayRate_Flag)//一秒更新一次
{
QueryPerformanceCounter(ref NewTimeValue);
QueryPerformanceFrequency(ref freq);
long addtime = (NewTimeValue > OldTimeValue) ? (long)(((NewTimeValue - OldTimeValue) * 1000) / (double)(freq)) : 0;
OldTimeValue = NewTimeValue;
//System.Diagnostics.Debug.WriteLine("收发显示时间差,{0}(毫秒)", addtime); //获取当前时间
float Tvalue1 = ((float)((t_sequence_number - t_number) * 1000)) / ((float)addtime);
float Tvalue2 = ((float)((r_sequence_number - r_number) * 1000)) / ((float)addtime);
label1_Trate.Text = String.Format("{0:F}", Tvalue1) + "帧/S";//默认为保留两位
label1_Rrate.Text = String.Format("{0:F}", Tvalue2) + "帧/S";//默认为保留两位
r_number = r_sequence_number;
t_number = t_sequence_number;
if((OldCAN_Status != CAN_Status) || (CAN_Rate != OldCAN_Rate))//更新CAN收发器状态
{
OldCAN_Rate = CAN_Rate;
OldCAN_Status = CAN_Status;
if (0x07 == OldCAN_Status)
{
OldCAN_Rate = CAN_Rate;
this.Text = "XCAN" + "-CAN" + m_canind.ToString()+ "已开启" + "(" + OldCAN_Rate.ToString()+"K)";
}
else if(0x01 != (CAN_Status&0x01))
{
this.Text = "XCAN" + "-设备未开启";
}
else if (0x02 != (CAN_Status & 0x02))
{
this.Text = "XCAN" + "-设备未初始化";
}
else if (0x03 != (CAN_Status & 0x03))
{
this.Text = "XCAN" + "-通道未开启";
}
else
{
this.Text = "XCAN" + "-请重启软件";
}
}
}
else
{
if(0 == VCI_ConnectDevice(m_devtype, m_devind))//每隔一秒检查设备连接状态
{
CAN_Status = 0;
MainWindows_Output_Reminder("设备不存在或USB掉线");
}
}
}
///
/// 更新datagridview
///
///
///
private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
try
{
switch (e.ColumnIndex)
{
case 0:
e.Value = tr_can_information[e.RowIndex].序号;
break;
case 1:
e.Value = tr_can_information[e.RowIndex].时间戳;
break;
case 2:
e.Value = tr_can_information[e.RowIndex].传输方向;
break;
case 3:
e.Value = tr_can_information[e.RowIndex].传输通道;
break;
case 4:
e.Value = tr_can_information[e.RowIndex].帧ID;
break;
case 5:
e.Value = tr_can_information[e.RowIndex].帧格式;
break;
case 6:
e.Value = tr_can_information[e.RowIndex].帧类型;
break;
case 7:
e.Value = tr_can_information[e.RowIndex].数据长度;
break;
case 8:
e.Value = tr_can_information[e.RowIndex].帧数据;
break;
default:
;
break;
}
}
catch
{
}
}
///
/// 弹出一个设置窗口,用来初始化CAN0/CAN1通道
///
///
///
///
private void 开启ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!Set_Form.isopen_setcan)
{
Set_Form form2 = new Set_Form(updata_can_parameter);
form2.Show();
}
}
private void 设置ToolStripMenuItem1_Click(object sender, EventArgs e)
{
}
private void 数据分析ToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void 帮助ToolStripMenuItem_Click(object sender, EventArgs e)
{
}
[DllImport("winmm")]
static extern void timeBeginPeriod(int t);
[DllImport("winmm")]
static extern void timeEndPeriod(int t);
}
}