尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FPGA实战:DHT11温湿度传感器Verilog驱动设计与单总线时序解析

FPGA实战:DHT11温湿度传感器Verilog驱动设计与单总线时序解析 简介面向FPGA初学者的温湿度传感器DHT11读写Verilog驱动源码包基于Altera Cyclone IV E系列EP4CE10F17C8器件在Quartus 18.0环境下完成工程搭建实现FPGA对DHT11温湿度数据的采集、解析并通过动态数码管实时显示同时支持按键切换查看温度或湿度数据可作为智能环境监测、温湿度采集等应用的核心控制模块。压缩包体积约6.19MB共包含289个文件以tdf和v格式的Verilog源码、Quartus工程配置文件及编译生成文件为主另含sof、jic等固件下载文件目录结构清晰可直接打开工程进行仿真与上板验证。已有1369人学习使用。代码采用顶层模块例化的方式将DHT11驱动、按键消抖、温湿度选择控制、数码管扫描显示等功能独立封装逻辑层次分明注释易读适合学习单总线时序设计、模块化编程以及FPGA与传感器接口开发的完整流程工程文件齐全便于直接复用与二次开发。1. 从一根信号线说起为什么DHT11驱动值得用Verilog重写第一次拿到DHT11数据手册的人多半会盯着那个单总线时序图发一会儿呆。一根线既要发起始信号又要读从机响应还得在40个数据位上做严格的时间窗判断——20微秒的空闲窗口决定读到的是0还是1。这种纳秒级敏感的时序用单片机裸机轮询加上延时函数勉强能跑但在FPGA上全部要用计数器切成离散的时钟周期误差累积起来、状态机一乱读回来的温湿度就可能变成0xFF这种明显的坏值。这个标题里的Verilog驱动源码和Quartus工程文件解决的就是把DHT11的时序协议“硬件化”的问题。基于FPGA实现的意义在于驱动逻辑不占用CPU、时序完全由时钟边沿驱动、多路采集时每个传感器分配独立的状态机互不干扰。常见的使用场景包括环境监控节点、机房温湿度采集卡以及教学实验里用来理解单总线协议和状态机设计的经典案例。适合的人群是已经跑通LED流水灯、正准备接触真实外部传感器时序的FPGA学习者以及需要在板卡上做分布式环境采集的工程师。DHT11的协议本身不复杂但它的坑藏在细节里。总线释放、上拉电阻、起始信号长度、应答窗口、每位数据的电平宽度——这些参数在数据手册上都有标称值但真正落到不同厂家、不同批次的传感器上时序余量并不一致。下面按从协议拆解到工程落地的顺序把驱动代码的完整实现路径讲清楚。2. DHT11单总线时序拆解与Verilog实现原理2.1 DHT11数据帧结构40位数据的排列与校验规则DHT11一次完整的数据传输返回40位数据排列顺序依次是湿度整数部分8位、湿度小数部分8位、温度整数部分8位、温度小数部分8位、校验和8位。其中湿度小数部分和温度小数部分在DHT11上通常读出为0但驱动代码仍须完整接收并解析因为校验和的计算包含了这8位。校验算法很简单前四个字节相加取低8位与第五个字节相等则校验通过。以下面这帧数据为例湿度整数0x32 (50%RH) 湿度小数0x00 温度整数0x1C (28℃) 温度小数0x00 校验和0x4E (0x320x000x1C0x000x4E)在校验计算时有一个常见的歧义点Verilog里做8位截断加法需要显式声明一个足够宽的中间变量否则按标准加法规则会产生进位丢失的隐患。比较安全的写法是声明一个[31:0]类型的累加器再把累加结果的低8位与校验字节比较。校验失败后的处理策略也有讲究。直接丢弃整帧数据是保守做法但在一秒一次的采样周期里偶尔丢一帧会导致输出曲线出现毛刺。更平滑的办法是保留上次有效数据同时内部维护连续失败计数——连续3次以上失败才判定传感器异常并向外部输出一个错误标志。这种策略在后面的顶层模块里会体现。2.2 单总线时序的四个核心阶段起始、应答、数据位、结束DHT11的单总线通信可以拆成四个阶段每个阶段的时序参数对应状态机里的一个分支。第一阶段是主机发起起始信号。主机先把总线拉低保持至少18毫秒典型值是18~30ms然后释放总线。这段时间要足够长让DHT11内部的模拟电路完成复位检测。之后主机释放总线并切换为输入模式同时总线被外部上拉电阻拉高。第二阶段是从机应答。DHT11检测到起始信号后会先把总线拉低80微秒作为应答信号然后释放总线再拉高80微秒。这段时间主机的职责是检测总线上的低电平出现——如果等待时间超过100微秒还没看到低电平跳变就判定传感器无响应直接超时退出。第三阶段是数据位传输。每个数据位都从主机释放总线开始DHT11把总线拉低约50微秒然后释放。如果接下来是高电平持续约26~28微秒表示逻辑“0”如果高电平持续约70微秒表示逻辑“1”。判断的关键在于在40微秒左右的时间点采样总线电平采样到低电平说明是0采样到高电平说明是1。注意实际工程中数据位高电平的判定边界在30~80微秒之间都有传感器在正常工作因此不要在采样窗口上卡得太死否则低温环境下容易批量误判。第四阶段是通信结束。40位数据全部接收完后DHT11会再次拉低总线50微秒释放之后总线回到空闲高电平状态。2.3 为什么状态机设计决定了驱动稳定性DHT11驱动的核心是一个包含有限状态跳转的状态机。状态划分的粒度直接决定代码的复杂度——划分太粗每个状态下要同时判断多个时间窗口逻辑混乱划分太细则状态数膨胀综合后的组合逻辑路径变长。常见的做法是按“动作”而不是按“时间长度”来划分状态也就是说一个状态对应一次总线方向切换或一位数据采样。完整的DHT11读时序状态机按IDLE、START、RESPONSE、READ、DONE五个阶段拆分。其中READ阶段内部再细分到位级采样循环每采样一位数据切换一次状态采满40位后跳到DONE。这样每个状态下需要判断的定时参数只有1~2个状态之间的迁移条件清晰综合后也不会出现隐式的锁存器警告。状态机实现时有一个关键参数是时钟频率。不同开发板上的系统时钟不一样——50MHz、100MHz、12MHz都很常见因此驱动代码里计数器上限值必须按实际时钟频率推算。比如50MHz时钟下18毫秒的起始信号对应900000个时钟周期这个值如果手写死移植到100MHz时钟的板子上就变成了9毫秒时序完全不达标。下一节给出整个驱动模块的完整代码和一个与时钟频率解耦的参数化设计方便在不同板卡上直接复用。3. 从零写好DHT11驱动Verilog模块实例与Quartus工程搭建3.1 驱动模块顶层端口设计与参数化时钟分频驱动模块与外部交互的端口越简单越好。除了系统时钟和复位对外只需要一根三态总线dht11_data以及一组解析完成的温湿度输出。下面是一个可以直接实例化的端口定义module dht11_driver #( parameter CLK_FREQ_MHZ 50 )( input wire clk, input wire rst_n, inout wire dht11_data, output reg [7:0] humidity_int, output reg [7:0] humidity_dec, output reg [7:0] temperature_int, output reg [7:0] temperature_dec, output reg data_valid ); // 内部信号声明 localparam IDLE 4d0; localparam START 4d1; localparam RESPONSE 4d2; localparam READ 4d3; localparam DONE 4d4; // 其余信号略下节完整展开 endmodule这里用参数CLK_FREQ_MHZ而不是直接写死计数上限目的是让同一个模块可以方便地适配不同晶振频率的板卡。实例化时只需改变参数值内部所有时序参数全部按参数推算。端口里没有像某些开源代码那样输出原始40位数据——把原始数据暴露出去反而让上层逻辑容易被未解析的位序绕晕。封装的思路是模块内部完成移位、解析、校验对外只给整型温度和湿度值数据有效标志data_valid负责通知上层“这帧数据已经校验通过可以采样”。3.2 状态机全流程代码起始信号、等待应答、位采样完整的状态机实现涉及计数器复用。用一个32位的cycle_cnt计数器来做所有时序计数不同状态下的计数上限各不相同。以下是实现的核心代码// 时钟边沿驱动的状态机主流程 reg [31:0] cycle_cnt; reg [5:0] bit_cnt; reg [39:0] data_shift; reg bus_dir; // 1: 输出模式0: 输入模式 reg [15:0] fail_cnt; reg last_data_valid; reg [7:0] last_humi_int, last_temp_int; always (posedge clk or negedge rst_n) begin if (!rst_n) begin state IDLE; cycle_cnt 32d0; bit_cnt 6d0; data_shift 40d0; humidity_int 8d0; humidity_dec 8d0; temperature_int 8d0; temperature_dec 8d0; data_valid 1b0; end else begin case (state) IDLE: begin bus_dir 1b1; // 空闲时总线置高 dht11_data 1b1; // 释放总线 // 每1毫秒启动一次采集避免连续高压损坏传感器 if (cycle_cnt CLK_FREQ_MHZ * 1000) begin state START; cycle_cnt 32d0; end else begin cycle_cnt cycle_cnt 1b1; end end START: begin // 总线拉低至少18ms典型值取20ms留余量 dht11_data 1b0; if (cycle_cnt CLK_FREQ_MHZ * 20_000) begin bus_dir 1b0; // 切换到输入模式 dht11_data 1bz; // 三态释放 state RESPONSE; cycle_cnt 32d0; end else begin cycle_cnt cycle_cnt 1b1; end end // 后续RESPONSE和READ状态的代码在下一节展开 endcase end end这段代码里有一个值得注意的设计选择空闲状态里加了“每隔1毫秒启动一次采集”的条件。DHT11数据手册规定两次读取间隔不得小于1秒但实际工程中很多驱动会在状态机回到空闲后立刻启动下一次采集最终测出传感器异常发热甚至数据漂移。把采集间隔写在驱动模块内部对外部使用者就少了一个必须记得的约束。参数说明CLK_FREQ_MHZ * 20_000这个表达式里CLK_FREQ_MHZ是50的时候计算结果就是1_000_000对应50MHz时钟下的20毫秒。如果改用100MHz时钟仅需在实例化时把参数改成100所有时间窗口自动适配。3.3 响应等待与超时退出机制应答阶段需在空闲释放总线后持续监测总线电平。DHT11在接收到起始信号后会拉低总线约80微秒作为应答主机侧需在100微秒内检测到该低电平否则应主动退出状态机。RESPONSE: begin // 等DHT11拉低总线应答120us超时判定无设备 if (cycle_cnt CLK_FREQ_MHZ * 120) begin // 超时处理保留上次数据fail_cnt加1 state IDLE; fail_cnt fail_cnt 1b1; if (fail_cnt 3) begin // 连续失败3次输出一个特殊错误码 humidity_int 8hFF; temperature_int 8hFF; end end else begin cycle_cnt cycle_cnt 1b1; if (!dht11_data) begin // 采样到低电平应答到达等待80us低电平结束 state RESPONSE_HIGH; cycle_cnt 32d0; end end end RESPONSE_HIGH: begin // 应答信号的低电平结束总线拉高准备接收数据位 if (dht11_data) begin state READ; bit_cnt 6d0; cycle_cnt 32d0; end else if (cycle_cnt CLK_FREQ_MHZ * 100) begin // 若一直低电平超过100us视为异常重新开始 state IDLE; end else begin cycle_cnt cycle_cnt 1b1; end end超时退出机制在这个位置很关键。如果总线上没有接传感器或者传感器已经损坏状态机会一直卡在RESPONSE状态等待整个采集链路全部瘫痪。备用的异常处理策略也包含在上面的代码里连续失败3次后将温度和湿度输出为0xFF工业现场可以把这个值当作“传感器断线”的判据。3.4 Quartus工程创建与文件组织建议在Quartus Prime或Quartus II中创建DHT11驱动的FPGA工程建议按模块划分文件而不是把所有代码堆在一个Verilog文件里。推荐的工程文件结构如下dht11_fpga/ ├── rtl/ │ ├── dht11_driver.v // 时序驱动核心 │ ├── dht11_top.v // 顶层封装例化驱动和LED显示逻辑 │ └── clk_div.v // 如需额外分频可加入 ├── sim/ │ └── tb_dht11.v // 测试激励文件 ├── quartus/ │ └── dht11_fpga.qpf // Quartus工程文件 └── constraints/ └── dht11_pins.sdc // 引脚约束和时钟约束在Quartus里需要设置的几个关键项第一个是器件型号选择。以Intel Cyclone 10 LP或MAX 10系列为例在“Assignments Device”里选择实际板卡对应型号注意速度等级不能选错影响时序收敛。第二个是引脚分配。在“Assignments Pin Planner”中把顶层模块的dht11_data引脚约束到FPGA的普通IO口上并设置IO标准为3.3V LVTTL。DHT11的数据线必须外接4.7kΩ上拉电阻到VCC这一点在原理图设计时就要留好位置FPGA内部的上拉使能强度不够时序宽松度差很多。第三个是全局时钟约束。在SDC文件里声明系统时钟频率否则Quartus默认按1GHz约束综合器会疯狂插入冗余逻辑去满足不合理的时序条件导致布局布线资源膨胀。# dht11_pins.sdc 文件内容 create_clock -name clk -period 20.000 [get_ports {clk}] set_input_delay -clock clk -max 5 [get_ports {dht11_data}] set_output_delay -clock clk -max 5 [get_ports {dht11_data}]这里把时钟周期设为20ns对应50MHz主频。用set_input_delay和set_output_delay约束数据脚的延迟窗口是为了让Quartus在布线时可以估计IO引脚上的信号到达时间。如果不加这两个约束软件会默认用最保守的延迟模型时序分析结果可能显示大量红色路径但其实实际电路是正常的。3.5 Modelsim仿真验证方法与激励编写Quartus自带的Modelsim仿真流程是验证DHT11驱动的首选方式——上板调试时序问题耗时且难以观察信号仿真阶段可以把时间尺度放大到微秒级每一拍的跳变都能看得清清楚楚。仿真激励文件需要模拟DHT11从机的行为。简单做法是用延时语句控制总线方向按协议顺序回复起始信号、应答信号和40位数据。下面是核心激励代码// 测试激励: 模拟DHT11回传一帧完整数据(温度28°C湿度50%RH) reg dht11_master_io; assign dht11_data dht11_master_io ? 1bz : 1b0; // 等待起始信号结束 (posedge start_end); #20; // 应答低电平80us dht11_master_io 1b0; #80; dht11_master_io 1b1; #80; // 发送40位数据0x32 0x00 0x1C 0x00 0x4E for (i 0; i 40; i i 1) begin dht11_master_io 1b0; #50; // 每位数据起始的低电平50us dht11_master_io 1b1; if (data_byte[i/8][7 - (i%8)]) begin #70; // 逻辑1: 高电平持续70us end else begin #28; // 逻辑0: 高电平持续28us end end dht11_master_io 1b1;在仿真时建议把时间单位设置为1us关键控制信号用$display打印当前状态值。仿真通过后再进行板卡实测出现问题时用SignalTap II Logic Analyzer抓取真实的时序波形重点对比应答信号宽度和数据位高电平时间这两个指标与数据手册中的典型值是否一致。仿真测试平台文件中还有一点要特别注意复位结束后的初始状态必须有一个明确的DHT11从机初始化过程否则仿真刚开始时总线浮空模型会处于未定义状态。在激励文件的开头先把总线拉高至少20us模拟上电稳定再执行读时序。板级调试与常见问题的细致分析放在下一章展开。4. 上板调试DHT11读不出的常见原因与Quartus抓波形技巧4.1 硬件连接层面的三个典型错误FPGA开发板与DHT11模块的连接比大多数教程里描述的更容易出错。很多模块是3.3V供电但DHT11原厂手册推荐工作电压是3.3V到5.5V单独用3.3V供电在长线传输时会导致上拉能力不足、信号边沿变缓。典型错误之一是忘记接上拉电阻。FPGA开发板上的IO口不一定默认带内部上拉即使带了内部上拉的阻值通常在50kΩ左右而单总线协议推荐的外部上拉电阻是4.7kΩ到10kΩ。没有外部上拉时总线释放的上升沿时间会拉长到微秒级别高速采样下数据位边沿触发容易错位。典型错误之二是杜邦线过长。DHT11的通信速率虽然只有几十kbps但信号的跳变时间要求很严超过20cm的杜邦线加上杂散电容高电平宽度会被拉宽40位数据里随机出现误码。建议在原理图设计阶段就把传感器接口做成板载排针或者用双绞线走线尽量短。典型错误之三是电源地没有共地。独立供电的传感器模块和FPGA开发板如果不共地总线上的电平判断会莫名其妙出错故障表现为偶尔能读到数据但校验经常不过。用万用表量一下两边GND之间的压差超过0.3V就有问题。4.2 时序参数边界为什么数据手册的典型值不一定好用DHT11的数据手册上有明确的时序参数表但在不同温度、不同供电电压下同一颗传感器的高低电平宽度波动范围其实不小。具体到驱动代码的实现上有几个值得关注的参数余量问题起始信号长度适合留余量到20毫秒但同时不能超过30毫秒否则部分批次的DHT11会漏检。关于应答信号的检测时间窗在120微秒等待时间里如果依然没有检测到低电平就判超时这个窗口已经包含了20微秒左右的额外裕度。数据位的采样窗口最多只能有15微秒左右的余量。逻辑“0”的高电平持续时间典型值约26~28微秒逻辑“1”的约70微秒如果采样点在40微秒处两个状态之间留了约12微秒的安全距离。在传感器长期工作在高温高湿环境、信号退化的情况下12微秒已经不算充裕因此采样点不建议再向后移动否则会把“1”误判成“0”。在代码实现层面应对这种时基漂移的办法是调整采样点位置。把基线上采样点的计数参数单独提取成parameter在Quartus工程里修改一个值就能快速试验不同采样窗口下的稳定性。4.3 SignalTap II在线逻辑分析仪抓取真实总线波形当驱动代码在Modelsim里仿真通过、上板却读数不稳定时直接抓FPGA引脚上的真实现场波形比反复改代码烧录试错要有效得多。Quartus自带的SignalTap II就是这个用途的工具——它利用FPGA内部未使用的RAM资源搭建一个逻辑分析仪实时抓取内部信号和引脚电平。在Quartus里启动SignalTap的方法如下首先在菜单栏打开“Tools SignalTap II Logic Analyzer”然后在JTAG链配置里选择当前连接的FPGA器件。接着需要选择要观察的信号把顶层模块的state、dht11_data、cycle_cnt几个关键内部信号添加进去。有一点要注意dht11_data是inout类型SignalTap里要同时看读方向和写方向的值建议在顶层模块里把输入路径单独引出一根线。例如wire dht11_in; assign dht11_in dht11_data;把这根dht11_in接进SignalTap后才可以观察到真实的总线输入电平。采样时钟选择系统时钟的上升沿采样深度设置为2K样本即可满足单帧40位数据的抓取。触发条件设置为“起始信号的下降沿”也就是dht11_in发生高电平到低电平的跳变。一旦DHT11被驱动并开始通信SignalTap就会捕获从起始信号到40位数据的完整波形展开后能看得清清楚楚。4.4 工程中常见编译警告的解读与处理在Quartus编译DHT11驱动时经常会产生一些特定的warning需要弄清哪些是隐患、哪些可以忽略。如果看到“Inferred latch for reg state”这种警告说明状态机里有一个状态的分支没有覆盖所有条件路径。DHT11驱动里如果RESPONSE状态的处理少写了超时分支综合器就会推断出锁存器时序仿真表现正常但上板后状态跳转不稳定。这类警告必须消除——检查每个状态是否都有完整的if-else或case默认分支。如果看到“Output port dht11_data is not a register”的警告这通常是inout端口直接连接到连续赋值语句导致的。在三态驱动设计中输出路径从寄存器到引脚的正确写法是把寄存器输出接到三态缓冲器的使能端而不是直接驱动引脚。还有一类警告是“Timing requirements not met”这常常是SDC约束不完整导致的。在不加input_delay/output_delay约束的情况下Quartus默认IO时序裕量为零稍微复杂的组合逻辑就会报红灯。此时按照前面的SDC约束补全延迟信息重新布线通常能解决。编译通过后还有一个容易忽略的步骤用Quartus的“Assignment Editor”确认dht11_data引脚是否使用了正确的高速IO标准并检查引脚是否被分配到了与DHT11模块实际连接的FPGA物理管脚上。管脚错位是硬件故障现象中最隐蔽的一种——软件逻辑完全正常示波器在错误的位置上当然抓不到信号。5. 驱动性能进阶连续采样平滑处理与资源占用对比5.1 多次采样取均值与滑动窗口滤波的Verilog实现单次读取DHT11得到的数据抖动范围通常在±1%RH和±1°C以内但环境风速变化或传感器附近有人走动时瞬时值可能出现短暂的脉冲跳变。对采集结果做数字滤波是工程上必要的步骤常见的两种做法是多次采样取平均值以及滑动窗口滤波。多次采样取平均值的实现比较简单连续采集N次通常取4次或8次对每次得到的有效数据求和再除以采样次数。平均值能够有效削弱随机噪声但对突变异常值敏感——一次错误读数会把均值拉偏。在驱动代码里这种滤波的Verilog实现如下reg [31:0] humi_sum; reg [31:0] temp_sum; reg [2:0] sample_cnt; // 每次data_valid有效时累加 always (posedge clk or negedge rst_n) begin if (!rst_n) begin humi_sum 32d0; sample_cnt 3d0; end else if (data_valid) begin humi_sum humi_sum {24d0, humidity_int}; temp_sum temp_sum {24d0, temperature_int}; if (sample_cnt 3d7) begin // 输出8次平均结果 humidity_int humi_sum[10:3]; temperature_int temp_sum[10:3]; humi_sum 32d0; sample_cnt 3d0; end else begin sample_cnt sample_cnt 1b1; end end end代码说明右移3位等价于除以8用位截断代替除法器资源。累加器位宽设为32位即使连续8次累加也不会溢出。这里注意humi_sum[10:3]的截取方式——因为最终要得到8位整数结果从第3位开始截取就相当于除以8后取整数部分。滑动窗口滤波更适合对实时性要求高的场景。用一个长度为16的移位寄存器保存最近16次采样值每来一次新数据整体左移一位并丢弃最旧的数据然后计算当前窗口的和。与均值滤波相比滑动窗口输出延迟更短对突变响应更快但占用寄存器资源也相应增加。5.2 低温环境下DHT11时序漂移的补偿策略在0°C以下DHT11的RC振荡器频率会漂移数据位的高电平持续时间可能从标称的70微秒漂移到60微秒左右这时候原本的采样点可能已经落入误判区间。应对低温状况的工程做法有以下几种第一种是分段调整采样窗口。在驱动模块内预置两套不同参数通过一个外部温度选择端口手动切换。这个方案的缺点是需要人工干预不够自动。第二种是自适应采样点跟踪。逻辑上每次采样后记录高电平的宽度然后在一段时间内取这些宽度值的中间数作为动态采样位置。这个逻辑在FPGA上实现起来相对复杂但对多温度场景是有效的。第三种做法最常见也最简单放宽采样窗口的区间把“0”的高电平判定范围放宽到15~50微秒“1”判定范围放宽到50~90微秒用一个大范围比较器代替原来的边沿采样。在实际项目中如果工作温度范围没有明确要求用第三种策略就够了。数据手册上的标称参数并不是绝对的物理极限实际验证时用高低温箱跑一遍观察误码率随窗口宽度的变化曲线就能找到当前温度下的最优参数组合。5.3 与同类型项目横向对比FPGA驱动和MCU方案的取舍在思考用Verilog实现DHT11驱动的同时有两条替代路线也值得对比参考。其一是基于微控制器的DHT11驱动用STM32或者Arduino上的HAL库驱动代码更简短调试工具链也更成熟特别适合采集点分散、通信主控不统一的场景。其缺点是CPU需要频繁参与总线时序控制在同时处理以太网、屏幕刷新等任务时容易产生时序抖动。其二是用专用温湿度传感器芯片替代DHT11例如SHT30通过I2C接口通信FPGA侧只需实现一个最简单的I2C主设备状态机即可稳定读取温湿度。I2C接口的优势是多设备挂接、时序要求宽松缺点是需要额外引入一颗传感器成本略高。回到标题所指向的Verilog驱动方案本身FPGA直读DHT11适合教学实验和简单的单点采集场景但如果是做多点分布式环境监测系统使用FPGA在多个独立IO口上并行采集多颗DHT11或用I2C替换为SHT30进行设备级联都是升级方向。工程选型时没有唯一正确的方案核心依据是系统对时序确定性、成本、开发周期的综合需求。最后补充一个调试技巧在Quartus工程里把DHT11驱动模块做成独立子模块顶层用虚拟引脚(virtual pin)把内部采样窗口参数暴露出来运行时就可以在不重编译逻辑的情况下通过JTAG在线调整采样参数。这个方法可以大幅缩短时序参数调试的迭代周期在低温试验和量产导入阶段尤其实用。本文还有配套的精品资源点击获取
返回列表