FPGA串口回环实验

2023-05-16

本文将从个人理解的角度,解释FPGA串口通信的原理,并进行实战演示。

1.写在前面的话

串口通信是初学FPGA必过的一道坎,如果能够在不参考任何资料的情况下自己手搓一套串口回环的代码,Veriolg应该就算基本入门了。下面我将从自己的理解出发,分享实现的方法。

2.预备知识

2.1波特率的意义

以115200波特率为例,它表示每秒传输115200个bit,因此每个bit传输时间为:

1000 000 000/115200=8680ns

如果开发板的时钟频率为50MHz(每个时钟周期为20ns),那么每个bit传输时间为:

8680/20=434个时钟周期

2.2串口助手的原理

推荐这一篇文章,讲的很清楚。

串口是怎样传输数据的_串口数据_Crazzy_M的博客-CSDN博客

简单概括一下,上位机的串口助手会将数据按照设定的波特率一位一位的发送给FPGA(串行),正常来讲在数据的起始要有一个起始位(数据线由高电平变为低电平)告诉FPGA要开始接收数据了,因此在后面设计串口接收时需要有检验下降沿的步骤;结束要有校验位(如果FPGA没有设计校验相关模块,那这一位可以不要)和停止位(数据线由低电平变为高电平)告诉FPGA停止接收数据。

串口传输一帧数据

3.FPGA串口回环设计原理

整个实验需要设计三个模块,串口接收、串口发送,以及顶层模块。

模块原理图

串口接收、发送的时序图

RX(接收)模块:将数据从串行转化为并行(借助一个缓冲向量),然后传给TX模块

TX(发送)模块:把接收到的并行数据一位一位的发送出去(线性序列机)也即并行化串行

下面用文字来描述整个串口回环的过程(以115200波特率为例),大家可以对照第四部分的源码进行理解:

上位机向FPGA发送8位二进制,注意,串口助手会将设定的数据按照设定的波特率一位一位的给FPGA(115200的波特率下,每秒可以发115200位二进制数据,也就是说 1位起始位+8位数据位 只要9/115200秒就可以发完),而FPGA时钟频率为50M(>>115200),所以虽然发送时间很短,但FPGA处理起来还是绰绰有余的(每位数据有50M/115200=434个时钟周期用来处理)

首先是接收模块,第一步要捕捉下降沿(当然可以在之前多加一个寄存器同步数据防止亚稳态),产生一个脉冲,告诉缓冲区马上要接受数据了,在115200波特率下,一位数据传输需要434个周期,因此要定义一个周期计数器;为了传输稳定,缓冲区每次接收数据最好在每位数据传输的中期(工程上上往往会多次取样确保正确,这里就算了),因此要定义一个中间信号位,告诉缓冲区应该接收数据了(接收时刻);传8位数据后停止,因此需要一个位数计数器。

开始缓冲区reg_data中每一位都是0,现在每个接收时刻都将reg_data右移一位(最低位舍弃),并将此时的reg3变成其最高位这样8个接收时刻后,reg_data[7:0]正好对应 最后一个rx—>第一个rx,这样就做到了把串行的数据rx全部缓冲到reg_data内,这个时候就产生缓冲完毕信号位rx_flag=1,进行整体赋值uart_data <= reg_data,这样就完成了数据的“串转并”。

receive_done导出接收完成的信号,在顶层通过flag与tx模块的uart_in_flag相连,从而使work_en置一,开始发送数据;uart_data将数据缓存器中的数据导出,在顶层中通过data线与tx模块uart_in_data相连,从而将并行数据作为发送模块的输入。

然后是发送模块。仍然采用115200发送,所以同接收模块,434个时钟发送一位,因而需要一个周期计数器(bps_count)、中间信号位(bit_flag)、位数计数器(bit_count)。

当中间信号位为1时将并行的数据,根据此时位数计数器的值,按位发出去。这样就完成了数据的“并转串”,这就是串口回环的整个过程。

4.源码分享

串口顶层模块

module uart_top (
    input  wire clk,
    input  wire rst_n,
    input  wire uart_rx,
    output wire uart_tx
//    output wire [3:0] led
);
parameter  SYSTERM_CLK = 26'd50_000_000;               //系统时钟频率
parameter  UART_BPS    = 17'd115200;                     //串口波特率

wire       flag;
wire [7:0] data;
//assign led = data[3:0];
uart_receive 
#(
    .SYSTERM_CLK   (SYSTERM_CLK   ),
    .UART_BPS      (UART_BPS      )
)
u_uart_receive(
    .clk          (clk          ),
    .rst_n        (rst_n        ),
    .uart_rx      (uart_rx      ),
    .receive_done (flag ),
    .uart_data    (data    )
);

uart_send 
#(
    .SYSTERM_CLK   (SYSTERM_CLK   ),
    .UART_BPS      (UART_BPS      )
)
u_uart_send(
    .clk          (clk          ),
    .rst_n        (rst_n        ),
    .uart_in_data (data ),
    .uart_in_flag (flag ),
    .uart_tx      (uart_tx      )
);

endmodule //uart_top

串口接收模块

module uart_receive (
    input  clk,
    input  rst_n,
    input  uart_rx,
    output reg receive_done,
    output reg  [7:0]   uart_data
);
parameter  SYSTERM_CLK = 50_000_000;               //系统时钟频率
parameter  UART_BPS    = 115200;                     //串口波特率
localparam BPS_COUNT_MAX   = SYSTERM_CLK/UART_BPS;     //为得到指定波特率
                                                   //需要对系统时钟计数BPS_COUNT次
reg      [7:0]       reg_data;//接受数据缓存
reg      [3:0]       bit_count;//接收数据时用于计数接收到了多少位
reg      [12:0]      bps_count;//用于按照时钟计算一个字节的时间
reg                  start_bit;//检测到起始位的下降沿之后触发一个时钟的高电平
reg                  reg1     ;
reg                  reg2     ;
reg                  reg3     ;           
reg                  bit_flag ;//在一个电平的中间位置产生高电平标志
reg                  work_en  ;//在本标志位高电平时,接受工作开始,在低电平时工作结束
reg                  rx_flag  ;//在数据缓存器存满了之后产生一个高电平

//插入两级寄存器进行数据同步(打两拍),用来消除亚稳态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        reg1 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平
    end
    else        begin
        reg1 <= uart_rx;
    end
end    
//插入两级寄存器进行数据同步(打两拍),用来消除亚稳态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        reg2 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平
    end
    else        begin
        reg2 <=reg1;
    end        
end
//插入两级寄存器进行数据同步(打两拍),用来消除亚稳态
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        reg3 <= 1'b1;//因为UART的空闲状态是高电平,所以复位时电平要设置为高电平
    end
    else        begin
        reg3 <=reg2;
    end        
end
//start_bit用来检测起始位的下降沿
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        start_bit <= 1'b0;
    end
    else    if ((reg3)&&(!reg2)) begin
        start_bit <= 1'b1;
    end
    else
        start_bit <= 1'b0;
end
//work_en,在本标志位高电平时,接受工作开始,在低电平时工作结束
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        work_en <= 1'b0;
    end
    else    if (start_bit) begin
        work_en <= 1'b1;
    end
    else    if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin
        work_en <= 1'b0;
    end
    else
        work_en <= work_en;  
end
//bps_count用来计数计算波特率
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bps_count <= 13'b0;
    end
    else    if ((bps_count == BPS_COUNT_MAX -1) || (work_en == 0)) begin
        bps_count <= 13'b0;//只有在工作使能的状态下才会计数
    end
    else    if (work_en == 1) begin
        bps_count <= bps_count + 1'b1;
    end
    else
        bps_count <= bps_count;    
end
//bit_flag,在一个字节的中点输出一个时钟的高电平
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bit_flag <= 1'b0;
    end
    else    if (bps_count == BPS_COUNT_MAX/2-1) begin
         bit_flag <= 1'b1;
    end
    else
        bit_flag <= 1'b0;       
end
//bit_count,用于计数当前接收到了第几bit
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
       bit_count <= 4'b0;  
    end
    else    if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin
        bit_count <= 4'b0;
    end
    else    if (bit_flag == 1'b1) begin
        bit_count <= bit_count + 1'b1;
    end
    else
        bit_count <= bit_count;       
end
//reg_data表示接收数据的缓存
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        reg_data <= 8'b0;
    end
    else    if ((bit_flag == 1) && (work_en == 1) && (bit_count <= 4'd8) && (bit_count >= 4'd1)) begin
//reg3<=reg2<=reg1<= uart_rx(打两拍防止亚稳态)
//所以每个接收时刻reg3中依次对应接收到的每位二进制数据
//开始reg_data中每一位都是0
//现在接收时刻都将reg_data右移一位(最低位舍弃),并将此时的reg3变成其最高位
//这样8个接收时刻后,reg_data[7:0]正好对应 最后一个rx——第一个rx
//这样就做到了把串行的数据rx全部缓冲到reg_data内
//这个时候就产生缓冲完毕信号位,进行整体赋值uart_data <= reg_data
//从而起到数据 串转并 的作用
        reg_data <= {reg3,reg_data[7:1]};
    end
    else
        reg_data <= reg_data;     
end
//rx_flag在接收缓存满了之后输出一个时钟的高电平
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rx_flag <= 1'b0;
    end
    else    if ((bit_count == 4'd8) && (bit_flag == 1'b1)) begin
        rx_flag <= 1'b1;
    end
    else
        rx_flag <= 1'b0;       
end
//uart_data将数据缓存器中的数据导出
//uart_data在顶层中通过data线与tx模块uart_in_data相连
//再将数据 并转串 一位位发送出去
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        uart_data <= 8'b0;
    end
    else    if (rx_flag == 1'b1) begin
        uart_data <= reg_data;
    end
    else
        uart_data <= uart_data;       
end
//receive_done导出接收完成的信号
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        receive_done <= 1'b0;
    end
    else    if (rx_flag == 1'b1) begin
        receive_done <= 1'b1;
    end
    else
        receive_done <= 1'b0;       
end

endmodule //uart_receive

串口发送模块

module uart_send (
input   wire                clk,
input   wire                rst_n,
input   wire      [7:0]     uart_in_data,
input   wire                uart_in_flag,
output  reg                 uart_tx
);
parameter  SYSTERM_CLK = 50_000_000;               //系统时钟频率
parameter  UART_BPS    = 115200;                     //串口波特率
localparam BPS_COUNT_MAX   = SYSTERM_CLK/UART_BPS;     //为得到指定波特率
                                                   //需要对系统时钟计数BPS_COUNT次
reg      [12:0]      bps_count;//用于按照时钟计算一个字节的时间
reg      [3:0]       bit_count;//接收数据时用于计数接收到了多少位
reg                  bit_flag ;//在一个电平的中间位置产生高电平标志
reg                  work_en  ;//在本标志位高电平时,接受工作开始,在低电平时工作结束

//bps_count波特率计数器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bps_count <= 13'b0;
    end
    else    if ((bps_count ==BPS_COUNT_MAX - 1'b1) || (work_en == 1'b0)) begin
//-1'b1是个小细节,因为bps_count=0也站一个时钟周期
        bps_count <= 13'b0;
    end
    else    if (work_en == 1'b1) begin
        bps_count <= bps_count + 1'b1;
    end
    else
        bps_count <= bps_count;     
end
//work_en发送工作使能
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        work_en <= 1'b0;
    end
    else    if ((bit_count == 4'd9) && (bit_flag == 1'b1)) begin
        work_en <= 1'b0;
    end
    else    if (uart_in_flag == 1'b1) begin
        work_en <= 1'b1;
    end
    else
        work_en <= work_en;       
end
//bit_flag每一个bit的信号
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bit_flag <= 1'b0;
    end
    else    if (bps_count == BPS_COUNT_MAX/2 - 1'b1) begin
         bit_flag <= 1'b1;
    end
    else
        bit_flag <= 1'b0;
end
//bit_count字节计数
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        bit_count <= 4'b0;
    end
    else    if ((bit_flag == 1'b1) && (work_en == 1'b1)) begin
        bit_count <= bit_count + 1'b1;
    end
    else    if ((bit_count == 4'd9) && (bit_flag == 1'b1)) begin
        bit_count <= 4'b0;
    end
    else
        bit_count <= bit_count;        
end
//uart_tx
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        uart_tx <= 1'b1;//串口传输,空闲时为高电平
    end
    else    if (bit_flag == 1'b1) begin
        case (bit_count)
            0:  uart_tx <= 1'b0           ;
            1:  uart_tx <= uart_in_data[0]; 
            2:  uart_tx <= uart_in_data[1]; 
            3:  uart_tx <= uart_in_data[2]; 
            4:  uart_tx <= uart_in_data[3]; 
            5:  uart_tx <= uart_in_data[4]; 
            6:  uart_tx <= uart_in_data[5]; 
            7:  uart_tx <= uart_in_data[6]; 
            8:  uart_tx <= uart_in_data[7]; 
            9:  uart_tx <= 1'b1           ;
            default uart_tx <= 1'b1       ;               
        endcase
    end
end
endmodule //uart_send

5.功能仿真

编写testbench如下,用Vivado软件自带的功能仿真,对串口回环设计进行检验。

`timescale 10ns / 1ps   //粘贴前把初始化的时间刻度删掉
module tb;
reg clk;
reg rst_n;
reg uart_rx;
wire uart_tx;

uart_top  uart_top_u(
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx)
);

initial begin
clk=0;  
rst_n=0;
#10 rst_n=1;
end

always#1 clk=~clk;//使时钟周期为20ns

initial begin
#20  uart_rx=0;

#868 uart_rx=1;//每434个时钟周期传一个比特
#868 uart_rx=1;
#868 uart_rx=0;
#868 uart_rx=1;
#868 uart_rx=1;
#868 uart_rx=0;
#868 uart_rx=1;
#868 uart_rx=0;

#868 uart_rx=1;
end
endmodule

仿真波形

6.板级验证

在完成功能仿真后,根据开发板原理图进行管脚约束,然后生成比特流文件,连接开发板后烧录即可。(注意,有些zynq开发板是通过跳帽选择PL或PS通信的,记得在验证前,将跳帽连接ch340和PL端的TX、RX)。

打开串口助手,设置波特率为115200,发送数据,如果在接收端接收到相同的数据,说明实验成功。

求学路上,你我共勉(๑•̀ㅂ•́)و✧

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FPGA串口回环实验 的相关文章

  • C/C++实现strcpy和strcat两个功能

    strcpy和strcat是string h头文件中分别实现字符串数组拷贝与拼接功能的函数 xff0c 详细使用相信大家都了解了 xff0c 如果还不了解看看实例 C C 43 43 笔试必须熟悉掌握的头文件系列 xff08 四 xff09
  • C/C++锁机制(boost)的认知和使用

    锁扩充 加锁的必需考虑三个问题 该锁的不锁 xff0c 将会导致各种莫名其妙的错误 xff1b 加锁范围太大 xff0c 虽然能避免逻辑错误 xff0c 但如果锁了不该锁的东西 xff0c 难免会降低程序的效率 xff1b 加锁方式不合适
  • QT之GPS

    http blog sina com cn s blog 7da13b510100xtgr html 前几天发现手里还闲着一块GPS 佳明的15W 也不知道是好的还是坏的呵呵一时兴起我就趁周六日没什么事情 用qt做了一个界面 现在已经调试完
  • 关于tcp/udp网络调试助手错误提示

    最近在学习网络调试助手与虚拟机中的Ubuntu系统通信 xff0c 在使用Ubuntu做服务器端时 xff0c tcp以及udp协议都遇到了问题 1 tcp协议遇到的问题是 xff1a 网络调试助手提示 xff1a 1035未知错误 xff
  • 结构体和结构体链表

    在c语言表针中有多种数据类型 xff0c 他们的应用使变量的应用变得灵活多变 而除了c语言默认的int xff0c float 等类型外 xff0c 我们还可以自己定义一些数据的类型 xff0c 结构体类型便是可以实现数据类型自定义的类型
  • 串口通信UART

    串口基本概念 串口通讯 Serial Communication 是指外设和计算机间 xff0c 通过数据信号线 地线等 xff0c 按位进行传输数据的一种通讯方式 其通讯协议可分层为协议层和物理层 物理层规定通信协议中具有机械 电子功能的
  • 一、Fmcw毫米波雷达原理

    0 概念 FMCW Frequency Modulated Continuous Wave xff0c 即调频连续波 FMCW技术和脉冲雷达技术是两种在高精度雷达测距中使用的技术 其基本原理为发射波为高频连续波 xff0c 其频率随时间按照
  • Makefile和CMake

    Makefile makefile主要规则 xff1a 伪对象 PHONY clean 规则1 main main o gcc main o o main 规则2 main o main c gcc c main c o main o 规则
  • C语言基础——结构体

    结构体的作用 在需要表示一些复杂信息时 xff0c 使用单纯的数据类型很不方便 比如 xff1a 学生信息 xff08 学号 xff0c 姓名 xff0c 班级 xff0c 电话 xff0c 年龄 xff09 xff1b GPIO信息 xf
  • Nginx 通过 header 中的标识进行分发

    Nginx可以根据请求头中自定义的标识将请求分发到不同的服务器 具体来说 xff0c 可以使用map指令将请求头中的自定义标识映射为不同的后端服务器地址 xff0c 然后使用proxy pass指令将请求转发到对应的后端服务器 以下是一个示
  • DB9接口详解---DB9引脚在 UART,CAN,RS485中的定义

    DB9的公母如下 xff1a 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 超强整理!PCB设计之电流与线宽的关系

    关于pcb线宽和电流的经验公式 xff0c 关系表和软件网上都很多 xff0c 本文把网上的整理了一下 xff0c 旨在给广大工程师在设计PCB板的时候提供方便 以下总结了八种电流与线宽的关系公式 xff0c 表和计算公式 xff0c 虽然
  • nginx 主动健康检查搭建详解(nginx_upstream_check_module)

    版本信息 nginx 1 21 1 下载nginx upstream check module模块 nginx upstream check module master zip wget https codeload github com
  • paddle推理部署(cpu)

    我没按照官方文档去做 xff0c 吐槽一下 xff0c 官方文档有点混乱 一 概述 总结起来 xff0c 就是用c 43 43 示例代码 xff0c 用一个模型做推理 二 示例代码下载 https www paddlepaddle org
  • Vector的用法

    我不知道大家是怎么理解Vector和怎样使用的 xff0c 这篇文章主要是发表我自己对于Vector的看法 xff0c 仅仅属于个人理解 xff0c 如果有什么错误 xff0c 也希望大家指正哈 目录 1 xff1a Vector的概念 2
  • float的表示

    xfeff xfeff 先说一下计算机中二进制的算法 xff1a 整数 整数的二进制算法大家应该很熟悉 xff0c 就是不断的除以2取余数 xff0c 然后将余数倒序排列 比如求9的二进制 xff1a 9 2 61 4 余 1 4 2 61
  • cmake系列(三)

    目录 多个源文件 同一目录 xff0c 多个源文件 多个源文件 同一目录 xff0c 多个源文件 本小节对应的源代码所在目录 xff1a Demo2 上面的例子只有单个源文件 现在假如把 power 函数单独写进一个名为 MathFunct
  • ORACLE 字符串聚合函数 strcat

    create or replace type strcat type as object currentstr varchar2 4000 currentseprator varchar2 8 static function ODCIAgg
  • 无人机器件选择参考

    无人机飞控 xff0c 引脚预留数量 1 xff0c 四路pwm 2 xff0c 无线通信spi 3 xff0c 陀螺仪通信用iic 4 xff0c 串口调试用uart 5 xff0c led灯用普通io 6 xff0c 电量检测和电机堵塞
  • 字节对齐的规则总结

    一 什么是字节对齐 为什么要对齐 现代计算机中内存空间都是按照byte划分的 xff0c 从理论上讲似乎对任何类型的变量的访问可以从任何地址开始 xff0c 但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问 xff0c 这就需要

随机推荐

  • C++中第三方库的一般使用方式(libxl库为例)

    本篇介绍如何使用C C 43 43 的第三方库 xff0c 学会使用第三方库很重要 xff0c 尤其对于使用C C 43 43 语言的人来说 xff0c 标准库能做的事不能说太少 xff0c 恰当的说应该是没那么有趣 学会使用第三方库 xf
  • 三相电动机用单相电源

    三相电机改为单相运行 单相电机配用电容不是越大越好 三相电动机用单相电源 三相电机改为单相运行 介绍几种简便易行的方法 xff0c 可以不改动电机内部绕组而将三相电机改为单相运行 有6 种 xff1a 一 加电容法 xff39 形接法的三相
  • curl_init()和curl_multi_init()多线程的速度比较

    来源 http www webkaka com tutorial php 2013 102843 php中curl init 的作用很大 xff0c 尤其是在抓取网页内容或文件信息的时候 xff0c 例如之前文章curl获得header检测
  • 连接两字符串函数

    include lt stdio h gt include 34 string h 34 char Strcat char s1 char s2 printf 34 连接之后的字符串为 xff1a 34 for s1 61 39 0 39
  • CAN通信数据帧介绍

    CAN通信有五个帧 xff0c 其中最重要的是数据帧 xff01 xff01 xff01 xff01 我们下面开始讨论数据帧 一 数据帧的格式 xff08 数据帧有七个段组成 xff09 xff0c 帧起始 表示数据帧开始的段 xff0c
  • STM32压力传感器信号采集-24位AD HX720 HX711 原理介绍

    我做过很多工业用压力采集产品 xff0c 用过很多高分辨率的AD芯片 xff0c 其中有两款值得推荐 一个是海芯科技出的HX711等24位AD xff0c 一个是塞普拉斯出的CS5532等24位AD 国产芯片和进口芯片有差距 xff0c 但
  • stm32实现网络音频-原理图单片机程序C#上位机程序

    电子可以一边玩 xff0c 一边研究 xff0c 网络音频这个课题特别适合电子爱好者 几方面的挑战如下 xff0c 单片机实现对接以太网 实时对音频流解码播放 xff0c 上位机配合单片机做音频流传输控制 xff0c 音频信号的对接放大处理
  • rosdep init and update Error

    rosdep init Error sudo rosdep init ERROR default sources list file already exists br etc ros rosdep sources list d 20 de
  • Postman汉化版本竟如此简单,全中文真香

    对于国内程序员来说 xff0c 外国开发软件的一个使用门槛是全英文的 xff0c 对于不熟悉各种专业术语的同学 xff0c 上手比较麻烦 因此有种方法就是使用汉化版的外国软件 xff0c 但 Postman 并没有汉化版本 但是postma
  • YOLOv5识别目标的实时坐标打印

    引言 这个功能看似鸡肋 xff0c 但对于无人机目标识别与追踪有重要意义 xff0c 通过目标在摄像头视野的坐标位置 xff0c 可以推算出无人机相对与目标的位置 xff0c 从而对无人机进行位置矫正 因此 xff0c 添加代码打印坐标并不
  • 六、WebRTC中ICE的实现

    一 Candidate种类 amp 优先级 高到底 xff1a host srflx prflx relay 同一局域网内通过host类型的Candidate在内网建立连接 非同一局域网 xff0c 隔断从STUN TURN服务器中收集sr
  • 七、WebRTC中的SDP

    一 SDP标准规范 格式 xff1a lt type gt 61 lt value gt SDP 会话层 媒体层 媒体音频 媒体视频 二 WebRTC中的SDP的整体结构 1 媒体信息 m 61 行中描述媒体类型 传输类型 Playload
  • linux 信号量sem

    一 信号量 信号量如同一盏红绿信号灯 xff0c 用于临界资源 xff08 如公路 人行道 xff09 的管理 信号量是一种特殊的变量 xff0c 访问具有原子性 P等待 xff1a 信号量的值为0时 xff0c 不能减 xff0c 则进行
  • 1-4 实验3 串口通信

    串口通信 1 实验内容 xff1a PC端串口调试助手向板子发送数据 xff0c 板子接受到数据后 xff0c 再把数据发送回给PC端串口调试助手 2 串口发送接受数据的基本步骤 xff1a 初始化串口 xff08 设置波特率 中断等 xf
  • 1-6 实验5 无线温度检测实验

    无线温度检测实验 1 实验内容 xff1a 协调器建立ZigBee无线网络 xff0c 终端节点自动加入网络 xff0c 然后终端节点周期性地采集温度并将数据发送到协调器 协调器接受数据并通过串口把接受到的数据传给PC端的串口调试助手 2
  • 1-11 实验9 网络管理实验1 获取自身的和父节点网络地址、MAC地址

    p p p style color rgb 51 51 51 font family Arial font size 14px line height 26px 获取自身的和父节点网络地址 MAC地址 p p style color rgb
  • 1-14 实验11 获取网络拓扑

    获取网络拓扑 1 实验内容 xff1a PC端串口调试助手向协调器发送命名 topology 协调器接受到命令后 xff0c 将网络拓扑信息发送到PC机串口调试助手上 2 知识点 xff1a 在1 11 实验9 网络管理实验1 获取自身和父
  • S 串口编程 详解3 串口的初始化、打开/关闭

    串口编程 详解3 串口的初始化 程序打开串口 xff0c 采用两种方法 xff1a 1 程序启动 xff0c 调用OnInitDialog 函数 xff0c 打开串口 xff0c 缺省串口号为COM1 xff0c 如果COM1不存在或被占用
  • 求关键路径(包含邻接表的建立、拓扑排序)

    include lt stdio h gt include lt stdlib h gt typedef struct node int adjvex 邻接点域 int info 边上的信息 struct node next 指向下一个邻接
  • FPGA串口回环实验

    本文将从个人理解的角度 xff0c 解释FPGA串口通信的原理 xff0c 并进行实战演示 1 写在前面的话 串口通信是初学FPGA必过的一道坎 xff0c 如果能够在不参考任何资料的情况下自己手搓一套串口回环的代码 xff0c Verio