低速通信接口(一)UART

低速通信接口包括异步串行通信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图,画出图后写代码就很快了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值