1.根据功能需要设计模块,自上而下不断细化,确定端口、子模块、连线,最好就是画图出来,这里是设计的是把收到的串口数据重新发送出去
2.根据自己画的图,转换成verilo代码,并描述出来
//---------------------------------------------------------------------------
//-- 文件名 : Uart_Test_Top.v
//-- 作者 : LIZIYI
//-- 描述 : 串口收发测试顶层文件
//-- 修订历史 : 2018-7-23
//---------------------------------------------------------------------------
module Uart_Test
(
//输入端口
RST,CLK,UART_RX,
//输出端口
UART_TX
);
//---------------------------------------------------------------------------
//-- 外部端口声明
//---------------------------------------------------------------------------
input RST; //复位
input CLK; //时钟50M
input UART_RX; //串口接收
output UART_TX; //串口发送
//---------------------------------------------------------------------------
//-- 内部端口声明
//---------------------------------------------------------------------------
wire [7:0] data; //八位数据线
wire tx_start; //串口发送标志
wire rx_bps_start; //Rx波特率启动
wire rx_bps_flag; //Rx读取标志
wire tx_bps_start; //Tx波特率启动
wire tx_bps_flag; //Tx读取标志
//---------------------------------------------------------------------------
//-- 逻辑功能实现
//---------------------------------------------------------------------------
//例化RX波特率模块
Bps_Module Rx_Bps_Module_Init
(
.CLK (CLK),
.RST (RST),
.bps_start (rx_bps_start),
.bps_flag (rx_bps_flag)
);
//例化TX波特率模块
Bps_Module Tx_Bps_Module_Init
(
.CLK (CLK),
.RST (RST),
.bps_start (tx_bps_start),
.bps_flag (tx_bps_flag)
);
//例化Rx模块
Rx_Module Rx_Module_Init
(
.CLK (CLK),
.RST (RST),
.UART_RX (UART_RX),
.rx_bps_start (rx_bps_start),
.rx_bps_flag (rx_bps_flag),
.tx_start (tx_start),
.out_rx_data (data)
);
//例化Tx模块
Tx_Module Tx_Module_Init
(
.CLK (CLK),
.RST (RST),
.UART_TX (UART_TX),
.tx_bps_start (tx_bps_start),
.tx_bps_flag (tx_bps_flag),
.tx_start (tx_start),
.out_tx_data (data)
);
endmodule
//---------------------------------------------------------------------------
//-- 文件名 : Bps_Module.v
//-- 作者 : LIZIYI
//-- 描述 : 串口波特率发生器,当bps_start 为1的时候计数
//-- 修订历史 : 2018-7-23
//---------------------------------------------------------------------------
module Bps_Module
(
//输入端口
CLK,RST,bps_start,
//输出端口
bps_flag
);
//---------------------------------------------------------------------------
//-- 外部端口声明
//---------------------------------------------------------------------------
input CLK; //50M时钟
input RST; //复位
input bps_start; //rx或者tx给波特率发生器的开始信号
output bps_flag; //返回给波特率发生器的数据位中间时刻的标志信号
//---------------------------------------------------------------------------
//-- 内部端口声明
//---------------------------------------------------------------------------
reg [8:0] time_cnt; //用来计时,每个比特
reg [8:0] time_cnt_n;
reg bps_flag; //用来判断是否到达每个比特的中间时刻
reg bps_flag_n;
//设置定时器的时间 晶振为50Mhz 50M/115200=434
parameter SET_TIME_ONEBit = 9'd434; //每个比特需要计数434次
parameter SET_TIME_HALFBit = 8'd217; //半个比特就需要计数217次
//---------------------------------------------------------------------------
//-- 逻辑功能实现
//---------------------------------------------------------------------------
//time_cnt 实现计时
always @ (posedge CLK or negedge RST)
begin
if(!RST)
time_cnt <= 1'b0;
else
time_cnt <= time_cnt_n;
end
//自己写的代码
//always @ (*)
//begin
// if(time_cnt == SET_TIME_ONEBit)
// time_cnt_n = 1'b0;
// else if(bps_start)
// time_cnt_n = time_cnt + 1'b1;
// else
// time_cnt_n = time_cnt;
//end
//例程的代码
always @ (*)
begin
if((time_cnt == SET_TIME_ONEBit) || (!bps_start)) //当计满一位比特的时候,或者还没有收到开始信号的时候,计数值就为0
time_cnt_n = 1'b0;
else
time_cnt_n = time_cnt + 1'b1; //别的时候就+1
end
//---------------------------------------------------------------------------
//-- 文件名 : Rx_Module.v
//-- 作者 : LIZIYI
//-- 描述 : 串口RX模块
//-- 修订历史 : 2018-7-23
//---------------------------------------------------------------------------
module Rx_Module
(
//输入端口
CLK,RST,UART_RX,rx_bps_flag,
//输出端口
rx_bps_start,tx_start,out_rx_data
);
//---------------------------------------------------------------------------
//-- 外部端口声明
//---------------------------------------------------------------------------
input CLK; //50M时钟
input RST; //复位
input UART_RX; //串口RX接收端
input rx_bps_flag; //收到来自波特率发生器,每比特中间时刻的标志
output rx_bps_start; //给波特率发生器发送的开始信号
output tx_start; //给tx模块发送的,串口发送信号
output [7:0] out_rx_data; //收到的每帧串口数据,并行储存在这个端口
//---------------------------------------------------------------------------
//-- 内部端口声明
//---------------------------------------------------------------------------
reg [1:0] detect_reg; //检测RX跳变
wire [1:0] detect_reg_n;
reg negedge_reg; //判断跳变是否为下降沿
reg negedge_reg_n;
reg [7:0] shift_reg; //移位寄存器,把Rx的信号读取进来,因为串口先发送的信号为低位,把刚读到信号放在移位寄存器的最高位,然后往低位移动
reg [7:0] shift_reg_n;
reg [3:0] bit_cnt; //记录接收到的bit位
reg [3:0] bit_cnt_n;
reg [7:0] out_rx_data; //收到的每帧串口数据,并行储存在这个reg
reg [7:0] out_rx_data_n;
//---------------------------------------------------------------------------
//-- 逻辑功能实现
//---------------------------------------------------------------------------
//detect_reg
always @ (posedge CLK or negedge RST)
begin
if(!RST)
detect_reg <= 1'b0;
else
detect_reg <= detect_reg_n;
end
assign detect_reg_n = {detect_reg[0],UART_RX}; //detect_reg[0]就是上一时刻的rx状态
//negedge_reg
always @ (posedge CLK or negedge RST)
begin
if(!RST)
negedge_reg <= 1'b0;
else
negedge_reg <= negedge_reg_n;
end
always @ (*)
begin
if(detect_reg == 2'b10) //如果为下降沿,置一
negedge_reg_n = 1'b1;
else if(bit_cnt == 4'd9) //如果读取数据(读取了开始信号和八位数据)就置0
negedge_reg_n = 1'b0;
else
negedge_reg_n = negedge_reg;
end
assign rx_bps_start = negedge_reg; //当读取到下降沿的时候波特率开始信号置一
assign tx_start = !negedge_reg; //当读取完了八位数据位,tx才发送
//bit_cnt
always @ (posedge CLK or negedge RST)
begin
if(!RST)
bit_cnt <= 1'b0;
else
bit_cnt <= bit_cnt_n;
end
always @ (*)
begin
if(negedge_reg && rx_bps_flag) //每次读到中间时刻标志,位数+1
bit_cnt_n = bit_cnt + 1'b1;
else if(bit_cnt == 4'd9) //计满9次归0
bit_cnt_n = 1'b0;
else
bit_cnt_n = bit_cnt;
end
//shift_reg
always @ (posedge CLK or negedge RST)
begin
if(!RST)
shift_reg <= 1'b0;
else
shift_reg <= shift_reg_n;
end
always @ (*)
begin
if(rx_bps_flag)
shift_reg_n = {UART_RX,shift_reg[7:1]}; //移位寄存器,把Rx的信号读取进来,因为串口先发送的信号为低位,把刚读到信号放在移位寄存器的最高位,然后往低位移动
else
shift_reg_n = shift_reg;
end
//out_rx_data
always @ (posedge CLK or negedge RST)
begin
if(!RST)
out_rx_data <= 1'b0;
else
out_rx_data <= out_rx_data_n;
end
always @ (*)
begin
if(bit_cnt == 4'd9) //当读取玩数据的时候,就把数据存储这个寄存器里
out_rx_data_n = shift_reg;
else
out_rx_data_n = out_rx_data;
end
endmodule
//---------------------------------------------------------------------------
//-- 文件名 : Tx_Module.v
//-- 作者 : LIZIYI
//-- 描述 : 串口Tx部分
//-- 修订历史 : 2018-7-23
//---------------------------------------------------------------------------
module Tx_Module
(
//输入端口
CLK,RST,tx_bps_flag,tx_start,out_tx_data,
//输出端口
UART_TX,tx_bps_start
);
//---------------------------------------------------------------------------
//-- 外部端口声明
//---------------------------------------------------------------------------
input CLK; //50M时钟
input RST; //复位
input tx_bps_flag; //波特率发生器发送给tx的每bit中间时刻
input tx_start; //rx接收数据完毕,给tx发送的信号
input [7:0] out_tx_data; //需要发送的数据
output UART_TX; //串口tx接口
output tx_bps_start; //tx给波特率发生器发送的开始信号
//---------------------------------------------------------------------------
//-- 内部端口声明
//---------------------------------------------------------------------------
reg [1:0] detect_reg; //检测跳变
wire [1:0] detect_reg_n;
reg posedge_reg; //判断跳变是否为上升沿
reg posedge_reg_n;
reg [7:0] tx_temp_data; //将要发送的数据存储在这个寄存器
reg [7:0] tx_temp_data_n;
reg UART_TX; //串口tx
reg UART_TX_N;
reg [3:0] bit_cnt; //记录发送的bit位
reg [3:0] bit_cnt_n;
//---------------------------------------------------------------------------
//-- 逻辑功能实现
//---------------------------------------------------------------------------
//detect_reg
always @ (posedge CLK or negedge RST)
begin
if(!RST)
detect_reg <= 1'b0;
else
detect_reg <= detect_reg_n;
end
assign detect_reg_n = {detect_reg[0],tx_start}; //detect_reg[0]就是上一时刻的rx状态
//posedge_reg
always @ (posedge CLK or negedge RST)
begin
if(!RST)
posedge_reg <= 1'b0;
else
posedge_reg <= posedge_reg_n;
end
always @ (*)
begin
if(detect_reg == 2'b01) //如果为上升沿置一
posedge_reg_n = 1'b1;
else if(bit_cnt == 4'd10) //如果发送完成(起始位,8位数据位,停止位)置零
posedge_reg_n = 1'b0;
else
posedge_reg_n = posedge_reg;
end
assign tx_bps_start = posedge_reg; //如果读取到上升沿,给波特率发送器发送开始信号
//tx_temp_data
always @ (posedge CLK or negedge RST)
begin
if(!RST)
tx_temp_data <= 1'b0;
else
tx_temp_data <= tx_temp_data_n;
end
always @ (*)
begin
if(posedge_reg)
tx_temp_data_n = out_tx_data; //读取到上升沿那么保存要发送的数据
else
tx_temp_data_n = tx_temp_data;
end
//bit_cnt
always @ (posedge CLK or negedge RST)
begin
if(!RST)
bit_cnt = 1'b0;
else
bit_cnt = bit_cnt_n;
end
always @ (*)
begin
if(posedge_reg && tx_bps_flag) //记录发送的位数,每到一比特加一
bit_cnt_n = bit_cnt + 1'b1;
else if(bit_cnt == 4'd10) //发送完了一帧数据归0
bit_cnt_n = 1'b0;
else
bit_cnt_n = bit_cnt;
end
//UART_TX
always @ (posedge CLK or negedge RST)
begin
if(!RST)
UART_TX = 1'b1;
else
UART_TX = UART_TX_N;
end
always @ (*)
begin
if(posedge_reg)
case(bit_cnt)
4'd0: UART_TX_N = 1'b0; //起始位拉低
4'd1: UART_TX_N = tx_temp_data[0]; //八位数据位
4'd2: UART_TX_N = tx_temp_data[1];
4'd3: UART_TX_N = tx_temp_data[2];
4'd4: UART_TX_N = tx_temp_data[3];
4'd5: UART_TX_N = tx_temp_data[4];
4'd6: UART_TX_N = tx_temp_data[5];
4'd7: UART_TX_N = tx_temp_data[6];
4'd8: UART_TX_N = tx_temp_data[7];
4'd9: UART_TX_N = 1'b1; //停止位拉高
default UART_TX_N = 1'b1;
endcase
else
UART_TX_N = UART_TX;
end
endmodule
3.编译,分配管脚,下载验证,并查错修改,有条件还可以仿真