找回密码
 注册
关于网站域名变更的通知
查看: 265|回复: 1
打印 上一主题 下一主题

转——基于ZX-2型FPGA开发板的串口示波器(二) 

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-4-18 09:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
转——基于ZX-2型FPGA开发板的串口示波器(二)

: S/ l; y  k8 A4 g- x
串口发送接收模块设计代码分析
. T4 d# Q- H, G( D" d" E1.1Tx_Bps_Gen
  y) d+ s8 [3 F
Tx_Bps_Gen发送波特率生成模块,每当Byte_En信号到来时,即开始产生发送一个完整字节的数据需要的完整波特率时钟信号
( p6 g$ y- e% o' j/ t9 A本设计,波特率支持9600bps921600bps例如需要产生的波特率时钟为9600bps波特率时钟频率为9600Hz周期104.17us生成9600Hz波特率时钟的核心思想就是对系统时钟进行计数,这里设定系统时钟为50MHz,则一个时钟的周期为20ns,我们只需要对系统时钟计数5208每计数5208产生一个时钟周期的高电平脉冲,即可实现生成9600Hz波特率时钟的功能。相应代码如下所示:* x$ _, p+ {/ Z( P

5 y3 y, D- b/ Z2 ^5 q2 h! w2 D018     parameter system_clk = 50_000_000; /*输入时钟频率设定,默认50M*/" G9 B! |9 U! s8 W4 x
! _1 F8 C2 |8 O2 b
019
: C  f5 Q2 w& [: u' g2 j
8 U3 n7 ]( S$ ~7 m020 /*根据输入时钟频率计算生成各波特率时分频计数器的计数最大值*/        
- {! u- ]9 L* T7 x! ~* ?
% u  q0 U: L& r% ?5 B" k6 z- U, n4 ]021     localparam bps9600 = system_clk/9600 - 1;6 M$ f8 Q4 z9 \; X

: R0 h% `& @4 B3 g. w( R# R3 [' }& N022     localparam bps19200 = system_clk/19200 - 1;
0 k# ]) }% f8 R- {& f" ?: ]1 \: n
# V1 w% d% W1 q! k2 Z' b8 X023     localparam bps38400 = system_clk/38400 - 1;
& `! \) O9 H6 b' K3 R6 b  M  _  k; B9 H6 q+ p9 ^
024     localparam bps57600 = system_clk/57600 - 1;
" @0 }3 O# o1 L1 G1 l7 U- M4 V- P7 N% j
025     localparam bps115200 = system_clk/115200 - 1;
1 S- r3 v4 K% l' J5 Q7 Y) {0 M  {9 j# t0 E$ ~/ T1 A+ J
026     localparam bps230400 = system_clk/230400 - 1;
1 T' |+ B9 E: p5 j. `$ P5 y1 S& c  K4 |7 Z* M- Z" [5 d# c
027     localparam bps460800 = system_clk/460800 - 1;
! i/ F5 F3 [4 r' D% \
6 `8 d$ e/ g( W1 Q$ z028     localparam bps921600 = system_clk/921600 - 1;       . K% `% i3 i. A% [: a% e& B
1 b4 }# @" g  H' M& H( S  a; t% l
029     
# b8 B9 \- M  b1 u5 b4 F% X; U3 X8 m$ k1 Q  |+ b/ d  F
030     reg [31:0]BPS_PARA;/*波特率分频计数器的计数最大值*/
6 r/ o0 n' q, A: Z, _, c
$ J8 a1 z  [% ~, z8 D031
9 X! l+ E; K: b  p1 M
$ ~  r# W% M" s8 }1 b032     always@(posedge Clk or negedge Rst_n)% E4 e$ `# J; x
& I3 p/ Q9 R6 ^) J4 i) `) N, C4 o
033     if(!Rst_n)begin2 B" i  S) f7 _6 f& p

+ o  z# w! l/ @' Q' z034         BPS_PARA <= bps9600;/*复位时波特率默认为9600bps*/! r7 [1 _0 _4 E5 d( P+ c; E

* x& ?9 p* `5 q7 c" t3 L. b035     end
$ R/ A. {# {  M% k+ c5 O% U# p" n; I) r. A0 g# {
036     else begin3 E1 m0 y* ^. f* {- `2 c- C% m

7 X( b3 O* n" u: }% t: S037         case(Baud_Set)/*根据波特率控制信号选择不同的波特率计数器计数最大值*// G' m+ O/ g0 O' o$ m

$ |, s! j5 Q2 F$ W# Y( j7 x038             3'd0: BPS_PARA <= bps9600;
: Q2 n* G# X8 c& e; w; v2 w* \' |5 S$ z( I5 \1 m8 G
039             3'd1: BPS_PARA <= bps19200;1 W8 G' `) }4 d, O4 n
: P0 E0 F6 b5 o! z
040             3'd2: BPS_PARA <= bps38400;6 ^( E/ o% j- {8 e. r

  ]- i- d6 n" p  Q: s. r041             3'd3: BPS_PARA <= bps57600;
- y- V0 k& i1 c
& e8 w* f, f6 Q& o5 v0 b042             3'd4: BPS_PARA <= bps115200;
4 L0 W) s$ a; \7 t% X0 S+ n" R* c4 d  y  o
043             3'd5: BPS_PARA <= bps230400;6 E6 W7 \3 c1 t& [3 c
! L# q, C" D3 [- Z5 l( h
044             3'd6: BPS_PARA <= bps460800;
- j9 _+ d% u( I
/ L' m" ~) V8 [045             3'd7: BPS_PARA <= bps921600;            
4 `' X( G5 t7 w  u/ x, w' U2 J
) J7 e) C. X" G7 @9 P' V& j046             default: BPS_PARA <= bps9600;
8 T; O" u8 L5 N+ m2 Z; s. b7 E7 F6 A3 T& _0 Q1 f" M! e* z. G' k
047         endcase& g: q/ O6 g7 t) N
* J/ i( [! W8 X4 o/ B
048     end
* g/ n/ [) |. o1 E% n+ B% P6 m: a1 x
049     
- r) C( C% g2 t/ Q' S5 K; Y& ^; n  S( l. `
050 //=========================================================7 P- r1 {1 X7 T( J# r/ x4 e

: W; A. y7 G3 v5 ]051     reg[12:0]Count;9 d. c5 a5 l& `# |% O
8 P0 \* |& B9 ]- y# A, B, ?5 H5 f
052     % Y  z( {% E1 n4 z2 Q8 U4 T

( k9 B, P) Z. z  J$ i053     reg n_state;
8 X( P* d- C- P) T' }/ n% C! W* r% \5 N# c8 a8 [9 W
054     localparam IDEL_1 = 1'b0,3 i9 c% O6 q" [" x) c$ ?7 m

+ `( _; g" G8 Q" K- ]4 e& p4 J7 H055                   SEND   = 1'b1;' b, z" |. @1 J$ L5 x5 ?' s1 u
6 n* ~8 s' M- r- r
056                  
/ u. g" @; y- S3 |9 i% \6 G/ u# D* L  Z' e: H2 g
057     reg BPS_EN;& m7 v3 r& ?% W; @

% `/ @$ q+ M# A7 W# |058     - Y9 _( d* X9 u5 H& u4 A/ N
: g2 O* }$ S; e. w
059 /*-------波特率时钟生成控制逻辑--------------*/  ' l" ]. w3 u2 O4 x+ l4 _( @. U& ~

0 _, y; Z4 h6 ]1 _) X060     always@(posedge Clk or negedge Rst_n)5 ]9 t6 C# `8 }' Z" {* Z7 ?
4 l$ R- F7 R: S& R: _
061     if(!Rst_n)begin
8 l# i4 z7 x, K7 s( f
+ S% q( u5 h8 {  Y062         BPS_EN <= 1'b0;
( ^5 Y: p  d- l' p3 v9 Y% Z  p! T
/ `/ i* T4 `/ r# H7 g0 a( s063         n_state <= IDEL_1;) K) Q9 H: Y( l' M5 \3 Y/ d

! X5 D1 r# m5 ^2 X# |064     end1 n# y$ E) S% L" O  w; x/ ]* B3 Q

$ N) x2 _' I1 j  w# c- D. {. `- Y065     else begin
7 B3 _+ w1 q8 `+ P
4 ^- ~9 q- T* e5 d) ^' q9 j! |066         case(n_state)
0 J' M, T6 w9 v' B/ t
& ^) o7 I% s3 f. J0 o7 P' R067             IDEL_1:5 w7 ]; u# e! f* I( h8 u7 f% w8 w$ G% ~
, n( `, F9 H8 E. B- Q
068                 if(Byte_En)begin/*检测到字节发送使能信号,则启动波特率生成进程,同时进入发送状态*/
/ A$ Q! p! Z- L8 U" I
8 u: e5 G) A0 n" {" ^. p069                     BPS_EN <= 1'b1;/ e5 V$ A- [* Z7 y* v
  a; r! }/ t& V! X- F7 W% b0 _; v
070                     n_state <= SEND;' {7 M6 F+ `% o7 p

7 ?6 e- o% L  B+ P3 j2 ~071                 end
- m7 l; C3 A. ?) s; K3 J
4 Z& h4 [3 ~& o072                 else begin2 U# Y* o7 m0 G9 r1 C% l
9 i7 Q( X  {% ~7 ?
073                     n_state <= IDEL_1;# ?8 U9 E4 ]! {6 @* x' I0 U
& q2 v1 c5 \& ]! d
074                     BPS_EN <= 1'b0;
6 a, E+ p" d0 P( K4 o, ?8 l, u  l
' _- q+ B  M" \# |075                 end# \, n1 o/ a. I  p! j

* }* }$ Q4 l0 q8 n1 [076             SEND:
1 [. _7 ]7 \2 T
. l: t6 @" C! P& {, J; P  b4 I077                 if(Tx_Done == 1)begin/*发送完成,关闭波特率生成进程,回到空闲状态*/4 L5 b  @$ `; c9 S  i9 a. K

, |/ }8 p! Z' G078                     BPS_EN <= 1'b0;6 Y& ]' ^  W% g- F6 q

7 r/ \; b1 A' z  i5 w079                     n_state <= IDEL_1;
& o0 \3 s( y1 L( x( K+ \, T1 L& C9 ^- H
080                 end
: P- T5 A  E( ?5 V; g, f) I) F. X+ X/ W
081                 else begin7 A2 G" h7 i8 S+ g

/ {; }: ~0 y1 z- i082                     n_state <= SEND;
# V. c% x) l' B. h7 D3 j/ T; v
" Y& k" F) O9 }( ?% m083                     BPS_EN <= 1'b1;
  ]6 o0 u" l! L& a
7 k, y$ d# Y' ^: V$ l+ q' C084                 end
' `$ N5 O) @* t! v& H6 W; M" d1 O" [7 G' z3 I8 G
085             default:n_state <= IDEL_1;
  e. y; N( s' E, p5 R2 p
% b6 A2 T' w; t) A# _. \5 i' x086         endcase
5 N) J  }/ C+ ]/ m% @. Z2 b: n& I5 R) x4 {
087     end
/ t0 ~" S  G. c* e
& Z/ Q, t; E2 T+ n+ g0 @# G088  O' s$ C+ Z3 I, ?; E1 J2 Z
6 z" e7 I1 h% h8 u% K
089 /*-------波特率时钟生成定时器--------------*/
7 E' h( G" k' f! K0 x9 a) x' s1 |7 ^
090     always@(posedge Clk or negedge Rst_n)
% f0 r2 q  H- Q% O! o( Y8 X
+ A- q1 a9 P8 l5 ~* r3 V% _091     if(!Rst_n)
; g- \" M# R$ z# `
" h+ L+ Y+ c- S& l) u6 h2 K9 P092         Count <= 13'd0; " G9 o5 ]' h! u' e5 ~4 D7 c& e
: I* Z: N  n9 V& O' F. `# a
093     else if(BPS_EN == 1'b0)- J& L2 f/ ~7 [* X5 z

. P* d" |1 h# m5 d& F! g2 h094         Count <= 13'd0;9 B7 V! j* R* H! f
$ I. ^2 v1 Y3 J6 C3 ~
095     else begin9 L3 M" g* _0 ~

) |8 J8 h! P( Z$ L' y096         if(Count == BPS_PARA)4 A6 a% q) x' h7 N4 Z/ h

! F2 J; I9 s+ L$ l3 `097             Count <= 13'd0;$ ~! f7 {" i9 @7 V) u0 @

1 R0 w0 I4 t) s- C& e098         else
% k, D4 q5 b6 M* N9 z
' A2 i0 n+ e2 z1 d( e) ^099             Count <= Count + 1'b1;
& G/ S) `3 F, p; ?6 I. H  ^
4 `0 K& y; D( M% y6 T" M7 P: K% A100     end
6 o2 K; I% z3 g" _- X4 W9 n0 A! a* y2 H+ W- }. {! s
101     1 O/ R6 N( F( X
( x7 z4 a' n: x0 v' Z) r
102 /*输出数据接收采样时钟*/  " F" [5 ^$ Y+ `" z! x5 e3 m" S3 B7 k
" K% l% b) f9 b0 L' I
103 //-----------------------------------------------8 b; k/ S6 T( G2 S, x, q" l

. m" ~1 f% a! C& G5 {# G104     always @(posedge Clk or negedge Rst_n)
9 Q8 M) O6 W# f) I  e( a9 b' ?# ^7 C3 a& q
105     if(!Rst_n)
7 N' V: j9 h# l& V7 D. A9 @$ I+ L  L. y: j
106         Bps_Clk <= 1'b0;) H$ M/ b5 b0 ?/ @( H- b" L

7 V4 j( R, A1 g5 h, z8 O  `) [107     else if(Count== 1)
: V, y5 j: C2 _2 i
+ I1 V) j5 [# ~/ u2 {108         Bps_Clk <= 1'b1;6 `( u) d) x0 U, O$ H

1 L9 {: z6 l- ~109     else ' u5 n8 u& {. Z# `3 d

7 Q. Q7 L4 D; V3 @110         Bps_Clk <= 1'b0;7 u. x2 {8 e7 F

2 \8 ?) S' b: [: f0 e3 o
' s4 }0 |9 \- O' ]4 W
18行“parameter system_clk = 50_000_000;,这里用一个全局参数定义了系统时钟,暂时设定为50M,可根据实际使用板卡上的工作时钟进行修改。 0 Q5 @" [* x. L$ F( W9 l, {
所谓波特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信号的周期计算出来,1秒钟为1000_000_000ns,因此波特率时钟的周期Tb= 1000000000/115200 =8680.6ns,即115200信号的一个周期为8680.6ns,那么,我们只需要设定我们的定时器定时时间为8680.6ns,每当定时时间到,产生一个系统时钟周期长度高脉冲信号即可系统时钟频率为50MHz,即周期为20ns,那么我们只需要计数8680/20个系统时钟,就可获得8680ns的定时,bps115200=Tb/Tclk - 1=Tb*fclk - 1=fclk/115200-1。相应的,其它波特率定时值的计算与此类似,这里小梅哥就不再一一分析。2028为波特率定时器定时值的计算部分
" ?! T! r" d& c7 }: A为了能够通过外部控制波特率,设计中使用了一个3的波特率选择端口Baud_Set。通过此端口不同的,就能选择不同的波特率,此端口控制不同波特率的原理很简单,就是一个多路选择器,32至第48即为此多路选择器的控制代码, Baud_Set波特率的对应关系如下:
( d! d. B% ?; T* L! t: M$ K% b
9 r! X" v# C0 z2 u2 Y# C000 9600bps2 N% t6 }7 y. L" ?7 D4 v
& d" a) i- E( k6 V. [
001 19200bps;2 T# w8 f9 K& S1 M
0 F/ z) }' {' q
010 38400bps;' h; Y- _8 h/ x: c9 T" f
' T2 m  L, J2 Q0 B1 C( p
011 57600bps) N* u6 i. L0 A
* M* k# n0 f9 s0 h6 m) L+ \0 y/ g2 z
100 115200bps8 u" }0 O/ c; ?) C) S

3 l9 v$ \! M! ~2 j101 230400bps
/ P- F$ d3 q5 t( s
! M  ^9 s& O2 }8 @110 460800bps8 l' M# e8 r1 x* t# @; e+ e0 O

5 Y$ l3 c9 Z: H7 b( [" [# J5 c' E" s111 921600bps2 l4 d$ D% m) R9 D

4 h/ `" U; H7 P# ^- v' J
* \0 D, s$ i9 a. d1.2Uart_Byte_Tx
+ d' w1 C9 p+ o! E9 q- `4 \  T) g7 X
Uart_Byte_Tx字节发送模块该模块在波特率时钟的节拍下,依UART通信协议发送一个完整的字节的数据。当一个字节发送完毕后,Tx_Done产生一个高脉冲信号,以告知其它模块或逻辑一个字节的数据已经传输完成,可以开始下一个字节的发送了。发送一个字节数据实现代码如下:! u+ @% [9 Y$ _1 O7 V
+ }2 h' q' \) a/ R, u7 N
33  /*计数波特率时钟,11个波特率时钟为一次完整的数据发送过程*/    ; D( l0 K/ B# f( q2 a* n: ^

2 w, T! v+ \+ |& S! I- G( m! I34      always@(posedge Clk or negedge Rst_n)' h% }2 f5 U6 c3 Z! s( H$ J

- [( |# v1 ?+ ~, e35      if(!Rst_n)( w0 Q0 F: G+ j' f, J

" P; T; T. P+ K. p$ T+ _; v6 _7 m36          Bps_Clk_Cnt <= 4'b0;. ?  `/ n8 d$ [' d9 `& b, A
( t; ^- p. v* f/ j5 d4 Z
37      else if(Bps_Clk_Cnt == 4'd11)
1 W% Q. U5 {, ^6 ?" Z: }0 Z" ^! L& v: |. y
38          Bps_Clk_Cnt <= 4'b0;
3 h, @) c9 \3 f/ K7 \! ~. x
4 k+ R" l8 Y! O1 |" M9 b# A( L39      else if(Bps_Clk)
1 W  ~; f0 @0 I# t) [1 r; I( U4 A1 P! o& `# c6 s
40          Bps_Clk_Cnt <= Bps_Clk_Cnt + 1'b1;* U* C( q( @; Y3 U0 R  Z
( e1 E, K/ Y. p' I2 N% Z
41      else
( ?+ Q; [9 q& ]  J# ?# J4 @! ~# Z6 Y1 e4 S0 t4 A& R$ ?
42          Bps_Clk_Cnt <= Bps_Clk_Cnt;1 K1 t- g8 L, C
& F8 o, I; {# b6 u( T: Z) T# C( G
43: q0 n: ]" q9 X

! S* z3 U0 f. y0 }6 j8 \6 ~: m+ e2 {4 D44  /*生成数据发送完成标志信号*/        
' z4 p2 d$ A& K' x
; ~+ U( x% Z7 B45      always@(posedge Clk or negedge Rst_n)7 }- U+ V- Q" {* V* y: l8 b

1 ]# C0 T- }0 W+ F/ d46      if(!Rst_n)$ W3 Z) C  X( p- a# m8 V! s
* S& U0 T2 h$ F  n; o  R; ?
47          Tx_Done <= 1'b0;
" _+ v7 T1 d4 w; {
2 q" q% j) W6 X% b/ @  V2 s5 @, e/ g48      else if(Bps_Clk_Cnt == 4'd11)
6 f3 |; z  t! p2 ^  O8 B" z* y/ Y5 ]) R
49          Tx_Done <= 1'b1;+ ^" ?/ r2 {+ U  |- |6 h3 y/ n
: b+ N6 B! _- c4 W; c
50      else
2 c  A+ J% [6 M) m3 m0 R
3 q5 I! m9 \0 r5 \% o# m  u$ |: O4 ?51          Tx_Done <= 1'b0;1 N6 Z; Y) [+ U/ u

, r* \; i1 D5 A! T52. R/ Z- N2 q( u

6 n$ Q5 B. ]2 R9 i53  /*在开始发送起始位的时候就读取并寄存Data_Byte,以免Data_Byte变化导致数据的丢失*/      
0 `8 R' S8 ]8 q4 G) b' M5 X; \4 J" Y+ x* `) `6 g8 Z+ o0 E
54      always@(posedge Clk or negedge Rst_n)" `0 J0 E: U+ ^6 }
1 j3 x/ s- b; t5 C& p" Z" v: ^
55      if(!Rst_n)
9 M/ ?  b5 `( D6 ~, L9 y' H: C: z
56          Data = 8'd0;
+ B+ `  p& D1 h6 l0 w$ r: _
: _" F. z: v- {3 q' V" d57      else if(Bps_Clk & Bps_Clk_Cnt == 4'd1)' H: s* N! ^& p( O9 Y7 `0 G
7 [$ r: c! {6 U5 ^/ c
58          Data <= Data_Byte;& h# I0 s! t( C6 F: U

1 \" q- Z' r, r6 J* N0 m59      else
: z( I; P0 e4 K0 o/ U( N% i2 C1 a! [8 \2 \, }! [8 ~$ p$ ?2 ~
60          Data <= Data;
3 }2 Z7 {4 Y; P' z1 z
$ g7 p& _3 P- n61: C$ t5 k- J# T: ?9 F' F* Y! ~
2 b/ @% F. L, W7 r. A
62  /*发送数据序列机*/       ) ^% s+ o) J$ B9 ~8 W3 Z

8 M( ?8 Z# \3 K1 O/ K63      always@(posedge Clk or negedge Rst_n): [  {6 d  a/ h1 |" \/ d& C
1 R% u  h: e* w, `
64      if(!Rst_n)  
& G' [8 S3 V& W0 W2 I7 I5 k8 {
* Z. b+ V/ O2 f65          Rs232_Tx <= 1'b1;
2 K1 J3 Q6 L5 Z1 ~# j; ~/ d4 |. d# H0 m9 E: G( N( z) S5 @
66      else begin3 E: @5 p! @' {: f6 U

8 H; h- K& ?1 k' G67          case(Bps_Clk_Cnt)& u7 K% X* w* Q0 Z  h. o
  N7 `& Q4 X- Y8 ~, @
68              4'd1: Rs232_Tx <= 1'b0;
# e, @- y! B6 ^; w( p/ q' y, A# R, p  r+ D9 _! r: O
69              4'd2: Rs232_Tx <= Data[0];' ^5 u5 j1 o( w" f
. a, O1 R. _8 J9 ?6 a
70              4'd3: Rs232_Tx <= Data[1];
% v% N  ~1 |) K0 }! u: b
9 o: t' H, a( L$ ]5 ?  U; q, k' |71              4'd4: Rs232_Tx <= Data[2];  
& Q& o9 @2 P8 }- g/ ^/ O. A5 K
6 R7 z" u' u8 i# R" V% W72              4'd5: Rs232_Tx <= Data[3];
; U/ Q7 A) ]' M" F# E! e
- h1 I& u: q1 k9 U, Q, l5 T73              4'd6: Rs232_Tx <= Data[4];
, x% M4 S* D+ o7 ~& z
# G" Q7 ^0 M7 P  y! G74              4'd7: Rs232_Tx <= Data[5];5 ^7 \( j0 x+ \3 c; t# i1 i
: ?$ h, `0 [  ~: t
75              4'd8: Rs232_Tx <= Data[6];+ Z0 x& P8 l$ R! \+ X$ L+ ^) x& t/ q
4 k8 E* x( K0 d6 h" Y
76              4'd9: Rs232_Tx <= Data[7];
5 w2 @  a. z) g) y/ |, z2 y' }; w! _( w
77              4'd10: Rs232_Tx <= 1'b1;
# D5 s0 |/ M, n7 I0 U1 B4 }  H
$ L6 P' L& s9 Z% S4 S78              default:Rs232_Tx <= 1'b1;5 v" k1 x/ A" x& Z( T* y0 q- z
# K" p) z/ v* Z. `% g
79          endcase; X2 _$ L/ X- h- W4 ?, v  d  [( a
, l/ |' W! ]/ q1 P+ {
80      end! @. O+ b. H9 m- p3 B# [' o
4 y- A; T1 n: k& ]8 ~
0 x0 c* S/ q" \* C! @" r0 \
UART协议中,一个完整的字节包括一位起始8数据位一位停止位总共十位数据,那么,要完整的实现这十位数据的发送,就需要11波特率时钟脉冲,如下所示
. d" L% w! `3 J5 e5 `
0 X  g7 r  R9 j

- Y' r. }% d: X+ k) ?9 Z
2 I) v# W  X1 u. k8 [3 u8 T) ^' C
BPS_CLK信号的第一个上升沿到来时,字节发送模块开始发送起始位,接下来的29上升沿,发送8数据位,第10上升沿到第11个上升沿为停止位的发送。
+ e( K: S5 O1 g% Z* D, {
单个串口接收模块中实现串口数据接收的主要代码如下所示:
025     always @ (posedge Clk or negedge Rst_n)
026     if(!Rst_n) begin
027         Rs232_Rx0 <= 1'b0;
028         Rs232_Rx1 <= 1'b0;
029         Rs232_Rx2 <= 1'b0;
030         Rs232_Rx3 <= 1'b0;
031     end
032     else begin
033         Rs232_Rx0 <= Rs232_Rx;
034         Rs232_Rx1 <= Rs232_Rx0;
035         Rs232_Rx2 <= Rs232_Rx1;
036         Rs232_Rx3 <= Rs232_Rx2;
037     end
038     
039     wire neg_Rs232_Rx= Rs232_Rx3 & Rs232_Rx2 & ~Rs232_Rx1 & ~Rs232_Rx0;
040     
041     assign Byte_En = neg_Rs232_Rx;
042
043 /*----------计数采样时钟--------------*/
044 /*9倍波特率采样时钟,故一个完整的接收过程有90个波特率时钟*/
045     reg[6:0]Sample_Clk_Cnt;
046     always @ (posedge Clk or negedge Rst_n)
047     if(!Rst_n)
048         Sample_Clk_Cnt <= 7'd0;
049     else if(Sample_Clk)begin
050         if(Sample_Clk_Cnt == 7'd89)
051             Sample_Clk_Cnt <= 7'd0;
052         else
053             Sample_Clk_Cnt <= Sample_Clk_Cnt + 1'b1;
054     end
055     else
056         Sample_Clk_Cnt <= Sample_Clk_Cnt;
057
058     reg [1:0]Start_Bit; /*起始位,这里虽然定义,但并未使用该位来判断接收数据的正确性,即默认接收都是成功的*/
059     reg [1:0]Stop_Bit;  /*停止位,这里虽然定义,但并未使用该位来判断接收数据的正确性,即默认接收都是成功的*/
060     reg [1:0] Data_Tmp[7:0];/*此部分较为复杂,请参看说明文档中相关解释*/
061     
062     always @ (posedge Clk or negedge Rst_n)
063     if(!Rst_n)begin
064         Data_Tmp[0] <= 2'd0;
065         Data_Tmp[1] <= 2'd0;
066         Data_Tmp[2] <= 2'd0;
067         Data_Tmp[3] <= 2'd0;
068         Data_Tmp[4] <= 2'd0;
069         Data_Tmp[5] <= 2'd0;
070         Data_Tmp[6] <= 2'd0;
071         Data_Tmp[7] <= 2'd0;
072         Start_Bit <= 2'd0;
073         Stop_Bit <= 2'd0;      
074     end
075     else if(Sample_Clk)begin
076         case(Sample_Clk_Cnt)
077             7'd0:
078                 begin
079                     Data_Tmp[0] <= 2'd0;
080                     Data_Tmp[1] <= 2'd0;
081                     Data_Tmp[2] <= 2'd0;
082                     Data_Tmp[3] <= 2'd0;
083                     Data_Tmp[4] <= 2'd0;
084                     Data_Tmp[5] <= 2'd0;
085                     Data_Tmp[6] <= 2'd0;
086                     Data_Tmp[7] <= 2'd0;
087                     Start_Bit <= 2'd0;
088                     Stop_Bit <= 2'd0;   
089                 end
090             7'd3,7'd4,7'd5: Start_Bit <= Start_Bit + Rs232_Rx;
091             7'd12,7'd13,7'd14ata_Tmp[0] <= Data_Tmp[0] + Rs232_Rx;
092             7'd21,7'd22,7'd23ata_Tmp[1] <= Data_Tmp[1] + Rs232_Rx;
093             7'd30,7'd31,7'd32ata_Tmp[2] <= Data_Tmp[2] + Rs232_Rx;
094             7'd39,7'd40,7'd41:Data_Tmp[3] <= Data_Tmp[3] + Rs232_Rx;
095             7'd48,7'd49,7'd50:Data_Tmp[4] <= Data_Tmp[4] + Rs232_Rx;
096             7'd57,7'd58,7'd59:Data_Tmp[5] <= Data_Tmp[5] + Rs232_Rx;   
097             7'd66,7'd67,7'd68:Data_Tmp[6] <= Data_Tmp[6] + Rs232_Rx;
098             7'd75,7'd76,7'd77:Data_Tmp[7] <= Data_Tmp[7] + Rs232_Rx;   
099             7'd84,7'd85,7'd86:Stop_Bit <= Stop_Bit + Rs232_Rx;
100             default:;
101         endcase
102     end
103     else ;
根据串口发送协议,一个字节的数据传输是以一个波特率周期的低电平作为起始位的,因此,成功接收UART串口数据的核心就是准确检测起始位。由于外部串口发送过来的数据与接收系统不在同一个时钟域,因此不能直接使用该信号的下降沿来作为检测标志,我们需要在fpga中,采用专用的边沿检测电路来实现,第25至37通过四个移位寄存器,存储连续四个时钟上升沿时外部发送数据线的状态,第39通过比较前两个时钟时数据线的状态与后两个时钟时数据线的状态,来得到该数据线的准确下降沿,以此保证起始位的准确检测。
在简单的串口接收中,我们通常选取一位数据的中间时刻进行采样,因为此时数据最稳定,但是在工业环境中,存在着各种干扰,在干扰存在的情况下,如果采用传统的中间时刻采样一次的方式,采样结果就有可能受到干扰而出错。为了滤除这种干扰,这里采用多次采样求概率的方式。如下图,将一位数据平均分成9时间段,对位于中间的三个时间段进行采样。然后对三个采样结果进行统计判断,如果某种电平状态在三次采样结果中占到了两次及以上,则可以判定此电平状态即为正确的数据电平。例如456时刻采样结果分别为110那么就取此位解码结果为1否则,若三次采样结果为010则解码结果就为0
因为采样一位需要9时钟上升沿,因此,采样一个完整的数据需要10*9,即90时钟上升沿,这里,采样时钟为波特率时钟的9。产生采样时钟的部分代码如下所示:
089 /*-------波特率时钟生成定时器--------------*/
090     always@(posedge Clk or negedge Rst_n)
091     if(!Rst_n)
092         Count <= 10'd0;
093     else if(BPS_EN == 1'b0)
094         Count <= 10'd0;
095     else begin
096         if(Count == BPS_PARA)
097             Count <= 10'd0;
098         else
099             Count <= Count + 1'b1;
100     end
101     
102 //=====================================================
103 /*输出数据接收采样时钟*/
104     always @(posedge Clk or negedge Rst_n)
105     if(!Rst_n)
106         Sample_Clk <= 1'b0;
107     else if(Count== 1)
108         Sample_Clk <= 1'b1;
109     else
110         Sample_Clk <= 1'b0;
6 W1 s4 G5 Q4 X- b; k2 s& ?* [8 F; a
这里,BPS_PARA的计算原理和前面Tx_Bps_Gen模块中的BPS_PARA的计算原理一致,不过这里,因为采样时钟为波特率时钟的9,所以,BPS_PARA为Tx_Bps_Gen模块中的BPS_PARA1/9。计算BPS_PARA的相关代码如下:
018     parameter system_clk = 50_000_000;  /*输入时钟频率设定,默认50M*/
019
020 /*根据输入时钟频率计算生成各波特率时分频计数器的计数最大值*/   
021     localparam bps9600 = system_clk/9600/9 - 1;
022     localparam bps19200 = system_clk/19200/9 - 1;
023     localparam bps38400 = system_clk/38400/9 - 1;
024     localparam bps57600 = system_clk/57600/9 - 1;
025     localparam bps115200 = system_clk/115200/9 - 1;
026     localparam bps230400 = system_clk/230400/9 - 1;
027     localparam bps460800 = system_clk/460800/9 - 1;
028     localparam bps921600 = system_clk/921600/9 - 1;     
029     
030     reg [31:0]BPS_PARA;/*波特率分频计数器的计数最大值*/
031
032     always@(posedge Clk or negedge Rst_n)
033     if(!Rst_n)begin
034         BPS_PARA <= bps9600;    /*复位时波特率默认为9600bps*/
035     end
036     else begin
037         case(Baud_Set)  /*根据波特率控制信号选择不同的波特率计数器计数最大值*/
038             3'd0: BPS_PARA <= bps9600;
039             3'd1: BPS_PARA <= bps19200;
040             3'd2: BPS_PARA <= bps38400;
041             3'd3: BPS_PARA <= bps57600;
042             3'd4: BPS_PARA <= bps115200;
043             3'd5: BPS_PARA <= bps230400;
044             3'd6: BPS_PARA <= bps460800;
045             3'd7: BPS_PARA <= bps921600;            
046             default: BPS_PARA <= bps9600;/*异常情况,恢复到9600的波特率*/
047         endcase
048     end
4 u" J, ]( r  H: j. |3 p  X
小梅哥
2015年4月8日 于至芯科技

+ ?* I8 X8 i! b* h" P, ]7 m5 z4 n2 _$ V/ z5 {

, }" M6 ~) G* A7 l8 w* I* e. n( G! ?$ P7 j
3 ]8 ~, D2 h8 T5 U7 D
  I- m  ?' l8 B# ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-1 05:53 , Processed in 0.171875 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表