明白串口传输的收发过程之后,就可以通过代码实现了。首先,接收和发送可以划分成独立的两个模块。其次,串口波特率有9600bps、19200bps、38400bps、57600bps、115200bps等不同的波特率。那么,还要加一个波特率控制模块。
先讲一下波特率控制模块,这个模块本质上是对系统时钟做分频处理。通过计数,将25MHz的系统时钟分频成9600Hz、19200Hz等的周期信号。部分代码如下:
always @(posedge CLK_25M or negedge rst_n)
if (!rst_n)
cnt <= 12'd0;
else if(cnt == Baud)
cnt <= 12'd0;
else cnt = cnt + 1'd1;
always @(posedge CLK_25M or negedge rst_n)
if (!rst_n)
BPS_CLK_r <= 1'd0;
else if (cnt <= Baud >> 1) //相当于Baud/2
BPS_CLK_r <= 1'd0; //作为接收数据时的中间采样点,或发送数据时的位分界点
else
BPS_CLK_r <= 1'd1;
always@(posedge BPS_CLK or negedge rst_n)
if(!rst_n)
begin
j <= 4'd0;
data_in <= 8'd0;
data_inr <= 40'd0;
receive_data <= 40'd0;
end
else case(j)
4'd0: //判断起始标志
begin
if(!RX)
begin
data_in <= 8'd0;
j <= j+ 1'd1;
end
else j <= j;
end
4'd1,4'd2,4'd3,4'd4,4'd5,4'd6,4'd7,4'd8: //接收数据
begin
j <= j + 1'd1;
data_in <= {RX,data_in[7:1]};
end
4'd9: //接收校验位
begin
receive_data <= {receive_data[31:0],data_in};
j <= j + 1'd1;
end
4'd10: //接收停止位
begin
j <= 1'd0;
if(receive_data[7:0] == 8'b00001010)
begin
data_inr <= receive_data;
end
end
default: j <= 4'd0;
endcase
always @(posedge BPS_CLK or negedge rst_n)
if (!rst_n)
begin
i <= 14'd0;
TX_r <= 1'd1; //空闲状态为1
cnt <= 4'd0;
data_out <= 8'd0;
GINGKO <= {8'd71,8'd73,8'd78,8'd71,8'd75,8'd79,8'd13,8'd10};
end
else //开始发送DATA
case(i)
14'd0: begin //先发送起始位0
i <= i + 1'd1;
{data_out,GINGKO[63:8]} <= GINGKO;
TX_r <= 1'd0;
end
14'd1,14'd2,14'd3,14'd4,14'd5,14'd6,14'd7,14'd8: //TX_r将DATA数据发送出去
begin
i <= i + 1'd1;
{data_out[6:0],TX_r} <= data_out; //串口发送时,低位在先
end
14'd9: begin //1位奇偶校验位和1位停止位
i <= i + 1'd1;
TX_r <= 1'd1;
end
14'd10: begin //1位停止位
if(cnt == 4'd7)
begin
i <= i + 1'd1;
cnt <= 4'd0;
end
else
begin
i <= 14'd0;
cnt <= cnt + 1'd1;
end
end
14'd9600: begin //定时约为1s
i <= 14'd0;
GINGKO <= {8'd71,8'd73,8'd78,8'd71,8'd75,8'd79,8'd13,8'd10};
end
default: i <= i + 1'd1; //i为其他无效数值时,直接转到退出TXD模块状态
endcase