/**************************************************************************************************
** TLC549 AD转换器 verilog代码
** S1键启动ADC转换,S2键停止ADC转换
**************************************************************************************************/
module TLC549_ADC(
clk,
rst_n,
sw1_n,sw2_n,sw3_n,sw4_n,
adc_clk,
adc_data,
adc_cs_n,
digit_o,
cs
);
input clk; // 50MHz输入时钟
input rst_n; // 复位信号,低有效
input sw1_n,sw2_n,sw3_n,sw4_n; // 按键
input adc_data; // ADC芯片输出的数据
output adc_clk; // ADC芯片输入时钟
output adc_cs_n; // ADC芯片片选信号,低有效
output [7:0] digit_o; // 数码管输出
output [1:0] cs; // 数码管片选
//=================================================================================================
parameter // 字模
MSK_0 = 8'hC0, // '0'
MSK_1 = 8'hF9, // '1'
MSK_2 = 8'hA4, // '2'
MSK_3 = 8'hB0, // '3'
MSK_4 = 8'h99, // '4'
MSK_5 = 8'h92, // '5'
MSK_6 = 8'h82, // '6'
MSK_7 = 8'hF8, // '7'
MSK_8 = 8'h80, // '8'
MSK_9 = 8'h90, // '9'
MSK_A = 8'h88, // 'A'
MSK_B = 8'h83, // 'B'
MSK_C = 8'hC6, // 'C'
MSK_D = 8'hA1, // 'D'
MSK_E = 8'h86, // 'E'
MSK_F = 8'h8E; // 'F'
//=================================================================================================
/**************************************************************************************************
** 按键检测
**************************************************************************************************/
reg [3:0] key_rst; // 保存按键前一个状态
always @(posedge clk or negedge rst_n)
if (!rst_n)
key_rst <= 4'b1111;
else key_rst <= {sw4_n,sw3_n,sw2_n,sw1_n};
reg[3:0] key_rst_r; // 保存按键下一个状态
always @(posedge clk or negedge rst_n)
if (!rst_n)
key_rst_r <= 4'b1111;
else key_rst_r <= key_rst;
wire[3:0] key_val = key_rst_r & (~key_rst); // 检测是否有1到0跳变
reg[19:0] cnt; // 计数器
always @(posedge clk or negedge rst_n)
if (!rst_n)
cnt <= 20'd0;
else if (key_val) // 有按键按下(由1变为0)计数器开始计时 20ms
cnt <= 20'd0;
else
cnt <= cnt + 1'b1;
/*去抖动后的按键检测,仍然用两级寄存器*/
reg[3:0] low_sw;
always @(posedge clk or negedge rst_n)
if (!rst_n)
low_sw <= 4'b1111;
else if (cnt == 20'hfffff) // 20ms后的按键状态锁存到low_sw中
low_sw <= {sw4_n,sw3_n,sw2_n,sw1_n};
reg[3:0] low_sw_r;
always @(posedge clk or negedge rst_n)
if (!rst_n)
low_sw_r <= 4'b1111;
else
low_sw_r <= low_sw;
wire[3:0] led_ctrl = low_sw_r & (~low_sw);
reg start_adc;
always @(posedge clk or negedge rst_n)
if (!rst_n)
start_adc <= 1'b0;
else if (led_ctrl[0] == 1) // S1键按下
start_adc <= 1'b1; // 启动ADC
else if (led_ctrl[1] == 1 ) // S2键按下
start_adc <= 1'b0; // 停止ADC
/*************************************************************************************************/
/*************************************************************************************************/
reg [10:0] clk_cnt; // clk计数器
wire cs_n_valid1;
wire cs_high;
wire cs_n_valid2;
always @(posedge clk or negedge rst_n)
if (!rst_n)
clk_cnt <= 11'd0;
else if (start_adc)
clk_cnt <= clk_cnt + 1'b1;
/*
** 完成一次转换需要75+8*64+850+75+8*64=2024个时钟周期
** adc_cs_n建立时间为75个时钟周期1.5us 转换时间保持高电平17us,即850个时钟周期
** adc_clk周期为系统时钟的64倍
*/
assign cs_n_valid1 = (clk_cnt > 11'd74) && (clk_cnt <= 11'd587);
assign cs_high = (clk_cnt > 11'd587) && (clk_cnt <= 11'd1437);
assign cs_n_valid2 = (clk_cnt > 11'd1512) && (clk_cnt <= 11'd2024);
//=================================================================================================
reg rAdc_cs;
always @(posedge clk or negedge rst_n)
if (!rst_n)
rAdc_cs <= 1'b1;
else if (start_adc) begin
rAdc_cs <= 1'b0;
if (cs_high)
rAdc_cs <= 1'b1;
else
rAdc_cs <= 1'b0;
end
assign adc_cs_n = rAdc_cs;
//=================================================================================================
reg [5:0] div_cnt; // 64分频计数器
reg rAdc_clk;
always @(posedge clk or negedge rst_n)
if (!rst_n) begin
div_cnt <= 6'd0;
rAdc_clk <= 1'b0;
end
else if ((cs_n_valid1) || (cs_n_valid2)) begin
div_cnt <= div_cnt + 1'b1;
if (div_cnt < 32)
rAdc_clk <= 1'b1;
else
rAdc_clk <= 1'b0;
end
assign adc_clk = rAdc_clk;
//=================================================================================================
reg [7:0] rAdc_data;
always @(posedge clk or negedge rst_n)
if (!rst_n)
rAdc_data <= 8'd0;
else
case (clk_cnt)
11'd1513:rAdc_data[7] <= adc_data;
11'd1577:rAdc_data[6] <= adc_data;
11'd1641:rAdc_data[5] <= adc_data;
11'd1705:rAdc_data[4] <= adc_data;
11'd1769:rAdc_data[3] <= adc_data;
11'd1833:rAdc_data[2] <= adc_data;
11'd1897:rAdc_data[1] <= adc_data;
11'd1961:rAdc_data[0] <= adc_data;
default:rAdc_data[0] <= 1'b0;
endcase
/**************************************************************************************************
** 数码管显示
**************************************************************************************************/
reg [1:0] cs; // 片选信号
reg [16:0] cnt2; // 计数寄存器2,确定扫描间隔
reg [3:0] submsk; // 保存要显示的数据
always @(posedge clk or negedge rst_n)
if (!rst_n)
begin
cnt2 <= 17'd0; // 计数器2置零
cs <= 2'b01;
end
else begin
cnt2 <= cnt2 + 1'b1; // 计数器2开始计数
if (cnt2 == 17'd0) // 溢出了,又从0开始
begin
if (cs == 2'b01)
begin
cs <= 2'b10; // 选择第2个数码管
submsk <= rAdc_data[3:0]; // 显示低4位
end
else if (cs == 2'b10)
begin
cs <= 2'b01; // 选择第1个数码管
submsk <= rAdc_data[7:4]; // 显示高4位
end
end
end
reg [7:0] digit_o; // 数码管输出寄存器
always @(submsk)
case (submsk)
4'h0: digit_o <= MSK_0;
4'h1: digit_o <= MSK_1;
4'h2: digit_o <= MSK_2;
4'h3: digit_o <= MSK_3;
4'h4: digit_o <= MSK_4;
4'h5: digit_o <= MSK_5;
4'h6: digit_o <= MSK_6;
4'h7: digit_o <= MSK_7;
4'h8: digit_o <= MSK_8;
4'h9: digit_o <= MSK_9;
4'hA: digit_o <= MSK_A;
4'hB: digit_o <= MSK_B;
4'hC: digit_o <= MSK_C;
4'hD: digit_o <= MSK_D;
4'hE: digit_o <= MSK_E;
4'hF: digit_o <= MSK_F;
default: digit_o <= MSK_0;
endcase
endmodule
用户1861976 2015-12-1 22:20