FPGA学习之数模转换(TLC5620)(通过4个按键输入,输出数模转换需要的数据和数码管显示需要的数据)

​1.数模转换器即DAC,一般情况下由四个部分组成,权电阻网络,运算放大器,基准电源和模拟开关。是一种以二进制显示的数字量转换成以参考电压为基准的模拟量转换器。

2.设计原理:

TLC5620是一个拥有4路输出的数模转换器,时钟频率最高可以达到1MHZ,在本实例中它可以将输入的数字量转换为实际的模拟量(电压),并通过4个按键控制4路输出电压,每按一次,电压随之上升,同时数码管上依次显示相应的值:A1,A0,RNG,以及输入的数字量,采用开发板的基准电压2.5v。

芯片端口图:

点击此处添加图片说明文字

实际的电压公式是:V = REF*(CODE/256)*(1+RNG)

REF为基准电压,CODE为输入的8位数据,RNG为输入范围

3.key_test模块:按键控制通道选择

module key_test(
    input clk,
    input rst_n,
    input [3:0] key,  //4个按键组合信号
    
    output  [10:0] wr_data,     //输出一帧数据
    output  [19:0] out_data    //输出数码管的显示数据
);

reg [30:0] cnt;     //计数器分频
reg clk_r;   //分频时钟:在消抖的时钟频率下进行按键检测

reg [7:0] data;   //按键输入的数据
reg [1:0] channel;   //通道选择
reg [7:0] key1,key2,key3,key4;   //4个按键

always @(posedge clk or negedge rst_n)  //按键消抖,每0.2s进行一次检测
begin
    if(!rst_n)
        begin
            cnt <= 0;
            clk_r <= 0;
        end
    else if(cnt < 30'd1000_0000) //系统时钟5M,要0.2检测一次,就用50000000/(1/0.2)
        cnt <= cnt + 1;
    else
        begin
            cnt <= 0;
            clk_r <= ~clk_r;
        end
end


always @(posedge clk_r or negedge rst_n)  //按键低电平有效,当检测到相应的按键按下时,
                                               //相应数值加一,并显示相应的通道
begin
    if(!rst_n)
        begin
            data <= 0;
            channel <= 0;
            key1 <= 0;
            key2 <= 0;
            key3 <= 0;
            key4 <= 0;
        end 
    else
        case(key)
            4'b1110:begin     //按键1:选择通道A,输入数字量加一
                        channel <= 2'b00;
                        key1 <= key1 + 1'b1;
                        data <= key1;
                    end
            4'b1101:begin     //选择通道B,输入数字量加一
                        channel <= 2'b01;
                        key2 <= key2 + 1'b1;
                        data <= key2;
                    end
            4'b1011:begin     //选择通道C,输入数字量加一
                        channel <= 2'b10;
                        key3 <= key3 + 1'b1;
                        data <= key3;
                    end
            4'b0111:begin     //选择通道D,输入数字量加一
                        channel <= 2'b11;
                        key4 <= key4 + 1'b1;
                        data <= key4;
                    end  
            default : ; 
        endcase
end
//用赋值语句将需要的数据组合起来,在此例中RNG默认为1
assign wr_data = {channel,1'b1,data};
assign out_data = {3'b000,channel[1],3'b000,channel[0],4'h1,data};
endmodule

4.TLC_DA模块:数模转换芯片的驱动程序

点击此处添加图片说明文字

点击此处添加图片说明文字

module TLC_DA(
    input clk,
    input rst_n,
    input [10:0] data_in,  //输入一帧数据
    
    output da_data,   //串行数据接口
    output da_clk,    //串行时钟接口
    output reg da_ladc,   //更新控制信号
    output reg da_load    //串行加载控制接口
);

reg [30:0] cnt;  
wire da_clk_r;    //TLC5620内部的时钟信号
//计时器时钟分频:根据芯片内部的时序要求进行分频
always @(posedge clk or negedge rst_n)   //频率不大于1MHZ
begin
    if(!rst_n)
        cnt <= 6'd0;
    else
        cnt <= cnt + 1'b1;
end

assign da_clk_r = cnt[5];

//接受时序的序列机
reg [2:0] state;
reg [3:0] cnt_da;
reg da_data_r;
reg da_data_en;   //限定da_data和da_clk的有效区域
always @(posedge da_clk_r or negedge rst_n)
begin
    if(!rst_n)
        begin
            state <= 0;
            cnt_da <= 0;
            da_data_r <= 1'b1;
            da_data_en <= 0;
            da_load <= 1;
            da_ladc <= 0;
        end
    else
        case(state)
            0:state <= 1;
            1:begin
                da_data_en <= 1;
                da_load <= 1;
                if(cnt_da <= 10)
                    begin
                        cnt_da <= cnt_da + 1'b1;
                        case(cnt_da)
                            0:da_data_r <= data_in[10];
                            1:da_data_r <= data_in[9];
                            2:da_data_r <= data_in[8];
                            3:da_data_r <= data_in[7];
                            4:da_data_r <= data_in[6];
                            5:da_data_r <= data_in[5];
                            6:da_data_r <= data_in[4];
                            7:da_data_r <= data_in[3];
                            8:da_data_r <= data_in[2];
                            9:da_data_r <= data_in[1];
                            10:da_data_r <= data_in[0];
                        endcase
                        state <= 1;
                    end
                else
                    begin
                        cnt_da <= 0;
                        state <= 2;
                        da_data_en <= 0;
                    end
              end
            2:begin
                da_load <= 0;
                state <= 3;
              end
            3:begin
                da_load <= 1;
                state <= 0;
              end            
            default : state <= 0;
        endcase
end
assign da_data = (da_data_en) ? da_data_r:1'b1;
assign da_clk = (da_data_en) ? da_clk_r:1'b0;
endmodule

5.seg_sum模块:数码管显示

处添加图片说明文字

点击此处添加图片说明文字

module seg_sum(
    input clk,
    input rst_n,
    input [19:0] data_in,          //20位输入数据
    
    output reg [7:0] seg,
    output reg [2:0] sel
);

reg [3:0] num;    //数码管的位数
always@(*)
case(sel)
    4:num = data_in[3:0];       //第5个数码管显示数据的低四位
    3:num = data_in[7:4]; 
    2:num = data_in[11:8]; 
    1:num = data_in[15:12]; 
    0:num = data_in[19:16]; 
    default:;
endcase

always @(*)
case(num)
    0:seg <= 8'hC0;
    1:seg <= 8'hF9;
    2:seg <= 8'hA4;
    3:seg <= 8'hB0;
    4:seg <= 8'h99;
    5:seg <= 8'h92;
    6:seg <= 8'h82;
    7:seg <= 8'hF8;
    0:seg <= 8'h80;
    0:seg <= 8'h90;
    default:seg <= 8'hFF;
endcase
//计数器分频:用cnt在第10位的变化作为分频时钟
reg [23:0] cnt;
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt <= 4'b0;
    else
        cnt <= cnt + 1'b1;

 //在分频时钟下,数码管的0~4位依次循环
always @(posedge cnt[10] or negedge rst_n) //分频时钟为2的10次方除以50M
    if(!rst_n)
        sel <= 0;
    else if(sel < 4)
        sel <= sel + 1'b1;
    else
        sel <= 0;
endmodule

6.顶层文件:

module top(
    input clk,
    input rst_n,
    input [3:0] key,
    
    output da_data,   //串行数据接口
    output da_clk,    //串行时钟接口
    output da_ladc,   //更新控制信号
    output da_load,    //串行加载控制接口
    output  [7:0] seg,
    output  [2:0] sel
);

//内部信号
wire [10:0] wr_data;     //输出一帧数据
wire [19:0] out_data;    //输出数码管的显示数据

//实例化
TLC_DA TLC_DA(
    .clk(clk),
    .rst_n(rst_n),
    .da_data(da_data),
    .da_clk(da_clk),
    .da_ladc(da_ladc),
    .da_load(da_load),
    .data_in(wr_data)
);

key_test key_test(
    .clk(clk),
    .rst_n(rst_n),
    .key(key),
    .out_data(out_data),
    .wr_data(wr_data)
);

seg_sum seg_sum(
    .clk(clk),
    .rst_n(rst_n),
  
    .data_in(out_data),
    
    .sel(sel),
    .seg(seg)
);
endmodule

7.仿真测试文件

点击此处添加图片说明文字

`timescale 1 ns/ 1 ps
module TLC_DA_tb();
parameter T = 20;
/********************系统输入**********************/
reg clk;
reg rst_n;                                           
reg   [3:0] key;
/*********************系统输出*****************/
wire   da_data;
wire  da_clk;
wire da_ladc;
wire da_load;

                    

initial 
begin                                                  
    clk = 1'b0;
	rst_n = 1'b0;  
    key = 4'b1111;
	#1000.1 rst_n = 1'b1;
    #100 key = 4'b1110;
    
    $stop;  	                 
end                                                                                                 
always #(T/2)  clk = ~clk;      
TLC_DA TLC_DA(
    .clk(clk),
    .rst_n(rst_n),
    .da_data(da_data),
    .da_clk(da_clk),
    .da_ladc(da_ladc),
    .da_load(da_load),
    .data_in(wr_data)
);

key_test key_test(
    .clk(clk),
    .rst_n(rst_n),
    .key(key),
    .out_data(out_data),
    .wr_data(wr_data)
);

seg_sum seg_sum(
    .clk(clk),
    .rst_n(rst_n),
  
    .data_in(out_data),
    
    .sel(sel),
    .seg(seg)
);               
endmodule

8.RTL图

点击此处添加图片说明文字

工程文件上传至qq群:868412045

  • 6
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
单片机数模转换程序 将da#include //52系列单片机头文件 #include #define uchar unsigned char #define uint unsigned int sbit dula=P2^6; //申明U1锁存器的锁存端 sbit wela=P2^7; //申明U2锁存器的锁存端 sbit adwr=P3^6; //定义AD的WR端口 sbit adrd=P3^7; //定义AD的RD端口 sbit led=P2^5; sbit DAC0832_CS = P3^2; sbit DAC0832_WR = P3^6; sbit AD_CS=P0^7; uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71}; uchar weima[] = {0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; void delayms(uint xms) { uint i,j; for(i=xms;i>0;i--) //i=xms即延时约xms毫秒 for(j=110;j>0;j--); } void display(uchar bai,uchar shi,uchar ge) //显示子函数 { dula=1; P0=table[bai]|0x80; //送段选数据 dula=0; P0=0xff; //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0x7e; //送位选数据 wela=0; delayms(1); //延时 dula=1; P0=table[shi]; dula=0; P0=0xff; wela=1; P0=0x7d; wela=0; delayms(1); dula=1; P0=table[ge]; dula=0; P0=0xff; wela=1; P0=0x7b; wela=0; delayms(1); } /*void displays(uchar a ,uchar b,uchar c) //显示子函数 { dula=1; P0=table[a]; //送段选数据 dula=0; P0=0xff; //送位选数据前关闭所有显示,防止打开位选锁存时 wela=1; //原来段选数据通过位选锁存器造成混乱 P0=0x77; //送位选数据 wela=0; delayms(1); //延时 dula=1; P0=table[b]; dula=0; P0=0xff; wela=1; P0=0x6f; wela=0; delayms(1); dula=1; P0=table[c]; dula=0; P0=0xff; wela=1; P0=0x5f; wela=0; delayms(1); } */ void displays(uchar shuzi,uchar weizhi,bit dp) { dula=1; if(dp) P0 = table[shuzi]|0x80; else P0 = table[shuzi]; dula=0; wela=1; P0 = weima[weizhi]; wela=0; } void main() // 主程序 { uint ad; uchar A1,A2,A3,adval; AD_CS=1; //置CSAD为0,选通ADCS 以后不必再管ADCS DAC0832_CS = 0; DAC0832_WR = 0; while(1) { wela=1; P0=0x7f; wela=0; adwr=1; _nop_(); adwr=0; //启动AD转换 _nop_(); adwr=1; P1=0xff; //读取P1口之前先给其写全1 adrd=1; //选通ADCS _nop_(); adrd=0; //AD读使能 _nop_(); adval=P1; ad=adval*1.941; //AD数据读取赋给P1口 adrd=1; A1=ad/100; //分出百,十,和个位 A2=ad0/10; A3=ad; P1=(~adval); P0=adval; displays(adval/100,4,0); delayms(1); displays(adval0/10,5,0); delayms(1); displays(adval,6,0); delayms(1); display(A1,A2,A3); } } ad的数据相互转换

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值