使用软件: Vivado
开发板: EGO1采用Xilinx Artix-7系列XC7A35T-1CSG324C FPGA
功能描述及分析
实现功能
(1)发送:8个拨码开关控制数码管最后后两位显示16进制数字,按下按键,数码管显示的内容通过TX发送,通过串口调试助手接收到内容。
(2)接收:从串口调试助手发送两位16进制数,接收到之后通过数码管倒数3、4位显示。
UART管脚约束:
串行发送程序设计
收发的过程,在发送器空闲时间,数据线处于逻辑 1 状态,当提示有数据要
传输时,首先使数据线的逻辑状态为低,之后是 8 个数据位、一位校验位、一位
停止位,校验一般是奇偶校验,停止位用于标示一帧的结束,接收过程亦类似,
当检测到数据线变低时,开始对数据线以约定的频率抽样,完成接收过程。本例
数据帧采用:无校验位,停止位为一位。
系统启动后进入空闲态IDLE,如果按了实验电路板中间的按键(S2)也可以进入IDLE状态。如果有其他的按键按下,开始发送数据,数据为拨码开关设置的8位数值,在时钟的有效边沿进入START状态发送起始位,时钟选用clk_x约为9600Hz。
串行接收程序设计
采用16倍于波特率的频率时钟clk_16x进行采样,在第8个周期采集数据值。
由上图可知,将串行接收状态划分为4个主要状态。系统启动后进入空闲态IDLE,如果捕捉到了RXD信号的下降沿,开始接收数据启动计数。因为这里是启动信号0的开始,所以延后24个时钟,24=16+8,就大约到了数据位0的中间,在这个时间点上才转换到接收数据态ONE。
在接收数据态ONE,每隔16个时钟,就采集一次数据,分别存放到寄存器data_out的对应位。在第136分时钟开始之后的16个时钟,处于检查校验的状态TWO,判断校验是否有误,如果有误,则置位校验出错信号data_error,如果无误,则置位数据准备好信号data_ready。
之后进入STOP状态,等待时钟计数到168,清时钟计数回到IDLE态,继续监测串行输入RXD信号的到来。文章来源:https://www.toymoban.com/news/detail-491274.html
代码实现
顶层设计代码
`timescale 1ns / 1ps
//
// Module Name: v_uart
// Revision 0.01 - File Created
// Additional Comments:
//
//
module v_uart(
input clk,//时钟输入
input[7:0] sw,//拨码开关输入
input[4:0] btn,//键盘输入
output[7:0] seg,//段码
output[7:0] seg1,
output[7:0] an,
output[7:0] led,//led
output txd,//数据发送
input rxd //数据接收
);
wire clk_ms,clk_20ms,clk_16x,clk_x;
wire[4:0] btnout;
wire[15:0] data_disp;//显示数据
wire data_ready;//数据是否准备好
wire data_error;
//调用分频模块
//clk 输入时钟50Mhz
//clk_ms 输出时钟1Khz
//clk_20ms 输出时钟50Hz
//clk_x 输出时钟9600Hz
//clk_16x 输出时钟9600hz*16
divclk my_divclk(
.clk(clk),
.clk_ms(clk_ms),
.btnclk(clk_20ms),
.clk_16x(clk_16x),
.clk_x(clk_x)
);
v_smg uut_disp( //显示
.clk(clk),
.show_data({data_disp[15:0],sw[7:0]}),
.seg(seg),
.seg1(seg1),
.an(an)
);
v_ajxd uut_ajxd(//按键消抖
.clk(clk_ms),
.btn_clk(clk_20ms),
.btn(btn),
.btn_out(btnout)
);
uart_tx(//调用串口发送模块
.clk_x(clk_x),
.data_in(sw[7:0]),
.btn(btnout),
.txd(txd),
.led(led)
);
uart_rx(
.clk_16x(clk_16x),
.rst(btnout[0]),
.rxd(rxd),
.data_disp(data_disp),
.data_ready(data_ready),
.data_error(data_error)
);
endmodule
时钟分频
`timescale 1ns / 1ps
//
// Module Name: divclk
// Revision 0.01 - File Created
// Additional Comments:
//
//
//分频模块
/*
clk:输入时钟100MHZ
clk_ms:输出时钟 1KHz
clk_20ms:输出时钟50HZ
clk_x 输出时钟9600HZ
clk_16x 输出时钟9600hz*16
*/
module divclk(clk,clk_ms,btnclk,clk_16x,clk_x);
input clk;
output clk_ms,btnclk,clk_16x,clk_x;
reg[31:0] cnt1=0;
reg[31:0] cnt2=0;
reg[31:0] cnt3=0;
reg[31:0] cntclk_cnt=0;
reg clk_ms=0;
reg btnclk=0;
reg clk_16x=0;
reg clk_x=0;
always@(posedge clk)//系统时钟分频 100M/1000 = 100000 1000HZ
begin
if(cnt1==26'd50000)
begin
clk_ms=~clk_ms;
cnt1=0;
end
else
cnt1=cnt1+1'b1;
end
always@(posedge clk)//20MS: 100M/50 = 2000 000 50HZ
begin
if(cntclk_cnt==1000000)
begin
btnclk=~btnclk;
cntclk_cnt=0;
end
else
cntclk_cnt=cntclk_cnt+1'b1;
end
always@(posedge clk)//100M/153600 = 651 9.6K*16=153.6k
begin
if(cnt2=='d326)
begin
clk_16x<=~clk_16x;
cnt2<='d0;
end
else
cnt2=cnt2+1'b1;
end
always@(posedge clk)//100M/9600 = 10416.67 9600HZ
begin
if(cnt3=='d5208)
begin
clk_x<=~clk_x;
cnt3<= 0;
end
else
cnt3=cnt3+1'b1;
end
endmodule
数码管显示
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/10/05 20:00:57
// Design Name:
// Module Name: v_smg
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module v_smg(
input clk,
input[19:0] show_data, //开关
output[7:0] seg,//段选,高有效
output[7:0] seg1,
output[7:0] an //位选,低有效
);
reg[18:0] divclk_cnt = 0;//分频计数器
reg divclk = 0;//分频后的时钟
reg[7:0] seg=0;//段码
reg[7:0] seg1=0;
reg[7:0] an=8'b00000001;//位码
reg[3:0] disp_dat=0;//要显示的数据
reg[2:0] disp_bit=0;//要显示的位
parameter maxcnt = 50000;// 周期:50000*2/100M
always@(posedge clk)
begin
if(divclk_cnt==maxcnt)
begin
divclk=~divclk;
divclk_cnt=0;
end
else
begin
divclk_cnt=divclk_cnt+1'b1;
end
end
always@(posedge divclk) begin
if(disp_bit >= 4)
disp_bit=0;
else
disp_bit=disp_bit+1'b1;
case (disp_bit)
3'b000 :
begin
disp_dat=show_data[3:0];
an=8'b00000001;//显示第一个数码管,高电平有效
end
3'b001 :
begin
disp_dat=show_data[7:4];
an=8'b00000010;//显示第二个数码管,低电平有效
end
3'b010 :
begin
disp_dat=show_data[11:8];
an=8'b00000100;//显示第三个数码管,低电平有效
end
3'b011 :
begin
disp_dat=show_data[15:12];
an=8'b00001000;//显示第四个数码管,低电平有效
end
3'b100 :
begin
disp_dat=show_data[19:16];
an=8'b00010000;//显示第五个数码管,低电平有效
end
default:
begin
disp_dat=0;
an=8'b00000000;
end
endcase
end
always@(disp_dat)
begin
if(an > 8'b00001000) begin
case (disp_dat)
//显示0-F
4'h0 : seg = 8'hfc;
4'h1 : seg = 8'h60;
4'h2 : seg = 8'hda;
4'h3 : seg = 8'hf2;
4'h4 : seg = 8'h66;
4'h5 : seg = 8'hb6;
4'h6 : seg = 8'hbe;
4'h7 : seg = 8'he0;
4'h8 : seg = 8'hfe;
4'h9 : seg = 8'hf6;
4'ha : seg = 8'hee;
4'hb : seg = 8'h3e;
4'hc : seg = 8'h9c;
4'hd : seg = 8'h7a;
4'he : seg = 8'h9e;
4'hf : seg = 8'h8e;
endcase
end
else begin
case (disp_dat)
//显示0-F
4'h0 : seg1 = 8'hfc;
4'h1 : seg1 = 8'h60;
4'h2 : seg1 = 8'hda;
4'h3 : seg1 = 8'hf2;
4'h4 : seg1 = 8'h66;
4'h5 : seg1 = 8'hb6;
4'h6 : seg1 = 8'hbe;
4'h7 : seg1 = 8'he0;
4'h8 : seg1 = 8'hfe;
4'h9 : seg1 = 8'hf6;
4'ha : seg1 = 8'hee;
4'hb : seg1 = 8'h3e;
4'hc : seg1 = 8'h9c;
4'hd : seg1 = 8'h7a;
4'he : seg1 = 8'h9e;
4'hf : seg1 = 8'h8e;
endcase
end
end
endmodule
串行发送
`timescale 1ns / 1ps
//
// Module Name: uart_tx
// Revision 0.01 - File Created
// Additional Comments:
//
//
//发送器设计
module uart_tx(clk_x,data_in,btn,txd,led);
input clk_x;
input[7:0] data_in;
input[4:0] btn;
output txd;
output[7:0] led;
reg txd=1;
reg[7:0] led=8'b00000000;
reg[10:0] clk_x_cnt=0;
reg[7:0] data_in_buf;
reg[4:0] btn_out0,btn_out1;
reg[4:0] btn_down;
parameter
idle=5'b00000,
start=5'b00001,
b0=5'b00011,
b1=5'b00010,
b2=5'b00110,
b3=5'b00111,
b4=5'b00101,
b5=5'b00100,
b6=5'b01100,
b7=5'b01101,
check=5'b01111,
stop=5'b01110;
reg[4:0] present_state=idle;
//assign led[4:0]=present_state;
always@(posedge clk_x)
begin
btn_out0<=btn;
btn_out1<=btn_out0;
btn_down<=btn_out0&~btn_out1;
led[4:0]<=present_state;
if(btn_down[0]) //复位
begin
present_state <= idle;
led[6] <= 0;//指示空闲状态
clk_x_cnt <= 'd0;
txd <= 1;
end
else begin
led[6]<=1; //指示开始发送数据
case(present_state)
idle: begin //空闲状态
txd<=1;
data_in_buf<=data_in;
led[6]<=0;
if(btn_down[4:1]>0) //如果按键按下
begin
present_state <= start;
end
else
present_state <= idle;
end
start: begin
led[6]<=1;//指示正在发送数据
txd <= 'd0; //发送起始位
present_state <= b0;
end
b0: begin
txd <= data_in_buf[0];//发送位0
present_state<=b1;
end
b1: begin
txd<=data_in_buf[1];//发送位1
present_state<=b2;
end
b2: begin
txd<=data_in_buf[2];//发送位2
present_state<=b3;
end
b3: begin
txd<=data_in_buf[3];//发送位3
present_state<=b4;
end
b4: begin
txd<=data_in_buf[4];//发送位4
present_state<=b5;
end
b5: begin
txd<=data_in_buf[5];//发送位5
present_state<=b6;
end
b6: begin
txd<=data_in_buf[6];//发送位6
present_state<=b7;
end
b7: begin
txd<=data_in_buf[7];//发送位7
present_state<=check;
end
check: begin//发送偶校验
txd<=data_in_buf[7]^data_in_buf[6]^data_in_buf[5]^data_in_buf[4]^data_in_buf[3]^data_in_buf[2]^data_in_buf[1]^data_in_buf[0];
present_state<=stop;
end
stop: begin//发送停止位
txd<='d1;
led[6]<=0;//指示发送数据完成
present_state<=idle;//回到空闲状态
end
endcase
end
end
endmodule
串行接收
`timescale 1ns / 1ps
//
// Create Date: 2022/10/06 14:19:41
// Design Name:
// Module Name: uart_rx
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_rx(clk_16x,rst,rxd,data_disp,data_ready,data_error);//接收器设计
input clk_16x;//16倍的波特率采样时钟信号
input rst;//复位信号
input rxd;//接收串行数据输入
output data_ready;//数据准备好信号,当data_ready=1时,提醒后级设备可以接收这8位数据
output data_error;//奇偶校验错
output[15:0] data_disp;
reg data_ready,data_error,framing_error;
reg[7:0] data_out,data_out1;
reg rxd_buf;
reg[15:0] clk_16x_cnt;
reg rxd1,rxd2;
reg start_flag;
parameter width=3;
parameter idle=1,one=2,two=3,stop=4;//状态机的4个状态
reg[width-1:0] present_state,next_state;//状态机当前状态和下一个状态
assign data_disp[15:8]=0;
assign data_disp[7:0]=data_out1;
assign check=^data_out;
initial
begin
clk_16x_cnt=0;
present_state=idle;
next_state=idle;
rxd1=1'd1;
rxd2=1'd1;
data_ready='d0;
start_flag=0;
end
//更新状态机当前状态
always@ (posedge clk_16x)
begin
if(rst)
present_state<=idle;
else
present_state<=next_state;
end
always@(clk_16x_cnt)//根据当前状态机的状态和判断条件,决定状态机的下一个状态
begin
if(clk_16x_cnt<='d8)//校验起始位条件
next_state=idle;
if(clk_16x_cnt>'d8 && clk_16x_cnt <= 'd136)//接收8位数据条件
next_state=one;
if(clk_16x_cnt>'d136 && clk_16x_cnt <= 'd152)//奇偶校验位条件
next_state=two;
if(clk_16x_cnt>'d152 && clk_16x_cnt <= 'd168)//检验停止位条件
next_state=stop;
if(clk_16x_cnt > 'd168)
next_state=idle;
end
always@(posedge clk_16x)//根据当前状态机的状态,决定输出
begin
if(rst)
begin
rxd1<=1'd1;
rxd2<=1'd1;
data_ready<='d0;
clk_16x_cnt<='d0;
start_flag<=0;
end
else begin
case(present_state)
idle: begin //检测开始位
rxd1<=rxd;
rxd2<=rxd1;
if((~rxd1)&&rxd2)//检测开始位,看rxd是否由高电平跳变到低电平
start_flag<='d1;//当rxd1=0,rxd2=1时,高电平跳变到低电平
else if(start_flag==1)
clk_16x_cnt<=clk_16x_cnt+'d1;
end
one: begin //接收8位数据
clk_16x_cnt<=clk_16x_cnt + 'd1;
if(clk_16x_cnt=='d24)data_out[0]<=rxd;
else if(clk_16x_cnt=='d40)data_out[1]<=rxd;
else if(clk_16x_cnt=='d56)data_out[2]<=rxd;
else if(clk_16x_cnt=='d72)data_out[3]<=rxd;
else if(clk_16x_cnt=='d88)data_out[4]<=rxd;
else if(clk_16x_cnt=='d104)data_out[5]<=rxd;
else if(clk_16x_cnt=='d120)data_out[6]<=rxd;
else if(clk_16x_cnt=='d136)data_out[7]<=rxd;
end
two: begin//奇偶校验位
if(clk_16x_cnt=='d152)
begin
if(rxd_buf==rxd) data_error<=1'd0;//无错误
else data_error<=1'd1;//有错误
end
clk_16x_cnt <= clk_16x_cnt+'d1;
end
stop: begin //停止位
if(clk_16x_cnt=='d168)
begin
if(1'd1==rxd)
begin
data_error<=1'd0;//无错误
data_ready<='d1;
end
else begin
data_error<=1'd1;//有错误
data_ready<='d0;
end
end
data_out1<=data_out;
if(clk_16x_cnt>168)
begin
clk_16x_cnt <= 0;
start_flag <= 0;
end
else
clk_16x_cnt <= clk_16x_cnt + 'd1;
end
endcase
end
end
endmodule
约束
## clk
set_property PACKAGE_PIN P17 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
## switch
##smg位码
set_property PACKAGE_PIN G2 [get_ports an[7]]
set_property IOSTANDARD LVCMOS33 [get_ports an[7]]
set_property PACKAGE_PIN C2 [get_ports an[6]]
set_property IOSTANDARD LVCMOS33 [get_ports an[6]]
set_property PACKAGE_PIN C1 [get_ports an[5]]
set_property IOSTANDARD LVCMOS33 [get_ports an[5]]
set_property PACKAGE_PIN H1 [get_ports an[4]]
set_property IOSTANDARD LVCMOS33 [get_ports an[4]]
set_property PACKAGE_PIN G1 [get_ports an[3]]
set_property IOSTANDARD LVCMOS33 [get_ports an[3]]
set_property PACKAGE_PIN F1 [get_ports an[2]]
set_property IOSTANDARD LVCMOS33 [get_ports an[2]]
set_property PACKAGE_PIN E1 [get_ports an[1]]
set_property IOSTANDARD LVCMOS33 [get_ports an[1]]
set_property PACKAGE_PIN G6 [get_ports an[0]]
set_property IOSTANDARD LVCMOS33 [get_ports an[0]]
##按键
set_property PACKAGE_PIN V1 [get_ports {btn[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[4]}]
set_property PACKAGE_PIN U4 [get_ports {btn[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[3]}]
set_property PACKAGE_PIN R11 [get_ports {btn[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[2]}]
set_property PACKAGE_PIN R17 [get_ports {btn[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[1]}]
set_property PACKAGE_PIN R15 [get_ports {btn[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {btn[0]}]
## 段码
set_property PACKAGE_PIN B4 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
set_property PACKAGE_PIN A4 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property PACKAGE_PIN A3 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property PACKAGE_PIN B1 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property PACKAGE_PIN A1 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property PACKAGE_PIN B3 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property PACKAGE_PIN B2 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property PACKAGE_PIN D5 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
# 段码2
set_property PACKAGE_PIN D4 [get_ports {seg1[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[7]}]
set_property PACKAGE_PIN E3 [get_ports {seg1[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[6]}]
set_property PACKAGE_PIN D3 [get_ports {seg1[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[5]}]
set_property PACKAGE_PIN F4 [get_ports {seg1[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[4]}]
set_property PACKAGE_PIN F3 [get_ports {seg1[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[3]}]
set_property PACKAGE_PIN E2 [get_ports {seg1[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[2]}]
set_property PACKAGE_PIN D2 [get_ports {seg1[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[1]}]
set_property PACKAGE_PIN H2 [get_ports {seg1[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg1[0]}]
## 拨码开关
set_property PACKAGE_PIN P5 [get_ports {sw[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[7]}]
set_property PACKAGE_PIN P4 [get_ports {sw[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[6]}]
set_property PACKAGE_PIN P3 [get_ports {sw[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[5]}]
set_property PACKAGE_PIN P2 [get_ports {sw[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[4]}]
set_property PACKAGE_PIN R2 [get_ports {sw[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[3]}]
set_property PACKAGE_PIN M4 [get_ports {sw[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[2]}]
set_property PACKAGE_PIN N4 [get_ports {sw[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[1]}]
set_property PACKAGE_PIN R1 [get_ports {sw[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sw[0]}]
## led
set_property PACKAGE_PIN F6 [get_ports {led[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[7]}]
set_property PACKAGE_PIN G4 [get_ports {led[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[6]}]
set_property PACKAGE_PIN G3 [get_ports {led[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[5]}]
set_property PACKAGE_PIN J4 [get_ports {led[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[4]}]
set_property PACKAGE_PIN H4 [get_ports {led[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property PACKAGE_PIN J3 [get_ports {led[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property PACKAGE_PIN J2 [get_ports {led[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property PACKAGE_PIN K2 [get_ports {led[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
## TX发送
set_property PACKAGE_PIN T4 [get_ports txd]
set_property IOSTANDARD LVCMOS33 [get_ports txd]
## RX接收
set_property PACKAGE_PIN N5 [get_ports rxd]
set_property IOSTANDARD LVCMOS33 [get_ports rxd]
结果
(1)串口调试助手发送16进制数:C4,实验板晶体管显示:C4;
(2)拨码开关4位一组,显示16进制数:F3,按一下按键之后,串口调试助手接收到F3
文章来源地址https://www.toymoban.com/news/detail-491274.html
到了这里,关于EGO1—UART串行接口设计及通信的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!