Uart空闲位起始位数据传输奇偶校验
时间: 2023-07-15 16:10:11 浏览: 111
UART(通用异步收发传输器)是一种串行通信协议,常用于将数据从一个设备传输到另一个设备。UART 通常有几个参数可以设置,包括:
1. 空闲位(Idle):这是传输线上未传输数据时的电平状态。通常为高电平。
2. 起始位(Start):这是传输的第一个数据位的电平状态。通常为低电平。
3. 数据位(Data):这是传输的实际数据位数。通常为 7 或 8 位。
4. 奇偶校验(Parity):这是一种数据校验方法,用于检测数据传输是否出错。奇偶校验分为奇校验和偶校验两种形式。
在 UART 通信中,发送方将数据按照以上参数进行编码后传输,接收方将数据解码后进行处理。
相关问题
给基础UART模块增加奇偶校验功能,通过端口parity(两位)使能控制模块的奇偶校验,00为不校验,01为奇校验,10为偶校验,端口check(一位)输出接收数据的奇偶校验结果,0表示校验正确,1表示校验错误。(verilog语言)
下面是基于Verilog语言实现基础UART模块增加奇偶校验功能的代码:
```verilog
module uart_with_parity_check
(
input clk,
input rst,
input en,
input parity_enable,
input [1:0] parity,
input rx,
output tx,
output reg check
);
// 定义状态机的状态
parameter [2:0] IDLE = 3'b000;
parameter [2:0] START = 3'b001;
parameter [2:0] DATA = 3'b010;
parameter [2:0] PARITY = 3'b011;
parameter [2:0] STOP = 3'b100;
reg [2:0] state; // 状态寄存器
reg [7:0] data_reg; // 数据寄存器
reg [1:0] parity_reg; // 奇偶校验寄存器
reg parity_check; // 校验结果寄存器
reg [3:0] bit_cnt; // 位计数器
assign tx = (state == DATA) ? data_reg[0] : 1'b1;
always @(posedge clk, posedge rst)
begin
if (rst == 1'b1) // 复位
begin
state <= IDLE;
data_reg <= 8'h00;
parity_reg <= 2'b00;
parity_check <= 1'b0;
bit_cnt <= 4'h0;
check <= 1'b0;
end
else if (en == 1'b1)
begin
case (state)
IDLE: // 空闲状态
begin
if (rx == 1'b0) // 接收到起始位
begin
state <= START;
data_reg <= 8'h00;
parity_reg <= 2'b00;
parity_check <= 1'b0;
bit_cnt <= 4'h0;
check <= 1'b0;
end
end
START: // 起始位
begin
if (parity_enable == 1'b1) // 奇偶校验使能
begin
parity_reg <= parity; // 保存奇偶校验方式
state <= PARITY; // 进入奇偶校验状态
end
else // 不校验奇偶性
begin
state <= DATA; // 进入数据状态
end
end
DATA: // 数据位
begin
if (bit_cnt < 4'h8) // 数据位
begin
data_reg <= {data_reg[6:0], rx}; // 存储接收到的数据
bit_cnt <= bit_cnt + 1'b1; // 计数器加1
end
else if (bit_cnt == 4'h8) // 校验位
begin
if (parity_enable == 1'b1) // 奇偶校验
begin
parity_reg[1:0] <= data_reg[0] ^ parity_reg[1:0]; // 更新奇偶校验寄存器
state <= PARITY; // 进入奇偶校验状态
end
else // 不校验奇偶性
begin
state <= STOP; // 进入停止位状态
end
end
end
PARITY: // 奇偶校验位
begin
if (bit_cnt < 4'h9) // 奇偶校验位
begin
parity_reg[1:0] <= parity_reg[1:0] ^ rx; // 更新奇偶校验寄存器
bit_cnt <= bit_cnt + 1'b1; // 计数器加1
end
else if (bit_cnt == 4'h9) // 停止位
begin
if ((parity_reg == 2'b00 && parity == 2'b00) || // 不校验奇偶性
(parity_reg == 2'b01 && (data_reg ^ 1'b1) == parity_reg[0]) || // 奇校验
(parity_reg == 2'b10 && (data_reg ^ 1'b0) == parity_reg[0])) // 偶校验
begin
parity_check <= 1'b0; // 校验正确
end
else
begin
parity_check <= 1'b1; // 校验错误
end
state <= STOP; // 进入停止位状态
end
end
STOP: // 停止位
begin
if (bit_cnt < 4'hA) // 停止位
begin
bit_cnt <= bit_cnt + 1'b1; // 计数器加1
end
else if (bit_cnt == 4'hA) // 完成
begin
check <= parity_check; // 输出校验结果
state <= IDLE; // 回到空闲状态
end
end
endcase
end
end
endmodule
```
在这个代码中,我们使用了一个状态机来实现UART模块的接收功能,并在数据接收完成后根据奇偶校验结果设置输出端口check的值。其中,输入参数parity_enable和parity分别表示奇偶校验是否使能和奇偶校验方式,输出端口check表示校验结果。
module uart_tx( input clk, input rst_n, output reg tx, input [7:0] data, input tx_en, output tx_done, input [3:0] DataLen_wire, input isParity_wire, input ParityMode_wire ); reg busy; //线路状态指示,高为线路忙,低为线路空闲 reg send; reg wrsigbuf; reg wrsigrise; reg presult; reg [7:0] cnt; reg [3:0] DataLen = 4'd8; reg isParity = 1'b0; reg paritymode = 1'b0; reg [3:0] dataN_send = 4'd0; //记录当前将要发送的数据(亦即已发送的数据位个数) always @(negedge rst_n) begin //在rst拉低时配置数据位长度、是否使用校验位、奇偶校验 DataLen <= DataLen_wire; isParity <= isParity_wire; paritymode <= ParityMode_wire; end //检测上升沿 always @(posedge clk) begin wrsigbuf <= tx_en; wrsigrise <= (~wrsigbuf) & tx_en; end //发送结束信号 assign tx_done = ~busy; //启动串口发送程序 always @(posedge clk) begin if(wrsigrise && (~busy)) begin //当发送命令有效且线路为空闲时,启动新的数据发送 send <= 1'b1; end else if(cnt==((DataLen+2+isParity)<<4)-4) begin send <= 1'b0; end end //串口发送程序,16个时钟发送一个bit always @(posedge clk or negedge rst_n) begin if(!rst_n) begin tx <= 1'b1; busy <= 1'b0; cnt <= 8'd0; presult <= 1'b0; dataN_send <= 4'd0; end else if(send==1'b1) begin if(cnt==8'd0) begin tx <= 1'b0; //产生起始位 dataN_send <= 4'd0; presult <= paritymode; busy <= 1'b1; cnt <= cnt + 8'd1; end else if(cnt==(dataN_send+1)<<4 && dataN_send<DataLen) begin tx <= data[dataN_send]; //发送数据位 小端 presult <= data[dataN_send]^presult; busy <= 1'b1; cnt <= cnt + 8'd1; dataN_send <= dataN_send+1; end else if(cnt==(DataLen+1)<<4) begin if(isParity)begin tx <= presult; //发送奇偶校验位 busy <= 1'b1; cnt <= cnt + 8'd1; end else begin tx <= 1'b1; //发送停止位 busy <= 1'b1; cnt <= cnt + 8'd1; end end else if(cnt==((DataLen+2)<<4)-4) begin if(isParity) begin tx <= 1'b1; //发送停止位 busy <= 1'b1; cnt <= cnt + 8'd1; end else begin tx <= 1'b1; busy <= 1'b0; cnt <= cnt + 8'd1; end end else if(cnt==((DataLen+3)<<4)-4) begin tx <= 1'b1; busy <= 1'b0; cnt <= cnt + 8'd1; end else begin cnt <= cnt + 8'd1; end end else begin tx <= 1'b1; cnt <= 8'd0; busy <= 1'b0; end end endmodule
这是一个串口发送模块的Verilog代码,它可以将输入的数据通过串口发送出去。它支持配置数据位长度、是否使用校验位、奇偶校验等功能。该模块的工作原理是在clk的上升沿检测发送命令信号tx_en,如果该信号为有效且线路为空闲,就启动新的数据发送。在发送过程中,每16个时钟发送一个bit,包括起始位、数据位、校验位和停止位。发送完毕后,会发出tx_done信号。
阅读全文