dql2016 发表于 2021-12-15 21:02

【二哈识图人工智能视觉传感器】3、与处理器进行串口通信

<p><span style="font-size:16px;">本来计划使用imx6ull开发板的i2c接口进行和二哈识图的通信实验,正好最近在使用米尔的stm32mp1 linux开发板串口通信,而二哈识图的4pin接口不仅支持i2c接口还支持串口,于是就直接用了,因为对于linux应用层i2c/uart通信编程来说,并不需要关心用的什么开发板。这是米尔开发板串口使用的帖子:</span></p>

<p><span style="font-size:16px;"><a href="https://bbs.eeworld.com.cn/thread-1189218-1-1.html" target="_blank">https://bbs.eeworld.com.cn/thread-1189218-1-1.html</a></span></p>

<p><span style="font-size:16px;">二哈识图通信协议文档</span></p>

<p><span style="font-size:16px;"><a href="https://img.dfrobot.com.cn/wiki/5a93d3cc01cd38236f596279/994852f9f01e7581b775a90f90fada93.pdf" target="_blank">https://img.dfrobot.com.cn/wiki/5a93d3cc01cd38236f596279/994852f9f01e7581b775a90f90fada93.pdf</a></span></p>

<p>可知,二哈识图用户可以通过发送一个测试连接命令<strong><span style="color:#e74c3c;">55 AA 11 00 2C 3C</span></strong>来测试和二哈识图的通信是否正常。</p>

<p>如果通信正常,二哈识图会返回<strong><span style="color:#e74c3c;">55 AA 11 00 2E 3E</span></strong></p>

<p>&nbsp;</p>

<p></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">#include &lt;iostream&gt;

using namespace std;

#include &lt;sys/epoll.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;termios.h&gt;
#include &lt;string.h&gt;

#include &lt;chrono&gt;
#include &lt;thread&gt;   

class MySerial
{
private:
    int fd = -1;
    string serial_dev;
    int serial_baudrate;
    string serial_parity;
    int serial_databits;
    int serial_stopbits;
    void* (*rx_cb_fun)(void*);

    int epfd;
    struct epoll_event event;        // 告诉内核要监听什么事件
    struct epoll_event wait_event;
public:
    MySerial(string serial_dev, int serial_baudrate, string serial_parity, int serial_databits, int serial_stopbits,void* (*rx_cb_fun)(void*))
    {
       this-&gt; serial_dev= serial_dev;
      this-&gt; serial_baudrate= serial_baudrate;
      this-&gt; serial_parity= serial_parity;
      this-&gt; serial_databits= serial_databits;
      this-&gt; serial_stopbits= serial_stopbits;

      this-&gt;rx_cb_fun = rx_cb_fun;

      epfd = epoll_create(10); // 创建一个 epoll 的句柄,参数要大于 0, 没有太大意义

      if( -1 == epfd )
      {
            perror ("epoll_create");
      }

    };
    int OpenSerial()
    {
      struct termios tios;
      int speed;
      fd = open(serial_dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
      if (fd &lt; 0)
      {
            perror("open");
      }
      memset(&amp;tios, 0, sizeof(struct termios));
      switch (serial_baudrate)
      {
            case 50:
                speed = B50;
                break;
            case 75:
                speed = B75;
                break;
            case 110:
                speed = B110;
                break;
            case 134:
                speed = B134;
                break;
            case 150:
                speed = B150;
                break;
            case 200:
                speed = B200;
                break;
            case 300:
                speed = B300;
                break;
            case 600:
                speed = B600;
                break;
            case 1200:
                speed = B1200;
                break;
            case 1800:
                speed = B1800;
                break;
            case 2400:
                speed = B2400;
                break;
            case 4800:
                speed = B4800;
                break;
            case 9600:
                speed = B9600;
                break;
            case 19200:
                speed = B19200;
                break;
            case 38400:
                speed = B38400;
                break;
            case 57600:
                speed = B57600;
                break;
            case 115200:
                speed = B115200;
                break;
            case 230400:
                speed = B230400;
                break;
            case 460800:
                speed = B460800;
                break;
            case 500000:
                speed = B500000;
                break;
            case 576000:
                speed = B576000;
                break;
            case 921600:
                speed = B921600;
                break;
            case 1000000:
                speed = B1000000;
                break;
            case 1152000:
                speed = B1152000;
                break;
            case 1500000:
                speed = B1500000;
                break;
            case 2000000:
                speed = B2000000;
                break;
            case 2500000:
                speed = B2500000;
                break;
            case 3000000:
                speed = B3000000;
                break;
            case 3500000:
                speed = B3500000;
                break;
            case 4000000:
                speed = B4000000;
                break;
            default:
                speed = B9600;
                break;
      }
      if ((cfsetispeed(&amp;tios, speed) &lt; 0) || (cfsetospeed(&amp;tios, speed) &lt; 0))
      {
            close(fd);
            fd = -1;
            perror("cfsetispeed or cfsetospeed");
      }
      tios.c_cflag |= (CREAD | CLOCAL);
      tios.c_cflag &amp;= ~CSIZE;
      switch (serial_databits)
      {
            case 5:
                tios.c_cflag |= CS5;
                break;
            case 6:
                tios.c_cflag |= CS6;
                break;
            case 7:
                tios.c_cflag |= CS7;
                break;
            case 8:
            default:
                tios.c_cflag |= CS8;
                break;
      }
      if (serial_stopbits == 1)
      {
            tios.c_cflag &amp;= ~CSTOPB;
      }
      else
      {
            tios.c_cflag |= CSTOPB;
      }
      if (serial_parity == "none")
      {
            tios.c_cflag &amp;= ~PARENB;
      }
      else if (serial_parity == "even")
      {
            tios.c_cflag |= PARENB;
            tios.c_cflag &amp;= ~PARODD;
      }
      else if (serial_parity == "odd")
      {
            tios.c_cflag |= PARENB;
            tios.c_cflag |= PARODD;
      }
      tios.c_lflag &amp;= ~(ICANON | ECHO | ECHOE | ISIG);
      if (serial_parity == "none")
      {
            tios.c_iflag &amp;= ~INPCK;
      }
      else
      {
            tios.c_iflag |= INPCK;
      }
      tios.c_iflag &amp;= ~(IXON | IXOFF | IXANY);
      tios.c_oflag &amp;= ~OPOST;
      tios.c_cc = 0;
      tios.c_cc = 0;
      if (tcsetattr(fd, TCSANOW, &amp;tios) &lt; 0)
      {
            close(fd);
            fd = -1;
            perror("tcsetattr");
      }

      event.data.fd = fd;        
      event.events = EPOLLIN; // 表示对应的文件描述符可以读
      // 事件注册函数,将描述符fd加入监听事件
      int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &amp;event);
      if(-1 == ret)
      {
            perror("epoll_ctl");
      }
      return fd;
    }

    void loop()
    {
      int ret;
            // 监视并等待文件描述符的属性变化(是否可读)
            // 没有属性变化,这个函数会阻塞,直到有变化才往下执行,这里没有设置超时
            ret = epoll_wait(epfd, &amp;wait_event, 2, -1);
            if(ret == -1)// 出错
            {
                close(epfd);
                perror("epoll");
            }
            else if(ret &gt; 0)// 准备就绪的文件描述符
            {
                //char buf = {0};
                if((fd == wait_event.data.fd) &amp;&amp; (EPOLLIN == wait_event.events &amp; EPOLLIN))
                {
                  rx_cb_fun(&amp;fd);
                }
            }
            else if(0 == ret)
            {
                printf("time out\n");
            }
    }
    ~MySerial()
    {
      close(fd);
      close(epfd);
    }
};

void *SerialRxCB(void* arg)
{
    int fd = *(int*)arg;
    char buf;
    read(fd, &amp;buf, 1);
    printf("%02x\n", buf);
    return NULL;
}

void thread_task(void* arg)
{
        int fd = *(int*)arg;
        while(1)
        {
                char tx_buf[]={0x55,0xAA,0x11,0x00,0x2C,0x3C};
                this_thread::sleep_for(chrono::seconds(2));
                write (fd, tx_buf, sizeof(tx_buf));
        }
}

int main(int argc,char* argv[])
{
    MySerial *ps = new MySerial("/dev/ttySTM3",9600,"none",8,1,SerialRxCB);
    int ret = ps-&gt;OpenSerial();
    if(ret &lt; 0)
    {
      perror("open serial");
      return -1;
   }
   
    thread t(thread_task,&amp;ret);
    t.detach();
   
    while(1)
    {
      ps-&gt;loop();
    }
    return 0;
}
</code></pre>

<p>首先将测试程序复制到开发板,连接TTL串口调试模块后可以看到数据收发正常:</p>

<p></p>

<p>接下来,将二哈识图的串口连接到开发板的串口3,测试效果如下:</p>

<p><iframe allowfullscreen="true" frameborder="0" height="450" src="//player.bilibili.com/player.html?bvid=19F411z7Ux&amp;page=1" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
&nbsp;</p>

<p>通信成功,收到了二哈识图返回的数据。</p>

<p>&nbsp;</p>

<p></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

freebsder 发表于 2021-12-16 16:36

<p>一大半都是对串口的设置,C搞起来确实麻烦,费代码。</p>

dql2016 发表于 2021-12-16 19:07

freebsder 发表于 2021-12-16 16:36
一大半都是对串口的设置,C搞起来确实麻烦,费代码。

<p>人生苦短,需要python</p>

freebsder 发表于 2021-12-20 09:41

dql2016 发表于 2021-12-16 19:07
人生苦短,需要python

<p>那玩意还是得先解决脚本上电自动执行的问题吧。</p>

mameng 发表于 2022-1-8 20:30

<p>你这是测试了个寂寞啊&nbsp;</p>
页: [1]
查看完整版本: 【二哈识图人工智能视觉传感器】3、与处理器进行串口通信