DA是数字信号转换为模拟信号的模块,应用的话,最近在准备电赛,可以通过主控芯片给的数字信号来模拟出信号源(后面博文会讲)(但是不推荐使用,因为信号的噪声太多,经过运放后基本不可以使用。。。准备比赛的话还是选高精度是DA/DA吧)
DA 百度百科
DA这里用的是iic协议,在之前的博文中也讲过iic协议的一些编写方法,下面就直接贴代码,我的测试是用开发板的da进行呼吸灯的显示,比较简单,不多说了,代码如下:
da驱动代码(可以共用,需要作改动)
moduledac_drive(dac_data,rst_n,clk,scl,sda,dac_en ); inputclk ;//输入时钟信号分频后inputrst_n ;//复位信号input [7:0]dac_data;//DAC输出数据inputdac_en ;//使能信号outputregscl ;//IIC的SCLinoutsda ;//IIC的SDAparameterI2C_ILDE=4'D0, //起始状态 I2C_START=4'D1, //起始信号 I2C_DAC_ADDR=4'D2, //器件地址 I2C_DAC_ACK1=4'D3, //应答信号 I2C_DAC_CTRL_MS=4'D4, //控制信号+4位数据 I2C_DAC_ACK2=4'D5, //应答信号 I2C_DAC_LS_NONE=4'D6, //4位数据+无用信号 I2C_DAC_ACK3=4'D7, //应答信号 I2C_STOP=4'D9; //停止信号parameterDEVICE_ADDR=8'b1001_1000; //器件地址wire [7:0]dac_mdata={4'b0000,dac_data[7:4]};wire [7:0]dac_ldata={dac_data[3:0],4'b0000};parameterI2C_FREQ=250, //时钟频率SEND_BIT=8; //发送数据位数reg [7:0]cnt; //scl计数寄存器reg [2:0]byte_cnt; //数据位寄存器reg [3:0]state_c,state_n;//状态寄存器regsdar; //sda输出寄存器regsdalink; //sda方向控制器0-input1-outputassignscl_hc=(cnt==(I2C_FREQ>>2)); assignscl_lc=(cnt==(I2C_FREQ>>2)*3); //iic时钟信号产生逻辑always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=1'b0;endelseif(cnt==I2C_FREQ-1'b1)begincnt<=1'b0;endelsebegincnt<=cnt+1'b1;endendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginscl<=1'b0;endelseif(cnt>=1'b0 &&cnt <= (I2C_FREQ>>1)-1'b1)beginscl<=1'b1;endelsebeginscl<=1'b0;endend//iic状态机控制信号always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginstate_c<=I2C_ILDE; endelsebeginstate_c<=state_n; endendalways@(*)beginstate_n<=state_c; case(state_c) I2C_ILDE: if(dac_en==1'b1)beginstate_n<=I2C_START; endI2C_START: if(scl_hc==1'b1)beginstate_n<=I2C_DAC_ADDR; endI2C_DAC_ADDR: if(scl_lc==1'b1&&byte_cnt==3'd0)beginstate_n<=I2C_DAC_ACK1; endI2C_DAC_ACK1: if(scl_lc==1'b1)beginstate_n<=I2C_DAC_CTRL_MS; endI2C_DAC_CTRL_MS: if(scl_lc==1'b1&&byte_cnt==3'd0)beginstate_n<=I2C_DAC_ACK2; endI2C_DAC_ACK2: if(scl_lc==1'b1)beginstate_n<=I2C_DAC_LS_NONE; endI2C_DAC_LS_NONE: if(scl_lc==1'b1&&(byte_cnt==3'd0))beginstate_n<=I2C_DAC_ACK3; endI2C_DAC_ACK3: if(scl_lc==1'b1)beginstate_n<=I2C_STOP; endI2C_STOP: if(scl_hc==1'b1)beginstate_n<=I2C_ILDE; enddefault:state_n<=I2C_ILDE; endcaseend//数据位寄存器控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginbyte_cnt<=3'd0;endelsebegincase(state_c) I2C_DAC_ADDR,I2C_DAC_CTRL_MS,I2C_DAC_LS_NONE: if(scl_lc==1'b1)beginbyte_cnt<=byte_cnt-1'b1;enddefault: byte_cnt<=3'd7;endcaseendend//数据输入输出控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsdar<=1'b1;sdalink<=1'b1;endelsebegincase(state_c) I2C_ILDE: beginsdar<=1'b1;sdalink<=1'b1;endI2C_START: beginif(scl_hc==1'b1)beginsdar<=1'b0;sdalink<=1'b1;endendI2C_DAC_ADDR: beginif(scl_lc==1'b1)beginsdar<=DEVICE_ADDR[byte_cnt]; sdalink<=1'b1;endendI2C_DAC_CTRL_MS: beginif(scl_lc==1'b1)beginsdar<=dac_mdata[byte_cnt]; sdalink<=1'b1;endendI2C_DAC_LS_NONE: beginif(scl_lc==1'b1)beginsdar<=dac_ldata[byte_cnt]; sdalink<=1'b1;endendI2C_DAC_ACK1,I2C_DAC_ACK2: beginif(scl_lc==1'b1)beginsdar<=1'b0;sdalink<=1'b0;endendI2C_DAC_ACK3: beginif(scl_lc==1'b1)beginsdar<=1'b0;sdalink<=1'b1;endendI2C_STOP: beginif(scl_hc==1'b1)beginsdar<=1'b1;sdalink<=1'b1;endenddefault: ; endcaseendendassignsda=sdalink?sdar:1'bz;endmodule
测试模块:
moduledac_controller(clk,rst_n,en,dac_data ); inputclk; inputrst_n; outputen; outputreg[7:0]dac_data; reg [17:0] cnt; //10ms计数器always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=18'd0;endelseif(cnt<18'd249_999)begincnt<=cnt+1'b1;endelsebegincnt<=1'b0;endendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begindac_data<=1'b0;endelseif(cnt==18'd249_999)begindac_data<=dac_data+1'b1;endendassignen=1'b1; endmodule
顶层模块连接:
moduletop(clk,rst_n,iic_sck,iic_sda ); inputclk; inputrst_n; outputiic_sck; inoutiic_sda; wire [7:0]dac_data; dac_driveuut_dac_drive( .dac_data(dac_data), .rst_n(rst_n), .clk(clk), .scl(iic_sck), .sda(iic_sda), .dac_en(dac_en) ); dac_controlleruut_dac_controller( .clk(clk), .rst_n(rst_n), .en(dac_en), .dac_data(dac_data) ); endmodule
下板子后就可以在自己的对应的da模块上显示呼吸灯的效果了。
(后面讲简单的波形发生器,还有DDS的可调信号发生器)