c - AVR 编程,在 7 段上显示错误值。引领

标签 c embedded avr atmega

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

#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;
}

最佳答案

问题是归纳。

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

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

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

1) 的完整代码

#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;
}

关于c - AVR 编程,在 7 段上显示错误值。引领,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48401340/

相关文章:

c - 浅拷贝结构在 Xcode 上得到奇怪的结果

c - 尽管声明了 const 限定符,为什么嵌套结构成员会发生更改?

c - 查找多项式 y、导数和积分值的程序(已更新)

C 设计模式在不阻塞的情况下执行操作列表?

c - .o 文件中 undefined symbol

c++ - AVR-Studio 中的 vector 头文件

c - 使用 c 得出下一个小于 k 的回文

c - 需要将我的固件镜像迁移到 ROM 掩码

c - uint64_t 类型的问题

c - ATmega88 中断服务程序执行两次