最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How do I get ADC to work on an ATtiny212 using Microchip Studio C code? - Stack Overflow

programmeradmin1浏览0评论

I am new to the tinyavr 1 series microcontrollers. I've tried copying the basic example out of the Microchip TB3209 guide, but it doesn't seem to do anything.

I use the below code, where PA3 is an LED and PA6 is my ADC pin. All it's supposed to do is on boot, read the ADC pin, and if it is below the threshold, do nothing, otherwise turn the LED on. But not matter if I have the ADC grounded or pulled to 5V, it always gets a reading from the ADC that is higher than the threshold.

The below code is straight from Microchip.

/* ATMEL ATTINY212
   Pin 6 is /RESET
   
               +-\/-+
         Vcc  1|    |8  GND
DAC TXD  PA6  2|    |7  PA3 SCK
    RXD  PA7  3|    |6  PA0 UPDI RESET
SDA MOSI PA1  4|    |5  PA2 MISO SCL
               +----+

   PA3 is the LED output pin
   PA6 is the ADC pin AIN6
   
*/

#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz

#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t adcVal;
void ADC0_init(void);
uint16_t ADC0_read(void);
void ADC0_init(void)
{
    /* Disable digital input buffer */
    PORTA.PIN6CTRL &= ~PORT_ISC_gm;
    PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
    /* Disable pull-up resistor */
    PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm;
    ADC0.CTRLC = ADC_PRESC_DIV4_gc /* CLK_PER divided by 4 */
    | ADC_REFSEL_INTREF_gc; /* Internal reference */
    ADC0.CTRLA = ADC_ENABLE_bm /* ADC Enable: enabled */
    | ADC_RESSEL_10BIT_gc; /* 10-bit mode */
    /* Select ADC channel */
    ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc;
}
uint16_t ADC0_read(void)
{
    /* Start ADC conversion */
    ADC0.COMMAND = ADC_STCONV_bm;
    /* Wait until ADC conversion done */
    while ( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )
    {
        ;
    }
    /* Clear the interrupt flag by writing 1: */
    ADC0.INTFLAGS = ADC_RESRDY_bm;
    return ADC0.RES;
}
int main(void)
{
    ADC0_init();
    adcVal = ADC0_read();
    
    // set PA3 to output mode
    PORTA.DIR |= (1 << 3);
    
    if(adcVal > 10) {
        // PA3 LED on
        PORTA.OUTSET = (1 << 3);
    } else {
        // PA3 LED off
        PORTA.OUTCLR = (1 << 3);
    }
    
    while (1)
    {
        ;
    }
}

As of the board, it's working with a blink or digital input code properly. It's just a SOIC to DIP adapter on a bread board going to an LED (with CLR) and a potentiometer.

I am new to the tinyavr 1 series microcontrollers. I've tried copying the basic example out of the Microchip TB3209 guide, but it doesn't seem to do anything.

I use the below code, where PA3 is an LED and PA6 is my ADC pin. All it's supposed to do is on boot, read the ADC pin, and if it is below the threshold, do nothing, otherwise turn the LED on. But not matter if I have the ADC grounded or pulled to 5V, it always gets a reading from the ADC that is higher than the threshold.

The below code is straight from Microchip.

/* ATMEL ATTINY212
   Pin 6 is /RESET
   
               +-\/-+
         Vcc  1|    |8  GND
DAC TXD  PA6  2|    |7  PA3 SCK
    RXD  PA7  3|    |6  PA0 UPDI RESET
SDA MOSI PA1  4|    |5  PA2 MISO SCL
               +----+

   PA3 is the LED output pin
   PA6 is the ADC pin AIN6
   
*/

#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz

#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t adcVal;
void ADC0_init(void);
uint16_t ADC0_read(void);
void ADC0_init(void)
{
    /* Disable digital input buffer */
    PORTA.PIN6CTRL &= ~PORT_ISC_gm;
    PORTA.PIN6CTRL |= PORT_ISC_INPUT_DISABLE_gc;
    /* Disable pull-up resistor */
    PORTA.PIN6CTRL &= ~PORT_PULLUPEN_bm;
    ADC0.CTRLC = ADC_PRESC_DIV4_gc /* CLK_PER divided by 4 */
    | ADC_REFSEL_INTREF_gc; /* Internal reference */
    ADC0.CTRLA = ADC_ENABLE_bm /* ADC Enable: enabled */
    | ADC_RESSEL_10BIT_gc; /* 10-bit mode */
    /* Select ADC channel */
    ADC0.MUXPOS = ADC_MUXPOS_AIN6_gc;
}
uint16_t ADC0_read(void)
{
    /* Start ADC conversion */
    ADC0.COMMAND = ADC_STCONV_bm;
    /* Wait until ADC conversion done */
    while ( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )
    {
        ;
    }
    /* Clear the interrupt flag by writing 1: */
    ADC0.INTFLAGS = ADC_RESRDY_bm;
    return ADC0.RES;
}
int main(void)
{
    ADC0_init();
    adcVal = ADC0_read();
    
    // set PA3 to output mode
    PORTA.DIR |= (1 << 3);
    
    if(adcVal > 10) {
        // PA3 LED on
        PORTA.OUTSET = (1 << 3);
    } else {
        // PA3 LED off
        PORTA.OUTCLR = (1 << 3);
    }
    
    while (1)
    {
        ;
    }
}

As of the board, it's working with a blink or digital input code properly. It's just a SOIC to DIP adapter on a bread board going to an LED (with CLR) and a potentiometer.

Share Improve this question edited Feb 5 at 18:10 emacs drives me nuts 4,01218 silver badges40 bronze badges asked Jan 30 at 20:25 Erik VincentErik Vincent 112 bronze badges 3
  • You are showing the code (and rightly so). What makes you think that your hardware is correctly set up? Was assembling required? Supply voltage attached? Right way round? Etc. you know what I mean. I assume this is the "HelloWorld" version for that embedded environment, right? Or is there anything simpler you could try? Maybe a digital input instead of the ADC? Or maybe just some basic debugger comissioning test? – Yunnosch Commented Jan 31 at 6:32
  • You should probably read the ADC result before clearing the flag. Store it in a temporary variable, then clear the flag, then return the temporary variable's value. – Lundin Commented Jan 31 at 8:46
  • Maybe you want the ADC reading and LED action in the loop? – emacs drives me nuts Commented Jan 31 at 17:29
Add a comment  | 

1 Answer 1

Reset to default 0

So, I've determined the example in the Microchip ADC Technical Brief just doesn't work for whatever reason. However, I have written code that does work. Below is that code:

/*
 * t212 adc.c
 *
 * Created: 1/30/2025 2:43:59 PM
 * Author : erik.vincent
 */

/* ATMEL ATTINY212
   Pin 6 is /RESET
   
               +-\/-+
         Vcc  1|    |8  GND
DAC TXD  PA6  2|    |7  PA3 SCK
    RXD  PA7  3|    |6  PA0 UPDI RESET
SDA MOSI PA1  4|    |5  PA2 MISO SCL
               +----+

   PA3 is the LED output pin
   PA6 is the ADC pin AIN6
   
*/

#define F_CPU 3333333UL // Default Setting micro to 3.33MHz
// #define F_CPU 20000000UL // Setting micro to 20MHz
#define ADC_SHIFT_DIV64    (6)  // ADC Sample Accumulator 0x06 is 64 samples

#include <avr/io.h>
#include <util/delay.h>

void adc_init (void);
uint16_t read_adc(void);

void adc_init (void) {
    ADC0_CTRLA = (0 << ADC_RUNSTBY_bp) | (0 << ADC_RESSEL_10BIT_gc) | (1 << ADC_ENABLE_bp); // Disabled run in standby, enabled ADC & full 10-bit resolution
    VREF_CTRLA = (1 << VREF_ADC0REFSEL0_bp);                                                // ADC voltage reference = 1.1V (0x1)
    ADC0_CTRLC = (1 << ADC_SAMPCAP_bp) | (0 << ADC_REFSEL_gp);                              // Set Internal reference, set reduced size of sampling capacitance, set prescaler to CLK_PER/4
    ADC0_CTRLD = (1 << ADC_INITDLY1_bp) | (0 << ADC_ASDV_bp) | (0 << ADC_SAMPDLY0_bp);      // These bits define the delay when initializing the ADC or changing the source of the reference voltage.
    ADC0_SAMPCTRL = (1 << ADC_SAMPLEN4_bp);                                                 // 0x10, These bits control the ADC sampling time in number of CLK_ADC cycles,
    ADC0_CTRLB = ADC_SAMPNUM_ACC64_gc;                                                      // 64 samples
    ADC0_MUXPOS = 6;                                                                        // Set to AIN6
}

uint16_t read_adc(void) {
    // Read ADC
    uint16_t adc_val = 0;
    uint16_t adc_ave = 0;   // ADC average from accumulator

    _delay_ms(1);       // give it a moment to switch

    ADC0_COMMAND = (1 << ADC_STCONV_bp);            // Start conversion//Writing a '1' to this bit in single-shot mode starts one conversion.
    while (ADC0_COMMAND & (1 << ADC_STCONV_bp));    // while conversion is on-going
    _delay_ms(10);
    adc_val = ((ADC0_RESH << 8) | ADC0_RESL);       // ADC conversion result to make sure ADC reading is good
    
    adc_val = ((ADC0_RESH << 8) | ADC0_RESL);       // Do it a second time, because the first time will be bogus
    adc_ave = adc_val >> ADC_SHIFT_DIV64;           // Get average value from ADC sampler
    
    return adc_ave;
}
int main(void)
{
    adc_init();
    uint16_t adcVal = read_adc();
    
    // set PA3 to output mode
    PORTA.DIR |= (1 << 3);
    
    if(adcVal > 10) {
        // PA3 LED on
        PORTA.OUTSET = (1 << 3);
    } else {
        // PA3 LED off
        PORTA.OUTCLR = (1 << 3);
    }
    
    while (1) {
        ;
    }
}
发布评论

评论列表(0)

  1. 暂无评论