首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AVR编程,在7段显示错误的值。LED

AVR编程,在7段显示错误的值。LED
EN

Stack Overflow用户
提问于 2018-01-23 20:06:30
回答 1查看 326关注 0票数 1

我正在将LM35与Atmega8连接起来。为了显示数字,我使用7段LED阳极显示器,两端都连接到AVR (它不用晶体管就能处理,所以为什么不呢)。奇怪的事情发生了:从adc分配后的res值是237 (23.7度)。我想在我的显示器上打印第一个数字(2)。如果我将while中的最后一行注释掉,显示器首先正确地显示数字2,但在第一次延迟后,它显示1而不是2。否则,我将正确显示数字2。为什么会发生这种情况?

代码语言:javascript
复制
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU

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

#define DELAY_IN_MS 500 /* 0.5 sec */

int numbers[] = {
    0b01000000,
    0b01110011,
    0b00100100,
    0b00100001,
    0b00010011,
    0b00001001,
    0b00001000,
    0b01100011,
    0b00000000,
    0b00000001,
    0b11111111 // off
};

uint8_t digits[3];

void initADC()
{
    ADMUX=(1<<REFS1)|(1<<REFS0);
    ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

uint16_t ReadADC(uint8_t ch)
{
    //Select ADC Channel ch must be 0-7
    ch=ch&0b00000111;
    ADMUX|=ch;

    //Start Single conversion

    ADCSRA|=(1<<ADSC);

    //Wait for conversion to complete
    while(!(ADCSRA & (1<<ADIF)));

    //Clear ADIF by writing one to it
    ADCSRA|=(1<<ADIF);

    return(ADC);
}

int main()
{
    DDRD = 0xFF;
    PORTD = 0xFF;

    DDRB = 0b00000001;
    PORTB = 1;

    initADC();

    uint16_t adc_value;
    uint16_t res;
    while(1)
    {
        adc_value = 0;
        for (int i = 0; i < 250; i++)
        {
            adc_value += ReadADC(0);
        }

        adc_value=(adc_value/25)/4;
        res = adc_value;

        for(int j = 2; j >= 0; j--) {
            digits[j] = res%10;
            res /= 10;
        }

        uint8_t dig = digits[0];
        PORTD = numbers[dig];
        _delay_ms(DELAY_IN_MS);

        // if following is uncommented there blinks digit two correctly
        // if commented there is unblinking digit 1 
        PORTD = numbers[10]; // display off
    }

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-15 17:13:34

问题是归纳。

我的电路在非焊接区有很多导线。当显示器打开时,ADC输入/LM35输出上的结果电压发生了大量的感应变化。有不止一种解决方案。

1)软件:我将ADC转换移到了中断功能中。它关闭显示器,从lm35转换值,并在适当的显示器上显示数字。它发生得如此之快,以至于肉眼无法察觉。我现在更喜欢这个,因为它使我的电路更简单。

2)硬件:在adc引脚上加L/C或R/C滤波器可以解决这个问题。

1的完整代码)

代码语言:javascript
复制
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU

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

#define DELAY_IN_MS 5000 /* ms */
#define NUM_OF_MEASUREMENTS 100
#define NUM_DISPLAYS 3

int numbers[] = {
    0b10000001,
    0b10011111,
    0b10100100,
    0b10010100,
    0b10011010,
    0b11010000,
    0b11000000,
    0b10011101,
    0b10000000,
    0b10010000,
    0b11111111 // off
};

int display = 0;
uint8_t digits[NUM_DISPLAYS];
volatile uint16_t adc_values[NUM_OF_MEASUREMENTS];
int adc_read_cycle_index = 0;
uint32_t res;

void initADC()
{
    ADMUX=(1<<REFS1)|(1<<REFS0);
    ADCSRA=(1<<ADEN)|(1<<ADPS2);
}

uint16_t ReadADC(uint8_t ch)
{
    //Select ADC Channel ch must be 0-7
    ch=ch&0b00000111;
    ADMUX|=ch;

    //Start Single conversion
    ADCSRA|=(1<<ADSC);

    //Wait for conversion to complete
    while (ADCSRA & (1<<ADSC));

    return(ADC);
}

void readDegrees()
{
    adc_values[adc_read_cycle_index] = (ReadADC(0)*10)/4;

    if(adc_read_cycle_index + 1 == NUM_OF_MEASUREMENTS) {
        adc_read_cycle_index = 0;
    } else {
        adc_read_cycle_index++;
    }
}

void fetchTemperatureDigits() {
    res = 0;
    for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
        res += adc_values[i];
    }
    res /= NUM_OF_MEASUREMENTS;

    for(int j = 2; j >= 0; j--) {
        digits[j] = res%10;
        res = res / 10;
    }
}

void initTimer0()
{
      // Prescaler = FCPU/64
      TCCR0|=(1<<CS01);//|(1<<CS00);

      //Enable Overflow Interrupt Enable
      TIMSK|=(1<<TOIE0);

      //Initialize Counter
      TCNT0=0;
}

ISR(TIMER0_OVF_vect)
{
    // turn off displays
    PORTD = numbers[10];

    // read ADC and convert to degrees
    readDegrees();

    // turn on proper anode
    PORTB &= 0b11111000;
    PORTB |= (1<<display);

    // show digit
    PORTD = numbers[digits[display]];
    // show decimal point for second display (21.5 - second display shows "1.")
    if(display == 1) {
        PORTD &= 0b01111111;
    }
    // next display for next interruption
    display++;
    if(display == NUM_DISPLAYS) {
        display = 0;
    }
}

int main()
{

    initADC();
    for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
        readDegrees();
    }

    DDRD = 0xFF;
    PORTD = 0;

    DDRB |= 0b00000111;
    PORTB |= 1;

    initTimer0();

    sei();

    while(1) {
        fetchTemperatureDigits();
        _delay_ms(DELAY_IN_MS);
    }

    return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48401340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档