学习笔记: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