学习笔记:FPGA之多终端点歌系统设计一:UART通信协议

一,UART是什么?

来自百度百科:https://baike.baidu.com/item/UART/4429746

二,UART通信协议

(1)UART传输速度    

    UART作为异步串行通信接口,也就是说,它的数据传输不需要时钟,只要两条信号线分别进行数据收发。收发双方只需要约定好数据传输的速度和帧格式,就能保证数据收发的准确性。简单的讲就是约定好一个数据位传输的时间和一个数据的长短。

    UART的数据传输速度是用波特率来描述的,即每秒钟传输的数据位,例如1000波特率表示每秒钟传输1000比特的数据,或者说每个数据位持续1毫秒。波特率不是随意的,必须服从一定的标准,如果希望设计123456波特率的RS-232接口,是不行的。常用的串行传输速率值包括以下几种:1200bps,9600bps,38400bps,115200bps等、在115200bps下,每位数据持续(1/114200)=8.68us.如果传输8位数据,共持续8*8.68us=69.44us。但是每个字节的传输又要求额外的“开始位”和“停止位”,所以实际上需要10*8.68us=86.8us的时间。因此最大的有效数据传输率只有达到11.5KBytes每秒。

(2)UART的帧格式

 通过该图,我们可以看出, 它是由1个起始位(必须为0),8个数据位(用户数据),1个奇偶校验位(用于简单地纠错保证传输可靠性)和1或2个停止位(必须为1)组成。除了奇偶校验位,其他3个部分都是必须的。通过这个UART帧格式图我们可以知道,UART的通信是十分简单的,它是以低电平作为起始位,高电平作为停止位,中间可传输5~8比特数据和1比特奇偶校验位,奇偶校验位的有无和数据比特的长度由通信双方约定。发送端发送数据时先发一低电平,然后发送8比特数据,之后马上把信号拉高,从而完成一帧数据传送。接收端收到低电平开始计数,然后接受8比特信息位后如果检测到高电平即认为已接受完一帧数据,继续等待下一帧起始信号低电平的到来,若接受完8比特数据后没有检测到高电平则认为这不是一帧有效数据,将其丢弃,继续等待起始信号。收发可同时进行,互不干扰。一帧数据传输完毕后可以继续传输下一帧数据,也可以继续保持为高电平。两帧之间保持高电平,持续时间可以任意长。

(3)UART协议使用。

发送0-9这十个数字来控制蜂鸣器的发声。

1,功能模块图

(2)verilog代码:

//波特率产生采样信号模块
module Uart_Bps_Module
(
    //输入端口
    CLK_50M,RST_N,bps_start,
    //输出端口
    bps_flag
);


input    CLK_50M;
input    RST_N;
input    bps_start;    //接受和发送端口的波特率时钟启动信号    
output   bps_flag;    //接受数据位的中间采样点,发送数据的数据改变点


reg    [12:0]    time_cnt;
reg    [12:0]    time_cnt_n;
reg    bps_flag;
reg    bps_flag_n;

//波特率为115200,一位周期为1/115200=8.69us,8.68/(1/50)=434
parameter    BPS_PARA=9'd434;
parameter    BPS_PARA_2=8'd217;//中间采样

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        time_cnt<=13'b0;
    else
        time_cnt<=time_cnt_n;
end

always @ (*)
begin
    if((time_cnt==BPS_PARA)||(!bps_start))
        time_cnt_n=1'b0;
    else
        time_cnt_n=time_cnt+1'b1;
end

alwways @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        bps_flag<=1'b0;
    else
        bps_flag<=bps_flag_n;
end

always @ (*)
begin
    if(time_cnt==BPS_PARA_2)
        bps_flag_n=1'b1;//采样标志
    else
        bps_flag_n=1'b0;
end
endmodule

//UART解析模块
module Uart_Rx_Module
(
    //input
    CLK_50M,RST_N,UART_RX,rx_bps_flag,
    //output
    out_rx_data,rx_bps_start
);



input    CLK_50M;
input    RST_N;
input    UART_RX;//FPGA的接受端口,串口cp2102的发送端口
input    rx_bps_flag;
output    rx_bps_start; //接受端口的波特率时钟启动信号
output    [7:0]    out_rx_data;//解析完成的数据



reg    [1:0]    detect_edge;//下降沿
wire    [1:0]    detect_edge_n;
reg    negedge_reg;//下降沿标志
wire    negedge_reg_n;
reg    rx_bps_start;
reg    rx_bps_start_n;
reg    [3:0]    bit_cnt;//记录接受数据位
reg    [3:0]    bit_cnt_n;
reg    [7:0]    shift_data;//接受串行数据流中用到的移位寄存器
reg    [7:0]    shift_data_n;
reg    [7:0]    out_rx_data;//从UART_RX数据线中解析完后的数据
reg    [7:0]    out_rx_data_n;



always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        detect_edge<=2'b11;
    else
        detect_edge<=detect_edge_n;
end
//接受uart_rx信号
assign detect_edge_n={detect_edge[0],UART_RX};



always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        negedge_reg<=1'b0;
    else
        negedge_reg<=negedge_reg_n;
end

//判断下降沿
assign negedge_reg_n=(detect_edge==2'b10)?1'b1:1'b0;

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        rx_bps_start<=1'b0;
    else
        rx_bps_start<=rx_bps_start_n;
end

//下降沿到来,就启动波特率计数器
always @(*)
begin
    if(negedge_reg)
        rx_bps_start_n=1'b1;
    else if(bit_cnt==4'd9)
        rx_bps_start_n=1'b0;
    else
        rx_bps_start_n=rx_bps_start;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        bit_cnt<=4'b0;
    else
        bit_cnt<=bit_cnt_n;
end

//判断是否中间采样点采样
always @(*)
begin
    if(rx_bos_flag)
        bit_cnt_n=bit_cnt+1'b1;
    else if(bit_cnt==4'd9)
        bit_cnt_n=1'b0;
    else
        bit_cnt_n=bit_cnt;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        shift_data<=8'b0;
    else
        shift_data<=shift_data_n;
end

//中间点采样,每采样一个便开始启动移位寄存器记录数据
always @(*)
begin
    if(rx_bps_flag)
        shift_data_n={UART_RX,shift_data[7:1]};
    else
        shift_data_n=shift_data;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        out_rx_data<=8'b0;
    else
        out_rx_data<=out_rx_data_n;
end

//数据是否接受完成
always @(*)
begin
    if(bit_cnt==4'd9)
        out_rx_data_n=shift_data;
    else
        out_rx_data_n=out_rx_data;
end


endmodule


//蜂鸣器模块
module Bepp_Module
(
    //input
    CLK_50M,RST_N,KEY,
    //output
    BEEP
);


input     CKL_50M;
input     RST_N;
intput    [7:0]    KEY;
output    BEEP;




reg    [15:0]    time_cnt;
reg    [15:0]    time_cnt_n;
reg    [15:0]    freq;
reg    [15:0]    freq_n;
reg    beep_reg;
reg    beep_reg_n;



always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        time_cnt<=16'b0;
     else
        time_cnt<=time_cnt_n;
end

always @(*)
begin
    if(time_cnt==freq)
        time_cnt_n=16'b0;
    else
        time_cnt_n=time_cnt+1'b1;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        beep_reg<=1'b0;
    else
        beep_reg<=beep_reg_n;
end

always @(*)
begin
    if(time_cnt==freq)
        beep_reg_n=~beep_reg;
    else
        beep_reg_n=beep_reg;
end

always @(posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        freq<=16'b0;
    else
        freq<=freq_n;
end

always @(*)
begin
    case(KEY)
        8'h30:freq_n=16'd0;
        8'h31:freq_n=16'd47774;
        8'h32:freq_n=16'd42568;
        8'h33:freq_n=16'd37919;
        8'h34:freq_n=16'd35791;
        8'h35:freq_n=16'd31888;
        8'h36:freq_n=16'd28409;
        8'h37:freq_n=16'd25309;
        8'h38:freq_n=16'd23889;
        8'h39:freq_n=16'd21276;
    default:feq_n=freq;
endcase
end

assign BEEP=beep_reg;

endmodule




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章