串口发送重发超时重发思路


       #region 串口发送
        //str 是发送的字符,retry_num 是重发次数timeout 是超时时间
        public bool UartSend(string str,UInt32 retry_num, UInt32 timeout)
        {
            try
            {
                myUart.IsReceive = false;//发送数据前重置接收标志
                for (int i = 0; i < retry_num; i++)
                {
                    myUart.UartSerialPort.Write(str);//串口发送数据
                    while (myUart.IsReceive == false)
                    {
                        Thread.Sleep(10);
                        count++;
                        if (count >= timeout / 10)
                            break;
                    }
                    if (count < timeout / 10) //如果在规定的时间内收到了应答,则直接返回,如果没有应答则继续重发
                        return true;

                    WriteLog(Brushes.Red, $"发送次数 + {i} \r\n");

                    count = 0;
                }

                return false;//如果发送次数超过3次,依然没有收到应答,则认为发送指令失败
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }
        #endregion

```c
  private void ModbusPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                Thread.Sleep(100);//延缓一会,用于防止硬件发送速率跟不上缓存数据导致的缓存数据杂乱
                int len = UartSerialPort.BytesToRead;
                Byte[] readBuffer = new Byte[len];
                UartSerialPort.Read(readBuffer, 0, len); //将数据读入缓存
                if(readBuffer[0] == 49 && readBuffer[1] == 50 && readBuffer[2] == 51)//如果收到了"123"字符,则认为收到应答
                    IsReceive = true;
            }
            catch (Exception exception)
            {
                //MessageBox.Show(exception.Message);
            }
        }


设置一个定时器,发送的时候,打开定时器,同时计算时间,定时3秒内,在定时器中断中改变状态。类似长按短按的功能。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的使用epoll实现多路485通讯,并在超时时自动重新发送的例子: ```c++ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/epoll.h> #include <termios.h> #define MAX_EVENTS 10 // epoll监听的最大事件数 #define BUF_SIZE 256 // 读写缓冲区大小 int main(int argc, char *argv[]) { int fd[MAX_EVENTS], i, n, ret, timeout; // fd数组用于存放文件描述符,i和n用于循环,ret用于保存读写返回值,timeout用于超时设置 char buf[MAX_EVENTS][BUF_SIZE]; // 缓冲区数组,每个串口对应一个缓冲区 struct termios oldtio[MAX_EVENTS], newtio[MAX_EVENTS]; // 用于保存串口设置 struct epoll_event ev, events[MAX_EVENTS]; // ev用于注册文件描述符,events用于存放激活的事件 int epfd; // epoll描述符 struct timeval tv; // 超时时间结构体 if (argc < 2) { printf("Usage: %s /dev/ttyS0 [/dev/ttyS1 ...]\n", argv[0]); exit(1); } // 打开串口设备并进行初始化 for (i = 1; i < argc; ++i) { fd[i - 1] = open(argv[i], O_RDWR | O_NOCTTY); if (fd[i - 1] < 0) { perror("open"); exit(1); } // 保存原始串口设置 tcgetattr(fd[i - 1], &oldtio[i - 1]); // 初始化新的串口设置 memset(&newtio[i - 1], 0, sizeof(newtio[i - 1])); newtio[i - 1].c_cflag = B9600 | CS8 | CLOCAL | CREAD; newtio[i - 1].c_iflag = IGNPAR; newtio[i - 1].c_oflag = 0; newtio[i - 1].c_lflag = 0; newtio[i - 1].c_cc[VTIME] = 0; newtio[i - 1].c_cc[VMIN] = 1; // 应用新的串口设置 tcflush(fd[i - 1], TCIFLUSH); tcsetattr(fd[i - 1], TCSANOW, &newtio[i - 1]); } // 创建epoll描述符 epfd = epoll_create(MAX_EVENTS); if (epfd < 0) { perror("epoll_create"); exit(1); } // 注册文件描述符 for (i = 0; i < argc - 1; ++i) { ev.events = EPOLLIN | EPOLLET; // 监听读事件和边缘触发模式 ev.data.fd = fd[i]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i], &ev) < 0) { perror("epoll_ctl"); exit(1); } } while (1) { // 设置超时时间为1秒 tv.tv_sec = 1; tv.tv_usec = 0; // 等待事件激活 n = epoll_wait(epfd, events, MAX_EVENTS, 1000); if (n < 0) { perror("epoll_wait"); break; } // 处理激活的事件 for (i = 0; i < n; ++i) { if (events[i].events & EPOLLIN) { // 读事件 ret = read(events[i].data.fd, buf[i], BUF_SIZE); if (ret < 0) { perror("read"); exit(1); } else if (ret == 0) { printf("Serial port %d closed\n", events[i].data.fd); exit(0); } else { printf("Received %d bytes from serial port %d: %s\n", ret, events[i].data.fd, buf[i]); } } if (events[i].events & EPOLLERR) { // 错误事件 perror("epoll_wait"); exit(1); } if (events[i].events & EPOLLOUT) { // 写事件 ret = write(events[i].data.fd, buf[i], strlen(buf[i])); if (ret < 0) { perror("write"); exit(1); } else { printf("Sent %d bytes to serial port %d: %s\n", ret, events[i].data.fd, buf[i]); } } } // 超时重新发送 for (i = 0; i < argc - 1; ++i) { if (strlen(buf[i]) > 0) { timeout = 0; while (1) { tv.tv_sec = 1; tv.tv_usec = 0; ret = select(fd[i] + 1, NULL, &ev, NULL, &tv); if (ret < 0) { perror("select"); exit(1); } else if (ret == 0) { printf("Timeout on serial port %d, resend\n", fd[i]); ret = write(fd[i], buf[i], strlen(buf[i])); if (ret < 0) { perror("write"); exit(1); } ++timeout; if (timeout >= 3) { printf("Resend failed on serial port %d, exit\n", fd[i]); exit(1); } } else { break; } } } } } // 恢复原始串口设置并关闭设备 for (i = 0; i < argc - 1; ++i) { tcsetattr(fd[i], TCSANOW, &oldtio[i]); close(fd[i]); } return 0; } ``` 该例子使用epoll监听多个串口设备的读事件和错误事件,并在超时时重新发送。每个串口对应一个缓冲区,可以分别存放收到的数据和待发送的数据。在每次epoll_wait返回后,先处理激活的事件,然后对于每个串口,判断是否有待发送的数据,如果有则进行超时重发的处理。超时时间设置为1秒,如果重发3次仍然失败,则退出程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值