低速通信接口包括异步串行通信UART、同步串行通信I2C和SPI。
首先简单介绍以下:
串行通信:计算机与I/O设备之间的传输的数据是一位接一位的依次传送的。
并行通信:计算机与I/O设备之间通过多条数据传输线交换数据。
异步通信:数据传送以字符为单位;用起始位和停止位标识每个字符的开始和结束;相邻字符之间间隔任意长,只需要接受时钟频率和发送时钟频率相同即可。异步通信不需要传递同步时钟信号。
同步通信:以数据块为单位传送信息。在数据块开始处用同步字符来指示,由于传送数据较多,接受时钟域发送时钟严格同步。
UART(Universal Asynchronous Receiver and Transmitter)
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。将计算机内部传送过来的并行数据转换为输出的串行数据流。将计算机外部来的串行数据转换为字节,供计算机内部并行数据的器件使用。(相当于一个能读取和写入的8位输入和输出端口)在输出的串行数据流中加入奇偶校验位,并对从外部接收的数据流进行奇偶校验。在输出数据流中加入启停标记,并从接收数据流中删除启停标记。
URAT以ASCII码交换文本数据,数据构成如下:
(1)起始位:1bit低电平,作为通信起始信号;
(2)数据位:5/6/7/8bit,[LSB:MSB]
(3)校验位:分为奇校验、偶校验和无校验,1bit,奇校验时,若数据位中1位奇数,则校验位为0,若为偶数,校验位为1,保证“数据位+校验位=奇数”
(4)停止位:1/1.5/2bit高电平,作为终止信号;
(5)空闲位:高电平,直到起始位。
UART物理层实现形式:根据物理层的不同分为TTL/RS232等。
(1)TTL:5V代表1,0V代表0,单端,全双工;
(2)RS232:RS232采用负逻辑 , Logic1:-25V~-3V, Logic0:+3V~+25V ,-3V~+3V为过渡区,单端,全双工。
波特率和比特率的区别:
比特率:单位时间内传输的比特(bit)的个数,比特率≥波特率;
波特率:单位时间内传输的码元的个数,对于二进制,1bit代表一个码元(0/1),对于四进制,2bit代表一个码元(00/01/10/11),此时波特率为比特率的1/2。
常用波特率:300、1200、2400、4800、9600、19.2k、 38.4k、57.6k等。
UART发送器,以并行格式取出数据并指定UART以串行格式发送。
UART接受机,以串行格式接收数据,去掉起始位和停止位后以并行格式存储数据。
首先是UART发送器设计:
设计参数:
(1)波特率为300
(2)7bit有效数据,1bit停止位
(3)奇偶校验可选
输入信号为:
DIN[6:0]:数据信号
send:发送触发信号,高电平有效,采用与BUSY信号的握手协议,直到BUSY信号拉低,信号方才拉低。
parityselect:奇偶选择,高为奇校验,低为偶校验
输出信号为:
Busy:开始发送数据后拉高,数据发送完成后拉低。
DOUT[9:0]:输出数据信号
module uart_control(
input clk,
input rst_n,
input send,
input next_bit,
input count10,
output reg busy,
output reg load,
output reg shift,
output reg rst_300,
output reg rst_10);
reg [2:0] current_state;
reg [2:0] next_state;
parameter idle=3’b000;
parameter load_state=3’b001;
parameter shift_state=3’b100;
parameter wait_state=3’b010;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
current_state<=idle;
else
current_state<=next_state;
end
always@(*)
begin
case(current_state)
idle:
begin
if(send)
next_state=load_state;
else
next_state=idle;
end
load_state:
begin
if(next_bit)
next_state=shift_state;
else
next_state=wait_state;
end
wait_state:
begin
if(next_bit)
next_state=shift_state;
else
next_state=wait_state;
end
shift_state:
begin
if(count10)
next_state=idle;
else
next_state=shift_state;
end
endcase
end
always@(posedge clk)
begin
case(current_state)
idle:
begin
busy<=0;
load<=0;
shift<=0;
rst_300<=0;
rst_10<=0;
end
load_state:
begin
busy<=1;
load<=1;
rst_300<=1;
rst_10<=1;
end
wait_state:
begin
load<=0;
end
shift_state:
begin
shift<=1;
end
endcase
end
endmodule
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
module uart_data(
input clk,
input rst_n,
input load,
input shift,
input rst_300,
input rst_10,
output reg next_bit,
output reg count10,
input [6:0] data_in,
output reg data_out,
input parity_select);
wire parity_bit;
reg [9:0] data;
reg [31:0] timer_300;
reg [3:0] count_10;
assign parity_bit=data_in[6:0]parity_select;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data<=0;
else if(load)
data<={1’b1,parity_bit,data_in[6:0],1’b0};
else if(next_bit)
begin
data_out<=data[0];
data<=data>>1;
end
end
always@(posedge clk)
begin
if(!rst_300)
timer_300<=0;
else if(timer_300<=32’d1666_67-1)
timer_300<=timer_300+1’b1;
else
timer_300<=0;
end
always@(posedge clk)
begin
if(timer_300==32’d1666_67-1)
next_bit<=1’b1;
else
next_bit<=0;
end
always@(posedge clk)
begin
if(!rst_10)
count_10<=0;
else if(count_10<=4’d11-1&&next_bit&&shift)
count_10<=count_10+1’b1;
else if(count_10==4’d11)
count_10<=0;
end
always@(posedge clk)
begin
if(count_10==4’d11-1)
count10<=1;
else
count10<=0;
end
endmodule
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
tb文件如下:
module tb();
reg send;
reg parity_select;
reg [6:0] data_in;
reg clk;
reg rst_n;
wire dout;
wire busy;
initial
begin
clk=0;
forever #(20/2) clk=~clk;
end
initial
begin
rst_n=0;
#60;
rst_n=1;
end
initial
begin
send=1;
parity_select=1;
data_in=7’b0101011;
end
uart_control u1(
.clk(clk),
.rst_n(rst_n),
.send(send),
.next_bit(next_bit),
.count10(count10),
.busy(busy),
.load(load),
.shift(shift),
.rst_300(rst_300),
.rst_10(rst_10));
uart_data u2(
.clk(clk),
.rst_n(rst_n),
.load(load),
.shift(shift),
.rst_300(rst_300),
.rst_10(rst_10),
.next_bit(next_bit),
.count10(count10),
.data_in(data_in),
.data_out(data_out),
.parity_select(parity_select));
endmodule
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
URAT接受端(负责接收串行比特流,去除起始位,并以并行格式将数据保存到与主机数据总线相连的:
如何解决接收器的时钟如何与数据同步?
即设计采用300*8HZ时钟频率进行采样。
采用更高频率的本地时钟(发送位时钟频率的8倍)对接受数据进行采样并保证其完整性,如果再提高频率,很难保证sample_clock前沿与起始位沿之间的少许差距不会影响采样:
(1)能够检测到起始位到达
(2)能够采用到8个数据位
(3)能够把采样数据送到本地总线
输入变为低电平(连续采样3次确定起始位有效)->进入起始位,此后8个连续位都将再比特时间的中间附近被采样。
module uart_receive_control(
input clk,
input rst_n,
input ready,
input ser_in_0,
input sc_eq_3,
input sc_lt_7,
input bc_eq_8,
output reg error1,
output reg error2,
output reg ready_out,
output reg clr_scounter,
output reg incr_scounter,
output reg clr_bit_counter,
output reg incr_bit_counter,
output reg shift,
output reg load);
reg [1:0] current_state;
reg [1:0] next_state;
parameter idle=2’b00;
parameter starting=2’b01;
parameter receiving=2’b10;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
current_state<=idle;
else
current_state<=next_state;
end
always@(*)
begin
case(current_state)
idle:
begin
if(ser_in_0)
next_state=starting;
else
next_state=idle;
end
starting:
begin
if(sc_eq_3)
next_state=receiving;
else
next_state=idle;
end
receiving:
begin
if(sc_lt_7||(!sc_lt_7&&!BC_eq_8))
next_state=receiving;
else
next_state=idle;
end
end
always@(posedge clk)
begin
case(current_state)
idle:
begin
error1<=1’b0;
error2<=1’b0;
ready_out<=1’b0;
clr_scounter<=1’b0;
incr_scounter<=1’b0;
clr_bit_counter<=1’b0;
incr_bit_counter<=1’b0;
shift<=1’b0;
load<=1’b0;
end
starting:
begin
if(!sc_eq_3)
clr_scounter<=1’b1;
else
clr_scounter<=1’b1;
end
receiving:
begin
if(sc_lt_7)
incr_scounter<=1’b1;
else
begin
clr_scounter<=1’b1;
if(BC_eq_8)
begin
ready_out<=1’b1
clr_bit_counter<=1’b1;
if(!ready)
error1<=1’b1;
else
begin
if(ser_in_0)
error2<=1’b1;
else
load<=1’b1;
end
end
else
begin
shift<=1’b1;
incr_bit_counter<=1’b1;
end
end
end
end
endmodule
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
module uart_receive_data(
input clk,
input rst_n,
input serial_in,
input incr_scounter,
input clr_scounter,
input incr_bit_counter,
input clr_bit_counter,
input shift,
input load,
output ser_in_0,
output sc_eq_3,
output sc_lt_7,
output BC_eq_8,
output reg [7:0] data_reg);
reg [4:0] sample_counter;
reg [4:0] bit_counter;
reg [7:0] shift_reg;
assign ser_in_0=(serial_in==1'b0);
assign BC_eq_8=(bit_counter==5'd8);
assign sc_eq_3=(sample_counter==5'd3);
assign sc_lt_7=(sample_counter<5'd7);
always@(posedge clk)
begin
if(!rst_n)
begin
data_reg<=8’d0;
sample_counter<=5’d0;
bit_counter<=5’d0;
shift_eg<=5’d0;
end
else
begin
if(incr_scounter)
sample_counter<=sample_counter+1’b1;
else if(clr_scounter)
sample_counter<=1’b0;
if(incr_bit_counter)
bit_counter<=bit_counter+1’b1;
else if(clr_bit_counter)
bit_counter<=1’b0;
if(shift)
shift_reg<={serial_in,shift_reg[7:1]};
if(load)
data_reg<=shift_reg;
end
end
endmodule
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
在本文中,是以控制通路结合数据通路的形式来写出一个UART发送器和一个URAT接收器,所以本文中最重要的在于如何画出ASMD图;
(1)首先确定数据通路与控制通路的输入与输出以及内部所需的寄存器
(2)根据控制通路画出状态机(确定好moore型状态机还是mealy型状态机)
(3)对于控制通路的输入状态和输入数据,确定输出数据以及输出状态;并作出ASMD图,画出图后写代码就很快了。