好久没写博客了,说起来满丢人的自从大二做了数字钟后,FPGA上一直没有什么进展。如果不会用接口,等于不会FPGA。但因为觉得没有扎实的理论基础,也没有必要学习FPGA。这期间学了微机原理,信号与系统,数字信号处理,通信原理的一些知识,觉得有必要推动一下FPGA实际编程了。
今天来讲一下串口通信,其实微机原理课设的时候用过串口,但本人学了verilog后,比较痴迷于FPGA,FPGA和单片机的串口差别蛮大的。单片机我学习的主要是写控制字。好了废话不多说了,原谅我的废话,开始正题吧。
首先来讲下原理吧,其实也不用知道,会调用就行,我在这里顺便提一手。我一直很喜欢折腾,就学了一些通信原理的东西。首先要知道串口大概率属于基带数字通信(他封装好了我也不知道,但有线的一般是基带数字通信)。这就涉及到一个问题,同步。同步什么意思呢?给你一段波形01010101,计算机的接口要正确的接受它,就必须要知道0与1每个码元之间间隔了多少时间。顺带提一手,我个人认为时钟信息属于双方提前约定好的,而不是从码元提取的。才能正确的对之进行采样。串口通信里面所提及的波特率其实就是这个东西,这应该属于叫做软件无线电吧,PC端你是可以通过软件来设置的,一个接口是支持不同的波特率的,因为要通用嘛。
还有一个概念叫做异步通信,这个其实你也不用知道。但是我还是想告诉你,为什么需要发送终止位和起始位。 根本原因在于这是异步的。异步意味着什么呢。 我可以发一个码元,搁很久很久再发一个码元,所以在发码元的前得先发个码元告诉你,在发完后呢,我还得收个尾告诉你我发完了。
好了概念基本都清楚了,那就开始FPGA怎么发吧,FPGA只用做一件事情就行了,以正确的频率和规则将信号传给内在的RS232端口模块就行了。是的就这么简单。只用控制一根信号线TX上的电压。
很好那何谓正确的频率呢?首先FPGA自己有个晶振,你可以按波特率算一算大概分频分多少,举个例子就是我网上买的一块板子50MHZ,我想发9600的波特率(吐槽我个人认为叫bit率比较贴切),那我分频分多少呢50*10^6/9600就是我的分频频率。
看到这恭喜你你已经会了,就这么简单。我下面给的一个例子是FPGA一直发0F给PC端的。代码及演示如下。其实知道咋发,再根据具体应用改就行。
module uart_tx(
Clk, //50M时钟输入
Rs232_Tx,//Rs232输出信号
Rst_n //模块复位
);
input Clk;
input Rst_n;
output reg Rs232_Tx;
localparam START_BIT = 1'b0;
localparam STOP_BIT = 1'b1;
localparam [7:0]t_data_byte = 8'b00001111;
reg [15:0]div_cnt;//分频计数器
reg [4:0]bps_cnt;
//counter
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
div_cnt <= 16'd0;
else begin
if(div_cnt == 16'd5208)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
bps_cnt <= 4'd0;
else if(bps_cnt == 4'd11)
bps_cnt <= 4'd0;
else if(div_cnt == 16'd5208)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Rs232_Tx <= 1'b1;
else begin
case(bps_cnt)
0:Rs232_Tx <= 1'b1;
1:Rs232_Tx <= START_BIT;
2:Rs232_Tx <= t_data_byte[0];
3:Rs232_Tx <= t_data_byte[1];
4:Rs232_Tx <= t_data_byte[2];
5:Rs232_Tx <= t_data_byte[3];
6:Rs232_Tx <= t_data_byte[4];
7:Rs232_Tx <= t_data_byte[5];
8:Rs232_Tx <= t_data_byte[6];
9:Rs232_Tx <= t_data_byte[7];
10:Rs232_Tx <= STOP_BIT;
default:Rs232_Tx <= 1'b1;
endcase
end
endmodule