之四:UART接收器模块设计
时间:10-02
整理:3721RD
点击:
很遗憾很遗憾,中间放了个暑假时间拖到了试用期结束,这篇之后马上到小处理器。
一、UART接收器
写了三四遍的verilog代码,总是觉得有种必须得写成状态机形式的感觉。写了几遍加上sigaltap都调不好,最后无奈画出了一个方框图,按照图才出了一个有效的uart接收器代码。之所以要写一个接收器,是因为如果要对一个MCU编程的话,通过uart串口很简便。框图如下。

二、图中的异步复位触发器
异步复位触发器的写法一般是:
always@(posedge clk or negedge rst)
begin
if(~rst) q<=0;
else q<=d;
end
这个看起来很像是边沿触发来复位:加入rst一直为低,q并不会被复位成0.但是实际上由于上电时D触发器的输出一般是低电平,所以rst一直为低的情况也可以认为是电平复位;而如果复位将q变成1,这就不是一个正确的电平异步复位了:上电开始时,rst为0,q也为0,不满足复位条件。
三、框图含义
由于uart的协议是先发一个起始位,然后发送8位数据。在9600波特率的要求下,使用FPGA的时钟源325分频出16倍于9600bit/s的时钟送入到uart模块中。
首先是边沿检测,图中电路保证一个下降沿来临之后,其余电路开始工作,即开始记录比特位;同时将这个边沿检测电路的输入屏蔽掉。
在计数到8位有效位都读出之后,counter输出变为0,将边沿检测部分复位,counter失去时钟源。另外,counter输出的0经过两个延时之后将自己复位,输出重新变为1,这个负脉冲经过反相器即可作为对外部的通知信号:来读取串口数据吧。
四、verilog源代码
module newart(
input dat,
input clk,
output ex0,
output reg [7:0]bufout);
reg ck;
reg [7:0]buftmp;
reg [7:0]count;
reg enout;
reg enout2;
reg enout3;
wire ck1;
wire rst0;
reg rst1;
reg [8:0]count1;//325 freq divide;
reg [7:0]count2;//180 times,make the ck high;
wire dat0;
assign rst0=enout2;
always@(posedge clk)
begin
count1<=count1+1;
count2<=count2+1;
if(count1==0)begin
ck<=0;
count2<=0;
end
else begin
if(count1==324) count1<=0;
if(count2==180) begin ck<=1;count2<=0;end
end
end
always@(negedge rst0 or negedge dat0)//it seems that it is a edge detect,however it is a level driven.
begin
if(~rst0)enout<=0;
else enout<=1;
end
assign ck1=ck&enout;
assign dat0=enout|dat;
always@(posedge ck1 or negedge rst1)
begin
if(~rst1)begin enout2<=1;count<=0;end
else begin
count<=count+1;
case(count)
24:buftmp[0]<=dat;
40:buftmp[1]<=dat;
56:buftmp[2]<=dat;
72:buftmp[3]<=dat;
88:buftmp[4]<=dat;
104:buftmp[5]<=dat;
120:buftmp[6]<=dat;
136:buftmp[7]<=dat;//the above get 8 bit;
152:begin enout2<=0;bufout<=buftmp;end
endcase
end
end
always@(posedge ck)
begin
enout3<=enout2;
rst1<=enout3;
end
assign ex0=~rst1;
endmodule
将上述代码作为一个模块嵌入到下面的代码中:
//this uart only can receive info from master,used as uart program!
//this test module detects A,B,C,D,E;
module comuart(
input clk,
input dat,
output reg led1,
output reg led2,
output reg led3,
output reg led4,
output reg led5,
output led6
);
wire ex0;
wire [7:0]bufout;
newart u1(dat,clk,ex0,bufout);
//how does the sub module attach to top module?
//the sub module must be connected to a wire.
always@(posedge ex0)
begin
case(bufout)
65:begin led1<=0;
led2<=1;
led3<=1;
led4<=1;
led5<=1;
end
66:begin led1<=1;
led2<=0;
led3<=1;
led4<=1;
led5<=1;
end
67:begin led1<=1;
led2<=1;
led3<=0;
led4<=1;
led5<=1;
end
68:begin led1<=1;
led2<=1;
led3<=1;
led4<=0;
led5<=1;
end
69:begin led1<=1;
led2<=1;
led3<=1;
led4<=1;
led5<=0;
end
default:begin led1<=1;
led2<=1;
led3<=1;
led4<=1;
led5<=1;
end
endcase
end
assign led6=dat;//led6 is tested alone for the uartin.
endmodule
五、结果及最后的工作
结果见下述小视频:
http://v.youku.com/v_show/id_XMzA0NzE1MzU4NA==.html?spm=a2hzp.8253869.0.0
通过串口发送A/B/C/D/E,会点亮对应的灯。如果应用于准备写的超低端处理器中,就是一条一条的指令了。
最后,再次对没有按时完成计划表示道歉。
一、UART接收器
写了三四遍的verilog代码,总是觉得有种必须得写成状态机形式的感觉。写了几遍加上sigaltap都调不好,最后无奈画出了一个方框图,按照图才出了一个有效的uart接收器代码。之所以要写一个接收器,是因为如果要对一个MCU编程的话,通过uart串口很简便。框图如下。

二、图中的异步复位触发器
异步复位触发器的写法一般是:
always@(posedge clk or negedge rst)
begin
if(~rst) q<=0;
else q<=d;
end
这个看起来很像是边沿触发来复位:加入rst一直为低,q并不会被复位成0.但是实际上由于上电时D触发器的输出一般是低电平,所以rst一直为低的情况也可以认为是电平复位;而如果复位将q变成1,这就不是一个正确的电平异步复位了:上电开始时,rst为0,q也为0,不满足复位条件。
三、框图含义
由于uart的协议是先发一个起始位,然后发送8位数据。在9600波特率的要求下,使用FPGA的时钟源325分频出16倍于9600bit/s的时钟送入到uart模块中。
首先是边沿检测,图中电路保证一个下降沿来临之后,其余电路开始工作,即开始记录比特位;同时将这个边沿检测电路的输入屏蔽掉。
在计数到8位有效位都读出之后,counter输出变为0,将边沿检测部分复位,counter失去时钟源。另外,counter输出的0经过两个延时之后将自己复位,输出重新变为1,这个负脉冲经过反相器即可作为对外部的通知信号:来读取串口数据吧。
四、verilog源代码
module newart(
input dat,
input clk,
output ex0,
output reg [7:0]bufout);
reg ck;
reg [7:0]buftmp;
reg [7:0]count;
reg enout;
reg enout2;
reg enout3;
wire ck1;
wire rst0;
reg rst1;
reg [8:0]count1;//325 freq divide;
reg [7:0]count2;//180 times,make the ck high;
wire dat0;
assign rst0=enout2;
always@(posedge clk)
begin
count1<=count1+1;
count2<=count2+1;
if(count1==0)begin
ck<=0;
count2<=0;
end
else begin
if(count1==324) count1<=0;
if(count2==180) begin ck<=1;count2<=0;end
end
end
always@(negedge rst0 or negedge dat0)//it seems that it is a edge detect,however it is a level driven.
begin
if(~rst0)enout<=0;
else enout<=1;
end
assign ck1=ck&enout;
assign dat0=enout|dat;
always@(posedge ck1 or negedge rst1)
begin
if(~rst1)begin enout2<=1;count<=0;end
else begin
count<=count+1;
case(count)
24:buftmp[0]<=dat;
40:buftmp[1]<=dat;
56:buftmp[2]<=dat;
72:buftmp[3]<=dat;
88:buftmp[4]<=dat;
104:buftmp[5]<=dat;
120:buftmp[6]<=dat;
136:buftmp[7]<=dat;//the above get 8 bit;
152:begin enout2<=0;bufout<=buftmp;end
endcase
end
end
always@(posedge ck)
begin
enout3<=enout2;
rst1<=enout3;
end
assign ex0=~rst1;
endmodule
将上述代码作为一个模块嵌入到下面的代码中:
//this uart only can receive info from master,used as uart program!
//this test module detects A,B,C,D,E;
module comuart(
input clk,
input dat,
output reg led1,
output reg led2,
output reg led3,
output reg led4,
output reg led5,
output led6
);
wire ex0;
wire [7:0]bufout;
newart u1(dat,clk,ex0,bufout);
//how does the sub module attach to top module?
//the sub module must be connected to a wire.
always@(posedge ex0)
begin
case(bufout)
65:begin led1<=0;
led2<=1;
led3<=1;
led4<=1;
led5<=1;
end
66:begin led1<=1;
led2<=0;
led3<=1;
led4<=1;
led5<=1;
end
67:begin led1<=1;
led2<=1;
led3<=0;
led4<=1;
led5<=1;
end
68:begin led1<=1;
led2<=1;
led3<=1;
led4<=0;
led5<=1;
end
69:begin led1<=1;
led2<=1;
led3<=1;
led4<=1;
led5<=0;
end
default:begin led1<=1;
led2<=1;
led3<=1;
led4<=1;
led5<=1;
end
endcase
end
assign led6=dat;//led6 is tested alone for the uartin.
endmodule
五、结果及最后的工作
结果见下述小视频:
http://v.youku.com/v_show/id_XMzA0NzE1MzU4NA==.html?spm=a2hzp.8253869.0.0
通过串口发送A/B/C/D/E,会点亮对应的灯。如果应用于准备写的超低端处理器中,就是一条一条的指令了。
最后,再次对没有按时完成计划表示道歉。
不错的资料分享
栏目分类
射频专业培训教程推荐