AVR 328pb ADC基本介绍和使用

AVR 328pb ADC基本介绍和使用


  • 结合参考同架构lgt8f328p中文文档:http://www.prodesign.com.cn/wp-content/uploads/2023/03/LGT8FX8P_databook_v1.0.4.pdf

328pb ADC特性

• 10-bit Resolution 10位分辨率
• 0.5 LSB Integral Non-linearity 0.5 LSB积分非线性
• ± 2 LSB Absolute Accuracy ±2 LSB绝对精度
• 13 - 260 μs Conversion Time 13-260μs转换时间
• Up to 76.9 kSPS (Up to 15 kSPS at Maximum Resolution) 高达76.9 kSPS(最大分辨率高达15 kSPS)
• 6 Multiplexed Single Ended Input Channels 6个多路复用单端输入通道
• 2 Additional Multiplexed Single Ended Input Channels (TQFP and QFN/MLF Package only) 2个额外的多路复用单端输入通道(仅限TQFP和QFN/MLF封装)
• Temperature Sensor Input Channel 温度传感器输入通道
• Optional Left Adjustment for ADC Result Readout ADC结果读数的可选左调整
• 0 - VCC ADC Input Voltage Range ADC结果读出的可选左调整0 - VCC
• Selectable 1.1V ADC Reference Voltage 可选1.1V ADC参考电压
• Free Running or Single Conversion Mode 自由运行或单次转换模式
• Interrupt on ADC Conversion Complete ADC转换完成时中断
• Sleep Mode Noise Canceler 睡眠模式降噪器

  • 中断向量表:
    AVR 328pb ADC基本介绍和使用_第1张图片

  • ADC模数转换器块原理图
    AVR 328pb ADC基本介绍和使用_第2张图片

  • ADC自动触发逻辑
    AVR 328pb ADC基本介绍和使用_第3张图片

  • ADC转换和分频
    AVR 328pb ADC基本介绍和使用_第4张图片
    默认情况下,逐次近似电路需要一个输入频率在50 kHz和200 kHz之间的时钟频率,以获得最大分辨率。如果需要低于10位的分辨率,则对ADC的输入时钟频率可以高于200 kHz,以获得更高的采样率。

  • ADC时序图,第一次转换(单次转换模式)
    AVR 328pb ADC基本介绍和使用_第5张图片

  • ADC定时图,自动触发转换

AVR 328pb ADC基本介绍和使用_第6张图片

  • ⌛ADC转换时间
    AVR 328pb ADC基本介绍和使用_第7张图片

ADC 参考电压

ADC的参考电压(VREF)表示ADC的转换范围。超过VREF的单端通道将导致代码接近0x3FF。VREF可以选择为AVCC、内部1.1V参考或外部AREF引脚。

ADC 相关寄存器

  • ADC多路复用器选择寄存器:ADMUX
    AVR 328pb ADC基本介绍和使用_第8张图片
  • 6-7位决定ADC参考电压选择。

位5-ADLAR: ADC左调整结果ADLAR位影响ADC转换结果在ADC数据寄存器中的呈现。向左写入一个ADLAR调整结果。否则,结果右调整。更改ADLAR位将立即影响ADC数据寄存器,而不管任何正在进行的转换。有关该位的完整描述,请参阅ADCL和ADCH。
位3:0-MUX[3:0]:模拟通道选择这些位的值选择哪些模拟输入连接到ADC。如果在转换期间更改了这些位,则在此转换完成之前更改不会生效。
AVR 328pb ADC基本介绍和使用_第9张图片
AVR 328pb ADC基本介绍和使用_第10张图片

  • ADC控制和状态寄存器A:ADCSRA
    AVR 328pb ADC基本介绍和使用_第11张图片
    AVR 328pb ADC基本介绍和使用_第12张图片

  • ADC控制和状态寄存器B:ADCSRB
    AVR 328pb ADC基本介绍和使用_第13张图片

  • ADC数据寄存器低字节和高字节(ADLAR=0):ADCL and ADCH
    ADCL和ADCH寄存器对代表16位值,ADC数据寄存器。低字节[7:0](后缀L)可在原始偏移量处访问。高字节[15:8](后缀H)可在偏移量+0x01处访问。有关读取和写入16位寄存器的更多详细信息,请参阅访问16位定时器/计数器寄存器。当ADC转换完成时,结果在这两个寄存器中找到。当读取ADCL时,ADC数据寄存器不会更新,直到读取ADCH。因此,如果结果保持调整,并且不需要超过8位精度,则读取ADCH就足够了。否则,必须先读取ADCL,然后再读取ADCH。ADLAR位和ADMUX中的MUXn位会影响从寄存器读取结果的方式。如果设置了ADLAR(ADLAR=1),则结果向左调整。如果ADLAR被清除(ADLAR=0,这是默认值),则结果向右调整。
    AVR 328pb ADC基本介绍和使用_第14张图片

  • ADC数据寄存器低字节和高字节(ADLAR=1):(ADCL and ADCH)
    ADCL和ADCH寄存器对代表16位值,ADC数据寄存器。低字节[7:0](后缀L)可在原始偏移量处访问。高字节[15:8](后缀H)可在偏移量+0x01处访问。有关读取和写入16位寄存器的更多详细信息,请参阅访问16位定时器/计数器寄存器。当ADC转换完成时,结果在这两个寄存器中找到。当读取ADCL时,ADC数据寄存器不会更新,直到读取ADCH。因此,如果结果保持调整,并且不需要超过8位精度,则读取ADCH就足够了。否则,必须先读取ADCL,然后再读取ADCH。ADLAR位和ADMUX中的MUXn位会影响从寄存器读取结果的方式。如果设置了ADLAR(ADLAR=1),则结果向左调整。如果ADLAR被清除(ADLAR=0,这是默认值),则结果向右调整。
    AVR 328pb ADC基本介绍和使用_第15张图片

测试例程

  • 例程采用AREF引脚的使用5V供电电压作为参考。采集通道0(PC0引脚)输入电压值。
//官方ADC例程编号:AN17644 Getting STARTED with AVR
#include "atmel_start.h"

#include 
#include 
#include 
#include 
#include 
#include "stdio.h"

uint16_t adc_res = 0;

/**************************************************************
PIN change interrupt ISR
LED toggle code is commented as LED dimming code has been added in main
****************************************************************/

ISR(PCINT0_vect)
{
    // 	if (!(PINB & (1<
    // 	{
    // 		PORTB |= (1<
    // 	}
    // 	else
    // 	{
    // 		PORTB &= ~(1<
    // 	}
}

uint16_t ReadADC(uint8_t ADCchannel)
{
    // select ADC channel with safety mask
    ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);//
    // single conversion mode
    ADCSRA |= (1 << ADSC);
    // wait until ADC conversion is complete
    while (ADCSRA & (1 << ADSC))
        ;
    return ADC;
}
void optimize_power_consumption()
{
    DIDR0 |= 0xC0; /*ADC7D and ADC6D are undefined in header file so set bits this way*/

    /* Disable digital input buffer on Analog comparator pins */
    DIDR1 |= (1 << AIN1D) | (1 << AIN0D);
    /* Disable Analog Comparator */
    ACSR |= (1 << ACD);

    /*Watchdog Timer OFF*/

    /* Disable interrupts */
    cli();
    /* Reset watchdog timer */
    wdt_reset();
    /* Clear WDRF in MCUSR */
    MCUSR &= ~(1 << WDRF);
    /* Turn off WDT */
    WDTCSR = 0x00;
    /* Set sleep mode */
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

int main(void)
{
    system_init();
    optimize_power_consumption();

    TIMSK1 |= (1 << OCIE1A); // Enable output compare match A interrupt

    PCMSK0 |= (1 << PCINT7); // Enable Pin Change Interrupt 7
    PCICR |= (1 << PCIE0);   // Enable the interrupt enable bit for PCINT
    sei();

    while (1)
    {
        ADCSRA &= ~(1 << ADEN);//禁用ADC
        power_adc_disable();
        sleep_mode();
        power_adc_enable();//AVCC AREF使用5V供电电压作为参考
        ADCSRA |= (1 << ADEN);//使能ADC

        adc_res = ReadADC(0);//通道0:PC0
        printf("adc_value:%d",adc_res);
        _delay_ms(1000);
        LED_toggle_level();
    }
    return 0;
}

  • 裸机ADC0测试代码
/*
 * USART_PRINTF.c
 *
 * Created: 2024/2/8 19:50:27
 * Author : Administrator
 */

#include 
#include "util/delay.h"
//#include "util/setbaud.h"
#include "avr/sfr_defs.h"//包含loop_until_bit_is_set函数
#include "avr/interrupt.h"
// Standard Input/Output functions
#include 


// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (0<<ADLAR))

// Read the AD conversion result
unsigned int ReadADC(unsigned char adc_input)
{
    ADMUX=adc_input | ADC_VREF_TYPE;
    // Delay needed for the stabilization of the ADC input voltage
    _delay_us(10);
    // Start the AD conversion
    ADCSRA|=(1<<ADSC);
    // Wait for the AD conversion to complete
    while ((ADCSRA & (1<<ADIF))==0);
    ADCSRA|=(1<<ADIF);
    return ADCW;
}

// ADC initialization
void ADC_Init(void)
{

    // ADC Clock frequency: 125.000 kHz
    // ADC Voltage Reference: AVCC pin
    // ADC Auto Trigger Source: Free Running
    // Digital input buffers on ADC0: Off, ADC1: On, ADC2: On, ADC3: On
    // ADC4: On, ADC5: On, ADC6: On, ADC7: On
    DIDR0=(0<<ADC7D) | (0<<ADC6D) | (0<<ADC5D) | (0<<ADC4D) | (0<<ADC3D) | (0<<ADC2D) | (0<<ADC1D) | (1<<ADC0D);
    ADMUX=ADC_VREF_TYPE;
    ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
    ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);

    // Ensure that the ADC is enabled
    PRR0&= ~(1<<PRADC);
}

static int	uart_putchar(char c, FILE *stream)
{

    //   if (c == '\n')
    //       uart_putchar('\r', stream);
    //   loop_until_bit_is_set(UCSR0A, UDRE0);//需包含:avr/sfr_defs.h
    // /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) );
    UDR0 = c;
    return 0;
}

// 配置输出流
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
                       _FDEV_SETUP_WRITE);
//static FILE USART0_stream = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_RW);//


#define BAUD 9600
#define F_CPU 16000000UL
#define MYUBRR (F_CPU/16/BAUD-1)

// 串口初始化
void USART0_Init(void)
{
    UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (0<<U2X0) | (0<<MPCM0);
    /*Enable receiver and transmitter */
    UCSR0B=(1<<RXCIE0) | (0<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
    /* Set frame format: 8data, 1stop bit */
    UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
    /*Set baud rate */
    UBRR0H = (unsigned char)(MYUBRR>>8);
    UBRR0L = (unsigned char)MYUBRR;
    stdout = &mystdout;//输出流配置

    // Ensure that the USART0 is enabled
    PRR0&= ~(1<<PRUSART0);


    // Globally enable interrupts
    sei();

}
void USART_Transmit( unsigned char data )
{
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) )
        ;
    /* Put data into buffer, sends the data */
    UDR0 = data;
}

unsigned char USART_Receive( void )
{
    /* Wait for data to be received */
    while ( !(UCSR0A & (1<<RXC0)) )
        ;
    /* Get and return received data from buffer */
    return UDR0;
}

void SYS_Clock_Init()
{
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
}

int main(void)
{
    /* Replace with your application code */
    unsigned int adc_res;
    SYS_Clock_Init();
    USART0_Init();
    DDRB = PINB5;//配置PB5为输出模式
    ADC_Init();//ADC initialization
    while (1)
    {
        PORTB ^= (1 << PINB5);//PB5状态翻转
        _delay_ms(1000); // 使用util/delay.h中的宏函数来实现1毫秒的延时
        adc_res = ReadADC(0);//通道0:PC0
        printf("adc_value:%d",adc_res);

    }
}


AVR 328pb ADC基本介绍和使用_第16张图片

你可能感兴趣的:(AVR单片机,AVR,ADC)