当前位置: 首页 > news >正文

差分曼彻斯特编码这东西挺有意思的,每个比特中间必须跳变,数据本身由比特开始处有无跳变决定。今天咱们直接撸Verilog代码,看看怎么在硬件层面实现编解码

差分曼彻斯特编解码功能模块,纯verilog代码实现,有仿真环境和激励数据。

先看编码模块。核心逻辑是时钟周期划分和跳变控制:

module diff_man_encoder( input clk, input rst_n, input [7:0] data_in, input data_valid, output reg encoded_out ); reg [3:0] bit_counter; reg [7:0] shift_reg; reg last_level; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin shift_reg <= 8'd0; bit_counter <= 4'd8; encoded_out <= 1'b1; last_level <= 1'b1; end else if(data_valid) begin if(bit_counter == 4'd8) begin shift_reg <= data_in; bit_counter <= 4'd0; last_level <= encoded_out; end else begin // 中间跳变 encoded_out <= ~encoded_out; // 根据数据决定起始跳变 if(shift_reg[7] ^ last_level) begin last_level <= encoded_out; end else begin encoded_out <= ~encoded_out; last_level <= ~encoded_out; end shift_reg <= {shift_reg[6:0], 1'b0}; bit_counter <= bit_counter + 1; end end end endmodule

这段代码的精髓在状态机切换。注意last_level寄存器保存前一个电平状态,当前数据位与前电平异或结果为真时需要改变起始电平。每个比特周期强制中间跳变的设计,用简单的取反操作实现。

解码模块更有挑战性,得同时恢复时钟和数据:

module diff_man_decoder( input clk, input rst_n, input encoded_in, output reg [7:0] data_out, output reg data_ready ); reg [2:0] sync_window; reg [3:0] sample_cnt; reg [7:0] shift_reg; reg last_edge; // 跳变检测 wire edge_detected = (sync_window[2] ^ sync_window[1]); always @(posedge clk or negedge rst_n) begin if(!rst_n) begin sync_window <= 3'b111; sample_cnt <= 4'd0; shift_reg <= 8'd0; last_edge <= 1'b0; end else begin sync_window <= {sync_window[1:0], encoded_in}; if(edge_detected) begin // 时钟恢复逻辑 if(sample_cnt > 4'd3) begin // 提取数据位 shift_reg <= {shift_reg[6:0], ~last_edge}; sample_cnt <= 4'd0; end last_edge <= sample_cnt[3]; // 记录跳变位置 end sample_cnt <= (sample_cnt == 4'd7) ? 4'd0 : sample_cnt + 1; // 8位收集完成 data_ready <= (shift_reg[7] && sample_cnt == 4'd7); data_out <= shift_reg; end end endmodule

这个解码器的巧妙之处在于用syncwindow做跳变检测窗口,通过samplecnt实现过采样。重点注意时钟恢复逻辑——当检测到跳变时,根据采样计数值判断是中间跳变还是起始跳变,从而确定数据位值。

差分曼彻斯特编解码功能模块,纯verilog代码实现,有仿真环境和激励数据。

测试平台得模拟真实信号传输,这里用PRBS生成测试数据:

initial begin // 伪随机序列生成 reg [7:0] prbs = 8'hA5; for(int i=0; i<32; i++) begin prbs = {prbs[6:0], prbs[7] ^ prbs[5] ^ prbs[4] ^ prbs[2]}; test_data[i] = prbs; end // 编码器输入 foreach(test_data[i]) begin @(negedge clk); data_in = test_data[i]; data_valid = 1; @(negedge clk); data_valid = 0; repeat(16) @(negedge clk); // 等待编码完成 end end

验证环节需要对比原始数据和解码输出,这里用自动校验:

always @(posedge data_ready) begin if(test_data[packet_cnt] !== data_out) begin $error("Mismatch at packet %d", packet_cnt); end packet_cnt++; end

实际跑仿真时会发现,解码器对信号抖动有一定容忍度。当把编码输出通过非理想信道传输(比如添加毛刺)后,只要跳变沿检测窗口设置合理,依然能正确恢复数据。这种实现方式在工业现场总线通信中很常见,抗干扰能力比标准曼彻斯特编码更强。

有个调试小技巧:在仿真波形里同时观察编码输出信号的跳变沿位置和数据有效信号,可以快速定位是编码阶段还是解码阶段的问题。比如遇到连续0或1时,必须确保每个比特周期都有正确的跳变模式。

http://www.jsqmd.com/news/535157/

相关文章:

  • B2B行业实测:矩阵跃动小陌GEO助力询盘增长180%+,AI获客转化技术拆解
  • OpenClaw+GLM-4.7-Flash:个人健康管理助手
  • 工业上位机开发实战:基于.NET 6和CIP协议,5分钟搞定与ControlLogix PLC的数据对接
  • Halcon数组分析实战:5分钟搞定极值定位与可视化(附完整代码)
  • WVP-GB28181-Pro技术深度解析:国标视频监控平台的架构演进与行业价值重塑
  • NumPy 函数手册:条件筛选与逻辑运算
  • OpenClaw的安全反思——如果你跟OpenClaw说“我讨厌我老婆”,一分钟后它告诉你“我已经把她干掉了”,你是什么心情?
  • C++开发者必看:nlohmann::json实战避坑指南(含性能优化技巧)
  • 7×24小时无人值守:矩阵跃动龙虾机器人+GEO,AI流量闭环效率实测报告
  • 解决提示词「卡壳」难题:架构师的3个创新实践破解法
  • 云原生架构设计:新手入门的核心原则
  • 5个步骤掌握TinyMaix:从环境搭建到边缘部署
  • 嵌入式系统调试技术全解析:从SRAM到SWO
  • NetMount:跨平台云存储高效管理解决方案
  • 20252912 2024-2025-2 《网络攻防实践》实验三
  • STM32F746NG按键管理库:轻量级C++状态机设计
  • InSAR处理软件与时间序列分析工具:从商业到开源的全方位指南
  • 【学术写作利器】Academic Phrasebank:从零开始掌握论文核心段落写作
  • 避开KEIL调试大坑:从printf重定向到MicroLIB选择的完整避坑指南
  • RDMA 与RoCE v2
  • Crowbar:赋能创作者的开源游戏开发效率工具
  • 嵌入式硬件脉冲计数器:高精度零丢脉冲实现原理与跨平台实践
  • MinIO桶里文件太多,list_objects卡死?试试这个‘目录管家’方案(附SpringBoot代码)
  • Java 字符串三剑客:String、StringBuilder 与 StringBuffer 深度解析与选型指南
  • 管道导波检测进阶:如何用Comsol优化裂纹识别精度(含最新信号处理方法)
  • 2026-03-25 闲话
  • 超越基础:用rqt_plot+Python脚本实现ROS传感器数据持久化分析
  • C++与SolidWorks二次开发实战:从零绘制基础几何体
  • QoS实战:从原理到企业网络优化配置
  • 手把手教你设计反相输入有源低通滤波器(附Multisim仿真文件)