本文主要是介绍京微齐力:基于H7的曼彻斯特(编码解码串口)系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 前言
- 一、关于曼彻斯特编码
- 二、任务&实验效果
- 三、硬件选择
- 1、H7P20N0L176-M2H1
- 2、XC7A35TFGG484-2
- 四、程序设计
- 1、顶层模块
- 2、编码&发送模块
- 3、解码&接收模块
- 4、HC595驱动模块
- 5、段选&位选模块
- 五、debugware 回环实验
- 六、兼容设计
- 七、工程获取
前言
四月到现在一直比较忙,有一段时间没有做京微齐力器件的开发了,本次做一个新器件H7的曼彻斯特(编码&解码&通信)系统。
一、关于曼彻斯特编码
曼彻斯特编码(Manchester coding),又称自同步码、相位编码(phase encoding,PE),能够用信号的变化来保持发送设备和接收设备之间的同步。值得一提的是,曼彻斯特编码有两种截然相反的约定:
它用电压的变化来分辨0和1,从高电平到低电平的跳变代表1,而从低电平到高电平的跳变代表0(G.E.Tomas编码方式)。
从高电平到低电平的跳变代表0,而从低电平到高电平的跳变代表1(IEEE 802.3编码方式),信号的保持不会超过一个比特位的时间间隔。即使是0或1的序列,信号也将在每个时间间隔的中间发生跳变。这种跳变将允许接收设备的时钟与发送设备的时钟保持一致。
两种曼彻斯特编码:
优点:
与NRZ相比,曼彻斯特编码提供一种同步机制,保证发送端与接收端信号同步。
缺点:
曼彻斯特编码的频率要比NRZ高一倍,传输等量数据所需的带宽大一倍。
编码:
曼彻斯特编码是将时钟和数据包含在信号流中,在传输代码信息的同时,也将时钟同步信号一起传输到对方。曼彻斯特码是用“01”和“10”来表示普通二进制数据中的“1””和“0”的,因此在实际电路设计中,我们可以用采一个2选1数字选择器来完成此项功能。(IEEE 802.3编码方式)
解码:
曼彻斯特译码电路设计的目的,是如何准确地从曼彻斯特码的码流中提取出“10”和“01”信号,并将其转换成普通二进制编码中的“0”和“1”。
在实际设计电路中,可以采用一个缓存器,保存上一个时钟采集到的信号和当前时钟采集到的信号,当缓存器的内容是“01”时,输出“1”;当缓存器的内容是“10”时,输出“0”;当缓存器的内容是“00”或“11”时,输出维持不变。
曼彻斯特编码在FPGA领域的运用比较广泛:
以太网:在以太网中,曼彻斯特编码被用来将数据转换为数字信号,并通过物理媒介(如同轴电缆或光纤)传输。
远程控制系统:在无线遥控器中,曼彻斯特编码被用来将指令编码并通过无线信道发送给接收器。
工业自动化系统:在工业自动化系统中,曼彻斯特编码被用来将传感器测量值、控制信号等转换为数字信号,并通过数据总线传输。
汽车电子系统:在汽车电子系统中,曼彻斯特编码被用来将控制信号、传感器信号等转换为数字信号,并通过汽车网络传输。
曼彻斯特编码的时钟线与数据线结合一体,同步性高,错误检测性能好,去年在接触屏显项目的时候,便是用到了这一编码。
二、任务&实验效果
1、用两块FPGA开发板设计一个曼彻斯特码编码和解码系统;
2、第1块板负责在按键后将拨码开关拨出的8位二进制码用曼彻斯特码发出;
3、第2块板负责在收到曼彻斯特码号将其解析并在数码管上显示。两块板记得共地。(也可以用debugware进行波形读取)
进入正文前,先看实验效果:
京微齐力:基于H7的曼彻斯特(编码&解码&串口)系统
可以看到,H7端按下发送键后,第二块开发板,接收到信号并进行解码,结果(1111_0000)显示在8位数码管上。(具体过程请看程序解析)
三、硬件选择
1、H7P20N0L176-M2H1
本次实验使用H7作为主控板,HME-H7系列采用低功耗22nm 技术,集成了高性能ARM Cortex-M3 MCU(频率高达300M)、外围设备与大容量片上SRAM。本次实验只使用逻辑部分,后面根据需要再扩展MCU实验。
H7具有12K的6输入查找表,1个OSC(80Mhz片内振荡器),128 个 10x10 DSP模块,18个32Kx32 位 SRAM,拥有多个封装,能够兼容Altera的EP4CE10和Xilinx Spartan-6,适用于伺候电机、图像处理及通信网络等多种场景。
2、XC7A35TFGG484-2
因为H7板卡没有数码管,这里借助一块Spartan-7板卡展示实验效果。(如果没有多余板载数码管的开发板,可以使用FUXI软件的debugware IP进行波形观看)
四、程序设计
1、顶层模块
本模块,实现的是H7对tx_data(8’b11110000)进行编码,按下按键(tx_en_n)后,会以UART的方式发送数据到第2块开发板 (这里模拟一个通信的效果,如果有Lora模块的同学,可以接上模块,这样就实现了无线通信)。关于编码部分,原本是计划使用拨码开关来模拟需要发送的8bit数据,但是板卡没有拨码开关,这里例化的时候,直接对端口进行赋值。程序里仍保留了拨码开关接口,有需要的同学,可以自行例化。
//**************************************** Message ***********************************//
//技术交流:bumianzhe@126.com
//关注CSDN博主:“千歌叹尽执夏”
//Author: 千歌叹尽执夏
//All rights reserved
//----------------------------------------------------------------------------------------
// Target Devices: H7P20N0L176-M2H1
// Tool Versions: Fuxi 2023.1
// File name: hme_manchester
// Last modified Date: 2023年6月27日20:00:00
// Last Version: V1.1
// Descriptions: 曼彻斯特解码&编码&串口
//----------------------------------------------------------------------------------------
//****************************************************************************************//module hme_manchester(input sys_clk, //高频时钟,可以是50MHz,本次入20MHzinput rst_n,input rx_d, //接收到的bit数据(本实验支持回环)output tx_d, //将tx_data进行编码并以串口方式发送出去//发送使能input tx_en_n,//发送使能,使用按键控制input [7:0] tx_data,//发送的8bits数据,拨码开关控制output sh_cp, //串行数据输出output st_cp, //移位寄存器的时钟输出output ds //存储寄存器的时钟输出
);wire [7:0] rx_data;
wire rx_valid;
reg [7:0] rx_data_dis; //最终显示的接收数据
wire [7:0] sel; //数码管位选(选择当前要显示的数码管)
wire [6:0] seg; //数码管段选(当前要显示的内容)pll_v1 u_pll_v1(.clkin0 (sys_clk), //输入20MHz时钟.locked (),.clkout0 (clk) //输出50MHz时钟
);manchester_tx u_manchester_tx_0(.clk(clk), //高频时钟,可以是50MHz.rst_n(rst_n),//.tx_data(tx_data), //待发送的字节数据.tx_data(8'b11110000), //由于板卡上没有拨码开关,这里直接输入数据进行模拟.tx_en(!tx_en_n), //发送使能.tx_ready(),.tx_d(tx_d));
//如果没有两块板卡的,可以将manchester_tx的tx_d信号接到manchester_rx的rx_d
//形成回环实验,并利用debugware进行数据查看。
manchester_rx u_manchester_rx_0(.clk(clk), //高频时钟,可以是50MHz.rst_n(rst_n),.rx_d(rx_d), //接收到的bit数据//.rx_d(tx_d), //回环实验.rx_data(rx_data),.rx_valid(rx_valid));always@(posedge clk or negedge rst_n)
begin
if(!rst_n)rx_data_dis <= 8'd0;
elserx_data_dis <= rx_valid?rx_data:rx_data_dis;
endHC595_driver u_HC595_driver(.clk(clk),.reset_n(rst_n),.data({1'd0,seg,sel}),.s_en(1'b1),.sh_cp(sh_cp),.st_cp(st_cp),.ds(ds));Hex8 u_Hex8(.clk(clk),.reset_n(rst_n),.en(1'b1),.disp_data({3'd0,rx_data_dis[7],3'd0,rx_data_dis[6],3'd0,rx_data_dis[5],3'd0,rx_data_dis[4],3'd0,rx_data_dis[3],3'd0,rx_data_dis[2],3'd0,rx_data_dis[1],3'd0,rx_data_dis[0]}),.sel(sel),.seg(seg));
//使用debugware查看编码&解码波形
debugware_v2_1 u_debugware_v2_1(.trig_out_0 (),.data_in_0 ({tx_en_n,tx_d,rx_data}),.ref_clk_0 (clk)
);endmodule
2、编码&发送模块
本模块,对需要发送的8bit数据进行曼彻斯特编码,并以串口的方式发送出去(波特率9600)。
首先,当复位信号 rst_n 为低电平时,将会执行 if(rst_n==1’b0) 语句中的代码,对该模块中的所有寄存器进行初始化。
接着,在每一个时钟周期的上升沿,如果时钟倍频使能信号clk_bps_en 为真,则将执行 case(state) 语句中当前状态下对应的代码。
当状态机处于 IDLE 状态时,如果 tx_en 为真,则需要开始发送数据。此时,需要将状态切换为 TXS,将要发送的数据写入 tx_data_reg,设置 tx_ready_r 为低电平,并将 tx_cnt 设置为 0。
当状态机处于 TXS 状态时,需要根据已经发送的数据字节数 tx_cnt 来进行数据编码,同时更新 tx_ready_r、tx_d_r 和 tx_data_reg 的值。
具体编码过程如下:
当 tx_cnt 为 0 时,需要发送两个高电平(1bit数据编制成2bit数据)。当 tx_cnt 的值在 [1, 8] 之间时,需要按照 Manchester 编码方式编码数据并发送出去。
具体操作如下:
根据 tx_data_reg 的最高位来计算当前发送的是 01 还是 10。如果最高位为 1,则当前发送的是 01,否则当前发送的是 10。对于 tx_cnt 中的每一位(从右往左数),如果是 0,则发送的是 10,否则发送的是 01。
将 tx_data_reg 向左移动一位,为下一次计算做准备。
当 tx_cnt 的值大于 8 时,需要发送一个低电平,因此将 tx_d_r 设置为低电平。
如果 tx_cnt 达到了指定长度(这里是 19),则需要重新将状态切换为 IDLE,设置 tx_ready_r 为高电平,并将 tx_cnt 设置为 0。
//**************************************** Message ***********************************//
//技术交流:bumianzhe@126.com
//关注CSDN博主:“千歌叹尽执夏”
//Author: 千歌叹尽执夏
//All rights reserved
//----------------------------------------------------------------------------------------
// Target Devices: H7P20N0L176-M2H1
// Tool Versions: Fuxi 2023.1
// File name: manchester_tx
// Last modified Date: 2023年6月17日9:00:00
// Last Version: V1.1
// Descriptions: 编码&发送模块模块
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module manchester_tx(input clk, //高频时钟,可以是50MHzinput rst_n,input [7:0] tx_data,//待发送的字节数据input tx_en, //发送使能output tx_ready,output tx_d);parameter IDLE = 1'b0;//空闲状态parameter TXS = 1'b1;//发送状态reg tx_ready_r;reg tx_d_r;reg state;reg [4:0] tx_cnt;//发送的bits计数器reg [7:0] tx_data_reg;wire clk_bps_en;assign tx_ready = tx_ready_r;assign tx_d = tx_d_r;precise_divider//分频模块#(//DEVIDE_CNT = 85.89934592 * fo @50M//DEVIDE_CNT = 42.94967296 * fo @100M.DEVIDE_CNT(32'd1649267) //9600Hz * 2)u_precise_divider_0(//global clock.clk(clk),.rst_n(rst_n),//user interface//.divide_clk().divide_clken(clk_bps_en));always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)beginstate <= IDLE;tx_ready_r <= 1'b1;tx_d_r <= 1'b0;tx_data_reg <= 8'd0;tx_cnt <= 5'd0;endelse if(clk_bps_en)begincase(state)IDLE:beginstate <= tx_en?TXS:IDLE;tx_data_reg <= tx_en?tx_data:tx_data_reg;tx_ready_r <= tx_en?1'b0:1'b1;tx_cnt <= 5'd0;endTXS:begintx_cnt <= (tx_cnt >= 5'd19)?5'd0:tx_cnt+1'b1;state <= (tx_cnt >= 5'd19)?IDLE:TXS;tx_ready_r <= (tx_cnt >= 5'd19)?1'b1:1'b0;if(tx_cnt[4:1] == 4'd0)tx_d_r <= 1'b1;//发2个高电平else if(tx_cnt[4:1] <= 4'd8)begin//如果tx_data_reg[7]的值为1,则将tx_cnt[0]的值赋给tx_d_r;//否则将tx_cnt[0]的逻辑反值(即0变成1,1变成0)赋给tx_d_r。tx_d_r <= tx_data_reg[7]?tx_cnt[0]:!tx_cnt[0];//1--01 0--10tx_data_reg <= tx_cnt[0]?(tx_data_reg<<1):tx_data_reg;endelse begintx_d_r <= 1'b0;endendendcaseendend
endmodule
3、解码&接收模块
接收到的串行数据进行解串行化,然后进行解码。
解码与编码原理差不多,这里不做赘述。
//**************************************** Message ***********************************//
//技术交流:bumianzhe@126.com
//关注CSDN博主:“千歌叹尽执夏”
//Author: 千歌叹尽执夏
//All rights reserved
//----------------------------------------------------------------------------------------
// Target Devices: H7P20N0L176-M2H1
// Tool Versions: Fuxi 2023.1
// File name: manchester_rx
// Last modified Date: 2023年6月18日15:00:00
// Last Version: V1.1
// Descriptions: 解码&接收模块
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module manchester_rx(input clk, //高频时钟,可以是50MHzinput rst_n,input rx_d, //接收到的bit数据output [7:0] rx_data,output rx_valid
);parameter IDLE = 1'b0;//空闲状态parameter RXS = 1'b1;//接收状态reg state;reg rx_valid_r0,rx_valid_r;reg [15:0] rx_data_reg;//缓存16bits的rx数据,每2bits代表1bit数据//01:1 10:0reg [7:0] rx_data_r;wire [7:0] rx_data_w;wire clk_bps_en;reg [3:0] rx_cnt;//对16倍波特率的时钟计数reg [3:0] byte_cnt;//对已接收的字节计数assign rx_data = rx_data_r;assign rx_valid = rx_valid_r;//将一组长度为16的串行数据rx_data_reg转换成一组长度为8的并行数据rx_data_w,//即将接收到的串行数据进行解串行化。generategenvar i;for(i=0;i<8;i=i+1) begin:u1assign rx_data_w[i] = !rx_data_reg[i*2+1] && rx_data_reg[i*2];endendgenerateprecise_divider//分频模块#(//DEVIDE_CNT = 85.89934592 * fo @50M//DEVIDE_CNT = 42.94967296 * fo @100M.DEVIDE_CNT(32'd13194139) //9600Hz * 16)u_precise_divider_0(//global clock.clk(clk),.rst_n(rst_n),//user interface//.divide_clk().divide_clken(clk_bps_en));always@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)beginrx_data_r <= 8'd0;rx_valid_r <= 1'b0;endelsebeginrx_data_r <= rx_data_w;rx_valid_r <= rx_valid_r0;endendalways@(posedge clk or negedge rst_n)beginif(rst_n == 1'b0)beginstate <= IDLE;rx_data_reg <= 16'd0;rx_cnt <= 4'd0;byte_cnt <= 4'd0;rx_valid_r0 <= 1'b0;endelse if(clk_bps_en)begin case(state)IDLE:beginrx_cnt <= rx_d?(rx_cnt >= 4'd10)?4'd0:rx_cnt+1'b1:4'd0;state <= (rx_cnt >= 4'd10)?RXS:IDLE;rx_data_reg <= 16'd0;byte_cnt <= 4'd0;rx_valid_r0 <= 1'b0;endRXS:beginrx_cnt <= (rx_cnt >= 4'd7)?4'd0:rx_cnt+1'b1;if(rx_cnt >= 4'd7)rx_data_reg <= {rx_data_reg[14:0],rx_d};else rx_data_reg <= rx_data_reg;byte_cnt <= (rx_cnt >= 4'd7)?byte_cnt+1'b1:byte_cnt;state <= ((rx_cnt >= 4'd7) && byte_cnt == 4'd15)?IDLE:RXS;rx_valid_r0 <= ((rx_cnt >= 4'd7) && byte_cnt == 4'd15);endendcaseendend
endmodule
4、HC595驱动模块
第二块板卡的电路设计用到了芯片 74HC595,该芯片的作用是移位寄存器,通过移位的方式,节省 FPGA 的管脚。FPGA 只需要输出 3 个管脚,即可达到发送数码管数据的目的,与传统的选位选方式相比,大大节省了 IO 设计资源。(考虑到部分同学,只有普通的8段数码管模块,没有74HC595,在文末会添加传统的数码管驱动代码,方便大家做兼容设计)。
//**************************************** Message ***********************************//
//技术交流:bumianzhe@126.com
//关注CSDN博主:“千歌叹尽执夏”
//Author: 千歌叹尽执夏
//All rights reserved
//----------------------------------------------------------------------------------------
// Target Devices: H7P20N0L176-M2H1
// Tool Versions: Fuxi 2023.1
// File name: HC595_driver
// Last modified Date: 2023年6月11日20:00:00
// Last Version: V1.1
// Descriptions: 驱动HC595,发出数据和选通信号
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module HC595_driver(clk, reset_n,data,s_en,sh_cp,st_cp,ds
);input clk;input reset_n;input [15:0]data;input s_en;output reg sh_cp;output reg st_cp;output reg ds;assign reset=~reset_n;parameter CNT_MAX = 2;reg [15:0]r_data;always@(posedge clk)if(s_en)r_data <= data;reg [7:0]divider_cnt;//分频计数器;always@(posedge clk or posedge reset)if(reset)divider_cnt <= 0;else if(divider_cnt == CNT_MAX - 1'b1)divider_cnt <= 0;elsedivider_cnt <= divider_cnt + 1'b1;wire sck_plus;assign sck_plus = (divider_cnt == CNT_MAX - 1'b1);reg [5:0]SHCP_EDGE_CNT;always@(posedge clk or posedge reset)if(reset)SHCP_EDGE_CNT <= 0;else if(sck_plus)beginif(SHCP_EDGE_CNT == 6'd32)SHCP_EDGE_CNT <= 0;elseSHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;endelseSHCP_EDGE_CNT <= SHCP_EDGE_CNT;always@(posedge clk or posedge reset)if(reset)beginst_cp <= 1'b0;ds <= 1'b0;sh_cp <= 1'd0;end else begincase(SHCP_EDGE_CNT)0: begin sh_cp <= 0; st_cp <= 1'd0;ds <= r_data[15];end1: begin sh_cp <= 1; st_cp <= 1'd0;end2: begin sh_cp <= 0; ds <= r_data[14];end3: begin sh_cp <= 1; end4: begin sh_cp <= 0; ds <= r_data[13];end 5: begin sh_cp <= 1; end6: begin sh_cp <= 0; ds <= r_data[12];end 7: begin sh_cp <= 1; end8: begin sh_cp <= 0; ds <= r_data[11];end 9: begin sh_cp <= 1; end10: begin sh_cp <= 0; ds <= r_data[10];end 11: begin sh_cp <= 1; end12: begin sh_cp <= 0; ds <= r_data[9];end 13: begin sh_cp <= 1; end14: begin sh_cp <= 0; ds <= r_data[8];end 15: begin sh_cp <= 1; end16: begin sh_cp <= 0; ds <= r_data[7];end 17: begin sh_cp <= 1; end18: begin sh_cp <= 0; ds <= r_data[6];end 19: begin sh_cp <= 1; end20: begin sh_cp <= 0; ds <= r_data[5];end 21: begin sh_cp <= 1; end22: begin sh_cp <= 0; ds <= r_data[4];end 23: begin sh_cp <= 1; end24: begin sh_cp <= 0; ds <= r_data[3];end 25: begin sh_cp <= 1; end26: begin sh_cp <= 0; ds <= r_data[2];end 27: begin sh_cp <= 1; end28: begin sh_cp <= 0; ds <= r_data[1];end 29: begin sh_cp <= 1; end30: begin sh_cp <= 0; ds <= r_data[0];end31: begin sh_cp <= 1; end32: st_cp <= 1'd1;default: beginst_cp <= 1'b0;ds <= 1'b0;sh_cp <= 1'd0;endendcaseendendmodule
5、段选&位选模块
2个共阳极的7段4位数码管,采用动态扫描的显示方式,即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。
比较简单的数码管段选、位选模块,这里不做赘述。
//**************************************** Message ***********************************//
//技术交流:bumianzhe@126.com
//关注CSDN博主:“千歌叹尽执夏”
//Author: 千歌叹尽执夏
//All rights reserved
//----------------------------------------------------------------------------------------
// Target Devices: H7P20N0L176-M2H1
// Tool Versions: Fuxi 2023.1
// File name: Hex8
// Last modified Date: 2023年6月11日13:35:00
// Last Version: V1.1
// Descriptions: 分频信号,段选和位选信号生成,输出需要显示的数据、段选和位选值
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module Hex8(clk,reset_n,en,disp_data,sel,seg
);assign reset=~reset_n;input clk; //50Minput reset_n;input en; //数码管显示使能,1使能,0关闭input [31:0]disp_data;output [7:0] sel;//数码管位选(选择当前要显示的数码管)output reg [6:0] seg;//数码管段选(当前要显示的内容)reg [14:0]divider_cnt;//25000-1reg clk_1K;reg [7:0]sel_r;reg [3:0]data_tmp;//数据缓存// 分频计数器计数模块always@(posedge clk or posedge reset)if(reset)divider_cnt <= 15'd0;else if(!en)divider_cnt <= 15'd0;else if(divider_cnt == 24999)divider_cnt <= 15'd0;elsedivider_cnt <= divider_cnt + 1'b1;//1K扫描时钟生成模块 always@(posedge clk or posedge reset)if(reset)clk_1K <= 1'b0;else if(divider_cnt == 24999)clk_1K <= ~clk_1K;elseclk_1K <= clk_1K;//8位循环移位寄存器always@(posedge clk_1K or posedge reset)if(reset)sel_r <= 8'b0000_0001;else if(sel_r == 8'b1000_0000)sel_r <= 8'b0000_0001;elsesel_r <= sel_r << 1;always@(*)case(sel_r)8'b0000_0001:data_tmp = disp_data[3:0];8'b0000_0010:data_tmp = disp_data[7:4];8'b0000_0100:data_tmp = disp_data[11:8];8'b0000_1000:data_tmp = disp_data[15:12];8'b0001_0000:data_tmp = disp_data[19:16];8'b0010_0000:data_tmp = disp_data[23:20];8'b0100_0000:data_tmp = disp_data[27:24];8'b1000_0000:data_tmp = disp_data[31:28];default:data_tmp = 4'b0000;endcasealways@(*)case(data_tmp)4'h0:seg = 7'b1000000;4'h1:seg = 7'b1111001;4'h2:seg = 7'b0100100;4'h3:seg = 7'b0110000;4'h4:seg = 7'b0011001;4'h5:seg = 7'b0010010;4'h6:seg = 7'b0000010;4'h7:seg = 7'b1111000;4'h8:seg = 7'b0000000;4'h9:seg = 7'b0010000;endcaseassign sel = (en)?sel_r:8'b0000_0000;endmodule
五、debugware 回环实验
本节适用于只有一块板卡的同学,将发送模块的tx_d信号接到接收模块的rx_d信号,形成回环实验,并调用debugware进行数据分析。
//如果没有两块板卡的,可以将manchester_tx的tx_d信号接到manchester_rx的rx_d
//形成回环实验,并利用debugware进行数据查看。
manchester_rx u_manchester_rx_0(.clk(clk), //高频时钟,可以是50MHz.rst_n(rst_n),//.rx_d(rx_d), //接收到的bit数据.rx_d(tx_d) //回环实验.rx_data(rx_data),.rx_valid(rx_valid));
例化一个debugware IP:
//使用debugware查看编码&解码波形
debugware_v2_1 u_debugware_v2_1(.trig_out_0 (),.data_in_0 ({tx_en_n,tx_d,rx_data_dis}), //数据拼接.ref_clk_0 (clk)
);
从debugware的波形看,使能按键按下后,编码模块将预留的数据进行编码并以串口的形式发送,rx_data_dis显示解码后的数据。
六、兼容设计
4.4节提到,为了方便只有传统数码管模块的同学进行设计,这里提供了传统的数码管驱动模块。
module hme_manchester(//其他信号-略//数码管output [6:0] odata0,odata1,odata2,odata3,odata4,odata5,odata6,odata7
);
//其他模块-略-自行复制补充HEX HEX_u(
.idata({3'd0,rx_data_dis[7],3'd0,rx_data_dis[6],3'd0,rx_data_dis[5],3'd0,rx_data_dis[4],3'd0,rx_data_dis[3],3'd0,rx_data_dis[2],3'd0,rx_data_dis[1],3'd0,rx_data_dis[0]}),
.rst(1'b1),
.clk(clk),
.odata0(odata0),
.odata1(odata1),
.odata2(odata2),
.odata3(odata3),
.odata4(odata4),
.odata5(odata5),
.odata6(odata6),
.odata7(odata7)
);
endmodule
module HEX(idata,rst,clk,odata0,odata1,odata2,odata3,odata4,odata5,odata6,odata7);
input [31:0] idata ;
input clk,rst;
output [6:0] odata0,odata1,odata2,odata3,odata4,odata5,odata6,odata7;
wire [6:0] d0,d1,d2,d3,d4,d5,d6,d7;
reg [6:0] odata0_r,odata1_r,odata2_r,odata3_r,odata4_r,odata5_r,odata6_r,odata7_r;assign odata0=odata0_r;
assign odata1=odata1_r;
assign odata2=odata2_r;
assign odata3=odata3_r;
assign odata4=odata4_r;
assign odata5=odata5_r;
assign odata6=odata6_r;
assign odata7=odata7_r;
SHEX SHEX0 (.idata(idata[3:0]),.rst(rst),.clk(clk),.odata(d0));
SHEX SHEX1 (.idata(idata[7:4]),.rst(rst),.clk(clk),.odata(d1));
SHEX SHEX2 (.idata(idata[11:8]),.rst(rst),.clk(clk),.odata(d2));
SHEX SHEX3 (.idata(idata[15:12]),.rst(rst),.clk(clk),.odata(d3));
SHEX SHEX4 (.idata(idata[19:16]),.rst(rst),.clk(clk),.odata(d4));
SHEX SHEX5 (.idata(idata[23:20]),.rst(rst),.clk(clk),.odata(d5));
SHEX SHEX6 (.idata(idata[27:24]),.rst(rst),.clk(clk),.odata(d6));
SHEX SHEX7 (.idata(idata[31:28]),.rst(rst),.clk(clk),.odata(d7));
always@(posedge clk or negedge rst)beginif(rst==1'b0)beginodata0_r<=7'd0;odata1_r<=7'd0;odata2_r<=7'd0;odata3_r<=7'd0;odata4_r<=7'd0;odata5_r<=7'd0;odata6_r<=7'd0;odata7_r<=7'd0;endelse beginodata0_r<=d0;odata1_r<=d1;odata2_r<=d2;odata3_r<=d3;odata4_r<=d4;odata5_r<=d5;odata6_r<=d6;odata7_r<=d7;endendendmodule
module SHEX (idata,rst,clk,odata);
input [3:0] idata;
input rst,clk;
output [6:0] odata;
reg [6:0] odata_r;
assign odata=odata_r;
always@(posedge clk or negedge rst)beginif(rst==1'b0)beginodata_r<=7'd0;endelsebegincase(idata)4'd0:odata_r<=7'b1000000;4'd1:odata_r<=7'b1111001;4'd2:odata_r<=7'b0100100;4'd3:odata_r<=7'b0110000;4'd4:odata_r<=7'b0011001;4'd5:odata_r<=7'b0010010;4'd6:odata_r<=7'b0000010;4'd7:odata_r<=7'b1111000;4'd8:odata_r<=7'b0000000;4'd9:odata_r<=7'b0010000;default:odata_r<=7'b0111111;endcaseendendendmodule
七、工程获取
链接:https://pan.baidu.com/s/1-5V5b6h9lPAKPwkta77wPw?pwd=JWQL
提取码:JWQL
–来自百度网盘超级会员V5的分享
这篇关于京微齐力:基于H7的曼彻斯特(编码解码串口)系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!