AVR microcontroller tutorial --ADC

ADC

The computer world is 0 and 1. SCM may be determined by reading the key state 0 and 1, 0 and 1 may be output to control the LED. Even PWM 0 and 1 does not look, if the output voltage can be between 0 to 5V as to achieve the effect between 0 and 1, but the essence is low or high.

But, after all, the world has 0 and 1 can not be expressed. If a voltage is applied between 0 to 5V on pin, the register PINxcan not tell us the circumstances, we can only indicate the voltage is below 1.5V or 3V above (refer to data sheet "Electrical characteristics"). This signal is called a continuously variable analog signals , and discrete, only 0 or 1 (0 or 5V) of the digital signal opposition.

This does not mean that the digital world can not process analog signals, on the contrary, a very commonly used method for processing an analog signal, is to convert the analog signal into a digital signal, it is calculated by the processor, and then converted to an analog signal. This process involves the analog - digital conversion and digital - analog conversion, the ADC and DAC are required to implement. Most single-chip, as in the real world tools, need to reach an analog signal, especially the input analog signal, will be integrated ADC.

ADC resolution is a parameter, it means the number of bits, the number may be generated reflecting different outputs (8-bit ADC may produce a value of 0 to 255) and the minimum physical quantized (typically a voltage) capacity (for example when the reference voltage of 2.56V, ideally, 8-bit ADC can resolve a difference of two different voltages of 0.01V). ADC AVR microcontrollers with a 10-bit.

Another parameter is the conversion rate, the number of times A / D conversion per second. ADC AVR microcontroller to achieve precision 10-bit resolution, the maximum conversion rate is 15 ksps (thousand samples per second). If lower accuracy is acceptable, can also be 200kSPS sampling, 8-bit data is obtained.

Resolution and accuracy are different concepts. In this entry-level tutorial, we need to know, A / D conversion there will be errors (data sheet 23.7.4 section describes the possible sources of error). Even with the same voltage, the two measurements may be different.

Results to the A / D conversion, it is necessary to provide a reference voltage and a voltage to be measured, converted to \ (\ {FRAC measured voltage a reference voltage} {} \ times 2 ^ {resolution} \) . Register ADMUXthe ADLARposition alignment control of the conversion result. When the right-justified, taking the resolution of the formula 10, the conversion result register 16 ADCin (actually two 8-bit registers ADCHwith ADCL, but the program can be used directly ADC, the compiler will take care of some notes); when Left , 8 take resolution, the conversion result ADCHin. Can be directly ADCused as 16-bit registers, the compiler will handle some notes.

ADC has 4 to choose the reference voltage, namely AREF, AVCC(5V), 1.1Vand 2.56Vby the REFS1:0selection. Eight single-ended ports (development board 4 leads to the port 0to 3), as well as some differential port ( 1x, 10x, 200xgain), and two reference voltages, a total of 32 channels can be connected to the ADC through a multiplexer for converted by MUX4:0choice. Note, ADC is only one, at the same time can only convert the voltage of a channel.

ADCSRAAnd ADCSRBfor controlling the A / D conversion. ADCSRAIn ADENenabled ADC component ADSCbit starts a conversion, the ADIFbit 1when the conversion is completed, need to write 1in order to be cleared. ADPS2:0Select ADC clock division factor, which is related to the conversion rate: first ADC sampling requires 25 clock cycles (at the same time or after the first ADC is enabled), then each sample requires 13. ADCSRBYou may be selected A / D conversion trigger.

Board provides 3.3V power supply, the device can be used to support only the 3.3V power supply. We use ADC to measure the voltage and then output on the serial port.

#include <avr/io.h>
#include <ee1/uart.h>

int main()
{
    uart_init(UART_TX);
    ADMUX  =    0b01 << REFS0  // AVCC as reference
           |     0b0 << ADLAR  // right adjust
           | 0b00000 << MUX0;  // ADC0 single ended
    ADCSRA =       1 << ADEN   // enable ADC
           |       1 << ADSC   // start conversion
           |       1 << ADIF   // clear flag
           |   0b111 << ADPS0; // divide by 128
           
    while (!(ADCSRA & 1 << ADIF)) // wait until flag is set
        ;
    
    uint16_t voltage = (uint32_t)ADC * 500 >> 10; // ADC / 1024 * 500 (* 10mV)
    uint8_t integer = 0;                          // integer part of voltage
    while (integer * 100 <= voltage)              // calculate integer part
        ++integer;
    --integer;
    uint8_t decimal = voltage - integer * 100;    // calculate decimal part
    
    uart_print_int(integer);                      // print the voltage
    uart_print_char('.');
    uart_set_align(UART_ALIGN_RIGHT, 2, '0');
    uart_print_int(decimal);
    uart_print_string("V\n");
    
    while (1)
        ;
}

Data Manual Section 28.8 indicates, when the ADC clock is 200kHz, ADC absolute accuracy can be achieved 1.9LSB (1LSB is 1024 1). Was calculated, in order to not exceed the ADC clock rate, the division factor 128 should take.

The measured voltage \ (Voltage = \ FRAC the ADC} {1024} {\ Times 5V \) , but this is directly related to the floating-point calculations, and the AVR hardware does not support floating-point, floating-point operations are all implemented in software , relatively slow speed, two floatmultiplication instruction requires more than 1,000 cycles, the division requires more, are to be trying to avoid. Even though the final voltage is a decimal, the decimal point by moving it into an integer. A 5V reference voltage, the accuracy 1.9LSB about 9.28mV, so the right by two to calculate the unit of 10mV. Multiplying the first count to avoid floating-point division, the equation becomes \ (Voltage = \ {FRAC the ADC \ Times 500} {1024} \) .

ADCThe value of direct and 500multiplying the overflow, so you need to upgrade to uint32_t. Of course, you can look at the formula about points, but does not change the fact that the overflow. Although 32-bit integer processing is not very good, but still much easier compared to floating-point numbers. Then a division. 16-bit integer divide instruction cycles required CPU 173 (refer to: the Multiply and Divide Routines ), it is time-consuming. Although this program only once, but still we should try to find a way to avoid time-consuming operation. Noting the divisor 1024is a special number, 10 is a power of 2, the division can be done by a shift operation, the shift operation is much faster compared to a divider (compiler will perhaps / 1024optimized to >> 10).

Then we need to put one hundred parts of this number as integer part of the voltage out of ten and a bit for the fractional part, by dividing 100and die 100to achieve. Because here 100is a compile-time constant, it is possible to compile the division and modulus optimize away, the process does not call more than 100 cycles. Here we feel the manual optimization. Since the variable voltagemust be smaller than 500, multiplication can be used to test and compare the cycles of the provider, the number of multiplication is performed wherein no more than 6 times --AVR microcontroller has two-cycle multiply instruction. Then, multiplication and subtraction to obtain the remainder.

ADC is relatively easy to use SCM case of floating-point multiplication and division, the design should try to avoid calculation algorithm, an algorithm or manually write optimized time-consuming to replace.

Potentiometer

Potentiometer, two boards on the right side a knob on the left, may be rotated continuously 300 °. Electrical properties equivalent rheostat physical experiment, if the two pieces connected VCCand GNDon-chip voltage movable knob can indicate the angle, and is generally proportional to the angle.

Previously mentioned, A / D conversion is an error, even if the input voltage is kept constant, the conversion result may fluctuate. If we add some electromagnetic interference, such as a motor near this noise will be more apparent. If a program needs to detect the rotational position of the potentiometer in which side midpoint, and just simply comparing the conversion result of 128the magnitude relation, such noise can cause serious consequences, as the waveform shown in red:

[picture]

The threshold value 128near the noise of the converter results fluctuate, leading to rapid judged state transition. The user just turned the knob slowly middle position, which is obviously not the result we want.

This time we need hysteresis comparator played. The core characteristics of hysteresis comparator is the output changes between 0 and 1, the input threshold value is different in the two directions: when the signal goes high over the threshold from low to high, output becomes 1; when the signals from the high to low crossing the low threshold, the output becomes 0; green as shown in the waveform (FIG. is inverted). Thus, when the input reaches the high threshold, the output becomes 1, as long as the noise at this time is not large enough to return to the input low threshold, the output will remain as a filtered noise.

We write a program, an LED to indicate which side of the midpoint position of the potentiometer knob, and outputs the state changes every time the serial port, to facilitate our observation.

#include <ee1/pot.h>
#include <ee1/led.h>
#include <ee1/uart.h>
#include <ee1/delay.h>

void init();
void normal();
void hysteresis();

int main()
{
    init();
    while (1)
    {
        normal();
//         hysteresis();
        delay(1);
    }
}

static bool status;

void change(bool _value)
{
    status = _value;
    uart_print_string(_value ? "on\n" : "off\n");
    led_set(LED_BLUE, _value);
}

void init()
{
    pot_init(ADC_0);
    led_init();
    uart_init(UART_TX);
    status = pot_read() >= 128;
}

void normal()
{
    bool now = pot_read() >= 128;
    if (status != now)
        change(now);
}

void hysteresis()
{
    uint8_t pot = pot_read();
    if (status && pot < 124)
        change(0);
    else if (!status && pot >= 132)
        change(1);
}

normalAnd hysteresisa function of a second election, in which an algorithm which uses a hysteresis comparator.

In normalmode, adjust the potentiometer to a position near the midpoint, you will find the yellow crazy TX indicator as to the flash, serial software displays a long list of "on" and "off" (careful tone, a certain there) - you do not need to create any disturbance, the error of the ADC alone can be very bad for programs to run. If you use a full 10-bit resolution, such a phenomenon will be more obvious.

In the hysteresismode, such a situation does not arise.

Photoresistance

Photoresistor is a special resistor, when the light intensity of a small resistance, a large resistance when the light is weak. A photoresistor in series with a common resistor, connected to VCCand GNDbetween the intermediate points of the measured voltage, can know the strength of the light.

Of course, the development board is known with a photoresistor in series resistance is 10 k [Omega, in accordance with a certain time ADC conversion result, this case can also be calculated photosensitive resistor. But do not get me wrong, the light intensity is obtained by voltage rather than resistance.

As with the potentiometer, if you want to detect strong and weak light of the two states, but also to use hysteresis comparator. Take two threshold values 100and 150, both large difference, because we want to turn on the lights when the light is weak, which in turn enhances the brightness (meaning little negative feedback), if the difference is not big enough, which will be caught in the cycle.

These two thresholds are easily taken, the practical application value should be based on specific conditions. So easy to think to put this function pulled out from the application to become a library. However, different from the commonly used before, so that customers return to the state to decide peripheral functions operate (although still could write), this library is event-driven: Action for customer registration event to be executed, the program flow to the frame to control.

Program is divided into three files: event.h, event.cand main.c, the first two can be separate into a library for later use, for convenience, and the executable program together.

event.h

#ifndef EVENT_H
#define EVENT_H

#include <stdint.h>
#include <stdbool.h>

void ldr_event_init(uint8_t _thl, uint8_t _thh, void (*_func)(bool));
void ldr_event_cycle();

#endif

event.c

#include "event.h"
#include <ee1/ldr.h>

static void (*handler)(bool);
static uint8_t low, high;
static bool status;

void ldr_event_init(uint8_t _thl, uint8_t _thh, void (*_func)(bool))
{
    ldr_init(ADC_1);
    low = _thl;
    high = _thh;
    handler = _func;
    uint8_t ldr = ldr_read();
    if (ldr <= low)
        handler(status = 0);
    else
        handler(status = 1);
}

void ldr_event_cycle()
{
    uint8_t ldr = ldr_read();
    if (status && ldr <= low)
        handler(status = 0);
    else if (!status && ldr >= high)
        handler(status = 1);
}

main.c

#include <ee1/led.h>
#include <ee1/delay.h>
#include "event.h"

void handler(bool e)
{
    if (e)
        led_off();
    else
        led_on();
}

int main()
{
    led_init();
    ldr_event_init(100, 150, handler);
    while (1)
    {
        ldr_event_cycle();
        delay(1000);
    }
}

Write your client event handler handler, the parameter is a boolreturn void, which is ldr_event_initprescribed. handlerThe implementation of the corresponding action parameter: When eis true, the light from weak to strong, lights; lights and vice versa. In the call ldr_event_init, the pointer to this function as a parameter. Subsequently, called once every second ldr_event_cycle.

Please take a moment to clearly understand each line library. Then, we stand on the customer's perspective, the use of this library is relatively easy - just consider the event that the change of light, regardless of the process, that is, how to detect this change - in fact, customers do not have to detect , let alone how the. However, the mainfunction must be called once every so often ldr_event_cycle. After studying the timer interrupt, mainthe function can be completely returned to the customer.

operation

  1. Access to relevant information, to understand what type of ADC.

  2. Improvement of a talk program RGBW light, the brightness of the LED light intensity adapt to the environment.

  3. Code digestion and absorption combined with the concept of event-driven. Recommended reading: Event-Driven Programming - TechnologyUK

Guess you like

Origin www.cnblogs.com/jerry-fuyi/p/12169442.html