Tabla de contenido
8. Módulo de control de botones
Enlace de descarga de este archivo de proyecto de diseño (incluidas las notas): https://download.csdn.net/download/qq_33231534/12450178
Los dos primeros artículos desarrollaron los módulos básicos del sistema de adquisición de datos, a continuación se presentarán los módulos de control para la interconexión y comunicación de estos módulos básicos, incluyendo el módulo de control de botones y el módulo de control FIFO.
8. Módulo de control de botones
La función principal del módulo de control de botones es: cuando se presiona el botón, controla los tiempos de transición de conversión analógica a digital del ADC.
La lista de puertos de señal de este módulo es la siguiente:
Nombre de la señal | E / S | Dígitos | Función descriptiva |
clk | yo | 1 | Reloj del sistema 50MHz |
rst_n | yo | 1 | Reinicio de sistema |
key_flag | yo | 1 | Botón de señal válida |
tran_num | yo | 7 | Conversiones |
adc_done | yo | 1 | Bandera de conversión completa de ADC one |
adc_en | EL | 1 | Bandera de habilitación de conversión de ADC |
El código del módulo es: key_ctrl.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name: key_ctrl.v
//Last modified Date: 2020/5/23
//Last Version:
//Descriptions: 按键控制模块:按键按下,控制ADC转换tran_num次
//-------------------------------------------------------------------
module key_ctrl(
input clk , //系统时钟50MHz
input rst_n , //系统复位
input key_flag , //按键有效信号
input [ 6: 0] tran_num , //转换次数
input adc_done , //ADC一次转换完成标志
output reg adc_en //ADC转换使能标志
);
reg [ 6: 0] cnt ; //计数器,计数ADC转换次数
reg add_flag ; //计数器加1标志
wire add_cnt ; //加一条件
wire end_cnt ; //结束条件
//按键按下,add_flag为1,开始计数
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
add_flag <= 0;
end
else if(key_flag) begin
add_flag <= 1;
end
else if(end_cnt)begin
add_flag <= 0;
end
end
//计数器,ADC使能一次,计数器加1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
end
assign add_cnt = add_flag==1 && adc_en;
assign end_cnt = add_cnt && cnt== tran_num-1;
//adc_en输出控制
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
adc_en <= 0;
end
else if(key_flag || (add_flag && adc_done)) begin
adc_en <= 1;
end
else begin
adc_en <= 0;
end
end
endmodule
Debido a que esta parte es relativamente simple, no se proporciona ningún diagrama de forma de onda de simulación.
Nueve, módulo de control FIFO
La función del módulo de control FIFO es: cuando se completa la conversión ADC, los datos se almacenan en el FIFO y, al mismo tiempo, cuando los datos se envían al puerto serie, los datos se leen del FIFO y los datos de 12 bits se dividen en dos de 8 bits y se envían al puerto serie.
La lista de puertos de señal de este módulo es la siguiente:
Nombre de la señal | E / S | Dígitos | Función descriptiva |
clk | yo | 1 | Reloj del sistema 50MHz |
rst_n | yo | 1 | Reinicio de sistema |
vacío | yo | 1 | señal nula de datos de FIFo |
tx_done | yo | 1 | Bandera de transmisión de datos en serie completa |
q | yo | 12 | Lectura de datos de FIFO |
adc_done | yo | 1 | Conversión ADC completada una vez marcada |
adc_data_out | yo | 12 | Datos de 12 bits convertidos por ADC |
rdreq | EL | 1 | Fifo read enable |
send_en | EL | 1 | Habilitación de envío de puerto serie |
data_byte | EL | 8 | Salida de datos enviados |
wrreq | EL | 1 | Habilitación de escritura FIFO, establecida en 1 después de que se completa la conversión de ADC |
data_to_fifo | EL | 12 | Los datos convertidos por ADC se almacenan en FIFO |
El código del módulo de control FIFO es: fifo_ctrl.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name: fifo_ctrl.v
//Last modified Date: 2020/5/23
//Last Version:
//Descriptions: FIFO控制模块:当ADC转换完成后,将数据存入FIFO,
// 同时在往串口发送数据时控制从FIFO读取数据并将12位
// 数据分成两次8位发送到串口
//-------------------------------------------------------------------
module fifo_ctrl(
input clk , //系统时钟50MHz
input rst_n , //系统复位
input empty , //fifo数据空信号
input tx_done , //串口数据发送完成标志
input [ 11: 0] q , //从fifo读出的数据
input adc_done , //ADC转换完成一次标志
input [ 11: 0] adc_data_out, //ADC转换完成的12位数据
output reg rdreq , //fifo读使能
output reg send_en , //串口发送使能
output reg [7:0] data_byte , //输出发送的数据
output reg wrreq , //FIFO写使能,在ADC转换结束后置1
output reg [11:0] data_to_fifo //ADC转换完成的数据存入FIFO
);
parameter IDLE = 3'b000 ; //空闲状态
parameter DATA_R = 3'b001 ; //当fifo数据不为空时,读取fifo数据
parameter DATA_S = 3'b010 ; //将fifo的12位数据发送出去
parameter SEND_1 = 3'b011 ; //发送前4位数据
parameter SEND_2 = 3'b100 ; //发送后8位数据
reg [ 2: 0] state_c ; //状态改变
reg [ 2: 0] state_n ; //现在状态
//状态机
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//状态改变条件
always @(*)begin
case(state_c)
IDLE:begin
if(empty==0)
state_n = DATA_R;
else
state_n = state_c;
end
DATA_R:state_n = DATA_S;
DATA_S:state_n = SEND_1;
SEND_1:begin
if(tx_done)
state_n = SEND_2;
else
state_n = state_c;
end
SEND_2:begin
if(tx_done)
state_n = IDLE;
else
state_n = state_c;
end
endcase
end
//各个状态下rdreq和send_en输出的结果
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rdreq <= 0;
send_en <= 0;
end
else begin
case(state_c)
IDLE: begin
if(empty==0)
rdreq <= 1;
else
rdreq <= 0;
end
DATA_R:begin rdreq <= 0; end
DATA_S:begin send_en <= 1; data_byte <= {4'd0,q[11:8]}; end
SEND_1:begin
send_en <= 0;
if(tx_done)begin
send_en <= 1;
data_byte <= q[7:0];
end
end
SEND_2:begin send_en <= 0; end
endcase
end
end
//ADC转换完成后将数据存入FIFO
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
data_to_fifo <= 0;
end
else if(adc_done) begin
data_to_fifo <= adc_data_out;
end
end
//ADC转换完成写使能打开
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
wrreq <= 0;
end
else if(adc_done) begin
wrreq <= 1;
end
else begin
wrreq <= 0;
end
end
endmodule
La prueba de simulación es la siguiente:
10. Módulo de control DAC
La función del módulo de control DAC es: al recibir el comando especificado por el puerto serie, comienza a convertir los datos sinusoidales de la ROM al DAC.
La lista de puertos de señal de este módulo es la siguiente:
Nombre de la señal | E / S | Dígitos | Función descriptiva |
clk | yo | 1 | Reloj del sistema 50MHz |
rst_n | yo | 1 | Reinicio de sistema |
data_rx | yo | 8 | Comando recibido del puerto serie |
rx_done | yo | 1 | Indicador de finalización de recepción de datos del puerto serie de 1 byte |
dac_done | yo | 1 | Indicador de conversión completa de DAC |
addr | EL | 12 | Línea de dirección ROM |
dac_en | EL | 1 | Indicador de habilitación de conversión DAC |
El código del módulo de control DAC es: dac_ctrl.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name: dac_ctrl.v
//Last modified Date: 2020/5/23
//Last Version:
//Descriptions: DAC控制模块:当接收串口指定的指令时,
// 开始将ROM的正弦数据进行DAC转换
//-------------------------------------------------------------------
module dac_ctrl(
input clk ,//系统时钟50MHz
input rst_n ,//系统复位
input [ 7: 0] data_rx ,//从串口接收到的指令
input rx_done ,//1字节串口数据接收完成标志
input dac_done ,//DAC转换完成标志
output reg [11:0] addr ,//ROM的地址线
output reg dac_en //DAC转换使能标志
);
//控制地址线自加1
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
addr <= 0;
end
else if(dac_en) begin
addr <= addr + 1'b1;
end
end
//DAC转换使能标志
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
dac_en <= 0;
end
else if(rx_done || dac_done) begin
dac_en <= 1;
end
else begin
dac_en <= 0;
end
end
endmodule
Este módulo es relativamente simple y no depura la simulación.
11. Integración del sistema
Después de completar la prueba de diseño y simulación de todos los módulos, integre los módulos de todo el sistema, cree un nuevo archivo de barra de nivel superior y cree una instancia y conecte cada módulo.
El código es el siguiente: data_collection_top.v
//-------------------------------------------------------------------
//https://blog.csdn.net/qq_33231534 PHF的CSDN
//File name:
//Last modified Date:
//Last Version:
//Descriptions:
//-------------------------------------------------------------------
module data_collection_top(
input clk ,//系统时钟50MHz
input rst_n ,//系统复位
input rs232_tx ,//串口向FPGA发送数据
input adc_data_din,//adc数据输出到FPGA
input key_in ,//按键输入
output wire dac_din ,//dac串行数据接口控制和数据输出
output wire dac_sclk ,//dac串行数据接口时钟信号
output wire dac_cs ,//dac串行数据接口使能信号
output wire adc_din ,//ADC控制信号,通道控制选取
output wire adc_sclk ,//ADC串行数据接口时钟信号
output wire adc_cs ,//ADC串行数据接口使能信号
output wire rs232_rx //串口接收FPGA数据
);
wire [ 7: 0] data_rx ;
wire rx_done ;
wire dac_en ;
wire [ 11: 0] addr ;
wire dac_done ;
wire [ 11: 0] data_rom ;
wire empty ;
wire adc_en ;
wire key_flag ;
wire adc_done ;
wire tx_done ;
wire rdreq ;
wire send_en ;
wire [ 7: 0] data_byte ;
wire wrreq ;
wire [ 11: 0] data_to_fifo ;
wire [ 11: 0] adc_data_out ;
wire [ 11: 0] fifo_data_out;
//串口接收模块
UART_Byte_Rx u_UART_Byte_Rx(
.clk (clk) ,
.rst_n (rst_n) ,
.rs232_tx (rs232_tx) ,
.baud_set (3'd1) ,
.data_byte (data_rx) ,
.rx_done (rx_done)
);
//DAC控制模块
dac_ctrl u_dac_ctrl(
.clk (clk) ,
.rst_n (rst_n) ,
.data_rx (data_rx) ,
.rx_done (rx_done) ,
.dac_done (dac_done) ,
.addr (addr) ,
.dac_en (dac_en)
);
//ROM模块
single_port_rom
#(.DATA_WIDTH(12), .ADDR_WIDTH(12))
u_single_port_rom(
.addr (addr) ,
.clk (clk) ,
.q (data_rom)
);
//DAC驱动模块
dac_driver1 u_dac_driver(
.clk (clk) ,
.rst_n (rst_n) ,
.dac_data_in({4'b1100,data_rom}),
.dac_en (dac_en) ,
.din (dac_din) ,
.dac_sclk (dac_sclk) ,
.cs (dac_cs) ,
.dac_down (dac_done) ,
.dac_state ()
);
//ADC驱动模块
adc_driver u_adc_driver(
.clk (clk) ,//系统时钟50MHz
.rst_n (rst_n) ,//复位
.channel (3'd0) ,//通道选择
.adc_en (adc_en) ,//使能单次转换,该信号为周期有效高脉冲使能一次转换
.dout (adc_data_din) ,//ADC转换结果,由ADC输给FPGA
.din (adc_din) ,//ADC控制信号,通道控制选择
.adc_sclk (adc_sclk) ,//ADC串行数据接口时钟信号
.cs (adc_cs) ,//ADC串行数据接口使能信号
.data_out (adc_data_out) ,//ADC转换结果
.adc_done (adc_done) ,//转换完成信号,完成后输出一个周期高脉冲
.adc_state () //ADC工作状态:0为空闲状态,1为转换状态
);
//按键控制模块
key_ctrl u_key_ctrl(
.clk (clk) ,
.rst_n (rst_n) ,
.key_flag (key_flag) , //按键信号
.tran_num (7'd100) , //转换次数
.adc_done (adc_done) ,
.adc_en (adc_en)
);
//按键消抖模块
key_filter u_key_filter(
.clk (clk) ,
.rst_n (rst_n) ,
.key_in (key_in) ,
.key_flag (key_flag) ,
.key_state ()
);
//FIFO控制模块
fifo_ctrl u_fifo_ctrl(
.clk (clk) , //系统时钟50MHz
.rst_n (rst_n) , //系统复位
.empty (empty) , //fifo数据空信号
.tx_done (tx_done) , //串口数据发送完成标志
.q (fifo_data_out) , //从fifo读出的数据
.adc_done (adc_done) ,
.adc_data_out(adc_data_out),
.rdreq (rdreq) , //fifo读使能
.send_en (send_en) , //串口发送使能
.data_byte (data_byte) , //输出发送的数据
.wrreq (wrreq) ,
.data_to_fifo(data_to_fifo)
);
//同步FIFO模块
sync_fifo
#(.WIDTH (12) , //缓存的数据宽度
.DEPTH (100) , //缓存的数据深度
.MAX_DEPTH_BIT(7)) //可设置的最大深度位数7,即最大深度为2^7-1
u_sync_fifo
(
.clk (clk) , //系统时钟
.rst_n (rst_n) , //系统复位
.wrreq (wrreq) , //写使能
.data (data_to_fifo) , //写数据
.rdreq (rdreq) , //读使能
.q (fifo_data_out) , //读数据
.empty (empty) , //空信号
.full () , //满信号
.half () , //半满信号
.usedw () //fifo中剩余数据个数
);
//串口发送模块
Uart_Byte_Tx u_Uart_Byte_Tx(
.clk (clk) ,
.rst_n (rst_n) ,
.send_en (send_en) ,
.data_byte (data_byte) ,
.baud_set (3'd1) ,
.rs232_tx (rs232_rx) ,
.tx_done (tx_done) ,
.uart_state()
);
endmodule
Después del análisis y la síntesis en el software quartus prime17.1, las asignaciones de pines se realizan de acuerdo con la conexión del circuito, como se muestra en la figura:
Después de la compilación completa, descargue el archivo sof en la placa y conecte el puerto de salida A del DAC al puerto de 1 canal del ADC con una línea DuPont para completar la conexión del circuito. Luego abra el asistente del puerto serie, use hexadecimal para enviar y recibir la pantalla, primero envíe el comando para controlar la conversión DA al puerto serie (aquí establecido en ff), para que el DAC convierta y emita la señal sinusoidal analógica de acuerdo con la señal sinusoidal en la ROM. Luego presione el botón nuevamente para controlar la conversión ADC 100 veces, y envíela al puerto serial para mostrarla en la PC.
El diagrama de relajación y recepción de su puerto serie es el siguiente:
Entre ellos, cada 16 bits de datos representa un resultado de conversión de ADC, por ejemplo, los primeros datos 06 1C, los primeros cuatro bits son todos 0. Esto se establece para la conveniencia del puerto serie que envía datos, el resultado de muestreo de ADC real es 0x61C.
La vista RTL general es la siguiente: