Diseño y verificación de módulo de envío de puerto serie para aprendizaje FPGA

Diseño y verificación de módulo de envío de puerto serie para aprendizaje FPGA

1. El propósito del experimento:

Realice una salida de puerto serie, compruebe si los datos recibidos son los datos enviados por el puerto serie a través de la computadora superior.

2. Introducción al experimento:

Aprenda el principio de comunicación UART y su diseño de circuito de hardware, use FPGA para realizar el diseño de la parte de transmisión de datos de la comunicación UART y use la herramienta ISSP para llevar a cabo la verificación a nivel de placa.

3. Principio experimental

(1) Principio de comunicación serial asíncrona

La comunicación en serie se refiere al uso de una línea de transmisión para transferir datos un bit en secuencia, y cada bit de datos ocupa un período de tiempo fijo.

La comunicación asíncrona utiliza un carácter como unidad de transmisión. El intervalo de tiempo entre dos caracteres en la comunicación no es fijo, pero el intervalo de tiempo entre dos bits adyacentes en el mismo carácter es fijo.
Inserte la descripción de la imagen aquí
Es decir, el intervalo de tiempo entre los datos de 10 bits de la figura siguiente es fijo. Este tiempo fijo se denomina velocidad en baudios, que se refiere a la cantidad de bits de datos que se pueden comunicar por segundo. Las velocidades en baudios típicas son 1200bps, 4800bps , 9600bps, 19200bps, 115200bps, etc. Generalmente, la velocidad en baudios en ambos extremos de la comunicación debe ser la misma.

Inserte la descripción de la imagen aquí

(2) Diagrama del marco del sistema

Para todo el módulo de envío del puerto serie, según los principios anteriores, comprenda las siguientes interfaces de entrada y salida:

1. Primero, como módulo de envío, debe haber un puerto de envío de datos de salida Rx232_Tx;

2. Para completar una transmisión de caracteres, es necesario decirle a la computadora superior que la transmisión de caracteres ha terminado y comenzar la siguiente transmisión, es decir, la señal de finalización de la transmisión marca Tx_Done. Cuando se completa la transmisión, un alto nivel de se emite un ciclo de reloj.

3. Cuando el módulo de puerto serie está enviando datos, debe haber un bit de estado de puerto serie de indicador de salida uart_state, es decir, es 1 cuando está en estado de envío, indicando a la computadora host que el módulo está actualmente ocupado.

4. La entrada debe tener reloj Clk y reiniciar la entrada Rst_n.
Inserte la descripción de la imagen aquí

5. Aunque hay varias velocidades en baudios de uso común en la figura anterior, cómo elegir la velocidad en baudios correspondiente a la computadora superior para realizar la comunicación entre diferentes computadoras superiores, por lo que aquí se necesita un puerto de entrada de selección de velocidad en baudios baud_set [3: 0] .

6. Si queremos enviar un dato, debemos controlar el módulo para que lo envíe cuando se necesiten los datos, y no se puede enviar de forma interminable, por lo que debe haber una señal de control de envío, es decir, enviando una habilitación. enviar señal

7. Los datos que se enviarán son datos_byte de entrada [7: 0];

Entonces, ¿qué tipo de circuito lógico existe entre estos puertos de entrada y salida para enviar datos?

Formato de salida de datos

Para la salida de datos de 1 byte y 10 bits, donde se conoce el formato de envío de datos, es decir, bit de inicio + 8 bits de datos + bit de parada (el bit de paridad no está disponible por defecto), entonces se necesita un multiplexor para seleccionar uno de 10 aquí, para que podamos elegir qué bit de datos enviar.

Inserte la descripción de la imagen aquí
Dado que RS232 es un transceptor asíncrono, para garantizar que los datos enviados sean estables cuando llega el reloj, es necesario registrar los datos de entrada.

Los datos válidos de 8 bits se envían al múltiplex de 10 selecciones a través del registro, y luego la señal de selección sel selecciona qué bit de datos enviar. Después de seleccionar los datos, se transmiten al registro data_reg.

Entonces, ¿cómo se genera la señal de selección de sel en la figura anterior?

Salida de conteo de flancos de reloj de velocidad en baudios 10 seleccione un control de multiplexor

Primero, ¿qué salida de datos es seleccionada por la señal de selección sel? Como se puede ver en la figura siguiente, podemos contar los flancos de reloj de BPS_CLK. Siempre que llega un flanco ascendente, el contador bps_cnt se incrementa en 1, y luego el número de bits de datos se selecciona de acuerdo con el resultado del recuento. Por ejemplo, cuando el contador cuenta hasta 7, la señal de selección es Elegirá enviar datos BIT [5].

Inserte la descripción de la imagen aquí

Y este contador sólo puede contar hasta 11 (se envía un byte). Cuando cuenta hasta 11, necesita generar una señal clara de clr.

Esta señal clara de clr proviene del puerto de salida mencionado anteriormente Tx_Done. Cuando el indicador de señal final Tx_Done emite un nivel alto para un ciclo de reloj, se determina que se ha transmitido un byte.

Cuando el contador bps_cnt_q es igual a 11, el resultado es verdadero y está conectado a la línea de señal clara clr para realizar la acción de limpieza.

Al mismo tiempo, el resultado de la comparación se transmite a la señal Tx_Done a través del registro para decirle a la computadora superior que la transmisión de caracteres ha terminado.

Inserte la descripción de la imagen aquí
Mirando la figura anterior, la señal BPS_Clk de entrada de bps_cnt es en realidad la señal de reloj correspondiente a la velocidad en baudios.

Reloj de velocidad en baudios de salida del contador divisor

Inserte la descripción de la imagen aquí
Debido a que el intervalo de tiempo entre los bits adyacentes de un carácter corresponde a la velocidad en baudios, y la transmisión de cada bit se basa en el borde ascendente de bps_clk, necesitamos diferentes bps_clk para corresponder a diferentes velocidades en baudios (1200bps, 4800bps, 9600bps, 115200bps) ).

El primer paso es generar diferentes velocidades en baudios. Debido a que el reloj del sistema es de 50 Mhz y el ciclo del reloj del sistema es de 20 ns, el contador de división de frecuencia se sigue utilizando para lograr diferentes velocidades de transmisión en baudios. La siguiente tabla muestra las relaciones de contador correspondientes a velocidades de transmisión comunes .:

Inserte la descripción de la imagen aquí
La tabla anterior muestra que la llamada generación de velocidad en baudios no es más que usar un temporizador para cronometrar la frecuencia y la frecuencia de reloj correspondiente a la velocidad en baudios.

Por ejemplo, cuando usamos 9600bps, necesitamos generar una señal de reloj con una frecuencia de 9600Hz. Entonces, ¿cómo generar esta señal?

Aquí, primero calculamos el período de la señal de reloj de 9600Hz, 1 segundo es 1000_000_000ns, por lo que el período de la velocidad de reloj de 9600bps es 1000_000_000 / 9600≈104166.6, es decir, un período de la señal de reloj de 9600Hz es 104166.6ns, siempre que el tiempo de temporización Cuando llegue el momento, genere una señal de pulso alta con una duración de ciclo de reloj del sistema. Dado que el ciclo de reloj del sistema es de 20 ns (50 MHz), solo es necesario contar 104166,6 / 20 relojes del sistema para obtener la temporización de 101166,6.

Inserte la descripción de la imagen aquí

Contador de divisores habilita el control

En correspondencia con un contador divisor de frecuencia, cuando el reloj del sistema está funcionando, ¿cuándo comienza a contar aunque pueda contar la señal? ¿Cuándo comienza a funcionar el conteo?

Este diseño utiliza dos multiplexores alternativos uno para generar la señal de conteo de habilitación Primero que todo, hay un problema de prioridad, porque cuando send_en envía la señal de habilitación a un nivel alto, entonces nuestro contador de división de frecuencia también comenzará Contado.

Sin embargo, la señal send_en solo mantiene un nivel alto durante un ciclo de reloj y permanece bajo durante el resto del tiempo. En este momento, se necesita un multiplexor dos a uno para darse cuenta de que cuando la señal send_en es alta, la salida "1 "para indicar el inicio del conteo.

¿Cómo darse cuenta de que cuando send_en es bajo, el contador divisor sigue contando? ¿Cuál es el signo del final de la cuenta?

De lo anterior se puede ver que se generará una señal de bandera Tx_Done después de que finalice la transmisión de datos. Esta señal se genera cuando el contador bps_cnt es igual a 11. El resultado de la comparación con 11 se conectará al contador bps_cnt para borrar el clr, esta señal también se puede utilizar como otro multiplexor dos a uno en el lado de la selección.

Inserte la descripción de la imagen aquí

Por lo tanto, cuando la señal send_en es baja, el segundo multiplexor uno de dos MUX2_2 se seleccionará como salida. El final de selección de MUX2_2 es ​​el mismo que clr. Por lo tanto, cuando el resultado de la comparación es falso, la salida de MUX2_2 es la entrada original UART_state. Es decir, para mantener el estado UART_state sin cambios, todavía significa que el contador divisor sigue contando.

Cuando el resultado de la comparación es verdadero, es decir, cuando se envían los datos, MUX2_2 generará "0". En este momento, UART_state generará un nivel bajo y la habilitación de conteo en_cnt controlará el contador divisor para detener el conteo.

Encuentre la salida del valor de conteo a diferentes velocidades en baudios

¿Cómo generar el valor de conteo bps_DR [15: 0] correspondiente a diferentes señales de reloj de velocidad en baudios?

Inserte la descripción de la imagen aquí

Aquí usamos la tabla de búsqueda LUT para realizar la señal baud_set para seleccionar diferentes velocidades en baudios y generar diferentes valores de conteo de reloj del sistema.

Diagrama de estructura del sistema

Por lo tanto, se puede dibujar el diagrama del marco del sistema de la lógica básica del módulo de envío del puerto serie:
Inserte la descripción de la imagen aquí

4. Implementación del código

De acuerdo con el diagrama de marco del sistema descrito anteriormente para realizar la parte correspondiente de la función:

Formato de salida de datos

Inserte la descripción de la imagen aquí

Salida de conteo de flancos de reloj de velocidad en baudios 10 seleccione un control de multiplexor

Inserte la descripción de la imagen aquí

Reloj de velocidad en baudios de salida del contador divisor

Inserte la descripción de la imagen aquí

Contador de divisores habilita el control

Inserte la descripción de la imagen aquí

Encuentre la salida del valor de conteo a diferentes velocidades en baudios

Inserte la descripción de la imagen aquí

Código general:

//--------------------------------------------------------------------------------------------
//      Component name  : uart_Tx	
//      Author          : 硬件嘟嘟嘟
//      time            : 2020.04.21
//      Description     : 串口发送模块
//      src             : FPGA系统设计与验证实战指南_V1.2
//--------------------------------------------------------------------------------------------

module uart_tx(Clk,Rst_n,send_en,baud_set,data_byte,Rx232_Tx,Tx_Done,uart_state);

		input Clk,Rst_n;
		input send_en;  //发送使能信号输入
		
		input [2:0] baud_set;  //波特率选择输入
		input [7:0] data_byte; //待发送数据
		//
		output Rx232_Tx;    //发送数据输出端口
		output Tx_Done;     //一字节发送结束标志位
		output uart_state;   //发送数据状态
		

		
//数据输入寄存,输出格式及输出寄存模块

//8位有效数据寄存
reg [7:0] r_data_byte;
always@(posedge Clk,negedge Rst_n)
			if(!Rst_n)
					r_data_byte <= 8'b0;
			else if(send_en)
					r_data_byte <= data_byte;
			else
					r_data_byte <= r_data_byte;

//10选1多路器模块
reg [3:0] bps_cnt_q;
reg Rx232_Tx;
localparam START_BIT = 1'b0,
           STOP_BIT  = 1'b1;
always@(posedge Clk,negedge Rst_n) 
		if(!Rst_n)
			Rx232_Tx = 1'b1;
		else begin 
			case(bps_cnt_q)
				0 : Rx232_Tx <= 1'b1;
				1 : Rx232_Tx <= START_BIT;
				2 : Rx232_Tx <= r_data_byte[0];
				3 : Rx232_Tx <= r_data_byte[1];
				4 : Rx232_Tx <= r_data_byte[2];
				5 : Rx232_Tx <= r_data_byte[3];
				6 : Rx232_Tx <= r_data_byte[4];
				7 : Rx232_Tx <= r_data_byte[5];
				8 : Rx232_Tx <= r_data_byte[6];
				9 : Rx232_Tx <= r_data_byte[7];
				10 : Rx232_Tx <= STOP_BIT;
				default : Rx232_Tx = 1'b1;
			endcase
		end
		
		

//波特率时钟沿计数输出10选一多路器控制
//10选1多路器控制信号产生
reg bps_clk;
always@(posedge Clk,negedge Rst_n)
			if(!Rst_n)
					bps_cnt_q <= 4'd0;
			else if(bps_clk)
					bps_cnt_q <= bps_cnt_q + 1'b1;
			else if(bps_cnt_q == 4'd11)
					bps_cnt_q <= 4'd0;
			else 
					bps_cnt_q <= bps_cnt_q;

//发送数据完成标志位
reg Tx_Done;
always@(posedge Clk,negedge Rst_n)
		if(!Rst_n)
			Tx_Done <= 1'b0;
		else if(bps_cnt_q == 4'd11)
			Tx_Done <= 1'b0;
		else 
			Tx_Done <= 1'b1;

//分频计数器输出波特率时钟

//分频计数
reg [15:0] bps_DR;
reg [15:0] div_cnt;
reg uart_state ;//en_cnt信号由uart_cnt寄存器寄存
always@(posedge Clk,negedge Rst_n)
		if(!Rst_n)
				div_cnt <= 16'd0;
		else if(uart_state)begin
			if(div_cnt == bps_DR)
				div_cnt <= 16'd0;
		else 
				div_cnt <= div_cnt + 1'b1;
		end
		else
		div_cnt <= 16'd0;
//输出波特率时钟信号模块
always@(posedge Clk,negedge Rst_n)
		if(!Rst_n)
				bps_clk <= 1'b0;
		else if(div_cnt == 16'd1)
				bps_clk <= 1'b1;
		else 
				bps_clk <= 1'b0;

//分频计数器计数使能控制
always@(posedge Clk ,negedge Rst_n)
		if(!Rst_n)
				uart_state <= 1'b0;
		else if(send_en)
				uart_state <= 1'b1;
		else if(bps_cnt_q == 4'd11)
				uart_state <= 1'b0;
		else 
				uart_state <= uart_state;

//不同波特率查找计数值输出
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd5207;
else begin
			case (baud_set)
				0:bps_DR <= 16'd10416;
				1:bps_DR <= 16'd5207;
				2:bps_DR <= 16'd2603;
				3:bps_DR <= 16'd1301;
				4:bps_DR <= 16'd433;
				default : bps_DR <= 16'd5207;
			endcase
		end
endmodule

Supongo que te gusta

Origin blog.csdn.net/sinat_41653350/article/details/105663810
Recomendado
Clasificación