【问题标题】:How to implement 8-bit DAC (Digital to Analog conversion) with Arduino - atmega 2560 microcontroller?如何使用 Arduino - atmega 2560 微控制器实现 8 位 DAC(数模转换)?
【发布时间】:2015-05-15 16:00:25
【问题描述】:

我正在开发一个记录器和播放器项目。我想同时实现 ADC(模数)和 DAC(数模)转换器。代码应在 Arduino - Atmega 2560(Atmel 微控制器)中实现。我尝试实现 ADC,发现以下代码:

void setup() 
{
    Serial.begin (9600);
    ADCSRA |= ((1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));
    ADMUX |=(1<<REFS0);
    ADCSRA |= (1<<ADEN);
    ADCSRA |= (1<<ADSC);
}

int read_adc( int channel )
{
    ADMUX &=0xE0;
    ADMUX |= channel & 0x07l;
    ADCSRB = channel & (1<<ADSC);
    ADCSRA |= (1<<ADSC);
    while (ADCSRA & (1<<ADSC))
    {
        return ADCW;
    }
}

void loop() 
{
    int w = read_adc(0);
    Serial.write(w);
}

在这里,我将数字化信号发送到串行端口。我有两个问题: 1-如何修改此代码以用作 8 位 ADC? 2-如何以与以前相同的方式实现DAC?我的意思是如何从串口读取数字信号,然后将其转换为模拟信号,如上面的算法?

感谢您的帮助。

【问题讨论】:

  • Arduino Mega 2560 没有任何 DAC 外设。您将需要一些额外的硬件来实现它。而且和ADC完全没有关系。
  • 你能指定哪个版本的Arduino有DAC外设吗?
  • 我不确定有没有。但是您可以轻松找到带有某种 I2C DAC 的 Arduino 兼容分线板。
  • 您还没有“实现 ADC”,您只是利用了芯片上的 ADC 硬件,您不能真正将这段代码描述为“算法”——它只是硬件初始化和 I/O .
  • 我很确定 read_adc() 中的 return 应该在循环之外 - 当代码按常规缩进时很容易发现错误。

标签: c arduino embedded atmega atmel


【解决方案1】:

ATMega2560 没有 DAC 外设,但是如果您的带宽要求相对较低,您可以使用带有适当外部模拟滤波的 PWM 输出来产生可变输出电压(与脉冲宽度成正比)。

PWM 频率越高,带宽越高,但分辨率越低,因此需要权衡取舍。一个简单的低通 RC 滤波器就足够了。在某些情况下 - 例如 LED 或直流电机驱动,您根本不需要任何滤波,而 PWM 在任何情况下都是驱动此类负载的更有效方法。然而,对于音频应用程序,您通常需要过滤,除非直接驱动 Class D ampifier

要实现 8 位 DAC,您需要将 PWM 配置为每周期 256 个计数,然后只需将脉冲宽度设置为从零到 255 个计数。当充分过滤时,这将产生模拟电压。为使滤波尽可能简单,PWM 频率应尽可能高,滤波器截止频率至少设置为该频率的一半,最好低于 f/5 或更高。这将决定您的音频带宽。对于语音,3Khz 就足够了(电话质量); 4.5KHz 是 AM 广播质量,而 15KHz 是 FM 广播/HiFi 质量。

有许多关于将 PWM 用作 DAC 和必要的滤波的在线资源;例如http://ltwiki.org/images/8/82/PWM_Filters.pdf

【讨论】:

  • 很少有板载 DAC 的 MCU 的原因是因为 PWM 方式,如本答案所述,通常就足够了,而且总是更具成本效益。如果你需要一个实际的 DAC 芯片,你可能正在做一些相当先进的信号处理,无论如何你都不会使用 8 位 MCU/Arduino。
【解决方案2】:

如果您的电路板没有 DAC,那么您可以使用额外的 DAC IC 并将其与 GPIO 端口连接。我在一个项目中完成了这项工作,我使用 CortexM0 微控制器的 GPIO 和 DAC 为直流电机生成模拟输出。根据您的应用类型,您可能还需要一个运算放大器来放大 DAC 输出。

【讨论】:

    【解决方案3】:

    市场上有许多使用 SPI 总线输入工作的 DAC 设备,分辨率从 8 位到 16 位(以及更高)不等。我已经查看了所有替代方案,恕我直言,价格和分辨率之间的最佳折衷方案是 MCP4xxx 系列。

    Adafruit 有一个MCP4921 分线板,可随时提供 12 位单通道。 I've chosen to use the MCP4822 提供 12 位双通道分辨率。 MCP48xx 系列还具有内部电压基准,可确保在面对可变电源电压时保持稳定的输出电压。这不如使用外部 Vref 的 MCP49xx 系列灵活。

    由于 AVR (Arduino) 电源上的数字噪声通常超过 20mV,因此使用超过 12 位分辨率 (1mv LSB) 似乎无法获得更高的精度。此外,16 位 DAC 的成本明显高于 MCP4xxx 系列。

    如果您需要支持 DC 的输出,则使用运算放大器来缓冲 DAC 是有意义的。或者,如果您只需要交流电(音频),那么有可用的 cheap headphone amplifiers 可以很好地作为缓冲区。

    如果您需要使用 AVR SPI 总线作为数据源(例如 uSD 卡)并且源速度很慢,那么您可以use a USART port on the ATmega2560 in MSPI Mode 使用中断驱动 DAC 而不会干扰主 SPI 接口。

    这是在 ATmega1284p 平台上实现的模拟接口的快照,我碰巧有它。

    DAC.h code 可以在 sourceforge 的AVRfreeRTOS 中找到。

    【讨论】:

      猜你喜欢
      • 2014-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多