|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
1.UART
- x3 k3 n; z9 \& J( Q4 k( e
% E1 e4 o! A& x$ ]% F+ o; Y \7 X" j UART是异步串行通信口的总称。它所包含的RS232\RS449\RS423等等是对应各种异步串行通信口的接口标准和总线标准。他们规定了通信口的电气特性、传输速率、连接特性和机械特性等一系列内容,实际上属于通信网络的底层概念,与通信协议没有直接关系。
, D, X( ?9 ^: m7 w1 G9 E, j6 D5 V, x1 l: w; _# J- M0 E6 e; G. b0 M
几个相关名词的解释:* h7 G. @" M: X% R8 T4 q% ], J
& z) J5 O) z* s
·波特率:每秒钟传送的bit的个数。
( {, D" n2 t! i/ S* w. h
4 B2 E3 O( |" y, q8 ?/ F& d, M ·起始位:先发出一个逻辑0的信号,表示传输数据的开始。6 @0 E/ s& B( n% I; r2 E
/ E. g' h H$ j
·数据位:衡量通信中实际数据位的参数,标准数据位可以是5、7、8位,从最低位开始传输。
; _: \& V, w$ m1 U# a7 O4 L( m+ Q8 j
5 u2 ^0 f, E$ `; K+ [* y$ g ·奇偶校验位:UART发送时,检查发送数据中“1”的个数,自动在奇偶校验位添加1/0,用于发送数据的校验。7 J: E4 z& h9 N* t7 ^; |* \2 O1 ]2 H
7 K8 l+ v- |* U7 T& M ·停止位:一个数据的结束标志,可以为1位、1.5位、2位的高电平。# W9 u7 w9 M) ?3 _( q0 @& L
% v7 P- E5 C$ J# E ·空闲位:处于逻辑1状态,表示当前线路上无数据传输。6 f* F! o! K! t6 I
6 J, H* h& c$ i, [* D9 F2 `% W ·发送数据过程:空闲状态,线路处于高电平,当收到发送数据指令后,拉低电平一个数据位的时间,接着数据按从低位到高位依次发送,数据发送完毕,接着发送奇偶校验位和停止位(停止位为高电平),一帧数据发送结束。
1 ~! W: i: }( G% m+ Z c* _- G( \: i3 H/ M/ C$ E% H8 `
·接收数据过程:空闲状态,线路处于高电平,当检测到线路的下降沿,说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕,接着接收并比较奇偶校验位是否正确,如果正确则通知接收端设备准备接收数据或存入缓存。7 i, e5 f& P) A3 h. I+ v
- }5 \6 J1 Z( ?/ E: f
由于UART是异步传输,没有同步传输时钟。为保证数据传输的正确性,每个数据有16个时钟采样,取中间的采样值,以保证不会误码或滑码。
$ o2 p( @; z8 X, {, F$ N- `% D5 {" \" K
·设计实例:
+ _) i6 N# ~ t+ ]* f4 @- u' l6 g9 l. M, s5 s" T( Z2 h
下面是一个UART的回环实例代码设计:5 u$ f5 p3 `9 H: U2 e0 G
; d# X# `; E. b
接收模块uart_rx:1 V. @1 L0 j6 n' c H7 H
module uart_rx(
5 L1 a$ i6 _3 B4 q( f/ @' y# C1 L input rxd,
, _7 p6 J" H3 A0 S input clk,
1 p8 u& _9 N* U5 \6 F2 y* \ output receive_ack,4 ?& U+ c, K6 F
output reg [7:0] data_i# X( G |" P1 H
);
3 Z* t4 `9 _; v% U
+ x/ Z. b0 H2 m parameter IDLE = 0;; r9 l% _: x3 U0 |# B! Y
parameter RECEIVE = 1;
, J \& K* K6 s& B. h parameter RECEIVE_END = 2;3 W, t. _; N- y7 v5 w/ L0 V3 B
3 t, Z1 M. ?/ H2 _3 W reg [3:0] CS,NS;
$ u. G: I; w4 U2 u$ k reg [4:0] count;
6 f& @3 y9 \& @% }) i D- Z9 A; V reg [7:0] data_o_tmp;
: m% T. y- a0 o
8 k: X. k( V. X; \2 C! Q- q always@(posedge clk)% R" J& d& V- A
CS <= NS;( m* \8 O! Q) T
( I* E6 [$ a' O' O9 O always@(*) begin
0 T( V5 g! O: z; _# Q6 t NS <= CS;
) r3 B' E1 X% H0 W case(CS)
; D! Z- x6 f# w IDLE: if(!rxd) NS = RECEIVE;
4 Q# @5 S0 y# H7 o' ^ RECEIVE: if(count == 7) NS = RECEIVE_END;else NS = NS;0 h" [7 q. O# c( {
RECEIVE_END:NS = IDLE;
/ B0 b% s* j' x u4 l default: NS = IDLE;
6 G3 P8 } t3 O+ K/ F% X+ C% j& d7 L endcase
/ \8 E9 R( I7 R* q% A end
! p+ d) S, k3 D: D * M1 |4 ^$ \2 q0 d8 Z" m) W
always@(posedge clk)
" x$ D# R# k' C0 m; P- x$ Q if(CS == RECEIVE)/ e2 k r! H# }* E r7 G
count <= count + 1;3 H% j( E5 W" Y. W
else if(CS == IDLE | CS == RECEIVE_END)
; ], f* n; {: O# v: { count <= 0;: q0 D$ k. H. _
9 O' q" h; N$ `. U6 A always @(posedge clk)" j( n7 A! Y+ J2 p
if(CS == RECEIVE)begin/ A6 F% \6 b8 o
data_i[6:0] <= data_i[7:1];
& f0 K8 L. R2 f1 O6 n$ W0 x7 a. B- S9 b data_i[7] <= rxd;4 C4 H5 B: k' \# n) R G ~
end" X6 [$ n F% S
9 A" t& i% M# I" m1 P+ H+ t assign receive_ack = (CS == RECEIVE_END) ? 1 : 0;
, N& `0 W; O+ B. f+ H + G: @1 v. g7 I, r6 j
endmodule, d1 ]. N3 c. ^* l# `
+ n% L# {! a$ a" U+ x0 M2 K& k发送模块uart_tx:' |' t3 t! x7 P1 H# S) [8 c
module uart_tx(
7 K7 A- b8 I2 X) [ input [7:0] data_o,6 U2 K! i$ P0 @% J h% c3 G
input clk,5 n7 z! ?% L) y& V+ u. X/ P
input receive_ack,7 b& i& f7 u- |! d4 Q. o
output reg txd
9 j5 f. l* E# y/ k, n& ^, H- e );7 j0 w9 d+ J* J, O( @9 S7 P
parameter IDLE = 0;
" W: O1 V1 ?+ a parameter SEND_START = 1;, y- I! S5 s V& l
parameter SEND_DATA = 2;4 \5 G3 K( E# ~+ @
parameter SEND_END = 3;
* x. ~: P# J$ \ 9 h* W0 A5 u4 y; T" o v
reg [3:0] CS,NS;! A9 C! L. X1 J3 W
reg [4:0] count;% y! O4 w3 b* q) T. N
reg [7:0] data_o_tmp;
b( j$ P7 \/ A4 c% B
& [2 _3 g( U6 {; X always @ (posedge clk). q. S: L* e2 s
CS <= NS;6 @9 f& j0 c8 N2 r
4 ]# L# k2 W8 F! W3 h+ N3 G always @ (*) begin
, N$ _% O% M" c' _' F5 ?; ~1 f NS <= CS;
& _$ H) H* v t3 [- _* O0 X case(CS)
+ D: x9 w# y* y( n+ X IDLE: begin if(receive_ack) NS = SEND_START; end
2 P3 y- g; L/ i" y; I5 B SEND_START: begin NS = SEND_DATA; end
( V/ W1 g$ t, Z1 m X SEND_DATA: begin if(count == 7) NS = SEND_END; end
3 f1 d: i7 A# _7 U5 W SEND_END: begin if(receive_ack) NS = SEND_START; end
4 l" f, B: Z; C: Q default: NS = IDLE;
1 ^' Q' |5 Z5 C endcase6 s) g* o* T& H# x! {& j
end5 d m% K$ C4 g" @
3 T. Z8 a- a5 `
always @(posedge clk)
2 U) H, ^) {- o) } if(CS == SEND_START)
& W6 k9 {3 e% L count <= count + 1;' o1 X4 m* w5 p
else if(CS == IDLE | CS == SEND_END)
* G& m) N9 i4 B, V* I( v# h count <= 0;9 T: J) d! @5 K& z6 S
else& R; ~8 z0 T k) n. n! F: H
count <= count;
9 m {9 |& D- G2 y2 I' B. _; b * D# t9 l0 ]5 @# S7 b+ n' P4 u0 a
always @(posedge clk)
6 I) O5 C& ]1 \) \: C% R if(CS == SEND_START)
$ S7 f: A1 \+ `0 J" { data_o_tmp <= data_o;+ v7 D& j% c1 J: U
else if(CS == SEND_DATA)4 E: c8 H b' [% P& ~
data_o_tmp[6:0] <= data_o_tmp[7:1];" X+ T$ {' H1 C" r/ @& O
, U- _9 f* ^2 d
always @(posedge clk)5 x6 a% f0 w& X5 u
if(CS == SEND_START)0 `- _$ n2 j9 V7 ~
txd <= 0;
+ ^" E6 t1 W& L7 W- \; z else if(CS == SEND_DATA)4 b6 c! K v, b
txd <= data_o_tmp;
& T, G# P3 i4 C( C9 } else if(CS == SEND_END)+ p7 c2 L$ K8 r" m/ L
txd <= 1; + `# E" h& c5 x' v1 ^/ f" a
5 z1 a6 |* |) ~+ P9 S1 G! [- vendmodule) ?: p0 }+ \- {# c3 O
module uart_tx(; z" F3 V8 K5 I& z0 s
input [7:0] data_o,; j6 R! o; w1 k% `
input clk,! \* S/ d% @6 R- D. V, j
input receive_ack,
4 k+ \- i! u* w9 r% U$ h output reg txd3 m: P% S) X0 T3 c
);! l6 I' z: X) R3 m$ O- l
parameter IDLE = 0;% c- w. Z$ r( @2 k$ M+ R6 K/ ?
parameter SEND_START = 1;
' i' G( s3 a; o0 Z. ~; X) E parameter SEND_DATA = 2;
* k) V6 k6 M P; \' S o+ K parameter SEND_END = 3;3 _- r% F/ v/ w5 r9 D/ m2 Q8 K1 \; f) y
( f# o! a2 V; y" \& D$ g9 r: E3 y$ e
reg [3:0] CS,NS;+ E. B0 U* F) o6 q( ?: J" M. J
reg [4:0] count;
1 I3 V3 W- m; O9 ]" Z reg [7:0] data_o_tmp;
% K2 W$ V% g7 J% M1 H
; S: ~8 m. p$ g$ O4 G always @ (posedge clk)% N# U) ~7 G; a, Z8 R0 i
CS <= NS;2 b8 _( f8 S: O7 n. V# E
) Y1 F$ \- G5 `# i$ w$ }
always @ (*) begin
9 [3 R# w' U7 G# a J NS <= CS;: m B- u9 j$ c! |0 _) z% a5 B
case(CS)- ?7 z$ w. b2 t
IDLE: begin if(receive_ack) NS = SEND_START; end& y$ k- U+ k' G3 X7 B! P, w
SEND_START: begin NS = SEND_DATA; end
6 D( q+ M/ Y" t8 i, w8 O SEND_DATA: begin if(count == 7) NS = SEND_END; end
# ?) X2 v3 W$ s7 [9 l SEND_END: begin if(receive_ack) NS = SEND_START; end: N2 K" N8 u$ G, N# a
default: NS = IDLE;+ \2 b+ l" Q" \
endcase
, b$ f+ _( _% {4 t# e F% q# o end! r+ ]8 ?4 N- D( Z/ D$ m, v
% Z; R; [" }5 A: t2 z; _% T
always @(posedge clk)
$ c3 c, _, g+ p9 s; o if(CS == SEND_START)
7 l4 T1 l8 U& r: {( Q. O9 x/ d count <= count + 1;) b7 E) L6 R7 D; {3 P5 o. D+ C
else if(CS == IDLE | CS == SEND_END)2 J, r8 \% g4 M* B5 a: p% b. p5 Y
count <= 0;' f2 N7 K5 Z6 l1 U* j- {( t, k- b
else$ W2 H+ I2 ~1 W0 u- {9 s* \ [$ ?
count <= count;
: H& G. N9 j# g& O6 [ 4 d; ]2 a* B& M/ u. K
always @(posedge clk)+ E! L- [8 _. u0 z5 w, U
if(CS == SEND_START)
" P) e P8 a' y5 B+ _1 ` data_o_tmp <= data_o;
3 T( e! P& _2 P$ {! G2 p6 t else if(CS == SEND_DATA)& O: J, c4 K8 Q1 r8 D8 E
data_o_tmp[6:0] <= data_o_tmp[7:1];& | f) i$ s. _
8 r* Q2 M+ F+ G" m s* h& r always @(posedge clk)
4 @8 T8 k& h4 Y) i' P/ |+ m if(CS == SEND_START)
9 \& b% A9 T8 k6 W6 X) @/ Y( m& x txd <= 0;/ q' B+ C$ t0 F
else if(CS == SEND_DATA)" W. Q+ r0 |3 H2 ~: y
txd <= data_o_tmp;6 b1 U) |% @9 T/ X9 l* \. `
else if(CS == SEND_END)
# ?8 V8 n' P, c( M+ D txd <= 1;
/ ~0 L' W4 z E$ i, H
" q( k$ X e3 [+ tendmodule
; K/ @' O& B% q' G" S$ u, q( o! Q) x+ z( M$ T4 s
特定波特率产生模块clk_div:
" @, q/ V4 w) `; j, y# nmodule clk_div(2 j" t: L% s3 I1 @& R( `
input clk,! g' y/ |% W2 V# F, Y9 O
output reg clk_out* y0 z# r9 l g- p% y3 l
);: H) [; X# _0 ]/ Y6 f: z1 C" e- p
" x/ U+ K3 o0 v' c: g& d& w: r9 m' E
parameter baud_rata = 9600;
6 @: z# V0 Y2 J parameter div_num = 'd125_000_000 /baud_rata; //分频数等于时钟频率除以想要得到的波特率! L* X: l% [+ G* L/ Q
reg [15:0] num;
$ }$ {/ Y- @2 u8 K7 j) {' z1 b- H* s5 n: {! F
always @(posedge clk) begin% v3 }, E8 h% u( E
if(num == div_num) begin
7 X- F: e$ _; E( r8 s num <= 0;) k6 s% t: Q3 ~1 D' r
clk_out <= 1;; z2 j8 _. {& ?" N
end+ t3 u7 t, i# c* d. A) s: b
else begin2 g. |+ Y6 M+ c; d4 `3 E
num <= num + 1;
0 |+ @* x& S7 t3 f8 d# a" O clk_out <= 0;
' A7 W! }: E }2 D0 N: D end
4 a8 E7 n3 [1 P& a end
5 D; u, C1 c. e2 s" g
; m; L; U4 D* @endmodule
( e3 {2 q- D6 y7 O8 z顶层文件uart_top:
, R2 T: `% |: L" h: Y4 ~% c
9 ~- X/ G4 N/ H+ A$ P) rmodule uart_top(2 P. s( B2 g$ [2 w
input clk,$ ^ H+ g$ s; }0 h" v% B5 U
input rxd, F) ]1 S" ?$ `0 @% N/ R. ]$ w
output txd
- K$ x: R) C1 I );
% {3 O# {9 w* d3 C$ \ W9 m! U/ |5 u) _9 u
wire clk_9600;3 W. w: y& H$ q, g7 d8 a) n
wire receive_ack;8 w$ x z0 D) f" B. H7 ^3 e5 c+ M
wire [7:0] data;
; @! ]) ]7 W# S
+ g1 i! |& w. h( x uart_tx uart_tx& o# X$ Z& a5 v( _9 W) @5 B" J
(5 w# S/ A$ I& d
.clk (clk_9600),% ?8 F; o9 ?' r6 w T7 w3 v
.txd (txd),: P, j/ }+ J' e$ F% t# ?# o e
.data_o (data),
) r: H5 ]; v9 J0 _0 S .receive_ack(receive_ack)4 y" H; L7 w8 A
);2 H, F: ^0 m, n1 Y+ J; K _' ^
- Q/ \' ?6 U* f: b# b- ]( s
uart_rx uart_rx
1 `6 p8 O; c$ b3 E5 X' Q: ` (
6 K0 L# Z& R# d2 i b; X1 c .clk (clk_9600),
$ K# L+ Q/ Y ] .rxd (rxd),) O& w- r& L4 ~& i
.data_i (data), ?) K: x# Q1 c5 b8 M
.receive_ack(receive_ack)
- [$ a! Y" m& v& U b );
; A7 @* b5 K; P. Q3 l+ m8 [# ^6 R$ y
; m5 T; {! Y* \; b O clk_div clk_div
- m) a5 T+ e! k a7 l (! e& D) ^) X* f8 |3 r
.clk (clk),
. A: R, D7 S2 i: D9 g! R* T .clk_out (clk_9600)6 W% L) H" |' l9 v% F- g+ @
);" Y" _; [" Q! c
- }+ A" s6 Y* b+ ?" wendmodule% h8 K' T* T7 [7 [
- i" C$ O/ \8 Q r9 G. D2.PS/2) U1 C# i$ i- _, i1 T9 T9 d2 ?
PS/2是一种双向同步串行通信协议。接口是一种6针的连接口,但只有四个引脚是有意义的,分别是Clock(时钟)、Data(数据)、VCC和GND。其中时钟和数据引脚是双向的。PS/2常用于连接某些输入设备,例如鼠标、键盘等。通信的两端通过时钟来同步,通过数据引脚来交换数据。任何一方想要抑制另外一方的通信,只需要将时钟引脚拉低即可。: o) H6 z, S8 i) V, J, a# L
如果是PC和PS/2键盘之间通信,PC必须做主机,即PC可以抑制键盘发送数据,而键盘不能抑制PC发送数据。) f9 C1 A3 v, f, z
PS/2的每一位数据帧包含11-12位,具体含义如下:
' f& W( B7 X; I" N# f数据位名称
/ }7 R5 y. r; T+ |说明
! v0 y; n9 R8 X* H0 K1个起始位
7 }. j" h: |& O0 V. Q" P总是逻辑0) |+ J' ~9 U$ V+ c# Q
8个数据位/ G4 y7 P/ S& \" ~0 K5 t; Z
低位在前% c8 f& k/ c8 u& k5 W/ Y
1个奇偶校验位 奇校验 C; K! p" ~* Q7 O. a Y. e
1个停止位
' E) v* Q( V" v; @1 Z" O* t) f+ @+ r' U3 T- m0 P. k, u
总是逻辑13 y7 q1 N7 b" O
1个应答位 仅用在主机对设备的通信中3 L8 }6 j, C+ c T/ Z
9 ]% e- D) ] \7 O# L
由设备产生时钟和数据,主机根据时钟来读取数据。以FPGA和PS/2键盘为例,键盘产生时钟和数据,FPGA只需要读数据。当时钟下降沿时,FPGA记录数据信号。
2 Z9 T& g4 i$ s! K7 ?6 b5 N. c& c·设计实例:' t' q" }+ ^* K% B+ P6 ]
主机为FPGA,根据PS/2的时序,得到键盘的按键值。虽然在时序图中,主机是在时钟下降沿读取数据,但实际上要为了排除噪声干扰,需要在FPGA端对信号进行滤波。下面给出设计代码。& _- c- E9 r9 G
module ps2_keyboard(
' t# H# v; ]2 z/ K t6 z input clk,% D! e* {7 K! a; C; @' _
input clr,
- m4 t3 l% k) o i8 Z. p1 J6 k input PS2C, //ps2 clk in
' `2 P+ M) G c( O% U; e input PS2D, //ps2 data in
+ s1 r% C3 G# S' Z- R
' i' V& v& O# [ output [15:0] xkey
4 T& ]+ w& \3 _( B5 L k);2 K, o+ ^4 C- @* Q' s a2 `
reg PS2CF;, f9 T, n3 t1 Z; ^1 j
reg PS2DF;0 a. X5 u9 Y9 n5 @
reg [7:0] ps2c_filter;
2 ^0 f. N ^, A. ~5 Qreg [7:0] ps2d_filter;
" I! v- @# d# r# ~$ c. Areg [10:0] shift1;) S- F F7 [3 W
reg [10:0] shift2;% P/ T+ z) R. H$ @
7 ~; {6 A+ k" x2 wassign xkey = { shift2[8:1], shift1[8:1] }; k+ h ]* n" a6 ~) Y& E1 G# {0 \. j! c
always @(posedge clk or posedge clr) begin1 M8 X- ?" w, o% T+ R4 }0 f+ ], I: A- w
if (clr) begin
/ y6 V* @' s" [5 C9 T9 h ps2c_filter <= 11'b0;
' y |# j0 {& `& n9 d. ? ps2d_filter <= 11'b0;
, _# c% r& |2 T( c \' ] PS2CF <= 1;
/ f% Z: m R! ], Q PS2DF <= 1;) {3 Z* z9 N" \* D W
end
k5 |' Q4 p- n( f else begin
8 X2 F. B% w( `5 c# G! p5 _7 p ps2c_filter[7] <= PS2C;3 o- D$ @8 L4 r. l
ps2c_filter[6:0] <= ps2c_filter[7:1];+ H; W K' d. W6 {' d9 w2 ^& v
ps2d_filter[7] <= PS2D;5 O$ M! p0 e' {% e0 Z1 t& w
ps2d_filter[6:0] <= ps2d_filter[7:1];
6 F( Q! R+ t6 T: H5 a3 F if(ps2c_filter == 8'b1111_1111)" O* ]4 N' m( o- ^. o% L
PS2CF <= 1; //去时钟毛刺
& I9 w( a! g$ H0 D N4 t q else if(ps2c_filter == 8'b0000_0000)
/ U* c E, M. ^. C PS2CF <= 0;
: j, e% {8 t0 ]. ]; ? ^ if(ps2d_filter == 8'b1111_1111)
1 @$ r! y+ e" f% J6 j6 V PS2DF <= 1; //去数据毛刺
" P- p# O) Q; t1 R! e! V else if(ps2d_filter == 8'b0000_0000)
4 j4 i$ O5 z, K6 a2 X" G- v+ d PS2DF <= 0;8 _4 `% V7 h% j
end
% T3 t2 S& | `( L2 R( `end
: {) K5 x3 w% q Z9 z2 H9 r9 m2 q, `3 {& I
always @(negedge PS2CF or posedge clr) begin
, D7 L# ?2 L) A+ v9 |" u0 {3 P if (clr) begin/ ~% Z( b; Y D; G f$ n
shift1 <= 11'b0;8 \# t8 \+ C) m' I) C* y( ~" f
shift2 <= 11'b0;
; @' ~: g; O6 w5 G6 S end
- W* S* ?( A: R7 b6 A7 m else begin
- k3 k. N2 _4 I9 V2 u6 v5 X shift1 <= {PS2DF, shift1[10:1]};
; Q6 Y/ Z6 l; y, _! c0 A$ l shift2 <= {shift1[0], shift2[10:1]};
( P: I; o( C3 y- C/ T% Y( H3 P, A8 E' R end1 ?3 q+ P& G- V, G; {1 O) U
end
5 W% Y* S. }2 {
0 S# b- q1 j" Jendmodule
2 ~8 z7 W5 B( W- e' ?* }) J: R |
|