如果我的单片机的基准电压为3.3V,而外部的模拟量输入为0—5V我要对这个模拟量直接用单片机的内部AD进行采

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如果我的单片机的基准电压为3.3V,而外部的模拟量输入为0—5V我要对这个模拟量直接用单片机的内部AD进行采相关的知识,希望对你有一定的参考价值。

如果我的单片机的基准电压为3.3V,而外部的模拟量输入为0—5V我要对这个模拟量直接用单片机的内部AD进行采样,该怎么办,串电阻吗

具体要看单片机AD的测量电压范围。比如说,有的AD基准电压为2.5V,但是,输入电压可以是两倍或4倍的基准。
你说的基准电压,应该是单片机的工作电压,一般AD不采用3.3V基准。
如果外部信号超过了AD测量范围,可以采用电阻分压的方法,但是要注意阻抗匹配。
最好是输入阻抗较高,而输出阻抗较低。
如果信号源的输出阻抗较大,一般采用电压跟随器之后接电阻分压的方法。如果AD的输入阻抗较低,那么分压器之后还需要在加一级电压跟随器。
参考技术A 既然你的单片机基准电压是3.3V了,那就没办法,输入的模拟量不能大于3.3V,用电阻分压小于3.3V后输入,如果有条件的就使用电压跟随器来隔离保证准确性。

“有的AD基准电压为2.5V,但是,输入电压可以是两倍或4倍的基准。”这只有独立的ADC芯片才是这样,比如ADS774。但单片机内部的ADC,其基准电压可来自于其内部基准源、工作电压或者外接参考电压,比如Atmega8单片机的ADC就是这样,可以用自带的2.56V、或者AREF引脚的外接参考电压或者来自VCC的单片机工作电压。像STM32单片机工作电压是3.3V,高端的STM32可以外接参考电压,低端的STM32就直接用的VCC,就是其ADC的参考电压直接连接到3.3V的,无法再设置参考电压的。
参考技术B 一般使用电压跟随器,最简单的办法是使用电阻限流

给你推荐一下,网上早一下这些资料: 单片机宝典从硬件到软件 chm
电子电路公式计算器 chm
参考技术C 电阻分压

FPGA的学习:简易电压表的设计与验证

外部挂载的高速 AD/DA 板卡的 A/D 部分将输入其中的模拟信号转换为数字量,将数字量传入 FPGA, FPGA 将传入的数字量通过计数转化为电压数值,通过数码管显示转化后的电压值,实现模拟信号的电压测量。

整体框图如图所示。
在这里插入图片描述
其中adc模块。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

`timescale  1ns/1ns
module  adc
(
    input   wire            sys_clk         ,   //时钟
    input   wire            sys_rst_n       ,   //复位信号,低电平有效
    input   wire    [7:0]   ad_data         ,   //AD输入数据

    output  wire            ad_clk          ,   //AD驱动时钟,最大支持20Mhz时钟
    output  wire            sign            ,   //正负符号位
    output  wire    [15:0]  volt                //数据转换后的电压值
);
//parameter define
parameter   CNT_DATA_MAX = 11'd1024;    //数据累加次数

//wire  define
wire    [27:0]  data_p      ;   //根据中值计算出的正向电压AD分辨率
wire    [27:0]  data_n      ;   //根据中值计算出的负向电压AD分辨率

//reg define
reg             median_en   ;   //中值使能
reg     [10:0]  cnt_median  ;   //中值数据累加计数器
reg     [18:0]  data_sum_m  ;   //1024次中值数据累加总和
reg     [7:0]   data_median ;   //中值数据
reg     [1:0]   cnt_sys_clk ;   //时钟分频计数器
reg             clk_sample  ;   //采样数据时钟
reg     [27:0]  volt_reg    ;   //电压值寄存
//数据ad_data是在ad_sys_clk的上升沿更新
//所以在ad_sys_clk的下降沿采集数据是数据稳定的时刻
//FPGA内部一般使用上升沿锁存数据,所以时钟取反
//这样ad_sys_clk的下降沿相当于sample_sys_clk的上升沿
assign  ad_clk = ~clk_sample;

//sign:正负符号位
assign  sign = (ad_data < data_median) ? 1'b1 : 1'b0;

//时钟分频(4分频,时钟频率为12.5Mhz),产生采样AD数据时钟
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            cnt_sys_clk <=  2'd0;
            clk_sample  <=  1'b0;
        end
        else
        begin
            cnt_sys_clk <=  cnt_sys_clk + 2'd1;
        if(cnt_sys_clk == 2'd1)
            begin
            cnt_sys_clk <=  2'd0;
            clk_sample  <=  ~clk_sample;
            end
        end

//中值使能信号
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        median_en   <=  1'b0;
    else    if(cnt_median == CNT_DATA_MAX)
        median_en   <=  1'b1;
    else
        median_en   <=  median_en;

//cnt_median:中值数据累加计数器
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_median    <=  11'd0;
    else    if(median_en == 1'b0)
        cnt_median    <=  cnt_median + 1'b1;

//data_sum_m:1024次中值数据累加总和
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_sum_m  <=  19'd0;
    else    if(cnt_median == CNT_DATA_MAX)
        data_sum_m    <=  19'd0;
    else
        data_sum_m    <=  data_sum_m + ad_data;

//data_median:中值数据
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_median    <=  8'd0;
    else    if(cnt_median == CNT_DATA_MAX)
        data_median    <=  data_sum_m / CNT_DATA_MAX;
    else
        data_median    <=  data_median;

//data_p:根据中值计算出的正向电压AD分辨率(放大2^13*1000倍)
//data_n:根据中值计算出的负向电压AD分辨率(放大2^13*1000倍)
assign  data_p = (median_en == 1'b1) ? 8192_0000 / ((255 - data_median) * 2) : 0;
assign  data_n = (median_en == 1'b1) ? 8192_0000 / ((data_median + 1) * 2) : 0;

//volt_reg:处理后的稳定数据
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        volt_reg    <= 'd0;
    else    if(median_en == 1'b1)
        if((ad_data > (data_median - 3))&&(ad_data < (data_median + 3)))
            volt_reg    <= 'd0;
        else    if(ad_data < data_median)
            volt_reg <= (data_n *(data_median - ad_data)) >> 13;
        else    if(ad_data > data_median)
            volt_reg <= (data_p *(ad_data - data_median)) >> 13;
    else
        volt_reg    <= 'd0;

//volt:数据转换后的电压值
assign  volt    =   volt_reg;

endmodule

顶层模块的设计:
在这里插入图片描述

`timescale  1ns/1ns
module  dig_volt
(
    input   wire            sys_clk     ,   //系统时钟,50MHz
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   ad_data     ,   //AD输入数据

    output  wire            ad_clk      ,   //AD驱动时钟,最大支持20Mhz时钟
    output  wire            stcp        ,   //数据存储器时钟
    output  wire            shcp        ,   //移位寄存器时钟
    output  wire            ds          ,   //串行数据输入
    output  wire            oe              //使能信号
);
//wire  define
wire    [15:0]  volt    ;   //数据转换后的电压值
wire            sign    ;   //正负符号位
//------------- adc_inst -------------
adc     adc_inst
(
    .sys_clk    (sys_clk    ),  //时钟
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低电平有效
    .ad_data    (ad_data    ),  //AD输入数据

    .ad_clk     (ad_clk     ),  //AD驱动时钟,最大支持20Mhz时钟
    .sign       (sign       ),  //正负符号位
    .volt       (volt       )   //数据转换后的电压值
);

//------------- seg_595_dynamic_inst --------------
seg_595_dynamic     seg_595_dynamic_inst
(
    .sys_clk    (sys_clk    ),  //系统时钟,频率50MHz
    .sys_rst_n  (sys_rst_n  ),  //复位信号,低有效
    .data       ({4'b0,volt}),  //数码管要显示的值
    .point      (6'b001000  ),  //小数点显示,高电平有效
    .seg_en     (1'b1       ),  //数码管使能信号,高电平有效
    .sign       (sign       ),  //符号位,高电平显示负号

    .stcp       (stcp       ),  //输出数据存储寄时钟
    .shcp       (shcp       ),  //移位寄存器的时钟输入
    .ds         (ds         ),  //串行数据输入
    .oe         (oe         )   //输出使能信号
);

endmodule

其中要将seg_595的文件添加到工程。
然后全编译,得到RTL视图。
在这里插入图片描述
最后进行仿真。

`timescale  1ns/1ns
module  tb_dig_volt();
//wire  define
wire            ad_clk  ;
wire            shcp    ;
wire            stcp    ;
wire            ds      ;
wire            oe      ;

//reg   define
reg             sys_clk     ;
reg             clk_sample  ;
reg             sys_rst_n   ;
reg             data_en     ;
reg     [7:0]   ad_data_reg ;
reg     [7:0]   ad_data     ;

//sys_rst_n,sys_clk,ad_data
initial
    begin
        sys_clk     =   1'b1;
        clk_sample  =   1'b1;
        sys_rst_n   =   1'b0;
        #200;
        sys_rst_n   =   1'b1;
        data_en     =   1'b0;
        #499990;
        data_en     =   1'b1; 
    end

always #10 sys_clk = ~sys_clk;
always #40 clk_sample = ~clk_sample;

always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        ad_data_reg <=  8'd0;
    else    if(data_en == 1'b1)
        ad_data_reg <=  ad_data_reg + 1'b1;
    else
        ad_data_reg <=  8'd0;

always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        ad_data <=  8'd0;
    else    if(data_en == 1'b0)
        ad_data <=  8'd125;
    else    if(data_en == 1'b1)
        ad_data <=  ad_data_reg;
    else
        ad_data <=  ad_data;

//------------- dig_volt_inst -------------
dig_volt    dig_volt_inst
(
    .sys_clk     (sys_clk   ),
    .sys_rst_n   (sys_rst_n ),
    .ad_data     (ad_data   ),

    .ad_clk      (ad_clk    ),
    .shcp        (shcp      ),
    .stcp        (stcp      ),
    .ds          (ds        ),
    .oe          (oe        )
);

endmodule

以上是关于如果我的单片机的基准电压为3.3V,而外部的模拟量输入为0—5V我要对这个模拟量直接用单片机的内部AD进行采的主要内容,如果未能解决你的问题,请参考以下文章

AD转化的基准电压的作用是啥?

单片机如何检测自身电压?或者基准电压?请看下面详细说明,求高手帮忙,分都不是问题!!

stm32的ADC功能。读取的是模拟量么?转化为数字量输出?

5V带AD转换单片机的基准电压是不是能超过5V 也就是说5V单片机是不是能测量超过5V的电压?求赐教

STM32单片机的最小系统板的供电电压是多少

单片机AD采集回来的数值如何能显示为对应的电压值?