• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Obliczanie średniej wartości z ADC na mikrokontrolerze ATmega32

VPS Starter Arubacloud
0 głosów
373 wizyt
pytanie zadane 17 stycznia 2021 w C i C++ przez tonn204 Mądrala (7,470 p.)

Witam, robię termometr z czujnika analogowego i ATmegai 32. Próbuję obliczyć średnią wartość zwracaną mi przez przetwornik analogowo-cyfrowy, Napisałem dwie funkcje, które za to odpowiadają, ale na wyświetlaczu najpierw przez dłuższy czas pokazuje się liczba -50, a potem 19.2. Co robię tutaj nie tak, że program nie działa jak chcę i co mam zmienić, żeby wartość ADC była uśredniona poprawnie?

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

#include "HD44780.h"

#define VREF_DIVIDED 25
#define SIZE 16

uint64_t adc_value;
uint16_t voltage_value;
int16_t cz_d, cz_u;
int16_t temp;
uint64_t adc_values_array[SIZE];
uint64_t counter = 0;
char decimal_buffer[33];
char fraction_buffer[33];

void ADC_init(void);

void average_adc(void);

uint64_t average_adc_read(void);

int main(void)
{
	// LCD init
	LCD_Initalize();
	
	// ADC init
	ADC_init();
	
	while (1)
	{
		average_adc();
		voltage_value = adc_value * VREF_DIVIDED;
		temp = voltage_value / 10 - 500;
		cz_d = temp/10;
		cz_u = temp%10;
		
		itoa(cz_d, decimal_buffer, 10);
		itoa(cz_u, fraction_buffer, 10);
		LCD_Clear();
		LCD_GoTo(2, 0);
		LCD_WriteText("Temperatura:");
		LCD_GoTo(6, 1);
		LCD_WriteText(decimal_buffer);
		LCD_WriteText(".");
		LCD_WriteText(fraction_buffer);
		_delay_ms(500);
	}
}

void ADC_init(void)
{
	DDRA &= ~(1 << PA5) | ~(1 << PA6) | ~(1 << PA4);
	ADMUX |= (1 << REFS1) | (1 << REFS0); // Vref = 2.56V
	ADMUX |= (1 << MUX0) | (1 << MUX2); // Pomiar na ADC5
	ADCSRA |= (1 << ADEN) | (1 << ADPS0) | (1 << ADPS1); // Włączenie ADC i preskaler = 64
}

uint64_t average_adc_read(void)
{
	uint64_t curren_adc_value = 0;
	
	for(int i = 0 ;i<SIZE-1; i++)
	{
		curren_adc_value += adc_values_array[i];
	}
	
	return curren_adc_value/SIZE;
}

void average_adc(void)
{
	//static uint64_t counter = 0;
	
	ADCSRA |= (1 << ADSC);
	while(ADCSRA & (1 << ADSC));
	
	counter++;
	adc_values_array[counter-1] = ADC;
	if(counter >= SIZE)
	{
		 counter = 0; 
		 adc_value = average_adc_read();
	}
}

 

komentarz 17 stycznia 2021 przez j23 Mędrzec (195,220 p.)
edycja 17 stycznia 2021 przez j23

Linia 65: dlaczego SIZE - 1 a nie po prostu SIZE?

    counter++;
    adc_values_array[counter-1] = ADC;

Chyba nigdy nie pojmę takich konstrukcji. Przecież wystarczy:

adc_values_array[counter++] = ADC;
if(counter == SIZE) { ... }

Dlaczego average_adc zwraca wynik w zmiennej globalnej zamiast normalnie zwrócić przez return?

1 odpowiedź

0 głosów
odpowiedź 17 stycznia 2021 przez j23 Mędrzec (195,220 p.)


IMO pierwsze wyświetlenie powinieneś zrobić dopiero po obliczeniu wartości średniej, czyli po SIZE odczytach z czujnika.

Podobne pytania

0 głosów
1 odpowiedź 881 wizyt
pytanie zadane 17 marca 2020 w C i C++ przez ResCrove Obywatel (1,700 p.)
+1 głos
3 odpowiedzi 696 wizyt
–1 głos
0 odpowiedzi 512 wizyt
pytanie zadane 18 stycznia 2016 w Inne języki przez niezalogowany

92,975 zapytań

141,939 odpowiedzi

321,182 komentarzy

62,302 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...