赞
踩
一、FPGA接收其他设备通过uart协议发送的数据
使用ISSP查看uart接收模块接收到的数据,串口接收到的数据由PC机发出
1. uart通信协议工业环境下数据接收实现(干扰状态,进行一些处理保证稳定性)
工业应用中,往往有较强的电磁干扰,因此只采集一次作为该数据的电平判定不保险,需要多次采样求概率
将每一位数据平均分成 16 小段,在刚发生变化和即将发生变化时期,数据极可能不稳定,因此灰色这段忽略。考虑中间6次采样,选取出现次数较多的电平。各占一半时判定当前通信线路环境非常恶劣,数据不具有可靠性,不进行处理。
将中间6次结果加起来(3位),>3(最高位为1)为1,<3为0,最高位数即为统计结果
reg [2:0] r_data_byte [7:0]8个3位寄存器,r_data_byte[0][2]:第0个寄存器的第2位
2. 异步时钟同步处理
Rs232_tx是外部输入信号,是异步信号,对其采样可能采集到不定态,D触发器会发生振荡,振荡后在下一个时钟信号到来前稳定下来,其稳定结果不确定,因此经过两级寄存器同步处理(与系统时钟变化一致)。
第一个D触发器采集异步信号,q有振荡,但在下一个时钟信号前稳定,因此第二级D触发器(延迟一个时钟周期)采集到的是稳定态
3. ISSP探针probe使用
外部输入Rs232_rx,使用探针(8位)探测 data_rx_r(只有在rx_done高电平时将data_rx赋值给data_rx_r)
二、时序图
uart发送端发送一个字节Byte(8bit)数据时序图
每个bps_clk上升沿发送数据
串口接收时序图
对数据线 Rs232_tx 上的每一位进行采样:开始和结束段数据变化,一般认为每一位数据的中间点最稳定,因此一般采集中间时刻时的电平即认为是此位数据的电平
bps_clk上升沿对齐中点,在每个上升沿读取数据
三、模块设计
起始位检测进程:起始位低电平,检测到下降沿,表面可能数据传输,开启波特率时钟(异步转 同步(两个同步寄存器s0_)、边沿检测(两个暂存寄存器tem0_,比较前后状态))。起始位可能检测错误,第12位起始位不为0(>=3)可判断为检测错误
波特率产生模块:每位采集16次,频率:Bps*16
数据接收进程
串口接收模块框图
先有顶层设计思路,再分块实现
注意
1.
一个bps_cnt会维持多个系统时钟,在Clk上升沿触发条件下,一个状态多次被检测到,多次相加
bps_clk为高电平时,bps_cnt才计数,在bps_cnt为指定值且bps_clk为高电平(已经是下一个)时才采样,则会滞后一个周期,即在bps_cnt为6时采样得到的是7对应的电平,因此可以将6改为5,得到6对应的电平
2.
data_byte的不同位来赋值,不是直接data_byte
3.
uart_state为触发条件,不能用nedge
uart_byte_rx
- module uart_byte_rx(
- Clk,
- Rst_n,
- Rs232_rx,
- baud_set,
- data_byte,
- rx_done
- );
- input Clk;
- input Rst_n;
- input Rs232_rx;//串行数据输入,一位
- input [2:0]baud_set;//5个bps,每种可能代表一个bps
-
- output reg [7:0]data_byte;//一个字节8位,每位有0、1两种可能
- output reg rx_done;
-
- reg s0_Rs232_rx, s1_Rs232_rx;
- reg tmp0_Rs232_rx, tmp1_Rs232_rx;
- reg [8:0]bps_DR;//计数,个数
- reg [8:0]div_cnt;
- reg bps_clk;
- reg [8:0]bps_cnt;
- reg [2:0]Start_bit,Stop_bit;//起始位、终止位要通过判断赋值!!
- reg [2:0]r_data_byte[7:0];//接受的数据共8位,每位对中间6次采样相加判定电平,6需要3位
- reg uart_state;//由下降沿判断串口状态,判断错误时由此结束
-
- wire nedge;
-
- //同步寄存器——消除亚稳态
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- s0_Rs232_rx <= 1'b0;
- s1_Rs232_rx <= 1'b0;
- end
- else begin
- s0_Rs232_rx <= Rs232_rx;
- s1_Rs232_rx <= s0_Rs232_rx;//外部输入的数据稳定寄存在s1_Ts232_rx中,后按bps_clk频率,bps_cnt采样
- end
-
- //数据寄存器——边沿检测
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- tmp0_Rs232_rx <= 1'b0;
- tmp1_Rs232_rx <= 1'b0;
- end
- else begin
- tmp0_Rs232_rx <= s0_Rs232_rx;
- tmp1_Rs232_rx <= tmp0_Rs232_rx;
- end
-
- assign nedge = !tmp0_Rs232_rx && tmp1_Rs232_rx;
-
- //baud_set ——> bps_DR ——> div_cnt(nedge) ——> bps_clk ——> bps_cnt(在此判断起始位检测是否正确,计数到12后才能判断)——>rx_done
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- bps_DR <= 9'd324;
- else begin
- case(baud_set)
- 3'd0: bps_DR <= 9'd324;
- 3'd1: bps_DR <= 9'd162;
- 3'd2: bps_DR <= 9'd80;
- 3'd3: bps_DR <= 9'd53;
- 3'd4: bps_DR <= 9'd26;
- default: bps_DR <= 9'd324;
- endcase
- end
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- div_cnt <= 9'd0;
- else if(uart_state)begin//下降沿只有一个周期,只能计一次,需要在接收段一直保持
- if(div_cnt == bps_DR - 1'd1)//波特率对应频率大于系统时钟,一个波特率周期包含多个系统时钟,对系统时钟计数得bps_cnt
- div_cnt <= 9'd0;
- else
- div_cnt <= div_cnt + 1'd1;
- end
- else
- div_cnt <= 9'd0;//不是复位,没有计满情况下清零(错误检测)
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- bps_clk <= 1'b0;
- else if(div_cnt == 9'd1 )//位数应为该变量的位宽
- bps_clk <= 1'b1;
- else
- bps_clk <= 1'b0;//其余情况为0,不是保持本身需要写明
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- bps_cnt <= 9'd0;
- else if(bps_cnt == 9'd159 || (bps_cnt==9'd12 && (Start_bit > 3'd2)))//10位,每位16次,计数到12,看起始位6次采样结果,>=3则为错误检测
- bps_cnt <= 9'd0;
- else if(bps_clk == 1'd1)
- bps_cnt <= bps_cnt + 1'd1;//后续按照bps_cnt计数接收数据,计满或检测错误为0,后续接收也为0
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- rx_done <= 1'b0;
- else if(bps_cnt == 9'd159)//能计满则表明起始位检测正确
- rx_done <= 1'b1;
- else
- rx_done <= 1'b0;
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- uart_state <= 1'b0;
- else if(nedge)
- uart_state <= 1'b1;
- else if(rx_done || (bps_cnt == 9'd12 && (Start_bit > 2)))
- uart_state <= 1'b0;
- else
- uart_state <= uart_state;//结束、错误才为0,在接收时一直保持1
-
- //数据接收暂存
- always@(posedge Clk or negedge Rst_n)//
- if(!Rst_n)begin
- Start_bit <= 3'd0;
- r_data_byte[0] <= 3'd0;
- r_data_byte[1] <= 3'd0;
- r_data_byte[2] <= 3'd0;
- r_data_byte[3] <= 3'd0;
- r_data_byte[4] <= 3'd0;
- r_data_byte[5] <= 3'd0;
- r_data_byte[6] <= 3'd0;
- r_data_byte[7] <= 3'd0;
- Stop_bit <= 3'd0;
- end
- else if(bps_clk == 1'b1)
- case(bps_cnt)
- 0: begin
- Start_bit <= 3'd0;
- r_data_byte[0] <= 3'd0;
- r_data_byte[1] <= 3'd0;
- r_data_byte[2] <= 3'd0;
- r_data_byte[3] <= 3'd0;
- r_data_byte[4] <= 3'd0;
- r_data_byte[5] <= 3'd0;
- r_data_byte[6] <= 3'd0;
- r_data_byte[7] <= 3'd0;
- Stop_bit <= 3'd0;
- end//下次计数要复位
- //bps_clk为高电平时,bps_cnt才计数,在bps_cnt为指定值且bps_clk为高电平(已经是下一个)时才采样,则会滞后一个周期,即在bps_cnt为6时采样得到的是7对应的电平,因此可以将6改为5,得到6对应的电平,
- 5,6,7,8,9,10: Start_bit <= Start_bit + s1_Rs232_rx;//一个bps_cnt会维持多个系统时钟,在Clk上升沿触发条件下,一个状态多次被检测到,多次相加
- 21,22,23,24,25,26: r_data_byte[0] <= r_data_byte[0] + s1_Rs232_rx;
- 37,38,39,40,41,42: r_data_byte[1] <= r_data_byte[1] + s1_Rs232_rx;
- 53,54,55,56,57,58: r_data_byte[2] <= r_data_byte[2] + s1_Rs232_rx;
- 69,70,71,72,73,74: r_data_byte[3] <= r_data_byte[3] + s1_Rs232_rx;
- 85,86,87,88,89,90: r_data_byte[4] <= r_data_byte[4] + s1_Rs232_rx;
- 101,102,103,104,105,106: r_data_byte[5] <= r_data_byte[5] + s1_Rs232_rx;
- 117,118,119,120,121,122: r_data_byte[6] <= r_data_byte[6] + s1_Rs232_rx;
- 133,134,135,136,137,138: r_data_byte[7] <= r_data_byte[7] + s1_Rs232_rx;
- 149,150,151,152,153,154: Stop_bit <= Stop_bit + s1_Rs232_rx;
- default: begin
- Start_bit <= Start_bit;
- r_data_byte[0] <= r_data_byte[0];
- r_data_byte[1] <= r_data_byte[1];
- r_data_byte[2] <= r_data_byte[2];
- r_data_byte[3] <= r_data_byte[3];
- r_data_byte[4] <= r_data_byte[4];
- r_data_byte[5] <= r_data_byte[5];
- r_data_byte[6] <= r_data_byte[6];
- r_data_byte[7] <= r_data_byte[7];
- Stop_bit <= Stop_bit;
- end//其他情况保持不变(数据接收完后)
- endcase
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)begin
- data_byte <= 8'd0;
- end
- else if(bps_cnt == 9'd159)begin
- data_byte[0] <= r_data_byte[0][2];//<3最高位为0;>3最高位为1,此处不考虑=3的恶劣情况
- data_byte[1] <= r_data_byte[1][2];
- data_byte[2] <= r_data_byte[2][2];
- data_byte[3] <= r_data_byte[3][2];
- data_byte[4] <= r_data_byte[4][2];
- data_byte[5] <= r_data_byte[5][2];
- data_byte[6] <= r_data_byte[6][2];
- data_byte[7] <= r_data_byte[7][2];
- end
-
- endmodule

uart_byte_rx_tb
- `timescale 1ns/1ns
- `define clk_period 20
-
- module uart_byte_rx_tb;
-
- reg Clk;
- reg Rst_n;
-
- wire [7:0]data_byte_r;
- wire rx_done;
-
- reg [7:0]data_byte_t;
- reg [2:0]baud_set;
- reg send_en;
-
- wire Rs232_tx;
- wire Tx_done;
- wire uart_state;
-
- uart_byte_rx uart_byte_rx(
- .Clk(Clk),
- .Rst_n(Rst_n),
- .Rs232_rx(Rs232_tx),
- .baud_set(baud_set),
- .data_byte(data_byte_r),
- .rx_done(rx_done)
- );
-
- uart_byte_tx uart_byte_tx(//发送模块产生数据,在tb中使用,工程没有使用,需要保存在该工程下同时setting中添加该文件
- .Clk(Clk),
- .Rst_n(Rst_n),
- .data_byte(data_byte_t),
- .baud_set(baud_set),
- .send_en(send_en),
-
- .Rs232_tx(Rs232_tx),
- .Tx_done(Tx_done),
- .uart_state(uart_state)
- );
-
- initial Clk = 1'b1;
- always#(`clk_period/2)Clk = ~Clk;
-
- initial begin
- Rst_n = 1'b0;
- data_byte_t = 8'd0;
- baud_set = 3'd4;
- send_en = 1'd0;
- #(`clk_period*20 + 1'b1)
- Rst_n = 1'b1;
- #(`clk_period*50)
- data_byte_t = 8'haa;
- send_en = 1'd1;
- #`clk_period;
- send_en = 1'd0;
-
- @(posedge Tx_done)
-
- #(`clk_period*5000);
- data_byte_t = 8'h55;
- send_en = 1'd1;
- #`clk_period;
- send_en = 1'd0;
- @(posedge Tx_done)
- #(`clk_period*5000);
- $stop;
- end
-
- endmodule

uart_byte_rx_top
- module uart_byte_rx_top(Clk,Rst_n,Rs232_rx);
-
- input Clk;
- input Rst_n;
- input Rs232_rx;
-
- reg [7:0]data_rx_r;//data_rx可能接收错误,rx_done时才将值赋到data_rx_r上
-
- wire rx_done;//不作为输出,内部信号作为赋值给data_rx_r的触发条件
- wire data_rx;//不作为输出,内部信号赋值给data_rx_r,再用探针
-
- uart_byte_rx uart_byte_rx(
- .Clk(Clk),
- .Rst_n(Rst_n),
- .Rs232_rx(Rs232_rx),
- .baud_set(3'd0),
- .data_byte(data_rx),
- .rx_done(rx_done)
- );
-
- issp issp(
- .probe(data_rx_r),//探针观测data_rx_r数据
- .source()
- );
-
- always@(posedge Clk or negedge Rst_n)
- if(!Rst_n)
- data_rx_r <= 8'd0;
- else if(rx_done)
- data_rx_r <= data_rx;
-
- endmodule

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。