电子大神的日记本,供应链专家的功夫茶盘,在这里记录、分享与共鸣。

登录以开始

ADC芯片TLC549的Verilog代码

 

/**************************************************************************************************
** 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

博主
1069217225@qq.com
只要你想,你可以做所有事情
To be a top of FPGA designer
点击跳转