欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-30 11:32:40
...

一,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的帧格式

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

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

(3)UART协议使用。

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

1,功能模块图

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

(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




 

相关标签: FPGA