1.UART
UART是异步串行通信口的总称。它所包含的RS232RS449RS423等等是对应各种异步串行通信口的接口标准和总线标准。他们规定了通信口的电气特性、传输速率、连接特性和机械特性等一系列内容,实际上属于通信网络的底层概念,与通信协议没有直接关系。
几个相关名词的解释:
·波特率:每秒钟传送的bit的个数。
·起始位:先发出一个逻辑0的信号,表示传输数据的开始。
·数据位:衡量通信中实际数据位的参数,标准数据位可以是5、7、8位,从最低位开始传输。
·奇偶校验位:UART发送时,检查发送数据中“1”的个数,自动在奇偶校验位添加1/0,用于发送数据的校验。
·停止位:一个数据的结束标志,可以为1位、1.5位、2位的高电平。
·空闲位:处于逻辑1状态,表示当前线路上无数据传输。
·时序图:
·发送数据过程:空闲状态,线路处于高电平,当收到发送数据指令后,拉低电平一个数据位的时间,接着数据按从低位到高位依次发送,数据发送完毕,接着发送奇偶校验位和停止位(停止位为高电平),一帧数据发送结束。
·接收数据过程:空闲状态,线路处于高电平,当检测到线路的下降沿,说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕,接着接收并比较奇偶校验位是否正确,如果正确则通知接收端设备准备接收数据或存入缓存。
由于UART是异步传输,没有同步传输时钟。为保证数据传输的正确性,每个数据有16个时钟采样,取中间的采样值,以保证不会误码或滑码。
·设计实例:
下面是一个UART的回环实例代码设计:
module uart_rx(
input rxd,
input clk,
output receive_ack,
output reg [7:0] data_i
);
parameter IDLE = 0;
parameter RECEIVE = 1;
parameter RECEIVE_END = 2;
reg [3:0] CS,NS;
reg [4:0] count;
reg [7:0] data_o_tmp;
always@(posedge clk)
CS <= NS;
always@(*) begin
NS <= CS;
case(CS)
IDLE: if(!rxd) NS = RECEIVE;
RECEIVE: if(count == 7) NS = RECEIVE_END;else NS = NS;
RECEIVE_END:NS = IDLE;
default: NS = IDLE;
endcase
end
always@(posedge clk)
if(CS == RECEIVE)
count <= count + 1;
else if(CS == IDLE | CS == RECEIVE_END)
count <= 0;
always @(posedge clk)
if(CS == RECEIVE)begin
data_i[6:0] <= data_i[7:1];
data_i[7] <= rxd;
end
assign receive_ack = (CS == RECEIVE_END) ? 1 : 0;
endmodule
发送模块uart_tx:
module uart_tx(
input [7:0] data_o,
input clk,
input receive_ack,
output reg txd
);
parameter IDLE = 0;
parameter SEND_START = 1;
parameter SEND_DATA = 2;
parameter SEND_END = 3;
reg [3:0] CS,NS;
reg [4:0] count;
reg [7:0] data_o_tmp;
always @ (posedge clk)
CS <= NS;
always @ (*) begin
NS <= CS;
case(CS)
IDLE: begin if(receive_ack) NS = SEND_START; end
SEND_START: begin NS = SEND_DATA; end
SEND_DATA: begin if(count == 7) NS = SEND_END; end
SEND_END: begin if(receive_ack) NS = SEND_START; end
default: NS = IDLE;
endcase
end
always @(posedge clk)
if(CS == SEND_START)
count <= count + 1;
else if(CS == IDLE | CS == SEND_END)
count <= 0;
else
count <= count;
always @(posedge clk)
if(CS == SEND_START)
data_o_tmp <= data_o;
else if(CS == SEND_DATA)
data_o_tmp[6:0] <= data_o_tmp[7:1];
always @(posedge clk)
if(CS == SEND_START)
txd <= 0;
else if(CS == SEND_DATA)
txd <= data_o_tmp;
else if(CS == SEND_END)
txd <= 1;
endmodule
module uart_tx(
input [7:0] data_o,
input clk,
input receive_ack,
output reg txd
);
parameter IDLE = 0;
parameter SEND_START = 1;
parameter SEND_DATA = 2;
parameter SEND_END = 3;
reg [3:0] CS,NS;
reg [4:0] count;
reg [7:0] data_o_tmp;
always @ (posedge clk)
CS <= NS;
always @ (*) begin
NS <= CS;
case(CS)
IDLE: begin if(receive_ack) NS = SEND_START; end
SEND_START: begin NS = SEND_DATA; end
SEND_DATA: begin if(count == 7) NS = SEND_END; end
SEND_END: begin if(receive_ack) NS = SEND_START; end
default: NS = IDLE;
endcase
end
always @(posedge clk)
if(CS == SEND_START)
count <= count + 1;
else if(CS == IDLE | CS == SEND_END)
count <= 0;
else
count <= count;
always @(posedge clk)
if(CS == SEND_START)
data_o_tmp <= data_o;
else if(CS == SEND_DATA)
data_o_tmp[6:0] <= data_o_tmp[7:1];
always @(posedge clk)
if(CS == SEND_START)
txd <= 0;
else if(CS == SEND_DATA)
txd <= data_o_tmp;
else if(CS == SEND_END)
txd <= 1;
endmodule
特定波特率产生模块clk_div:
module clk_div(
input clk,
output reg clk_out
);
parameter baud_rata = 9600;
parameter div_num = 'd125_000_000 /baud_rata; //分频数等于时钟频率除以想要得到的波特率
reg [15:0] num;
always @(posedge clk) begin
if(num == div_num) begin
num <= 0;
clk_out <= 1;
end
else begin
num <= num + 1;
clk_out <= 0;
end
end
endmodule
顶层文件uart_top:
module uart_top(
input clk,
input rxd,
output txd
);
wire clk_9600;
wire receive_ack;
wire [7:0] data;
uart_tx uart_tx
(
.clk (clk_9600),
.txd (txd),
.data_o (data),
.receive_ack(receive_ack)
);
uart_rx uart_rx
(
.clk (clk_9600),
.rxd (rxd),
.data_i (data),
.receive_ack(receive_ack)
);
clk_div clk_div
(
.clk (clk),
.clk_out (clk_9600)
);
endmodule
数据位名称 | 说明 |
1个起始位 | 总是逻辑0 |
8个数据位 |
低位在前 |
1个奇偶校验位 | 奇校验 |
1个停止位 | 总是逻辑1 |
1个应答位 | 仅用在主机对设备的通信中 |
-
module ps2_keyboard( input clk, input clr, input PS2C, //ps2 clk in input PS2D, //ps2 data in output [15:0] xkey ); reg PS2CF; reg PS2DF; reg [7:0] ps2c_filter; reg [7:0] ps2d_filter; reg [10:0] shift1; reg [10:0] shift2; assign xkey = { shift2[8:1], shift1[8:1] }; always @(posedge clk or posedge clr) begin if (clr) begin ps2c_filter <= 11'b0; ps2d_filter <= 11'b0; PS2CF <= 1; PS2DF <= 1; end else begin ps2c_filter[7] <= PS2C; ps2c_filter[6:0] <= ps2c_filter[7:1]; ps2d_filter[7] <= PS2D; ps2d_filter[6:0] <= ps2d_filter[7:1]; if(ps2c_filter == 8'b1111_1111) PS2CF <= 1; //去时钟毛刺 else if(ps2c_filter == 8'b0000_0000) PS2CF <= 0; if(ps2d_filter == 8'b1111_1111) PS2DF <= 1; //去数据毛刺 else if(ps2d_filter == 8'b0000_0000) PS2DF <= 0; end end always @(negedge PS2CF or posedge clr) begin if (clr) begin shift1 <= 11'b0; shift2 <= 11'b0; end else begin shift1 <= {PS2DF, shift1[10:1]}; shift2 <= {shift1[0], shift2[10:1]}; end end endmodule
参考文献:
[1]汤勇明,张圣清,陆佳华.搭建你的数字积木-数字电路与逻辑设计[M].北京:清华大学出版社,2017.
没有回复内容