2019年全国大学生电子设计大学(D 题)简易电路特性测试仪(2)基础部分电路与代码

先看基础部分第一问,首先经过测试,我的共射放大电路的放大倍数是280左右(分立元件每个人都不一样),选择放大倍数越小的三极管越好做(1)中有作解释。

基础部分硬件

输入电阻

DDS输出的正弦波幅值为1.1v,经过分压后,串联一个电阻,根据公式计算即可得出。电路图如下:

        上面那一路是分压十分之一,底下是百分之一,先说上面的作用,可以看到,上面是DDS接跟随后,经过隔直,再经过跟随后串联电阻,因为题目要求做的是输入电阻1K-50K,范围跨度比较大,所以在输入电阻比较大时串联大电阻,比较小时串联小电阻。

因为在实际过程中,AD对波形峰值判断不准(我也不懂为什么,我的学长也是同样的情况),加了算法以后效果不是特别理想,所以采用AD637峰值检波模块,这里介绍一下AD637,也算是记录一下这个芯片性能,以免忘掉。

AD637 是一款完整的高精度、单芯片均方根直流转换器,可计算任何复杂波形的真均方根值。它提供集成电路均方根直流转换器前所未有的性能,精度、带宽和动态范围与分立和模块式设计相当。AD637 提供波峰因数补偿方案,允许以最高为 10 的波峰因数测量信号,额外误差小于 1%。宽带宽允许测量 200 mV 均方根、频率最高达 600 kHz 的输入信号以及 1V 均方根以上、频率最高达 8 MHz 的输入信号。

中文资料网上都有,这里就不啰嗦了

原理图

当±5V供电时,输入有效值电压范围:0 ~ 3 V,当±15V供电时,输入有效值电压范围:0 ~ 6 V

所以直接将检出来的值接给AD,误差非常小并且非常稳定。

输出电阻与输入电阻非常类似,就不再详细展开说明了。

放大倍数

放大倍数是输入放大电路的Ui和带载的Uo,不可以直接拿DDS输出或者分压的输出算,必须是进入放大电路的Ui,直接用32AD两个通道采集峰值检波的值就一除就可以了。

幅频特性曲线

幅频特性曲线(1)中说过,要保证DDS在变频时,幅值变化不大,不然需要重新采集输入,会消耗时间,题目是有时间规定的,超时扣分。

(1)中提到过,可以用示波器或者扫频仪先测量出0.707倍时对应的频率,方便代码编写DDS输出频率

经测量我手头9850在100HZ-20M幅值都是1.1V,故不需要采集输入,因为输入端固定不变。测量后上下限频率分别是260HZ到十几MHZ,用DDS变一次频率就算一次放大倍数,最后将其显示在stm32lcd屏幕上。

需要注意的是:

一在放大倍数有变化的端可以多采集一些点,在中间放大倍数很固定的点可以少采集一点,这样曲线就会很平滑,不会像一次函数一样非常直。

二电阻分压噪声还是有些大,用运放会好一点。

基础部分硬件到这里就结束了,基础分是很好拿的,几乎没有难度很流畅。

代码

 #include “adc.h”
 #include “delay.h”
 #include “stdio.h”
 #include “math.h”
 #include “lcd.h”
 #include “led.h”
 #include “ad9850.h”
u8    Res_select=0;       
u32    large_Res=20000;
u32    little_Res=3000;    

u32    ui1=55;   //DDS_OUT直接用万用表测量解写入代码(单位:mv)
//DDS输出1.1v  经过分压后值是可知的不需要用ad或者峰值检波测量
//但为了误差小数据精确  用台式万用表测量写入代码

//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3                                                                       
void  Adc1_Init(void)
{     
    ADC_InitTypeDef ADC_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1    , ENABLE );      //使能ADC1通道时钟
 

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

    //PA1 作为模拟通道输入引脚                         
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模拟输入引脚
    GPIO_Init(GPIOC, &GPIO_InitStructure);    
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //模拟输入引脚
    GPIO_Init(GPIOA, &GPIO_InitStructure);    

    ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;    //ADC工作模式:ADC1和ADC2工作在独立模式
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;    //模数转换工作在单通道模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;    //模数转换工作在单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;    //转换由软件而不是外部触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;    //ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 3;    //顺序进行规则转换的ADC通道的数目
    ADC_Init(ADC1, &ADC_InitStructure);    //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

    //设置指定ADC的规则组通道,一个序列,采样时间
    //ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5 );    //ADC1,ADC通道,采样时间为239.5周期     
    //ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_239Cycles5 );    //ADC1,ADC通道,采样时间为239.5周期     
    //ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_239Cycles5 );    //ADC1,ADC通道,采样时间为239.5周期     

    ADC_Cmd(ADC1, ENABLE);    //使能指定的ADC1
    
    ADC_ResetCalibration(ADC1);    //使能复位校准  
     
    while(ADC_GetResetCalibrationStatus(ADC1));    //等待复位校准结束
    
    ADC_StartCalibration(ADC1);     //开启AD校准
 
    while(ADC_GetCalibrationStatus(ADC1));     //等待校准结束
    
    
    
//    ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //使能指定的ADC1的软件转换启动功能

}                  
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc1(u8 ch)   
{
//      //设置指定ADC的规则组通道,一个序列,采样时间
    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );    //ADC1,ADC通道,采样时间为239.5周期                      
  
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //使能指定的ADC1的软件转换启动功能    
     
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average1(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t<times;t++)
    {
        temp_val+=Get_Adc1(ch);
        delay_ms(5);
    }
    return temp_val/times;
}      


/*
//可以采用此函数计算波形峰值   但ad采不准    故我采用的方案为峰值检波
//用ad直接采集峰值检波口的波形幅值比较精确
#define N 50
u16 filter(u8 ch,u8 times)  
{
    char count,i,j;
    u32 Value_buf[N];
    u32 temp;
    u32 sum=0;
    for(count=0;count<N;count++)
        Value_buf[count]= 0;
    for(count=0;count<N;count++)
        Value_buf[count]= Get_Adc1(ch);
    for(j=0;j<(N-1);j++)
        for(i=0;i<(N-j);i++)
            if(Value_buf[i]>Value_buf[i+1])
            {
                 temp = Value_buf[i];
                 Value_buf[i]= Value_buf[i+1];
                  Value_buf[i+1]=temp;
            }
            for(count =1;count<N-1;count++)
                sum += Value_buf[count];
            return (u16)(sum/(N-2));
}


void    adc_ch_data(u8 Channel)
{
    u32    adcx[128];
    u16 i;
    for(i=0;i<128;i++)
    {
        adcx[i] = Get_Adc_Average1(Channel,10);     // 检测通道1的电压
        printf(“%d\r\n”,adcx[i]);
    }
}
*/

void    get_resin(void)
{
    float    res_in=0;
    float    adc_ch10=0;
    

    
    float    adc_ch10_v=0;
    jidianqi7=0;
    delay_ms(200);
    adc_ch10 = Get_Adc_Average1(ADC_Channel_10,10);       //采集通道1 的adc数值
    

    
    
    //Y1=0.6715X-1.2403
    //adc_ch10_v=((((adc_ch10+1.2403)/0.6715)*2)/80);
    adc_ch10_v=((((adc_ch10+1.2403)/0.6715)*2)/110);    
            //将其转换为电压
    //将其反算回去以后乘2的目的是使用峰峰值
    //除100的目的是   因为这个值比较小 实际测量中只有4mv
    //所以我在4mv输出后加了一级放大倍数为80倍的同相比例放大
    //故要在代码中除100     若不加放大则不需要除这100
    //不加放大测量结果正确    但是因为幅值比较小 采集不稳定  值跳变的厉害  但有正确的结果
    
    
    delay_ms(200);
    
    if(Res_select==1)
    {

        res_in=(adc_ch10_v*large_Res)/(ui1-adc_ch10_v);
    //输入电阻计算公式:     (Ui2*R)/(Ui1-Ui2)
        
    }
    else
    {
        res_in=(adc_ch10_v*little_Res)/(ui1-adc_ch10_v);    
    }

    printf(“%f\r\n”,res_in);
    //res_in=res_in/1000;
    LCD_ShowxNum(100,0, res_in,5,24,0);//显示ADC的值
    LCD_ShowxNum(100,120, adc_ch10_v,5,24,0);//显示ADC的值
    //printf(“%f\r\n”,res_in);
}


void    get_resout(void)
{    
    
    float    res_out=0;
    float    adc_ch11=0;
    float    adc_ch11_1=0;
    float    adc_ch11_v1=0;
    float    adc_ch11_v2=0;
    jidianqi6=1;      //空载
    //Y1=0.6715X-1.2403
    adc_ch11 = Get_Adc_Average1(ADC_Channel_12,10);       //采集通道11 的adc数值
    //adc_ch11_v1=(((adc_ch11+1.2403)/0.6715)*2)+1.1;    //将其转换为电压
    
    //adc_ch11_v1=adc_ch11*3.3/4096;
    
    //jidianqi闭合  低电平
    jidianqi6=0;        //带载
    LCD_ShowxNum(100,150, adc_ch11_v1,5,24,0);//显示ADC的值
    
    delay_ms(500);
    adc_ch11_1 = Get_Adc_Average1(ADC_Channel_12,10);       //采集通道11 的adc数值
    //adc_ch11_v2=adc_ch11_1*3.3/4096;
    
    //adc_ch11_v2=(((adc_ch11_1+1.2403)/0.6715)*2);
    //输出电阻测量        Ro=(Uo1-Uo2)*R/Uo2    R:带载阻值    
    
    LCD_ShowxNum(100,180, adc_ch11_v2,5,24,0);//显示ADC的值
    
    //res_out=((adc_ch11_v1-adc_ch11_v2)*2000)/adc_ch11_v2;
    res_out=((adc_ch11-adc_ch11_1)*2000)/adc_ch11_1;
    //res_out=((adc_ch11-adc_ch11_1)*2000)/adc_ch11_1;
    
    delay_ms(2);
    //res_out=res_out/1000;
    //printf(“%f\r\n”,res_out);
    LCD_ShowxNum(100,30, res_out,5,24,0);//显示ADC的值

}

void     get_Au(void)//增益
{
    
    u16    Au=0;
    float    Uo=0;//经过放大电路以后并未通过继电器的波形峰值
    //输出的波形峰值需要将直流量减掉    再进行峰值检波
    float    Ui_v=0;
    float    Uo_v=0;
    float    Ui=0;//输入放大电路的波形峰值
    Ui= Get_Adc_Average1(ADC_Channel_10,10);
    Ui_v=((((Ui+1.2403)/0.6715)*2)/100);    
    delay_ms(200);
    Uo= Get_Adc_Average1(ADC_Channel_12,10);
    
    Uo_v=(((Uo+0.12)*4)-6.35)*2;
    //Uo_v=(((Uo+1.2403)/0.6715)*2);    
    delay_ms(10);
    Au=Uo_v/Ui_v;
    //printf(“%d\r\n”,Au);
    LCD_ShowxNum(100,60, Au,5,24,0);//显示ADC的值
    
}

输入电阻、输出电阻、放大倍数都封装成了函数,在主函数中直接调就可以了。

幅频特性曲线坐标显示:

void zuobiao(void)
{
        POINT_COLOR = RED;
        LCD_Display_Dir(0);
        LCD_ShowString(30,0,210,24,24,”Ri =        “); 
        LCD_ShowString(30,30,210,24,24,”R0 =       “);
//        LCD_ShowString(30,60,210,24,24,”fL = “);                           
//        LCD_ShowString(30,90,210,24,24,”fH = “);
        LCD_ShowString(30,60,210,24,24,”Au = “);
        LCD_DrawLine(0,305,240,305);        
        LCD_DrawLine(15,140,15,320);  //x轴y轴
    
        LCD_DrawLine(240,305,230,315);   
        LCD_DrawLine(240,305,230,295); //箭头
    
        LCD_DrawLine(15,140,5,150);    
        LCD_DrawLine(15,140,25,150);   //箭头
     
        LCD_DrawLine(40,305,40,300);
        LCD_DrawLine(65,305,65,300);
        LCD_DrawLine(90,305,90,300);
        LCD_DrawLine(115,305,115,300);    
        LCD_DrawLine(140,305,140,300);    
        LCD_DrawLine(165,305,165,300);    
        LCD_DrawLine(195,305,195,300);
        
        LCD_DrawLine(15,275,20,275);
        LCD_DrawLine(15,245,20,245);
        LCD_DrawLine(15,215,20,215);
        LCD_DrawLine(15,185,20,185);    

        
        LCD_ShowString(220,307,200,12,12,”Hz”); 
        LCD_ShowString(20,307,200,12,12,”100″);
        LCD_ShowString(40,307,200,12,12,”200″);
        LCD_ShowString(60,307,200,12,12,”1K”);
        LCD_ShowString(80,307,200,12,12,”1.5K”);
        LCD_ShowString(100,307,200,12,12,”10K”);
        LCD_ShowString(120,307,200,12,12,”50K”);
        LCD_ShowString(140,307,200,12,12,”100K”);
        LCD_ShowString(160,307,200,12,12,”150K”);
        LCD_ShowString(180,307,200,12,12,”170K”);
        LCD_ShowString(2,270,200,12,12,”80″);
        LCD_ShowString(2,240,200,12,12,”10O”);
        LCD_ShowString(2,210,200,12,12,”12O”);
        LCD_ShowString(2,180,200,12,12,”14O”);
        LCD_ShowString(7,307,200,12,12,”O”);         
        LCD_Display_Dir(1);
        LCD_ShowString(145,0,200,12,12,”Gain”); 
        LCD_Display_Dir(0);
}

幅频特性曲线的显示:

//因为我手头的AD9850在变频率的时候不会变幅值
//9854在变频率的时候会改变幅值
//测量幅频特性曲线的时候 需要测量增益 若是DDS输出不变则不需要每次变频率采输入幅值
//同理若是变频率扫频时 幅值会变 则每变一次频率就应该采集一次输入 代码工作量比较大
//幅频特性曲线显示
float    signal[11]={100,200,500,1000,10000,50000,100000,150000,170000};//DDS输出频率
void boxin(void)    
{
    u32    Ui1=55;   //DDS_OUT直接用万用表测量解写入代码(单位:mv)
//DDS输出1.1v  经过分压后值是可知的不需要用ad或者峰值检波测量
//但为了误差小数据精确  用台式万用表测量写入代码
    u8 Au[9]={0,0,0,0,0,0,0,0,0};
    u8 i;
   
    float    adc_ch11_1=0;
    float    adc_ch11_v2=0;
    for(i=0;i<11;i++)
    {
        ad9850_wr_serial(0x00,(double)signal[i]);//DDS输出信号
        adc_ch11_1 = Get_Adc_Average1(ADC_Channel_12,10);       //采集通道11 的adc数值
        adc_ch11_v2=(((adc_ch11_1+1.2403)/0.6715)*2)+1.1;            //将其转换为电压
        Au[i]=adc_ch11_v2/Ui1;
    }      
//    for(i=0;i<8;i++)
//    {
//         au[i]=Au[i];
//    }
//    au[5]=au[4]-30;
//    au[6]=au[4]-60;
//    au[7]=au[4]-100;
       
        LCD_DrawPoint(20,305-Au[0]/20*30);
        LCD_DrawPoint(40,305-Au[1]/20*30);
        LCD_DrawPoint(60,305-Au[2]/20*30);
        LCD_DrawPoint(80,305-Au[3]/20*30);    
        LCD_DrawPoint(100,305-Au[4]/20*30);    
        LCD_DrawPoint(120,305-Au[5]/20*30);    
        LCD_DrawPoint(140,305-Au[6]/20*30);
        LCD_DrawPoint(160,305-Au[7]/20*30);    
        LCD_DrawPoint(180,305-Au[8]/20*30);

    LCD_DrawLine(20,305-Au[0]/20*30,40,305-Au[1]/20*30);
    LCD_DrawLine(40,305-Au[1]/20*30,60,305-Au[2]/20*30);
    LCD_DrawLine(60,305-Au[2]/20*30,80,305-Au[3]/20*30);
    LCD_DrawLine(80,305-Au[3]/20*30,100,305-Au[4]/20*30);
    LCD_DrawLine(100,305-Au[4]/20*30,120,305-Au[5]/20*30);
    LCD_DrawLine(120,305-Au[5]/20*30,140,305-Au[6]/20*30);
    LCD_DrawLine(140,305-Au[6]/20*30,160,305-Au[7]/20*30);
    LCD_DrawLine(160,305-Au[7]/20*30,180,305-Au[8]/20*30);   
//    LCD_DrawLine(65,305-Au[1]*t,70,305-Au[1]*t+k2*5-4);
//    LCD_DrawLine(70,305-Au[1]*t+k2*5-4,75,305-Au[1]*t+k2*10-5);
//    LCD_DrawLine(75,305-Au[1]*t-5+k2*10,80,305-Au[1]*t+k2*15-4);
//    LCD_DrawLine(80,305-Au[1]*t-4+k2*15,85,305-Au[1]*t+k2*20-3);
//    LCD_DrawLine(85,305-Au[1]*t-3+k2*20,90,305-Au[2]*t);
 
//    LCD_DrawLine(40,305-Au[0]*t,65,305-Au[1]*t);
//    LCD_DrawLine(65,305-Au[1]*t,90,305-Au[2]*t);
//    LCD_DrawLine(90,305-Au[2]*t,115,305-Au[3]*t);
//    LCD_DrawLine(115,305-Au[3]*t,140,305-Au[4]*t);
//    LCD_DrawLine(140,305-Au[4]*t,148,305-Au[5]*t);
//    LCD_DrawLine(148,305-Au[5]*t,156,305-Au[6]*t);
//    LCD_DrawLine(156,305-Au[6]*t,165,305-Au[7]*t);
//    LCD_DrawLine(165,305-Au[7]*t,195,305-Au[8]*t);
}
上面就是基础部分的全部了,都是已经测试完毕了的,没有问题。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2023年8月16日
下一篇 2023年8月16日

相关推荐