原创 ADC芯片TLC549的Verilog代码

2013-9-17 09:18 1365 5 6 分类: FPGA/CPLD

 

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

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户1861976 2015-12-1 22:20

采样时钟是多少啊?
相关推荐阅读
用户443437 2015-04-17 08:57
(多图)结合FPGA与DSP的仿人假手控制系统设计
仿人假手作为肢残患者重获人手功能的主要对象,具有重大的社会需求。理想的假手应具有人手的仿生特征,主要体现在假手构造、控制方式与环境感知3 个方面,但由于其有限的体积和复杂的传感器系统,对控制系统提出了...
用户443437 2014-05-10 14:37
熬了几个通宵,答辩终于搞掂
当答辩的评分老师问我:你有FPGA开发板了,外设也是买的,你还需要做什么硬件部分?其实那时我真的想问一下:老师,你其实懂不懂FPGA设计的?外设是谁来驱动的?它不同于ARM,可以用软件来驱动,做一...
用户443437 2014-04-25 09:52
[博客大赛]我也开始玩起Qsys
好久没有发博客了,前一段时间是毕业前的阵痛期,十分的纠结,关于FPGA的东西都不想理了,可以说是力不从心吧,实现就是这样,社会不急切需求这方面的人才,我该何去何从?恋上简单,爱上很难,且行且珍惜。...
用户443437 2014-04-10 17:23
[博客大赛]关于SD卡的读取问题
  最近一直在调试SD卡的读取数据,用串口调试助手来对比数据的正确,但是一直都读不出数据来,代码是特权同学的SD控制模块,我只是做了一些定制,用串口来调试,代码是没有问题的,纠结了我很久...
用户443437 2014-03-21 09:27
口头承诺真的成为了空谈
这几天终于把该忙的工作的搞掂了,接下来的时间都属于我自己的,可以安心去规划一下自己的未来发展方向了,之前一份做彩屏接口研发的工作是最适合我,本人也是对图像的处理感兴趣,第一份工作找的就是自己喜欢的...
用户443437 2014-03-15 11:06
【我要崛起】第五章 器件时序图的分析,状态机最重要。(1)(更新)
这一章出得有点慢,终于挤到时间出来好好地写,在总结之前要说明一点的是,这一章我分三个小节来叙说,第一小节是从基础的器件开始,咱们的字符型LCD1602的datasheet分析;到第二节的TFT-L...
EE直播间
更多
我要评论
1
5
关闭 站长推荐上一条 /3 下一条