public partial class MainWindow : Window
{
//空车数组
byte[] cCH_FreeTabB = {
0x0C,0x00,0x60,0x06,0x00,0x60,0x7F,0xF7,0xFF,0xE0,0x30,0xC0,0x19,0xC0,0xF0,0x30,
0x61,0xB0,0xE0,0x33,0xFE,0x3F,0xC0,0x30,0x06,0x00,0x30,0x06,0x07,0xFF,0x06,0x00,
0x30,0xFF,0xF0,0x30
};
public SerialPort serialPort = new SerialPort();
// 成员变量,用于判断是否收到应答
private volatile bool isAckReceived = false;
public MainWindow()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
InitializeComponent();
InitializeSerial();
//添加数据接收事件
serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPortDataReceived);
}
//初始化串口
private void InitializeSerial()
{
//实例化SerialPort对象
serialPort = new SerialPort();
//设置串口参数都设置默认值
serialPort.BaudRate = 9600;//波特率
serialPort.Parity = Parity.None;//校验位
serialPort.DataBits = 8;//数据位
serialPort.StopBits = StopBits.One;//停止位
string[] prots = SerialPort.GetPortNames();//获取当前机器的串口
cb_Prots.ItemsSource = prots;//下拉框获取串口数据
if (!serialPort.IsOpen)
{
cb_Prots.SelectedIndex = 0;//取默认第一个串口值
}
}
//打开串口
private void bt_SerialSwitch_Click(object sender, RoutedEventArgs e)
{
try
{
// 根据串口的当前打开状态来决定是打开还是关闭串口
if (!serialPort.IsOpen)
{
// 从ComboBox中获取选中的串口名称
string selectedPort = cb_Prots.SelectedItem as string;
if (string.IsNullOrEmpty(selectedPort))
{
MessageBox.Show("请先选择一个串口", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
serialPort.PortName = selectedPort;
serialPort.Open();//打开串口
MessageBox.Show("已打开");
bt_SerialSwitch.Content = "关闭串口";
tb_switchStatus.Text = "串口为打开状态";
e_status.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green);
}
else
{
serialPort.Close();//关闭串口
MessageBox.Show("已关闭");
bt_SerialSwitch.Content = "打开串口";
tb_switchStatus.Text = "串口为关闭状态";
e_status.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "异常", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// 发送数据包,并等待应答
private void SendDataPacketWithRetry(byte[] packet)
{
if (serialPort.IsOpen)
{
int retries = 0;
const int maxRetries = 3;
const int retryInterval = 1000; // 1秒重试间隔
const int responseTimeout = 5000; // 5秒应答超时
//创建计时器,用于应答超时
System.Timers.Timer responseTimer = new System.Timers.Timer(responseTimeout);
responseTimer.Elapsed += (sender, e) => isAckReceived = true; // 超时则视为断线,停止等待应答
responseTimer.AutoReset = false;//触发定时器
while (!isAckReceived && retries < maxRetries)
{
try
{
//收发的数据包
serialPort.Write(packet, 0, packet.Length);
//开始答应
responseTimer.Start();
//等待或者知道收到数据
System.Threading.Thread.Sleep(retryInterval);
if (isAckReceived)
{
responseTimer.Stop();
break;//收到答应退出循环
}
retries++;
}
catch (Exception ex)
{
MessageBox.Show("发送失败: " + ex.Message);
return; // 发生异常,退出方法
}
}
if (!isAckReceived)
{
MessageBox.Show("连接失败或丢失。"); // 重试三次后还未收到应答,通知用户
}
responseTimer.Dispose(); // 清理计时器资源
}
else
{
MessageBox.Show("串口未打开!");
}
}
private void ResponseTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
throw new NotImplementedException();
}
//串口数据接收事件
private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
//定义缓冲区
byte[] buffer = new byte[serialPort.BytesToRead];
//读取数据到缓冲区
int byteRead = serialPort.Read(buffer, 0, buffer.Length);
// 在UI线程上执行,因为我们可能需要更新UI
Dispatcher.Invoke(() =>
{
serialPort.Write("");
//收到数据答应
if (IsAcknowledge(buffer))
{
isAckReceived = true;
}
else
{
}
});
}
//检查是否答应
private bool IsAcknowledge(byte[] data)
{
// 具体的ACK字节可能会根据你的通信协议而不同。
// 这里我们以ASCII字符的ACK(值为0x06)作为示例。
const byte AckByte = 0x06;
// 检查数据数组是否只包含一个字节,且该字节是ACK字节。
return data.Length == 1 && data[0] == AckByte;
}
//构建数据包,报文头-长度-命令字-校验-报文尾
private byte[] BuildDataPacket(byte commandByte, byte[] content)
{
List<byte> packet = new List<byte>();
//报文头
byte[] Header = new byte[] { 0x40, 0x40, 0x63 };
packet.AddRange(Header);
// 计算长度字段,长度为命令字到校验之前的字节数
ushort length = (ushort)(1 + content.Length); // 命令字1个字节 + 内容的长度
byte[] Length = BitConverter.GetBytes(length);
// 如果系统为大端序,需要调整为小端序
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(Length);
}
// 添加长度字段到报文
packet.AddRange(Length);
// 命令字
packet.Add(commandByte);
// 内容
packet.AddRange(content);
// 校验,计算从长度到内容的所有字节进行异或(XOR)计算得出
byte checksum = CalculateChecksum(packet.ToArray().Skip(3).ToArray()); // Skip Header
packet.Add(checksum);
// 报文尾
byte[] Footer = new byte[] { 0x0D, 0x0A };
packet.AddRange(Footer);
return packet.ToArray();
}
// 校验方法
private byte CalculateChecksum(byte[] data)
{
byte checksum = 0;
foreach (byte b in data)
{
checksum ^= b;
}
return checksum;
}
//发送命令的方法
private void SendCommand(byte[] dataPacket)
{
if (serialPort.IsOpen)
{
serialPort.Write(dataPacket, 0, dataPacket.Length);
MessageBox.Show("命令已发送");
}
else
{
MessageBox.Show("串口未打开!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
wpf串口通信控制led点阵屏空车牌。各位抽出空闲时间看看我的代码有无问题,怎么通过空车按钮byte数组发送数据到led屏上显示出来卡住了。刚接触上位机。指点指点!