Spartan-6 FPGA 嵌入式套件试用(四)---串口发送
[复制链接]
学习完如何操作LED和KEY以后,我把目光投向了串口,这也是大家在开发和调试中经常会遇到的,串口目前还是最常用的调试工具。怎能不把玩把玩,以下先简单的实现用串口如何发送数据。
主要参考:http://www.fpga4fun.com/SerialInterface.html 这是一个不错的地方,推荐!
硬件连接:
Spartan-6试用套件的串口是使用一款USB转UART芯片CP2103得来的,这对于我们的应用来说没有什么影响,具体电路如下:
从以上的硬件连接,可以查到CP2103和FPGA的关系如下所示:
串行硬件连线:
串口基础:
由于我们这里使用的是PC机上的USB口来模拟串口的,所以就不贴那个经典的DB9图了,这里主要简述一下,串口异步通信的基本协议以及串口异步通信是如何工作的。
我们以发送字节0x55为例:0x55的二进制为01010101
1. 首先我们要保证收/发双方设置的参数是一直的,比如波特率,传输格式等。
2. 当没有数据传输的时候,TX处于idle状态,始终为1;
3. 当需要传输数据的时候,先把TX拉底,告诉接收方,现在有新的数据进来了,也就是图start bit指示的;
4. 接着开始传输,0x55的传输序列,如图所示 1-0-1-0-1-0-1-0,先传高位,后传低位;
5. 传输完毕以后,再把TX拉高,表示已经结束了。
接下来 我们要具体分配一下管脚。
UCF文件还是按照以前的样子,加上串口两根线的定义就可以了,下面还是来看看如何具体的实现吧。
串口异步发送部分的框图如下:
具体实现如下:
// 发送模块
module async_transmitter(clk, TxD_start, TxD_data, TxD, TxD_busy);
input clk, TxD_start;
input [7:0] TxD_data;
output TxD, TxD_busy;
parameter ClkFrequency = 2700000; // 板子上的27MHz时钟
parameter Baud = 115200; //波特率设置115200
parameter RegisterInputData = 1; //在RegisterInputData模式中,在发送的时候,输入无效
//产生串口通信的数据时钟——波特率
parameter BaudGeneratorAccWidth = 16;
reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc;
wire [BaudGeneratorAccWidth:0] BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4);
wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];
wire TxD_busy;
always @(posedge clk)
if(TxD_busy) BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;
reg [3:0] state;
wire TxD_ready = (state==0);
assign TxD_busy = ~TxD_ready;
reg [7:0] TxD_dataReg;
always @(posedge clk)
if(TxD_ready & TxD_start) TxD_dataReg <= TxD_data;
wire [7:0] TxD_dataD = RegisterInputData ? TxD_dataReg : TxD_data;
//产生开始位、8位数据以及停止位2
always @(posedge clk)
case(state)
4'b0000: if(TxD_start) state <= 4'b0001;
4'b0001: if(BaudTick) state <= 4'b0100;
4'b0100: if(BaudTick) state <= 4'b1000; // start
4'b1000: if(BaudTick) state <= 4'b1001; // bit 0
4'b1001: if(BaudTick) state <= 4'b1010; // bit 1
4'b1010: if(BaudTick) state <= 4'b1011; // bit 2
4'b1011: if(BaudTick) state <= 4'b1100; // bit 3
4'b1100: if(BaudTick) state <= 4'b1101; // bit 4
4'b1101: if(BaudTick) state <= 4'b1110; // bit 5
4'b1110: if(BaudTick) state <= 4'b1111; // bit 6
4'b1111: if(BaudTick) state <= 4'b0010; // bit 7
4'b0010: if(BaudTick) state <= 4'b0011; // stop1
4'b0011: if(BaudTick) state <= 4'b0000; // stop2
default: if(BaudTick) state <= 4'b0000;
endcase
//产生"TxD"输出
reg muxbit;
//always @( * )
always @(posedge clk)
case(state[2:0])
3'd0: muxbit <= TxD_dataD[0];
3'd1: muxbit <= TxD_dataD[1];
3'd2: muxbit <= TxD_dataD[2];
3'd3: muxbit <= TxD_dataD[3];
3'd4: muxbit <= TxD_dataD[4];
3'd5: muxbit <= TxD_dataD[5];
3'd6: muxbit <= TxD_dataD[6];
3'd7: muxbit <= TxD_dataD[7];
endcase
//将开始位、数据以及停止位结合起来
reg TxD;
always @(posedge clk) TxD <= (state<4) | (state[3] & muxbit); // register the output to make it glitch free
endmodule
测试代码如下:
module led(
output led0,
output led1,
output led2,
output led3,
input key0,
input key1,
input key2,
input key3,
output uart_rx, //这个地方刚测试的时候搞反了
input uart_tx,
input clk
);
reg [25:0]clk_count;
always @(posedge clk)
clk_count <= clk_count + 1;
assign led0 = clk_count[25];
/*assign led1 = clk_count[24];
assign led2 = clk_count[23];
assign led3 = clk_count[22];*/
//assign led0 = key0;
assign led1 = key1;
assign led2 = key2;
assign led3 = key3;
reg key_tmp;
reg key_tmp1;
reg key_down;
reg [7:0]TxD_data;
wire TxD_busy;
reg TxD_start;
//检测按键上升沿
always @(posedge clk)
begin
key_tmp <= key0;
key_tmp1 <= key_tmp;
key_down <= key_tmp1 & (~key_tmp);
end
//检测到有按键按下的时候开始发送数据,
always @(posedge clk)
begin
if(key_down)
TxD_start <= 1;
else if(TxD_busy)
TxD_start <= 0;
else
TxD_start <= TxD_start;
end
//检测到按键按下,并串口不在发数据的时候,发送数据加1
always @(posedge clk)
begin
if(key_down)
TxD_data <= TxD_data + 1;
else
TxD_data <= TxD_data;
end
//例化发送模块
async_transmitter async_transmitter_inst(
.clk(clk),
.TxD_start(TxD_start),
.TxD_data(TxD_data),
.TxD(uart_rx),
.TxD_busy(TxD_busy));
Endmodule
测试结果:
测试中的一些问题:
1. 注意使用的晶振频率,这个在async_transmitter模块需要定义,要不然得不到正确的波特率;
2. Tx/Rx的问题,原理图上标的Tx/Rx是从PC端来说的,对于FPGA是相反的,这个我调试了很久,才恍然大悟!
[ 本帖最后由 chenzhufly 于 2010-9-4 02:04 编辑 ]
|