ego1开发板大作业vivado实践指南:温度传感器数据采集系统

从零构建温度采集系统:Ego1开发板实战全解析

最近带学生做FPGA大作业,发现很多人卡在“温度传感器数据采集”这个项目上。其实这看似复杂的系统,拆解开来不过就是信号怎么来、数据怎么传、结果怎么用三个问题。

今天我就以Xilinx Ego1开发板为平台,带你完整走一遍基于Vivado的温度采集系统设计流程——不讲空话,只说实战中真正踩过的坑和验证有效的解法。


为什么选TMP102?不是所有传感器都适合FPGA新手

项目第一步永远是选型。面对热敏电阻、DS18B20、LM35、TMP102一堆选项,我为什么推荐TMP102?

因为对FPGA初学者来说,数字接口 > 模拟接口,标准协议 > 私有协议

  • 热敏电阻需要外接ADC + 校准曲线拟合,直接劝退;
  • DS18B20虽然也是数字输出,但用的是单总线(1-Wire),时序极其严格,一个周期差几纳秒就丢包;
  • TMP102走I²C,两根线、有规范、速率稳定,哪怕你代码写得糙一点,只要主循环够快,基本都能通。

更重要的是:它不需要外部元件。你在面包板上插个芯片,接两个4.7kΩ上拉电阻到3.3V,SCL/SDA连到FPGA引脚,就能通信。这对调试太友好了。

它的关键参数你也得记住:

参数数值
地址(默认)0x48
分辨率12位(0.0625°C/LSB)
测温范围-55°C ~ +128°C
接口速率支持100kHz / 400kHz

这些数字会直接影响你的状态机设计和数据处理逻辑。


FPGA如何“假装”是一个I²C主机?手把手教你写软核驱动

Artix-7没有硬核I²C控制器,所以我们必须“模拟”出整个协议过程——这就是所谓的Bit-Banging

别被术语吓到,其实就是让FPGA按顺序控制SCL和SDA的电平变化,模仿出起始条件、地址传输、应答检测等动作。

关键挑战:时序精度

I²C协议要求:
- 起始条件:SCL高时,SDA由高变低;
- 数据稳定期:SCL为高时,SDA不能变;
- 数据采样点:SCL下降沿写入,上升沿读取。

如果你用50MHz系统时钟(周期20ns),要生成100kHz的SCL(周期10μs),那每个SCL高低电平至少要维持50个时钟周期。

所以第一步:先做一个分频器

localparam CLK_DIV = 50_000_000 / (4 * 100_000) - 1; // ≈124 reg [7:0] clk_cnt; reg i2c_clk; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_cnt <= 0; i2c_clk <= 0; end else if (clk_cnt >= CLK_DIV) begin clk_cnt <= 0; i2c_clk <= ~i2c_clk; end else begin clk_cnt <= clk_cnt + 1; end end

这里我们把SCL分成四段,每段约2.5μs,这样可以在中间点进行数据切换和采样,避开边沿抖动区。

💡 小技巧:实际设计中建议使用三段式状态机,并在SCL低电平时更新SDA,在SCL高电平时采样SDA,避免违反“数据必须在SCL高期间保持稳定”的规定。

状态机才是核心:一步步发指令读数据

下面是简化版的状态流转图:

IDLE → START → 发送设备地址+写 → 等ACK → 发寄存器地址 → 等ACK → RESTART → 发设备地址+读 → 等ACK → 连续读2字节 → NACK → STOP

对应Verilog中的枚举类型:

typedef enum logic [3:0] { IDLE, START, ADDR_WR, WAIT_ACK1, REG_PTR, WAIT_ACK2, RESTART, ADDR_RD, WAIT_ACK3, READ_MSB, READ_LSB, SEND_NACK, STOP, DONE } i2c_state_t;

重点在于:每一个状态只做一件事,比如“发送一位地址”或“等待ACK”,而不是在一个状态里塞进多个操作。

双向IO怎么处理?inout端口的经典玩法

SDA是双向引脚,作为主机时既要能输出命令,又要能接收从机返回的ACK/NACK。

解决方法是引入三态控制:

inout sda; reg sda_out; reg sda_en; // 1=输出模式,0=输入模式(高阻) assign sda = sda_en ? sda_out : 1'bz;

当你要发送数据时,sda_en=1sda_out赋值;当你想读ACK时,设sda_en=0,然后读sda引脚的真实电平。

⚠️ 坑点提醒:一定要确保在释放SDA前,其他设备没有同时驱动!否则可能造成短路。


数据拿到之后怎么办?别忘了符号扩展!

TMP102返回的是16位数据,格式如下:

bit[15:12]: 温度整数部分(补码) bit[11:8]: 小数部分(0.0625°C步长) bit[7:0]: 保留(读出来可能是随机值)

例如收到16'h8080,你以为是正数?错!最高位是1,说明是负温度。

正确解析方式:

wire signed [15:0] raw = {rx_data[15], rx_data[15], rx_data[15], rx_data[15], rx_data[15:4]}; // 扩展成完整补码 wire [15:0] abs_val = (raw[15]) ? (~raw + 1) : raw; real temp_c = $itor(abs_val) * 0.0625; if (raw[15]) temp_c = -temp_c;

当然,你也可以在纯逻辑中用组合逻辑判断符号位并取反加一,但要注意延迟匹配。


更高级玩法:MicroBlaze + AXI 让开发效率翻倍

如果你已经掌握了纯逻辑设计,下一步可以尝试加入MicroBlaze 软核处理器,把复杂的数据处理交给C语言来做。

为什么这么做?

想想看:你现在要用数码管显示温度,还要支持小数点闪烁、负号显示、单位标注……这些逻辑用Verilog写起来又臭又长。

但如果有一个CPU呢?

你可以:
- 写一段C代码格式化字符串;
- 通过UART打印到电脑;
- 或者调用LCD驱动库直接显示;
- 甚至加个按键实现“切换摄氏/华氏”。

这一切只需要在Vivado里添加一个MicroBlaze IP核,再配一个AXI GPIO或自定义AXI Lite外设即可。

如何连接你的I²C模块?

最简单的办法:把你原来的temp_data输出接到一个只读寄存器上,然后把这个寄存器挂到AXI总线上。

在SDK中就可以这样访问:

uint16_t raw = Xil_In16(XPAR_TEMP_SENSOR_0_BASEADDR); float temp = (int16_t)(raw >> 4) * 0.0625f; xil_printf("Temp: %.2f°C\n", temp);

是不是瞬间清爽了?

而且一旦出了问题,你可以打printf调试,不像纯逻辑只能靠ILA抓波形。

✅ 实战建议:前期先用纯逻辑验证I²C通信是否正常;后期迁移到MicroBlaze提升交互能力。


实际搭建时最容易翻车的几个点

别以为仿真过了就能跑通,现场调试才是真考验。

1. 上拉电阻没接 or 阻值不对

I²C是开漏输出,必须外加上拉电阻!常见的错误包括:
- 忘记接;
- 接成10kΩ导致上升沿太慢(超过300ns);
- 只给SCL加上拉,SDA没接。

标准做法:SCL和SDA各接一个4.7kΩ3.3V电源

2. 引脚约束写错电压标准

Ego1开发板使用LVCMOS33电平。如果你在XDC文件里写成了LVCMOS25,轻则通信不稳定,重则烧IO。

正确的约束示例:

set_property PACKAGE_PIN "P14" [get_ports i2c_scl] set_property IOSTANDARD LVCMOS33 [get_ports i2c_scl] set_property PACKAGE_PIN "P15" [get_ports i2c_sda] set_property IOSTANDARD LVCMOS33 [get_ports i2c_sda]

3. 时钟分频算错,导致速率超标

有人直接拿50MHz除以100k得到500,然后计数到500翻转SCL——这是错的!

因为你每个状态至少占一个时钟周期,而SCL一个完整周期需要两次翻转(高→低→高),所以实际频率是clk_freq / (2 * count)

更安全的做法是:宁可慢一点,也不要超限。跑50kHz也能读数据,但跑500kHz可能直接失败。

4. 多次读取之间没有延时

TMP102内部转换需要时间(典型35ms)。如果你连续发起读操作,很可能拿到旧数据。

解决方案:
- 在状态机里加一个“delay”状态,持续若干毫秒;
- 或者查手册启用“one-shot”模式,每次触发才采样。


如何快速定位问题?ILA是你最好的朋友

Integrated Logic Analyzer(ILA)是Vivado内置的在线逻辑分析仪,能把FPGA内部信号实时抓出来看。

建议你至少监控这几组信号:
-scl,sda:观察实际波形是否符合I²C协议;
-curr_state:确认状态机有没有卡住;
-rx_data,done:检查数据是否正确接收。

设置触发条件也很关键:
- 触发条件设为start == 1
- 捕获深度设为1024点以上;
- 采样时钟选比I²C快至少4倍的时钟。

你会发现,很多时候你以为SDA拉低了,实际上因为竞争条件根本没生效。


最后一点思考:这个项目到底教会了我们什么?

完成一次温度采集,远不止“读个数”那么简单。

它让你亲手实践了:
-硬件描述语言的真实用途:不是写代码,而是“描述电路行为”;
-跨时钟域的基本意识:高速逻辑如何与低速外设握手;
-软硬件分工的设计思维:哪些该用逻辑实现,哪些交给软件更高效;
-从仿真到实物的鸿沟跨越:理论再完美,不上电就不知道哪里漏了上拉。

而这,正是现代嵌入式系统工程师的核心能力。


未来你可以在这个基础上继续拓展:
- 加一个PWM风扇,做成闭环温控;
- 接Pmod WIFI,把温度上传云端;
- 用BRAM缓存历史数据,画趋势图;
- 甚至部署轻量级神经网络做异常检测。

但所有这一切,都要从你第一次成功读出那个0x0080开始。

所以,现在就打开Vivado,新建工程吧。
遇到问题别怕,评论区见。

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

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

相关文章

Unity渲染排序:谁先画谁后画的底层逻辑

你打开 Unity,往场景里一顿猛拉: 地板、墙、树、石头 主角、怪物、NPC 粒子特效、雾、UI、血条…… 按理说,这么多东西,GPU 要是“随缘画”,早就乱成一锅粥: 有的本该挡住别人,结果被画在后面 透明玻璃盖不住后面的景 UI 时有时无 再加上性能雪崩:切换材质、切换 Shade…

SpringBoot+Vue 教学资源库平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价。我就是个在校研究生&#xff0c;兼职赚点饭钱贴补生活费&…

2026-01-11 全国各地响应最快的 BT Tracker 服务器(电信版)

数据来源&#xff1a;https://bt.me88.top 序号Tracker 服务器地域网络响应(毫秒)1udp://60.249.37.20:6969/announce广东东莞电信332http://43.250.54.137:6969/announce天津电信1393udp://209.141.59.25:6969/announce上海电信1424udp://152.53.152.105:54123/announce北京电…

新手必看:Multisim元件库下载入门教程

新手避坑指南&#xff1a;如何真正搞定 Multisim 元件库下载&#xff1f; 你是不是也遇到过这种情况—— 满心欢喜打开 Multisim 准备仿真一个经典电路&#xff0c;结果在“放置元件”对话框里翻了半天&#xff0c;就是找不到你手里那颗关键芯片&#xff1f;比如 TI 的 OPA21…

Proteus示波器多通道同步显示配置指南

用好Proteus示波器&#xff0c;让多路信号“对齐说话”在电子系统调试中&#xff0c;最怕的不是信号出不来&#xff0c;而是信号都出来了却看不懂时序关系。比如你设计了一个H桥驱动电路&#xff0c;四个MOSFET的栅极波形都在跳&#xff0c;但上下桥臂有没有“打架”&#xff1…

51单片机多个LED灯轮流点亮操作实例

51单片机玩转流水灯&#xff1a;从点亮第一盏LED到掌握嵌入式时序控制的全过程你有没有试过&#xff0c;把一块51单片机接上电源&#xff0c;写几行代码&#xff0c;让一个小灯亮起来&#xff1f;那一刻的感觉&#xff0c;就像第一次按下开关&#xff0c;看见世界被点亮。而当你…

从零实现Keil正确配置toolkit路径

如何一劳永逸解决 Keil 的c9511e编译器路径错误&#xff1f;——深入剖析 ARM 工具链配置的本质你有没有在打开一个旧项目、换了一台新电脑&#xff0c;或者刚装完 Keil 后&#xff0c;点击“编译”按钮却只看到这样一行红字&#xff1a;error: c9511e: unable to determine th…

解决Keil芯片包不识别Cortex-M设备的问题:深度剖析

解决Keil芯片包不识别Cortex-M设备的问题&#xff1a;从原理到实战的完整指南 你有没有遇到过这样的场景&#xff1f;打开Keil Vision&#xff0c;信心满满地准备新建一个基于STM32F407或NXP K66的工程&#xff0c;点击“Select Device for Target”——结果熟悉的MCU型号却 …

Day 09:【99天精通Python】字典与集合 - 键值对与去重利器

Day 09&#xff1a;【99天精通Python】字典与集合 - 键值对与去重利器 前言 欢迎来到第9天&#xff01; 在之前的学习中&#xff0c;我们使用了列表和元组来存储有序的数据序列。但是&#xff0c;如果我们想要存储"姓名"对应的"电话号码"&#xff0c;或者&…

软件I2C总线空闲状态判断逻辑:快速理解

软件I2C总线空闲状态判断&#xff1a;从原理到实战的深度拆解你有没有遇到过这样的情况&#xff1f;明明代码逻辑写得清清楚楚&#xff0c;可I2C通信就是“时好时坏”——有时候能读到传感器数据&#xff0c;有时候却连设备都找不到。调试半天发现&#xff0c;并不是地址错了&a…

Mybatis:关联映射

一、创建表结构1.学生表SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS student; CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT,Sname …

嘉立创EDA画PCB教程:STM32最小系统设计完整指南

从零开始打造STM32最小系统&#xff1a;嘉立创EDA实战全记录你是不是也曾在搜索“嘉立创eda画pcb教程”时&#xff0c;翻遍资料却仍被一堆术语绕晕&#xff1f;电源不稳、晶振不起、程序下不进去……明明照着电路连的&#xff0c;为什么就是跑不起来&#xff1f;别急。今天我们…

Keil与Proteus联调方法:零基础小白指南

Keil 与 Proteus 联调实战&#xff1a;从零开始搭建虚拟单片机实验室你是否曾因为没有开发板而无法完成单片机作业&#xff1f;是否在调试代码时&#xff0c;对着不亮的 LED 束手无策&#xff0c;却不知是程序写错了还是电路接反了&#xff1f;别担心——Keil 与 Proteus 联调&…

操作指南:利用波特图优化频率响应性能

用波特图“把脉”电路&#xff1a;手把手教你优化频率响应&#xff0c;让系统稳如泰山你有没有遇到过这样的情况&#xff1f;一个电源样机焊好了&#xff0c;输入输出电压都没问题&#xff0c;可一加负载&#xff0c;输出就开始“抽搐”——电压不停振荡&#xff0c;示波器上波…

嵌入式环境下堆溢出导致crash的系统学习

堆溢出为何让嵌入式系统“猝死”&#xff1f;一次 HardFault 背后的真相你有没有遇到过这样的场景&#xff1a;设备在实验室跑得好好的&#xff0c;一到现场却隔三差五重启&#xff1b;调试器抓到的调用栈停在free()里&#xff0c;但代码里明明没写错&#xff1b;翻遍逻辑也找不…

STM32CubeMX教程中SDIO接口初始化项目应用

用STM32CubeMX搞定SDIO&#xff1a;从配置到文件系统的实战全解析在嵌入式开发中&#xff0c;存储大容量数据早已不是“加分项”&#xff0c;而是许多项目的硬性需求。无论是工业设备的日志记录、医疗仪器的采样存储&#xff0c;还是音视频终端的缓存处理&#xff0c;都需要稳定…

⚡_实时系统性能优化:从毫秒到微秒的突破[20260110173735]

作为一名专注于实时系统性能优化的工程师&#xff0c;我在过去的项目中积累了丰富的低延迟优化经验。实时系统对性能的要求极其严格&#xff0c;任何微小的延迟都可能影响系统的正确性和用户体验。今天我要分享的是在实时系统中实现从毫秒到微秒级性能突破的实战经验。 &#…

ModbusTCP协议详解实时性优化在STM32上的实践

ModbusTCP协议详解&#xff1a;在STM32上实现高实时性通信的工程实践工业现场&#xff0c;时间就是控制命脉。一个典型的场景是&#xff1a;主控PLC通过以太网向远程I/O模块读取传感器状态&#xff0c;若响应延迟超过5ms&#xff0c;整个运动控制环路就可能失稳。而当你打开Wir…

REINFORCE 算法

摘要&#xff1a;REINFORCE算法是一种基于蒙特卡洛的策略梯度强化学习方法&#xff0c;由Williams于1992年提出。该算法通过采样完整情节轨迹&#xff0c;计算回报梯度并更新策略参数来优化智能体决策。其优势在于无需环境模型、实现简单且能处理高维动作空间&#xff0c;但存在…

Linux 运维:删除大日志文件时避免磁盘 IO 飙升,echo 空文件 vs truncate 命令对比实操

作为一名摸爬滚打11年的老运维&#xff0c;我踩过无数次“删大日志搞崩服务器”的坑。凌晨4点&#xff0c;监控告警疯狂刷屏&#xff1a;磁盘 IO 使用率 100%&#xff01;业务响应超时&#xff01;排查后发现&#xff0c;是同事直接 rm -rf 了一个 80G 的 Nginx 访问日志——瞬…