UART协议:
发送端:串并 接收端:并串
接口:clk rst_n uart_en tx_data (发送二进制的数据)
txd 发送端 uart_state(状态)
1.clk:50Mhz
2.rst_n 默认低电平有效,数据复位,当处于高电平时,程序正常工作。
3.tx_data 输入信号
4.当使能信号uart_en上升沿到达后,开始低位传输
5.当没有uart_en时,开始位1
6.uart_state,开始运行时,拉高(表示传输数据开始),在停止信号达到之前,拉低(表示传输数据结束)
7.波特率:bps 每传输一位需要多少时钟:
8.clk_cnt:
9.tx_cnt:
uart | spi | i2c |
2根线 | 4线工作(片选线cs、sck串行时钟、mosi模式、miso模式) | 2根线(SCL、SDA)实现双向通信,具有地址定向性和主从模式 |
优点: 1:适用性广泛; 2:长距离通信 缺点: 1:速度较低 2: 232全双工(单端传输);485半双工(差分传输),485相比于232拥有更强的抗干扰能力 3:不可靠由于uart是异步通信,可能会造成噪声和干扰的影响,导致数据传输不可靠 | 优点: 1:spi通信速度较快,适用于对速度要求较高的应用 2:全双工,支持全双工通信,可以同时进行数据接收和发送 3:通信协议相对简单,适用于快速开发和调试 缺点: 1:连线复杂,spi需要多根线进行连接,可能会增加硬件设计的复杂性,spi比i2c需要更多的引脚。 2:长距离传输受限,过长的线路可能会导致信号衰减或干扰 3: spi通常采用主从模式,主设备数量受限制,不适用于多主设备场景 | 优点: 1:多设备支持:i2c设备支持多个设备连接在同一条总线上,每个设备都有唯一地址 2:简单,i2c协议相对简单,易于实现和调试 3:低功耗,在空闲状态时,i2c总线上的器件进入低功耗模式,节省能量 半双工 缺点: 1:通信速度较慢,用于低俗设备; 2:i2c的总线长度和设备数量收到限制,过长的总线会导致通信问题 3:当多个设备尝试同时发送数据时,可能会发生冲突,需要额外的冲突检测和处理机制 |
module uart_tx(
input wire clk, //系统时钟50Mhz
input wire uart_rst_n, //复位信号低有效
input uart_en, //发送端使能信号
input wire [7:0] tx_data,
output reg txd , //发送的数据信号
output reg tx_state //发送端状态
wire en_flag ;//使能标志位
assign en_flag=(~uart_en_d1)&uart_en_d0;//检测到上升沿,使能信号拉高
);
//波特率定义模块
localparam clk_fre=50_000_000;
localparam baud=115200;
localparam baud_N=clk/baud;//传输一位需要的时钟周期
//发送端使能信号的异步两拍同步
always @(posedge clk or negedge urat_rst_n)begin
if(!uart_rst_n)begin
uart_en_d0<=1'b0;
uart_en_d1<=1'b0;
end
else begin
uart_en_d0<=uart_en;
uart_en_d1<=uart_en_d0;
end
end
module uart_tx.v(
input ckl,
input rst_n,
input [7:0] data,
input send_en,
input [5:0] baud_set,
output uart_tx,
output tx_done,
uart_state
);
reg [17:0] bps_DR ;
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_DR<=16'd5207;
else begin
case(baud_set)
0:bps_DR<=17'd5207;
1:bps_DR<=17'd2603;
2:bps_DR<=17'd1301;
4:bps_DR<=17'd867;
5:bps_DR<=17'd433;
default:bps_DR<=17'd5207; //默认状态为9600bps
endcase
end
reg [17:0] div_cnt; //波特率为300所对应的最大计数值
always@(posedge clk or negedge rst_n)
if(!rst_n)
div_cnt<=0;
else if(uart_state)begin
if(div_cnt==bps_DR)
end
end
endmodule
奇偶分频
一、N分频(N为偶数)
注意时钟翻转条件为N/2 -1(从0开始计数)
以8分频为例:
module div_clk(
input clk,
input rst_n,
output wire clk_8
);
reg [1:0] cnt
//计数器
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=2'd0;
else if(cnt_p==2'd3) //以0开始计数,当计数到(N/2 -1)时,计数清0
cnt<=2'd0;
else
cnt<=cnt+2'd1;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
clk_8<=1'd0;
end
else if(cnt==2'd3)
clk_8<=~clk_8;
else
clk_8<=clk_8;
end
endmodule
以7分频为例:(占空比不是50%)
对时钟上升沿计数即可,设置两个计数的翻转点,分别为0到(N-1)/2和N-1
module div_clk(
input clk,
input rst_n,
output reg clk_7
);
reg [2:0] cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=2'd0;
else if(cnt==3'd6)
cnt<=3'd0;
else cnt<=cnt+3'd1;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
clk_7<=1'd0;
end
else if(cnt<3'd4)//在0到N-1/2输出低电平,N-1/2 +1到N-1输出高电平(此时占空比不是百分之50)
clk_7<=1'd0;
else
clk_7<=1'd1;
endmodule
以7分频为例:(占空比50%)
a 分别设计上升沿计数器cnt_p、下降沿计数器cnt_n、上升沿分频器clk_p、下降沿分频器clk_n
b:
//复位信号均是低电平有效
module div_clk(
input clk,
input rst_n,
output wire clk_7 //占空比要求百分之50
);
reg [2:0] cnt_p;
reg [2:0] cnt_n;
reg clk_p;
reg clk_n;
//上升沿计数
always@(posedge clk or negedge rst_n) //时钟上升沿有效,上升沿开始计数
if(!rst_n)
cnt_p<=3'd0;
else if(cnt_p==3'd6)
cnt_p<=3'd0;
else
cnt_p<=cnt_p+3'd1;
//上升沿分频
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
clk_p<=1'd0;
end
else if((cnt_p==3'd3)||(cnt_p==3'd6))begin //(若计数器的上升沿计数到3或计数器计数到6,上升沿分频输出均取反操作)
clk_p<=~clk_p;
end
//下降沿计数
always@(negedge clk or negedge rst_n)// 时钟下降沿开始计数,下降沿有效
if(!rst_n)
cnt_n<=2'd0;
else if(cnt_n==3'd6)
cnt_n<=3'd0;
else
cnt_n<=cnt_n+3'd1;
//下降沿分频
always@(negedge clk or negedge rst_n)
if(!rst_n)begin
clk_n<=1'd0;
end
else if((cnt_n==3'd3)||(cnt_n==3'd6))begin//(若计数器的下降沿计数到3或计数器计数到6,下降沿分频输出取反操作))
clk_n<=~clk_n;
end
assign clk_7=(clk_p|clk_n) ;//将上升沿和下降沿取或操作,得到7分频输出,且占空比为50%
endmodule