openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144) - 验证

news2025/1/15 23:46:36

文章目录

    • openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144) - 验证
    • 概述
    • 笔记
    • 重复数字IO的问题
    • 想法
    • 手工实现
    • 程序实现
    • 确定要摘掉的数字重合线
    • 自动化测试的问题
    • 测试程序的场景
    • 测试程序的运行效果
    • 测试程序实现
    • 备注
    • END

openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144) - 验证

概述

飞达程序编写的笔记(openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144)实现)没写完, 博客编辑时, 卡的厉害, 在这个笔记中继续写.

主要是设备挂满飞达场景下的测试, 确实测试出一些问题, 并加以解决.

笔记

重复数字IO的问题

将飞达全部挂上, 测试时, 发现有的飞达通讯卡顿. 好多次才会偶尔通讯成功一次.
看串口调试日志, 发现中间步骤的回包不对.
因为我单独测试(设备上只挂一个飞达, 插入每个航插端子, 进行各种命令的测试)是好的, 通讯质量刚刚的.
开始以为是西门子二手飞达有问题, 但是单独测试又是好的.
后来发现是主控板STM32_NUCLEO-144板子上, 有一些数字IO是连在一起的. 导致飞达都挂上时, 通过一个数字IO通讯, 实际上是由多个飞达同时回包的, 导致回包数据被冲乱.
现在已经发现有2个数字IO是这样的.
官方图纸如果一个IO一个IO的看, 中间有跳线, 不容易看. 主要不是自己画的, 看起来太费劲.
在这里插入图片描述

想个办法, 将一个数字IO号码联通多个数字IO端子的情况排查出来. 重复的数字IO端子就留一个接上飞达.

想法

写个测试程序吧
硬件方面, 将飞达都取下来.

逻辑如下:

  • 先将所有数字IO设置为内部上拉, 这样读取时, 默认就是H
  • 再将一个数字IO设置为L, 去读剩下所有的数字IO, 如果哪个为L, 就说明这2个数字IO是在硬件电路上连在一起的.
  • 将所有数字IO都过一遍, 就知道所有重复数字IO.
  • 然后在重复的数字IO上, 只挂一个飞达, 就可以解决这个问题.

手工实现

如果想确认一个飞达确实只有一个数字IO来控制, 是非常麻烦的, 非人力所能为.
用手工找出2对.

测试前, 先将飞达都挂上, 给第一个飞达发命令, 必须有快速流畅的回答.连续实验10次. 如果发现回包时有时无, 而且看到串口调试日志上有回包msglen长度不对的提示, 那就有可能是多个飞达被主板连在一起, 一个数字IO可以控制多个飞达.
然后将该飞达摘掉.

再给该飞达的数字IO发同样的命令, 如果有回答, 那就说明这个数字IO上有多余一把的飞达.
摘掉剩下的一把飞达, 再发包给同样的数字IO, 看有没有回包, 如果没有回包了, 那么最后摘掉的那个飞达所在的数字IO, 就在主板上和当前测试的这个数字IO连在一起了.

如果找到了疑似的重合的数字IO, 再将最后拔掉的飞达插上, 如果有回包了, 那就找到了.

这好麻烦, 如果是2个以上的数字IO重合了, 那可咋整?
必须写测试程序来干这事啊.

程序实现

花了1个小时, 写好了测试程序. 跑了一下, 花了3秒钟.
居然找到5对数字IO重合.
我开始手工找到的那2对数字IO重合的线, 就在程序找出的这5对线之中.
还好写程序找到了, 否则存在数字IO重合问题, 就会影响通讯质量. 一旦通讯失败, openpnp任务就停了.

// @file FindSameDigtalIO
// @note run result below
/*
>> FindSameDigtalIO
------------------------------------------------------------
digtial IO io_sn below:
     0      1      2      3      4      5      6      7 
     8      9     10     11     12     13     14     15 
    16     17     18     19     20     21     22     23 
    24     25     26     27     28     29     30     31 
    32     33     34     35     36     37     38     39 
    40     41     42     43     44     45     46     47 
    48     49     50     51     52     53     54     55 
    56     57     58     59     60     61     62     63 
    64     65     66     67     68     69     70     71 
    72    192    193    194    195    196    197    198 
   199    200 
------------------------------------------------------------
find_same_digtial_io
D22 = D11 = 0
D56 = D31 = 0
D59 = D38 = 0
D71 = D6 = 0
D72 = D27 = 0
err - find connect pins = 5
END, dead loop

*/

#define ENABLE_UART_DEBUG_PRINT
#define UART_LOG_LEVEL_INFO 0
#define LINE_60 "------------------------------------------------------------"

int UartDebugPrintf(uint8_t log_level, const char *format, ...);

void setup() {
  //start serial connection
  Serial.begin(115200);
  //configure pin 2 as an input and enable the internal pull-up resistor
  // pinMode(2, INPUT_PULLUP);
  // pinMode(13, OUTPUT);

  UartDebugPrintf(UART_LOG_LEVEL_INFO, ">> FindSameDigtalIO\r\n");
}

int get_digtial_io_cnt();
int get_digtial_io_sn(int iPosition);
void show_all_digtial_io_value();
void find_same_digtial_io();
int find_same_digtial_io(int ipos);

void loop() {
  // 数字IO范围 D0 ~ D72, A0 ~A8
  // 数字IO的值范围 0 ~ 72, 0xC0 ~ 0xC8


  // //
  // //read the pushbutton value into a variable
  // int sensorVal = digitalRead(2);
  // //print out the value of the pushbutton
  // Serial.println(sensorVal);

  // // Keep in mind the pull-up means the pushbutton's logic is inverted. It goes
  // // HIGH when it's open, and LOW when it's pressed. Turn on pin 13 when the
  // // button's pressed, and off when it's not:
  // if (sensorVal == HIGH) {
  //   digitalWrite(13, LOW);
  // } else {
  //   digitalWrite(13, HIGH);
  // }

  show_all_digtial_io_value();
  find_same_digtial_io();

  UartDebugPrintf(UART_LOG_LEVEL_INFO, "END, dead loop\r\n");
  do {
    delay(1);
  } while (true);
}

int UartDebugPrintf(uint8_t log_level, const char *format, ...) {
#ifndef ENABLE_UART_DEBUG_PRINT
  return -1;
#else
  int iRc = 0;
  char szBuf[0x100];
  va_list args;

  switch (log_level) {
    // @info 如果要屏蔽哪一级的日志, 就将日志级别放在case中

    // 屏蔽case到的日志级别
    // case UART_LOG_LEVEL_INFO:
    //   {
    //     return -1;
    //   }
    //   break;
    default:
      break;
  }


  if (NULL == format) {
    return -1;
  }

  memset(szBuf, 0, sizeof(szBuf));
  va_start(args, format);
  iRc = vsnprintf(szBuf, sizeof(szBuf) - 1, format, args);
  va_end(args);

  if (iRc <= 0) {
    return iRc;
  }

  return Serial.printf(szBuf);
#endif  // #ifdef FLAG_UART_DEBUG_PRINT
}

const int g_digtial_io_cnt = ((72 - 0 + 1) + (0xA8 - 0xA0 + 1));
int get_digtial_io_cnt() {
  // 数字IO范围 D0 ~ D72, A0 ~A8
  // 数字IO的值范围 0 ~ 72, 0xC0 ~ 0xC8

  return g_digtial_io_cnt;
}

int get_digtial_io_sn(int iPosition) {
  if ((iPosition < 0) || (iPosition >= g_digtial_io_cnt)) {
    return -1;  // error
  }

  if ((iPosition >= 0) && (iPosition <= 72)) {
    return iPosition;
  } else {
    return (0xC0 + (iPosition - 72 - 1));
  }
}

void show_all_digtial_io_value() {
  int i = 0;
  int io_sn = 0;
  int i_col = 0;

  UartDebugPrintf(UART_LOG_LEVEL_INFO, "%s\r\n", LINE_60);
  UartDebugPrintf(UART_LOG_LEVEL_INFO, "digtial IO io_sn below:\r\n");
  for (i = 0; i < get_digtial_io_cnt(); i++) {
    io_sn = get_digtial_io_sn(i);
    UartDebugPrintf(UART_LOG_LEVEL_INFO, "%6d ", io_sn);
    // if (i <= 72) {
    //   UartDebugPrintf(UART_LOG_LEVEL_INFO, "%6d ", value);
    // } else {
    //   UartDebugPrintf(UART_LOG_LEVEL_INFO, "%6.2X ", /*"0x",*/ value);
    // }

    if (8 == ++i_col) {
      i_col = 0;
      UartDebugPrintf(UART_LOG_LEVEL_INFO, "\r\n");
    }
  }

  UartDebugPrintf(UART_LOG_LEVEL_INFO, "\r\n%s\r\n", LINE_60);
}

void find_same_digtial_io() {
  int i = 0;
  int i_pins_connect_cnt = 0;

  UartDebugPrintf(UART_LOG_LEVEL_INFO, "find_same_digtial_io\r\n");
  for (i = 0; i < get_digtial_io_cnt(); i++) {
    i_pins_connect_cnt += find_same_digtial_io(i);
  }

  if (0 == i_pins_connect_cnt) {
    UartDebugPrintf(UART_LOG_LEVEL_INFO, "ok - not find connect pins\r\n");
  } else {
    UartDebugPrintf(UART_LOG_LEVEL_INFO, "err - find connect pins = %d\r\n", i_pins_connect_cnt);
  }
}

int find_same_digtial_io(int ipos) {
  int i = 0;
  int io_sn = 0;
  int io_sn_pos = 0;
  int value_readback = 0;
  int value_ipos = 0;
  int i_pins_connect_cnt = 0;

  // 将 ipos位置的引脚设置为输出
  // 将其他引脚设置为输入
  for (i = 0; i < get_digtial_io_cnt(); i++) {
    io_sn = get_digtial_io_sn(i);
    if (i == ipos) {
      // 设置为输出
      pinMode(io_sn, OUTPUT);
    } else {
      // 设置为输入, 内部上拉
      pinMode(io_sn, INPUT_PULLUP);
    }
  }

  // 将ipos对应引脚设置为L
  io_sn = get_digtial_io_sn(ipos);
  io_sn_pos = io_sn;
  digitalWrite(io_sn, LOW);

  delay(10);

  for (i = 0; i < get_digtial_io_cnt(); i++) {
    if (i == ipos) {
      continue;
    }

    io_sn = get_digtial_io_sn(i);
    value_readback = digitalRead(io_sn);
    if (LOW == value_readback) {
      UartDebugPrintf(UART_LOG_LEVEL_INFO, "D%d = D%d = %d\r\n", io_sn_pos, io_sn, value_readback);
      i_pins_connect_cnt++;
    }
  }

  return i_pins_connect_cnt;
}

确定要摘掉的数字重合线

find_same_digtial_io
D22 = D11 = 0
D56 = D31 = 0
D59 = D38 = 0
D71 = D6 = 0
D72 = D27 = 0
err - find connect pins = 5

我的飞达控制工程中, 有数字IO对应的航插端口号, 找到之后, 将物理飞达摘掉.

// D22 = D11 = 0
// FD_TX69/D22_CN7_13/数字IO号码 = 22 // 保留FD_TX69
SoftwareSerial softUartToFd_22(22, 22, true);

// D22 = D11 = 0
// FD_TX70/D11_CN7_14/数字IO号码 = 11 // 摘掉FD_TX70飞达
SoftwareSerial softUartToFd_11(11, 11, true);

// D56 = D31 = 0
// FD_TX20/D56_CN9_14/数字IO号码 = 56 // 保留飞达 FD_TX20
SoftwareSerial softUartToFd_56(56, 56, true);

// D56 = D31 = 0
// FD_TX42/D31_CN10_25/数字IO号码 = 31 // 摘掉飞达 FD_TX42
SoftwareSerial softUartToFd_31(31, 31, true);


// D59 = D38 = 0
// FD_TX25/D59_CN9_20/数字IO号码 = 59 // 保留飞达FD_TX25
SoftwareSerial softUartToFd_59(59, 59, true);

// D59 = D38 = 0
// FD_TX41/D38_CN10_28/数字IO号码 = 38 // 摘掉飞达 FD_TX41
SoftwareSerial softUartToFd_38(38, 38, true);
// D71 = D6 = 0
// FD_TX24/D69_CN9_19/数字IO号码 = 69 // 保留FD_TX24
SoftwareSerial softUartToFd_69(69, 69, true);

D71在原理图上没用, 所以和D6不冲突.
在这里插入图片描述

// D72 = D27 = 0
// FD_TX50/D27_CN10_15/数字IO号码 = 27 // 保留FD_TX50
SoftwareSerial softUartToFd_27(27, 27, true);

D72在原理图中没用, 所以和D27不冲突.

综合以上, 需要摘到的飞达为3把:
// FD_TX70/D11_CN7_14/数字IO号码 = 11 // 摘掉FD_TX70飞达
// FD_TX42/D31_CN10_25/数字IO号码 = 31 // 摘掉飞达 FD_TX42
// FD_TX41/D38_CN10_28/数字IO号码 = 38 // 摘掉飞达 FD_TX41

在代码中已经记录了飞达的物理位置(和航插到飞达控制板插座的连接有关)

    // FD_TX70/D11_CN7_14/数字IO号码 = 11 // 面对设备背面, 从左往右数, 第17个航插  // 摘掉FD_TX70飞达
    FEEDER_UART_INFO(11, &softUartToFd_11),  // 正对设备背面, 从右往左第10个飞达 M615 N84\r\n M615 N85\r\n // 不好使

    // FD_TX42/D31_CN10_25/数字IO号码 = 31 // 摘掉飞达 FD_TX42
    FEEDER_UART_INFO(31, &softUartToFd_31),  // M615 N68\r\n M615N69 \r\n // 面对设备背面, 从左往右数, 第9个航插

    // FD_TX41/D38_CN10_28/数字IO号码 = 38 // 摘掉飞达 FD_TX41
    FEEDER_UART_INFO(38, &softUartToFd_38),  // M615 N70\r\n M615N71 \r\n // 面对设备背面, 从左往右数, 第10个航插

如果不是工程实现中记录的仔细, 要摘掉哪个飞达还真有点懵.
在这里插入图片描述

明天再测试一遍, 看看在物理飞达正常的情况下, 飞达通讯上是否非常流畅?
今天测试了一下, 除了个别飞达本身有问题, 换上好的飞达后, 通讯没问题, 再也没出现某个飞达因为回包乱码导致的通讯失败.

自动化测试的问题

在openpnp中, 最好某个固定位置的飞达有固定的飞达ID, 如果有问题, 或者飞达通讯失败, 可以马上发现.
这就需要将固定位置的飞达都设置为预想的ID.
但是, 西门子二手飞达难免发生问题, 如果再换一把飞达, 或者将飞达交换了位置, 此时, 还需要固定位置的飞达有固定的ID. 如果手工设置, 就太勉强了.

而且还想在openpnp运行前, 知道哪个飞达有通讯问题. 这也不是手工能便利做到的.
还是老套路, 写个测试程序.
测试程序的功能如下:

  • 遍历设备上的每个飞达航插位, 进行如下操作.
  • 如果飞达的ID不是预想的ID, 就设置为预想的ID
  • 如果飞达的状态是错误的, 就要报出来, 并统计总共有多少个错误.

正好以前在CSDN上传过串口测试程序, 将工程下载到本地, 将逻辑换为飞达控制板的协议就ok.
写了4个小时, 搞定. 运行一分钟不到, 就可以将设备上挂满飞达的场景全部测试, 设置完成.
自己会写2句程序, 管用啊.

测试程序的场景

设备挂满飞达. 除了数字IO重合的3把飞达, 总共挂了49把2x8mm的西门子飞达, 总共98个8mm料位.
挂满飞达就是为了测试满载状态下有没有可能会出问题? e.g. 电流不够, 通讯不畅.
结果很好, 没啥问题.
现在飞达都换成了测试通过的正常飞达, 开机上电后, 飞达都正常上了电, 没有飞达会出现错误指示灯:)
在这里插入图片描述

测试程序的运行效果

在这里插入图片描述
运行后, 如果有错误就报出, 如果没看到错误,就是飞达运行正常.
程序参数(串口号码, 波特率)可以由程序命令行参数给出, 也可以运行程序后, 根据程序的参数提示给出.


D:\my_dev\my_local_git_prj\hardware\LS_openpnp_hardware\src\my_SchultzController\case\test_all_feeder\src>test_all_feeder COM22 115200
>> test all feeder

argv[1] = COM22
argv[2] = 115200
-------------------------------------------------------------------------------------------------------------------------------------
|port_sn   |port_name |port_desc                                                   |port_hd_id                                      |
-------------------------------------------------------------------------------------------------------------------------------------
|0         |COM22     |STMicroelectronics STLink Virtual COM Port (COM22)          |USB\VID_0483&PID_374E&REV_0100&MI_02            |
-------------------------------------------------------------------------------------------------------------------------------------
|1         |COM8      |USB-SERIAL CH340 (COM8)                                     |USB\VID_1A86&PID_7523&REV_0264                  |
-------------------------------------------------------------------------------------------------------------------------------------
THE com port name is "COM22"

you select com timout(ms) is 100

you select data bits is 8

you select com parity type(sn) 0
you select com parity type is parity_none

you select com stopbits(sn) 1
you select com stop bits is 1bits

you select com flowcontrol(sn) 0
you select com flowcontrol is none

-------------------------------------------------------------------------------------------------------------------------------------
COM port info:
-------------------------------------------------------------------------------------------------------------------------------------
com port = COM22
baudrate = 115200
timout = 100(ms)
data bits = 8
parity type = parity_none
stop bits = 1bits
flowcontrol = none
-------------------------------------------------------------------------------------------------------------------------------------
COM port open ok!
process all feeder
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[1L] : N0
FeederNoBase1[1R] : N1
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[2L] : N2
FeederNoBase1[2R] : N3
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[3L] : N4
FeederNoBase1[3R] : N5
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[4L] : N6
FeederNoBase1[4R] : N7
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[5L] : N8
FeederNoBase1[5R] : N9
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[6L] : N10
FeederNoBase1[6R] : N11
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[7L] : N12
FeederNoBase1[7R] : N13
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[8L] : N14
FeederNoBase1[8R] : N15
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[9L] : N16
FeederNoBase1[9R] : N17
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[10L] : N18
FeederNoBase1[10R] : N19
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[11L] : N20
FeederNoBase1[11R] : N21
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[12L] : N22
FeederNoBase1[12R] : N23
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[13L] : N24
FeederNoBase1[13R] : N25
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[14L] : N26
FeederNoBase1[14R] : N27
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[15L] : N28
FeederNoBase1[15R] : N29
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[16L] : N30
FeederNoBase1[16R] : N31
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[17L] : N32
FeederNoBase1[17R] : N33
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[18L] : N34
FeederNoBase1[18R] : N35
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[19L] : N36
FeederNoBase1[19R] : N37
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[20L] : N38
FeederNoBase1[20R] : N39
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[21L] : N40
FeederNoBase1[21R] : N41
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[22L] : N42
FeederNoBase1[22R] : N43
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[23L] : N44
FeederNoBase1[23R] : N45
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[24L] : N46
FeederNoBase1[24R] : N47
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[25L] : N48
FeederNoBase1[25R] : N49
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[26L] : N50
FeederNoBase1[26R] : N51
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[27L] : N52
FeederNoBase1[27R] : N53
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[28L] : N54
FeederNoBase1[28R] : N55
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[29L] : N56
FeederNoBase1[29R] : N57
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[30L] : N58
FeederNoBase1[30R] : N59
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[31L] : N60
FeederNoBase1[31R] : N61
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[32L] : N62
FeederNoBase1[32R] : N63
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[33L] : N64
FeederNoBase1[33R] : N65
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[34L] : N66
FeederNoBase1[34R] : N67
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1 35 not exist, skip
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1 36 not exist, skip
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[37L] : N72
FeederNoBase1[37R] : N73
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[38L] : N74
FeederNoBase1[38R] : N75
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[39L] : N76
FeederNoBase1[39R] : N77
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[40L] : N78
FeederNoBase1[40R] : N79
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[41L] : N80
FeederNoBase1[41R] : N81
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[42L] : N82
FeederNoBase1[42R] : N83
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1 43 not exist, skip
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[44L] : N86
FeederNoBase1[44R] : N87
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[45L] : N88
FeederNoBase1[45R] : N89
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[46L] : N90
FeederNoBase1[46R] : N91
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[47L] : N92
FeederNoBase1[47R] : N93
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[48L] : N94
FeederNoBase1[48R] : N95
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[49L] : N96
FeederNoBase1[49R] : N97
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[50L] : N98
FeederNoBase1[50R] : N99
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[51L] : N100
FeederNoBase1[51R] : N101
-------------------------------------------------------------------------------------------------------------------------------------
FeederNoBase1[52L] : N102
FeederNoBase1[52R] : N103
-------------------------------------------------------------------------------------------------------------------------------------
ok : feeder process all ok
请按任意键继续. . .

测试程序实现

vs2019 + vc++ + console
都写在一个cpp中了, 不到800行, 写了4个小时, 边写边连着设备调试.

// @file test_all_feeder.cpp
// @brief 测试设备上的所有飞达
// @note 
// prj base https://lostspeed.blog.csdn.net/article/details/109882721 <<串口自动应答测试程序>>
// base prj download from : https://download.csdn.net/download/LostSpeed/13132083 <<ls_serial_port_test_tool_v1.zip>>

#include <windows.h>

#include <string>
#include <iostream>
#include <cstdio>

using namespace std;

#include "serial/serial.h"
#pragma comment(lib, "Setupapi.lib")

//#if (_MSC_VER >= 1915)
//#define no_init_all deprecated
//#endif

#define LINE_10 "----------"
#define LINE_3 "---"
#define LINE120 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_10 LINE_3
#define LINE_IND LINE120
#define LINE_TIP_FMT		"|%-10s|%-10s|%-60s|%-48s|\n"
#define LINE_CONTENT_FMT	"|%-10d|%-10s|%-60s|%-48s|\n"

#define LINE_DATA_BITS_TIP_FMT		"|%-10s %-10s %-60s %-48s|\n"
#define LINE_DATA_BITS_CONTENT_FMT	"|%-10d %-10s %-60s %-48s|\n"

#define LINE_PARITY_TIP_FMT		"|%-10s|%-10s %-60s %-48s|\n"
#define LINE_PARITY_CONTENT_FMT	"|%-10d|%-10s %-60s %-48s|\n"

#define LINE_STOPBITS_TIP_FMT		"|%-10s|%-10s %-60s %-48s|\n"
#define LINE_STOPBITS_CONTENT_FMT	"|%-10d|%-10s %-60s %-48s|\n"

#define LINE_FLOWCONTROL_TIP_FMT		"|%-10s|%-10s %-60s %-48s|\n"
#define LINE_FLOWCONTROL_CONTENT_FMT	"|%-10d|%-10s %-60s %-48s|\n"

const char* get_parity_type(serial::parity_t type)
{
	const char* psz_type = "unknown parity type";

	switch (type) {
	case serial::parity_t::parity_none:
		psz_type = "parity_none";
		break;

	case serial::parity_t::parity_odd:
		psz_type = "parity_odd";
		break;

	case serial::parity_t::parity_even:
		psz_type = "parity_even";
		break;

	case serial::parity_t::parity_mark:
		psz_type = "parity_mark";
		break;

	case serial::parity_t::parity_space:
		psz_type = "parity_space";
		break;

	default:
		break;
	}

	return psz_type;
}

const char* get_stopbits_type(serial::stopbits_t type)
{
	const char* psz_type = "unknown stopbits type";

	switch (type) {
	case serial::stopbits_t::stopbits_one:
		psz_type = "1bits";
		break;

	case serial::stopbits_t::stopbits_one_point_five:
		psz_type = "1.5bits";
		break;

	case serial::stopbits_t::stopbits_two:
		psz_type = "2bits";
		break;

	default:
		break;
	}

	return psz_type;
}

const char* get_flowcontroltype(serial::flowcontrol_t type)
{
	const char* psz_type = "unknown flowcontrol type";

	switch (type) {
	case serial::flowcontrol_t::flowcontrol_hardware:
		psz_type = "hardware";
		break;

	case serial::flowcontrol_t::flowcontrol_none:
		psz_type = "none";
		break;

	case serial::flowcontrol_t::flowcontrol_software:
		psz_type = "software";
		break;

	default:
		break;
	}

	return psz_type;
}

void proc_uart(serial::Serial& my_serial);

int main(int argc, char** argv)
{
	int i = 0;
	int i_tmp = 0;
	bool b_cmd_line_param = false;
	char szBufCmdLine_UartName[0x100];
	int BufCmdLIne_UartBps = 0;

	uint8_t buf_rx[4096] = {'\0'};
	size_t buf_rx_len = 0;
	size_t buf_rx_total_len = 0;

	uint8_t buf_tx[4096] = { '\0' };
	size_t buf_tx_len = 0;

	int dev_port = -1;
	uint32_t dev_baurd = 0;
	uint32_t dev_timeout = 0;
	serial::bytesize_t dev_data_bits = serial::bytesize_t::eightbits;
	serial::parity_t dev_parity_type = serial::parity_t::parity_none;
	serial::stopbits_t dev_stopbits = serial::stopbits_t::stopbits_one;
	serial::flowcontrol_t dev_flowcontrol_type = serial::flowcontrol_t::flowcontrol_none;

	ShowWindow(GetConsoleWindow(), SW_MAXIMIZE);	
	
	do {
		printf(">> test all feeder\n\n");

		if (3 == argc)
		{
			// 用户给了串口号和bps
			printf("argv[%d] = %s\n", 1, argv[1]);
			strcpy(szBufCmdLine_UartName, argv[1]);

			printf("argv[%d] = %s\n", 2, argv[2]);
			BufCmdLIne_UartBps = atoi(argv[2]);
			b_cmd_line_param = true;
		}

		vector<serial::PortInfo> devices_found = serial::list_ports();
		vector<serial::PortInfo>::iterator iter;

		// 选择串口
		// 顶住左边开始, 每30个字符为一个显示字段
		printf("%s\n", LINE_IND);
		printf(LINE_TIP_FMT, "port_sn", "port_name", "port_desc", "port_hd_id");
		printf("%s\n", LINE_IND);

		dev_port = 0;
		iter = devices_found.begin();
		while (iter != devices_found.end())
		{
			serial::PortInfo device = *iter++;

			printf(LINE_CONTENT_FMT, dev_port++, device.port.c_str(), device.description.c_str(), device.hardware_id.c_str());
			printf("%s\n", LINE_IND);
		}

		if (!b_cmd_line_param)
		{
			printf("please select com port(port_sn):");
			scanf_s("%2d", &dev_port);
			printf("you select com port(port_sn) is %d\n", dev_port);
		}
		else {
			// szBufCmdLine_UartName
			// BufCmdLIne_UartBps
			dev_port = -1;
			iter = devices_found.begin();
			while (iter != devices_found.end())
			{
				serial::PortInfo device = *iter++;
				dev_port++;
				if (0 == strcmp(szBufCmdLine_UartName, device.port.c_str()))
				{
					break; // find it
				}
			}
		}

		if ((dev_port < 0) || (dev_port >= devices_found.size())) {
			printf("com port select error!\n");
			break;
		}


		printf("THE com port name is \"%s\"\n\n", devices_found[dev_port].port.c_str());

		// 选择波特率
		if (!b_cmd_line_param)
		{
			printf("please select com baudrate:");
			scanf_s("%u", &dev_baurd);
			printf("you select com baudrate is %u\n\n", dev_baurd);
		}
		else {
			dev_baurd = BufCmdLIne_UartBps;
		}

		// 选择超时
		// printf("please select com timout(ms):");
		// scanf_s("%u", &dev_timeout);
		dev_timeout = 100;
		printf("you select com timout(ms) is %u\n\n", dev_timeout);

		// 选择数据位
		//printf("%s\n", LINE_IND);
		//printf(LINE_DATA_BITS_TIP_FMT, "bits", "", "", "");
		//printf("%s\n", LINE_IND);

		//for (i = (int)serial::bytesize_t::fivebits; i <= (int)serial::bytesize_t::eightbits; i++) {
		//	printf(LINE_DATA_BITS_CONTENT_FMT, i, "", "", "");
		//	printf("%s\n", LINE_IND);
		//}

		//printf("please select com data bits:");
		// scanf_s("%u", &i_tmp);
		i_tmp = 8;
		printf("you select data bits is %d\n\n", i_tmp);

		if ((i_tmp < (int)serial::bytesize_t::fivebits)
			|| (i_tmp > (int)serial::bytesize_t::eightbits)) {
			printf("error\n");
			break;
		}

		dev_data_bits = (serial::bytesize_t)i_tmp;

		// 选择校验位
		//printf("%s\n", LINE_IND);
		//printf(LINE_PARITY_TIP_FMT, "sn", "type", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_PARITY_CONTENT_FMT, (int)serial::parity_t::parity_none, "none", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_PARITY_CONTENT_FMT, (int)serial::parity_t::parity_odd, "odd", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_PARITY_CONTENT_FMT, (int)serial::parity_t::parity_even, "even", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_PARITY_CONTENT_FMT, (int)serial::parity_t::parity_mark, "mark", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_PARITY_CONTENT_FMT, (int)serial::parity_t::parity_space, "space", "", "");
		//printf("%s\n", LINE_IND);

		//printf("please select com parity type(sn):");
		// scanf_s("%u", &i_tmp);
		i_tmp = 0;
		printf("you select com parity type(sn) %d\n", i_tmp);

		if ((i_tmp < (int)serial::parity_t::parity_none)
			|| (i_tmp > (int)serial::parity_t::parity_space)) {
			printf("error\n");
			break;
		}

		dev_parity_type = (serial::parity_t)i_tmp;

		printf("you select com parity type is %s\n\n",
			get_parity_type(dev_parity_type));


		// 选择停止位
		//printf("%s\n", LINE_IND);
		//printf(LINE_STOPBITS_TIP_FMT, "sn", "bits", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_STOPBITS_CONTENT_FMT, (int)serial::stopbits_t::stopbits_one, "1 bits", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_STOPBITS_CONTENT_FMT, (int)serial::stopbits_t::stopbits_one_point_five, "1.5 bits", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_STOPBITS_CONTENT_FMT, (int)serial::stopbits_t::stopbits_two, "2 bits", "", "");
		//printf("%s\n", LINE_IND);

		// printf("please select com stopbits(sn):");
		// scanf_s("%u", &i_tmp);
		i_tmp = 1;
		printf("you select com stopbits(sn) %d\n", i_tmp);

		if ((i_tmp < (int)serial::stopbits_t::stopbits_one)
			|| (i_tmp > (int)serial::stopbits_t::stopbits_one_point_five)) {
			printf("error\n");
			break;
		}

		dev_stopbits = (serial::stopbits_t)i_tmp;

		printf("you select com stop bits is %s\n\n",
			get_stopbits_type(dev_stopbits));

		// 选择流控
		//printf("%s\n", LINE_IND);
		//printf(LINE_FLOWCONTROL_TIP_FMT, "sn", "type", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_FLOWCONTROL_CONTENT_FMT, (int)serial::flowcontrol_t::flowcontrol_none, "none", "", "");
		//printf("%s\n", LINE_IND);

		//printf(LINE_FLOWCONTROL_CONTENT_FMT, (int)serial::flowcontrol_t::flowcontrol_hardware, "hardware", "", "");
		//printf("%s\n", LINE_IND);		
		//
		//printf(LINE_FLOWCONTROL_CONTENT_FMT, (int)serial::flowcontrol_t::flowcontrol_software, "software", "", "");
		//printf("%s\n", LINE_IND);

		//printf("please select com flowcontrol(sn):");
		// scanf_s("%u", &i_tmp);
		i_tmp = 0;
		printf("you select com flowcontrol(sn) %d\n", i_tmp);

		if ((i_tmp < (int)serial::flowcontrol_t::flowcontrol_none)
			|| (i_tmp > (int)serial::flowcontrol_t::flowcontrol_hardware)) {
			printf("error\n");
			break;
		}

		dev_flowcontrol_type = (serial::flowcontrol_t)i_tmp;

		printf("you select com flowcontrol is %s\n\n",
			get_flowcontroltype(dev_flowcontrol_type));

		// 再整体打印一次用户的串口信息选择
		printf("%s\n", LINE_IND);
		printf("COM port info:\n");
		printf("%s\n", LINE_IND);
		printf("com port = %s\n", devices_found[dev_port].port.c_str());
		printf("baudrate = %u\n", dev_baurd);
		printf("timout = %u(ms)\n", dev_timeout);
		printf("data bits = %d\n", dev_data_bits);
		printf("parity type = %s\n", get_parity_type(dev_parity_type));
		printf("stop bits = %s\n", get_stopbits_type(dev_stopbits));
		printf("flowcontrol = %s\n", get_flowcontroltype(dev_flowcontrol_type));
		printf("%s\n", LINE_IND);

		serial::Serial my_serial(
			devices_found[dev_port].port.c_str(),
			dev_baurd,
			serial::Timeout::simpleTimeout(dev_timeout),
			dev_data_bits,
			dev_parity_type,
			dev_stopbits,
			dev_flowcontrol_type
		);

		if (my_serial.isOpen()) {
			printf("COM port open ok!\n");
		}
		else {
			printf("COM port open failed...\n");
			break;
		}

		/*
		  void setTimeout (
			  uint32_t inter_byte_timeout,
			  uint32_t read_timeout_constant,
			  uint32_t read_timeout_multiplier,
			  uint32_t write_timeout_constant,
			  uint32_t write_timeout_multiplier)*/
		my_serial.setTimeout(
			serial::Timeout::max(),
			dev_timeout /*1000*/ /*serial::Timeout::max()*/, // 这里是读超时,如果是发送完等接收,这里就设置正常ms超时值; 如果是被动等别人问,就设置成serial::Timeout::max()
			0,
			0,
			0);

		proc_uart(my_serial);

	} while (false);

	system("pause");
	return EXIT_SUCCESS;
}

void M999(serial::Serial& my_serial)
{
	size_t LenRx = 0;

	char szBufSend[1024];
	char szBufRecv[1024];

	do {
		memset(szBufSend, 0, sizeof(szBufSend));
		memset(szBufRecv, 0, sizeof(szBufRecv));

		// send M999
		sprintf(szBufSend, "M999\r\n");
		my_serial.write((uint8_t*)szBufSend, strlen(szBufSend));

		memset(szBufRecv, 0, sizeof(szBufRecv));
		LenRx = my_serial.read((uint8_t*)szBufRecv, sizeof(szBufRecv));
		if (LenRx <= 0)
		{
			break;
		}

		/*
		M115 MCODE_DRIVER_INFO
		M600 MCODE_PRE_PICK
		M601 MCODE_ADVANCE e.g. M601N0X1 is ok, M601N0X0 is err
		M602 MCODE_FEEDER_STATUS
		M603 MCODE_GET_FEED_COUNT
		M623 MCODE_CLEAR_FEED_COUNT
		M604 MCODE_GET_ERR42_COUNT
		M605 MCODE_GET_ERR43_COUNT
		M606 MCODE_GET_ERR44_COUNT
		M607 MCODE_GET_RESET_COUNT
		M608 MCODE_GET_PITCH
		M628 MCODE_TOGGLE_PITCH
		M610 MCODE_GET_FEEDER_ID
		M640 MCODE_SET_FEEDER_ID
		M630 MCODE_READ_EEPROM
		M615 MCODE_GET_FIRMWARE_INFO
		M650 MCODE_START_SELF_TEST
		M651 MCODE_STOP_SELF_TEST
		M998 MCODE_CLEAR_RX_BUF
		M999 MCODE_CMD_HELP
		*/

		printf("%s\n", szBufRecv);
	} while (false);
}

bool proc_uart_Nxx(serial::Serial& my_serial, int FeederNoBase1, int Nxx);

void proc_uart(serial::Serial& my_serial)
{
	int i = 0;
	int j = 0;
	int FeederNoBase1 = 0;
	int Nxx = 0;
	int i_err_cnt = 0;

	size_t LenRx = 0;

	char szBufNxx[0x100];


	// basic usage
	// buf_rx_len = my_serial.read(buf_rx + buf_rx_total_len, sizeof(char));
	// buf_tx_len = my_serial.write(buf_tx, 7); // send respond

	// M999(my_serial);

	/*
	    // FD_TX70/D11_CN7_14/数字IO号码 = 11 // 面对设备背面, 从左往右数, 第17个航插  // 摘掉FD_TX70飞达
    FEEDER_UART_INFO(11, &softUartToFd_11),  // 正对设备背面, 从右往左第10个飞达 M615 N84\r\n M615 N85\r\n // 不好使
	No.43 Feeder
	N84
	N85

    // FD_TX42/D31_CN10_25/数字IO号码 = 31 // 摘掉飞达 FD_TX42
    FEEDER_UART_INFO(31, &softUartToFd_31),  // M615 N68\r\n M615N69 \r\n // 面对设备背面, 从左往右数, 第9个航插
	No.35 Feeder
	N68
	N69

    // FD_TX41/D38_CN10_28/数字IO号码 = 38 // 摘掉飞达 FD_TX41
    FEEDER_UART_INFO(38, &softUartToFd_38),  // M615 N70\r\n M615N71 \r\n // 面对设备背面, 从左往右数, 第10个航插
	No.36 Feeder
	N70
	N71
	*/

	// 设备满配物理飞达数量52(正面26, 背面26), 因为数字IO重合, 导致一个数字IO会给多个飞达发包, 所以去掉了3把.
	printf("process all feeder\n");

	for (i = 0; i < 52; i++)
	{
		printf("%s\n", LINE_IND);

		FeederNoBase1 = i + 1;
		if ((43 == FeederNoBase1) || (35 == FeederNoBase1) || (36 == FeederNoBase1))
		{
			// 跳过因为数字IO重合而摘掉的物理飞达
			printf("FeederNoBase1 %d not exist, skip\n", FeederNoBase1);
			continue;
		}

		for (j = 0; j < 2; j++)
		{
			Nxx = (i * 2 + j);
			sprintf(szBufNxx, "FeederNoBase1[%d%s] : N%d", FeederNoBase1, ((0 == (Nxx % 2)) ? "L" : "R"), Nxx);
			printf("%s\n", szBufNxx);
			if (!proc_uart_Nxx(my_serial, FeederNoBase1, Nxx))
			{
				i_err_cnt++;
			}
		}
	}

	printf("%s\n", LINE_IND);

	if (0 == i_err_cnt)
	{
		printf("ok : feeder process all ok\n");
	}
	else {
		printf("error : 1 feeder process error counter = %d\n", i_err_cnt);
	}
	
}

bool is_err_recv(const char* psz_msg)
{
	// ok ID: 1001L
	// ok ID set

	bool b_err = true;
	const char* psz = NULL;

	do {
		if (NULL == psz_msg)
		{
			break;
		}

		psz = strstr(psz_msg, "err");
		if (psz == psz_msg)
		{
			break;
		}

		b_err = false;
	} while (false);
	

	return b_err;
}

bool is_dig_char(char c)
{
	if ((c >= '0') && (c <= '9'))
	{
		return true;
	}

	return false;
}

bool get_id_from_recv(const char* psz_msg, int& id, bool& isLeft)
{
	// ok ID: 1001L
	bool b_ok = false;
	const char* psz = NULL;

	do {
		if (NULL == psz_msg)
		{
			break;
		}

		psz = strstr(psz_msg, "ok ID: ");
		if (NULL == psz)
		{
			break;
		}

		psz_msg = psz;
		psz_msg += strlen("ok ID: ");
		id = atoi(psz_msg);
		do {
			if (is_dig_char(psz_msg[0]))
			{
				psz_msg++;
				continue;
			}

			break;
		} while (true);

		if (('L' != psz_msg[0]) && ('R' != psz_msg[0]))
		{
			break;
		}

		isLeft = ('L' == psz_msg[0]);
	
		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_read_status(serial::Serial& my_serial, int Nxx, char* psz_recv, int len_recv)
{
	// M602 MCODE_FEEDER_STATUS
	char szBufSend[1024];
	bool b_ok = false;
	int buf_rx_len = 0;

	do {
		sprintf(szBufSend, "M602 N%d\r\n", Nxx);
		my_serial.write((uint8_t*)szBufSend, strlen(szBufSend));

		memset(psz_recv, 0, len_recv);
		buf_rx_len = (int)my_serial.read((uint8_t*)psz_recv, len_recv);
		if (buf_rx_len < 0)
		{
			printf("error : 2 can't recv any form Nxx[%d]\n", Nxx);
			break;
		}

		if (is_err_recv(psz_recv))
		{
			printf("error : 3 [%s]\n", psz_recv);
			break;
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_read_ID(serial::Serial& my_serial, int Nxx, int& id, bool& isLeft)
{
	// M610 MCODE_GET_FEEDER_ID

	char szBufSend[1024];
	char szBufRecv[1024];
	int buf_rx_len = 0;
	bool b_ok = false;

	do {
		sprintf(szBufSend, "M610 N%d\r\n", Nxx);
		my_serial.write((uint8_t*)szBufSend, strlen(szBufSend));

		memset(szBufRecv, 0, sizeof(szBufRecv));
		buf_rx_len = (int)my_serial.read((uint8_t*)szBufRecv, sizeof(szBufRecv));
		if (buf_rx_len < 0)
		{
			printf("error : 5 can't recv any form Nxx[%d]\n", Nxx);
			break;
		}

		if (is_err_recv(szBufRecv))
		{
			printf("error : 6 recv content have error, szBufRecv[] = [%s]\n", szBufRecv);
			break;
		}

		// printf("%s\n", szBufRecv);
		// ok ID: 1001L

		if (!get_id_from_recv(szBufRecv, id, isLeft))
		{
			printf("error : 7 recv parse error, szBufRecv[] = [%s]\n", szBufRecv);
			break;
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_set_ID(serial::Serial& my_serial, int FeederNoBase1, int Nxx)
{
	// M640 MCODE_SET_FEEDER_ID

	char szBufSend[1024];
	char szBufRecv[1024];
	int buf_rx_len = 0;
	int id = 0;
	bool isLeft = 0;
	bool b_ok = false;

	do {
		sprintf(szBufSend, "M640 N%dX%d\r\n", Nxx, FeederNoBase1);
		my_serial.write((uint8_t*)szBufSend, strlen(szBufSend));

		memset(szBufRecv, 0, sizeof(szBufRecv));
		buf_rx_len = (int)my_serial.read((uint8_t*)szBufRecv, sizeof(szBufRecv));
		if (buf_rx_len < 0)
		{
			printf("error : 8 can't recv any form FeederNoBase1[%d]/Nxx[%d]\n", FeederNoBase1, Nxx);
			break;
		}

		// ok ID set
		if (is_err_recv(szBufRecv))
		{
			printf("error : 9 recv content have error\n");
			break;
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_Nxx_get_feeder_status(serial::Serial& my_serial, int FeederNoBase1, int Nxx)
{
	bool b_ok = false;
	char szRecv[1024];

	do {
		memset(szRecv, 0, sizeof(szRecv));
		if (!proc_uart_read_status(my_serial, Nxx, szRecv, sizeof(szRecv)))
		{
			break;
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_Nxx_try_to_change_ID(serial::Serial& my_serial, int FeederNoBase1, int Nxx)
{
	// M610 MCODE_GET_FEEDER_ID
	// M640 MCODE_SET_FEEDER_ID

	int buf_rx_len = 0;
	int id = 0;
	bool isLeft = 0;
	bool b_ok = false;

	do {
		if (!proc_uart_read_ID(my_serial, Nxx, id, isLeft))
		{
			break;
		}
		

		if (id != FeederNoBase1)
		{
			if (!proc_uart_set_ID(my_serial, FeederNoBase1, Nxx))
			{
				break;
			}
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

bool proc_uart_Nxx(serial::Serial& my_serial, int FeederNoBase1, int Nxx)
{
	bool b_ok = false;

	do {
		// 检测飞达ID, 如果不是FeederNoBase1, 改为FeederNoBase1
		if (!proc_uart_Nxx_try_to_change_ID(my_serial, FeederNoBase1, Nxx))
		{
			printf("error : 10 can't try to change ID to Feeder%d-%d\n", FeederNoBase1, Nxx);
			break;
		}

		if (!proc_uart_Nxx_get_feeder_status(my_serial, FeederNoBase1, Nxx))
		{
			printf("error : 11 can't get feeder status Feeder%d-N%d\n", FeederNoBase1, Nxx);
			break;
		}

		b_ok = true;
	} while (false);

	return b_ok;
}

备注

飞达控制这块就搞完了.

现在我设备这块, 还有点要优化.
顶部相机现在是100W像素的, 在openpnp中看不清PCB上的0201和01005焊盘.
已经买了1600W像素的USB摄像头模组(安装孔尺寸为28mm x 28mm, 和现在的顶部相机支架兼容), 回来试试.

现在手头这台设备, 所有细节(机械部分, 电气部分, 软件部分)都可以自己维护, 想搞就搞, 很舒服.

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1197742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐这款机器学习的特征筛选神器!

大家好&#xff0c;特征选择是机器学习建模流程中最重要的步骤之一&#xff0c;特征选择的好坏直接决定着模型效果的上限&#xff0c;好的特征组合甚至比模型算法更重要。除了模型效果外&#xff0c;特征选择还有以下几点好处&#xff1a; 提高模型性能并降低复杂性&#xff08…

Spring Cloud学习(六)【统一网关 Gateway】

文章目录 网关的功能搭建网关服务路由断言工厂Route Predicate Factory路由过滤器 GatewayFilter过滤器执行顺序跨域问题处理 网关的功能 网关功能&#xff1a; 身份认证和权限校验服务路由、负载均衡请求限流 在SpringCloud中网关的实现包括两种&#xff1a; gatewayzuul …

到底是什么是Python?语言的核心是什么?

文章目录 前言一、为什么提出python编程的核心是什么&#xff1f;二、Python需要REPL&#xff1f;三、Python的哪些部分需要被视为“Python”&#xff1f;四、需要多少兼容性才能有用&#xff1f;Python技术资源分享1、Python所有方向的学习路线2、学习软件3、精品书籍4、入门学…

计算机网络技术

深入浅出计算机网络 微课视频_哔哩哔哩_bilibili 第一章概述 1.1 信息时代的计算机网络 1. 计算机网络各类应用 2. 计算机网络带来的负面问题 3. 我国互联网发展情况 1.2 因特网概述 1. 网络、互连网&#xff08;互联网&#xff09;与因特网的区别与关系 如图所示&#xff0…

Windows11跳过联网激活 跳过登陆操作

1 背景 笔者使用VirtualBox时安装Win11&#xff0c;初始化的配置提示需要注册账户才能进行下一步操作&#xff0c;于是去查了一下发现有办法绕过&#xff0c;方法就是断网oobe\ByPassNRO.cmd&#xff0c;试了一下发现可以&#xff0c;便有了这篇文章。 2 流程 开机之前&…

【星海随笔】SDN neutron (二) Neutron-plugin(ML2)

Neutron架构之Neutron-plugin Core-plugin(ML2)篇 Neutron-server接收两种请求&#xff1a; REST API请求&#xff1a;接收REST API请求&#xff0c;并将REST API分发到对应的Plugin&#xff08;L3RouterPlugin&#xff09;。 RPC请求&#xff1a;接收Plugin agent请求&#…

QT 布局管理综合实例

通过一个实例基本布局管理&#xff0c;演示QHBoxLayout类、QVBoxLayout类及QGridLayout类效果 本实例共用到四个布局管理器&#xff0c;分别是 LeftLayout、RightLayout、BottomLayout和MainLayout。 在源文件“dialog.cpp”具体代码如下&#xff1a; 运行效果&#xff1a; Se…

【Spring】SpringBoot日志

SpringBoot日志 日志概述日志使用打印日志获取日志对象使用日志对象打印日志日志框架介绍门面模式SLF4J框架介绍(simple logging facade for java) 日志格式说明日志级别日志级别的分类日志级别的使用 日志配置配置日志级别日志持久化配置日志文件的路径和文件名配置日志文件的…

centos7安装linux版本的mysql

1.下载linux版本的mysql 进入mysql官网&#xff0c;点击社区版本下载&#xff1a; https://dev.mysql.com/downloads/mysql/ 选择版本&#xff0c;可以跟着我下面这个图进行选择&#xff0c;选择红帽版本的既可&#xff0c;都是linux版本的。 2.上传解压linux版本的mysql安装包…

C++初阶--类与对象(3)(图解)

文章目录 再谈构造函数初始化列表隐式类型转换explicit关键字 static成员友元类内部类匿名对象拷贝函数时的一些优化 再谈构造函数 在我们之前的构造函数中&#xff0c;编译器会通过构造函数&#xff0c;对对象中各个成员给出一个适合的初始值&#xff0c;但这并不能称之为初始…

思维模型 超限效应

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。物极必反。 1 超限效应的应用 1.1 教育中的超限效应 一位老师在课堂上批评了一位学生&#xff0c;这位学生可能会因为老师的批评而感到沮丧和失落。如果老师在接下来的课程中继续批评这位…

数据结构与算法—搞懂队列

csdn专栏&#xff1a;数据结构与算法 前言 栈和队列是一对紧密相关的数据结构。之前已经介绍过栈&#xff08;它遵循后进先出的原则&#xff09;&#xff0c;栈的机制相对简单&#xff0c;就像你进入一个狭窄的山洞&#xff0c;山洞只有一个出入口&#xff0c;因此你只能按照后…

【原创分享】Mentor PADS将PCB封装直接添加到PCB的教程

一般&#xff0c;批量添加封装到PCB板上有以下方法&#xff1a; 第一步&#xff1a;点击菜单栏“ECO模式--添加元器件”如图&#xff0c;点击以后弹出如图界面。 1&#xff09;元件类型 PCB封装必须得添加完元件类型&#xff0c;才能通过ECO模式添加到PCB界面里面&#xff0c…

[Linux打怪升级之路]-信号的保存和递达

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、信号的保…

红黑树-RBTree

目录 1. 红黑树的概念2. 红黑树的性质3. 结点的定义4. 结点的插入5. 整体代码 1. 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式…

基于51单片机RFID射频门禁刷卡系统设计

**单片机设计介绍&#xff0c; 基于51单片机RFID射频门禁刷卡系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序程序 六、 文章目录 一 概要 基于51单片机RFID射频门禁刷卡系统&#xff0c;是一种将单片机技术和射频标识技术应用于门禁控制系统的…

34 Feign最佳实践

2.4.2.抽取方式 将Feign的Client抽取为独立模块&#xff0c;并且把接口有关的POJO、默认的Feign配置都放到这个模块中&#xff0c;提供给所有消费者使用。 例如&#xff0c;将UserClient、User、Feign的默认配置都抽取到一个feign-api包中&#xff0c;所有微服务引用该依赖包…

一篇文章真正讲懂模型评估指标(准确率,召回率,精确率,roc曲线,AUC值)

背景&#xff1a; 最近在做一些数据分析的比赛的时候遇到了一些头疼的问题&#xff0c;就是我们如何评估一个模型的好坏呢&#xff1f; 准确率&#xff0c;召回率&#xff0c;精确率&#xff0c;roc曲线&#xff0c;roc值等等&#xff0c;但是模型评估的时候用哪个指标呢&…

[工业自动化-12]:西门子S7-15xxx编程 - PLC从站 - ET200 SP系列详解

目录 一、概述 1.1 概述 二、系统组成 2.1 概述 2.2 与主站的通信接口模块 2.3 总线适配器 2.4 基座单元 2.5 电子模块 2.6 服务器模块 一、概述 1.1 概述 PLC ET200 SP 是西门子&#xff08;Siemens&#xff09;公司生产的一款模块化可编程逻辑控制器&#xff08;PL…

初探SVG

SVG&#xff0c;可缩放矢量图形&#xff08;Scalable Vector Graphics&#xff09;。使用XML格式定义图像。SVG有以下优点&#xff1a;1&#xff09;可被非常多的工具读取和修改&#xff1b;2&#xff09;比JPEG和GIF尺寸更小&#xff0c;可压缩性更强&#xff1b;3&#xff09…