串口通信
串口通信协议
所谓通信协议是指通信双方的一种约定。约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。
对于一个设备来说,要接收和发送串行通信的数据,需要一个器件将串行的数据转换为并行的数据以便于处理器进行处理,这个器件就是UART(Universal Asynchronous Receiver/Transmitter)通用异步收发器。作为接口的一部分,UART提供以下功能:
- 将由计算机内部传送过来的并行数据转换为输出的串行数据流;
- 将计算机外部传来的串行数据转换为字节,供计算机内部使用并行数据的器件使用;
- 在输出的串行数据流中加入奇偶检验位,并对外部接收的数据流进行奇偶检验;
- 在输出数据流中加入启停标志,并从接收数据流中删除启停标记。
串口通信的数据格式:
首先看一下我们这个板子的电平转换芯片
我们这个开发板的电平转换芯片为MAX3462,所以先下载3462的datasheet。如下图:
我们这个板子的时钟是59MHz的。
总体设计思想是:
PC发送数据,由MAX3462完成RS-232电平到TTL电平的转换,FPGA内部的RXD模块负责转换后串行数据的接收,数据处理单元对接收数据进行处理,处理完成后将数据暂存于FIFO中,TDX读取暂存数据,并按照通信协议把数据发给MAX3462反馈给PC,分析数据是否符合要求,从而验证整个系统设计的合理性。
之前一直有一个问题,就是波特率到底有什么用,因为看了下面这个帧格式,并没有发现控制传输速度的地方。
波特率始终并没有表现在传输线上,它其实是用来指示我们每采样一个或者发送一个数据位的速度的。比如说,我们定义一个波特率时钟为115200,那么我们用这个时钟把数据串行一个一个的打出去,接收端只需要匹配一个相同的时钟,一个一个的数据位接收进来,数据传输就可以了。
对数据接收来说,一旦检测到起始位,就打开波特率时钟,等数据接收完成,启动一次数据传输,一帧数据传输完毕,关闭波特率时钟,然后标志位关闭,避免重复传输。
在我们这个项目中,主模块是top,它包含四个子模块,分别是接收模块uart_receive、接受模块的波特率时钟div_1_8m、发送模块uart_send、发送模块的波特率时钟div_baud。
这里面的发送和接收都是对FPGA而言的!
module top(clk59m,rst,txd,rxd,send_over,dout);
input clk59m;
input rst;
input rxd;
output txd;
output send_over;
output dout;
wire txd;
wire rxd;
//产生采样频率模块wire clk1_8m; //时钟连线
div_1_8m div_1_8m1 (
.clk59m(clk59m),
.clk1_8m(clk1_8m),
.rst(rst)
);
//产生发送模块波特率wire clk_baud;
div_baud div_baud1 (
.clk1_8m(clk1_8m),
.clk_baud(clk_baud),
.rst(rst)
);
//由于每有数据产生,所以手动编写数据wire wrn;
wire rdn;
wire send_over;
wire data_ready;
wire [7:0] dout;
wire [11:0] addra_cnt;
wire [7:0] douta;
wire [7:0] din;
uart uart1 (
.clk(clk1_8m),
.clk_baud(clk_baud),
.rst(rst),
.rxd(rxd),
.din(din),
.wrn(wrn),
.txd(txd),
.rdn(rdn),
.dout(dout),
.data_ready(data_ready),
.send_over(send_over)
);
endmodule
通常,我们在主模块top中不会写具体的代码,因为主模块的功能是将各个子模块连接在一起,这样比较有利于代码的维护。