Spartan-6 FPGA 嵌入式套件试用(五)----- 串口接收
[复制链接]
接着上一篇,这篇主要来学习一下串口的接收,设计的思路为:
1. PC端用串口助手发送数据;
2. Xilinx fpga同过串口接收数据;
3. 同过接收到的数据来控制板子上的LED的状态,数据和LED的对应关系如下:
对应的Bit为1 时,LED亮;为0时,LED灭。
串口异步接收部分的框图如下:
具体实现如下:
// RS-232 RX module
module async_receiver(clk, RxD, RxD_data_ready, RxD_data, RxD_endofpacket, RxD_idle);
input clk, RxD;
output RxD_data_ready;
output [7:0] RxD_data;
parameter ClkFrequency = 27000000; // Spartan-6板子上的27MHz时钟
parameter Baud = 115200; //波特率设置115200
output RxD_endofpacket; //一个时钟宽度,如果没有其他数据需要接收,RxD_idle等于1
output RxD_idle; //没有新数据接收的指示
//产生波特率
parameter Baud8 = Baud*8;
parameter Baud8GeneratorAccWidth = 16;
wire [Baud8GeneratorAccWidth:0] Baud8GeneratorInc = ((Baud8<<(Baud8GeneratorAccWidth-7))+(ClkFrequency>>8))/(ClkFrequency>>7);
reg [Baud8GeneratorAccWidth:0] Baud8GeneratorAcc;
always @(posedge clk)
Baud8GeneratorAcc <= Baud8GeneratorAcc[Baud8GeneratorAccWidth-1:0] + Baud8GeneratorInc;
wire Baud8Tick = Baud8GeneratorAcc[Baud8GeneratorAccWidth];
//同步RxD信号
reg [1:0] RxD_sync_inv;
always @(posedge clk)
if(Baud8Tick) RxD_sync_inv <= {RxD_sync_inv[0], ~RxD};
reg [1:0] RxD_cnt_inv;
reg RxD_bit_inv;
//对开始信号Start进行检测
always @(posedge clk)
if(Baud8Tick)
begin
if( RxD_sync_inv[1] && RxD_cnt_inv!=2'b11) RxD_cnt_inv <= RxD_cnt_inv + 2'h1;
else
if(~RxD_sync_inv[1] && RxD_cnt_inv!=2'b00) RxD_cnt_inv <= RxD_cnt_inv - 2'h1;
if(RxD_cnt_inv==2'b00) RxD_bit_inv <= 1'b0;
else
if(RxD_cnt_inv==2'b11) RxD_bit_inv <= 1'b1;
end
reg [3:0] state;
reg [3:0] bit_spacing;
wire next_bit = (bit_spacing==4'd10);
always @(posedge clk)
if(state==0)
bit_spacing <= 4'b0000;
else
if(Baud8Tick)
bit_spacing <= {bit_spacing[2:0] + 4'b0001} | {bit_spacing[3], 3'b000};
//一旦检测到"开始位",使用如下的状态机可以检测出接收到每一位数据
always @(posedge clk)
if(Baud8Tick)
case(state)
4'b0000: if(RxD_bit_inv) state <= 4'b1000; // start bit found?
4'b1000: if(next_bit) state <= 4'b1001; // bit 0
4'b1001: if(next_bit) state <= 4'b1010; // bit 1
4'b1010: if(next_bit) state <= 4'b1011; // bit 2
4'b1011: if(next_bit) state <= 4'b1100; // bit 3
4'b1100: if(next_bit) state <= 4'b1101; // bit 4
4'b1101: if(next_bit) state <= 4'b1110; // bit 5
4'b1110: if(next_bit) state <= 4'b1111; // bit 6
4'b1111: if(next_bit) state <= 4'b0001; // bit 7
4'b0001: if(next_bit) state <= 4'b0000; // stop bit
default: state <= 4'b0000;
endcase
//使用一个移位寄存器来存储接收到的数据
reg [7:0] RxD_data;
always @(posedge clk)
if(Baud8Tick && next_bit && state[3]) RxD_data <= {~RxD_bit_inv, RxD_data[7:1]};
reg RxD_data_ready, RxD_data_error;
always @(posedge clk)
begin
RxD_data_ready <= (Baud8Tick && next_bit && state==4'b0001 && ~RxD_bit_inv);
RxD_data_error <= (Baud8Tick && next_bit && state==4'b0001 && RxD_bit_inv);
end
reg [4:0] gap_count;
always @(posedge clk)
if (state!=0) gap_count<=5'h00;
else if (Baud8Tick & ~gap_count[4]) gap_count <= gap_count + 5'h01;
assign RxD_idle = gap_count[4];
reg RxD_endofpacket;
always @(posedge clk)
RxD_endofpacket <= Baud8Tick & (gap_count==5'h0F);
endmodule
测试代码如下:
wire RxD_data_ready;
wire [7:0]RxD_data;
wire RxD_endofpacket;
wire RxD_idle;
reg [7:0]RxD_data_tmp;
//保存接收到的串口数据
always @(posedge clk)
begin
if(RxD_data_ready)
RxD_data_tmp <= RxD_data;
else
RxD_data_tmp <= RxD_data_tmp;
end
//把串口接收到的数据和LED绑定,通过串口数据控制LED的状态
assign led0 = RxD_data_tmp[0]; // bit0
assign led1 = RxD_data_tmp[1]; //bit1
assign led2 = RxD_data_tmp[2]; //bit2
assign led3 = RxD_data_tmp[3]; //bit3
//例化串口接收模块
async_receiver async_receiver_inst(
.clk(clk),
.RxD(uart_tx),
.RxD_data_ready (RxD_data_ready),
.RxD_data (RxD_data),
.RxD_endofpacket (RxD_endofpacket),
.RxD_idle(RxD_idle));
测试结果:
有空拍几张效果图上来,哈哈
|