FAQ | Points | Add... | Recent posts | Search | Register | Log in


Atmega8 i zmienne float - problemy


Post new topic  Reply to topic      Main Page -> Forum Index -> Microcontrollers Generally -> AVR Microcontrollers -> Atmega8 i zmienne float - problemy
Author
Message
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#1 Post from the author of the topic 04 Mar 2010 11:41   

Atmega8 i zmienne float - problemy


Piszę program na Atmegę8 z zastosowaniem przetwornika ADC i poległem na zmiennych.
Będę odczytywał wartość napięcie w zakresie 0,370 - 0,693 i zamieniał je na temperaturę.
Zdjąłem charakterystykę f(v) = mc+b i próbuję zaprząc procesor do działania.
Na razie przetwornik (chyba) nie ruszył, bo nie widać zmian na wyświetlaczu, ale póki co zająłem się sprawdzaniem obliczeń i mam podejrzenia że procek nie radzi sobie ze zmiennymi typu float.

oto fragmenty programu:
Code:

void adc_init(void)
{
  ADMUX |= _BV(REFS0);
  ADMUX |= _BV(REFS1);
  ADMUX |= _BV(ADLAR);
  ADCSRA |= _BV(ADEN);
  ADCSRA |= _BV(ADPS0);
  ADCSRA |= _BV(ADPS1);
//  ADMUX = 0;
}

int getadc(uint8_t channel)
{
  ADMUX |= channel;
  ADCSRA |= _BV(ADSC);
  while (ADCSRA & _BV(ADSC)) {}
  return(ADCW);
}

int convert(int value)
{
  static const float c1=20.0;
  static const float v1=0.693;
  static const float c2=200.0;
  static const float v2=0.370;
  float  m = (v2-v1) / (c2-c1);
  return ((int)((float)value -(v1 - m*c1))/m);
}

int main(void)
{
  port_init();
  adc_init();
  while(1)
  {
    _delay_ms(100);
    pomiar = getadc(0);
    temp_current = convert2degree(pomiar);
  }
}


To fragment programu, jak wcześniej wspomniałem.
Wynik jest wyświetlany na trzech LEDach siedmiosegmentowych z multipleksowaniem sterowanym przerwaniem procesora.
Wyświetlanie jest poprawne jeżeli się poda bezpośrednio zmienną.
Natomiast wyświetlenie np m w postaci np a=1/m daje wynik 211, a powinno być 577
Wykonywałem też inne sprawdzenia z deklarowanymi stałymi i tez jest źle:

float a = v1*10;, temp_current = a*100; = 181 czyli źle
float a = v1*100; temp_current = a; = 69 czyli dobrze.

Zastanawiam się nad wymnożeniem stałych v1 i v2 o tysiąc czyli podawania mV, a nie V, a później podawanie do funkcji convert wartości pomiar*1000.

Za wszelką pomoc z góry dziękuję, bo w kwestii programowania uC orłem nie jestem.
Przeczytałem sporo wątków na Elektrodzie ale jednoznacznej odpowiedzi nie mam.
Back to top
   
loocasm
Poziom 12
Poziom 12


Joined: 18 Mar 2005
Posts: 107
Location: lubuskie

Post#2 04 Mar 2010 12:00   

Re: Atmega8 i zmienne float - problemy


Nigdzie nie podałeś (albo ja niedowidzę) jakiego typu jest zmienna temp_current ... a to pewnie jest przyczyną problemów
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#3 Post from the author of the topic 04 Mar 2010 12:24   

Re: Atmega8 i zmienne float - problemy


temp_current jest typu int, gdyż jest podawana na wyświetlacz, oczywiście z podziałem na setki, dziesiątki i jedności.
Back to top
   
loocasm
Poziom 12
Poziom 12


Joined: 18 Mar 2005
Posts: 107
Location: lubuskie

Post#4 04 Mar 2010 12:30   

Re: Atmega8 i zmienne float - problemy


Przy mnożeniu floatów przez stałe często widzi się "na siłę" robione ułamki, np. zamiast a*100 -- a*100.0, zaś przy przypisaniu tego do inta można jeszcze to rzutować... Może takie niepozorne zabiegi pomogą
Back to top
   
Google

Google Adsense


Post# 04 Mar 2010 12:30   





Back to top
   
albertb
Poziom 22
Poziom 22


Joined: 04 May 2004
Posts: 1875
Location: Nowy Targ

Post#5 04 Mar 2010 12:44   

Re: Atmega8 i zmienne float - problemy


A ja zawsze w takich przypadkach zastanawiam się, po co ludzie komplikują sobie życie używając arytmetyki zmiennoprzecinkowej. Najczęściej nie zdając sobie sprawy z ani połowy spraw, o których wypada wiedzieć, aby świadomie (a nie odpatrując, lub metodą prób i błędów) taki program napisać.
Przecież jako wejście nasz procesor otrzymuje jedną z 1024 wartości całkowitych.
A w wypadku tej konkretnej realizacji nawet mniej niż 350.
Jako wyjście trzeba dać jednoznacznie przyporządkowaną każdej z nich wartość całkowitą, która też może przybrać w tym wypadku maksymalnie 1000 wartości.
No być może jeszcze drugi prosty algorytm, który w zależności od tych samych danych wejściowych wygasi zera wiodące/zapali kropki.
Niezależnie od stopnia skomplikowania funkcji przejścia nie widzę motywacji dołączania bibliotek zmiennoprzecinkowych, konwersji, działań na tych liczbach, a następnie spowrotem.

Albert
Back to top
   
loocasm
Poziom 12
Poziom 12


Joined: 18 Mar 2005
Posts: 107
Location: lubuskie

Post#6 04 Mar 2010 13:06   

Re: Atmega8 i zmienne float - problemy


Swoją drogą też racja :)
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#7 Post from the author of the topic 16 Mar 2010 08:35   

Re: Atmega8 i zmienne float - problemy


Po powrocie z urlopu uruchomiłem przetwornik. Program na razie w okrojonej wersji aby przetestować sam ADC i wyświetlanie na trzech LEDach siedmiosegmentowych.

Przetwornik w zasadzie pracuje i pokazuje prawidłową wartość, ale dwie kwestie mnie niepokoją i prosił bym o pomoc w ich wyjaśnieniu.

Otóż, pierwsza sprawa to wahania napięcia. Podczas pracy przetwornika napięcie zasilające waha się w sposób cykliczny, czyli to nie jest sprawa stabilności zasilacza, bo po wyłączeniu przetwornika napięcie jest bardzo stabilne. Zmiany następują mniej więcej co 1-1,5s. Te wahania przekładają się oczywiście na pomiar, bo napięcie na wejściu PC0, gdzie dokonywany jest pomiar zmienia się na trzecim miejscu po przecinku i to objawia się skakaniem ostatniej cyfry na wyświetlaczu. Na podłączonym mierniku widać te zmiany także. Ewidentnie praca przetwornika wpływa jakoś na tą kwestię.
Druga sprawa to odczyt wartości "pomiar" w przerwaniu. Jak odczytuję wynik 8-bitowy (ADCH) to przy ustawieniu 0,2V na wejściu jest na wyświetlaczu 20 czyli OK.
Jak odczytuję z dokładnością 10-cio bitową (ADCW) wyświetlacz pokazuje zmieniające się dziwne wartości niewiele mające wspólnego z tym co powinno być. W przedmiotowym przykładzie powinienem odczytać wartość 80, a tak nie jest.

Wejście PC0 jest podpięte poprzez rezystor 10k do suwaka precyzyjnego potencjometru, który pozwala na zmiany napięcia na suwaku w zakresie 0-1V
Pin AREF ma podpięty C 100n.

Do pinów zasilania Atmegi z obu stron są podpięte kondensatory 100n oraz na wejściu zasilania jest 100µ.
Całość jest zmontowana na płytce stykowej bez specjalnego bałaganu.

Poniżej część programu. Usunąłem fragmenty mniej istotne aby nie zaciemniać, np sterowanie przyciskami itd. w każdym razie bez wpływu na działanie programu.

Code:


#define F_CPU 1000000L     //1 Mhz
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include<avr/interrupt.h>
#include <wyswietlacze.h>


volatile uint8_t wysw = 0;     // zmienna przechowująca numer aktywnego wyświetlacza
volatile uint8_t temp_sto;     // zmienna przechowująca setki temp
volatile uint8_t temp_dzi;     // zmienna przechowująca dziesiątki temp
volatile uint8_t temp_jed;     // zmienna przechowująca jedności temperatury
int temp_set = 100;           // zmienna przechowująca temp ustawianą
volatile uint8_t temp_wysw = 0; // zmienna przechowująca temp do wyświetlenia
volatile uint16_t pomiar;     // wartość zmierzona po konwersji
float wynik;
int temp_current;

void port_init(void)
{
DDRD=0xff;     //Port PD0-PD7 jako wyjścia                   /11111111
PORTD=0x7f;    //Port PD0-PD6 podciągnięciem do jedynki      /01111111
DDRB=0x0f;     //Port PB0-PB3 jako wyjścia,                  /001111
PORTB=0x37;    //Port PB0-PB2, PB4-PB5 z podciągnięciem do 1 /110111
DDRC=0x3e;     //Port PC0 jako wejście                       /111110
PORTC=0x20;    //Port PC5 z podciągnięciem do 1              /100000

}

void adc_init(void)
{
  ADMUX |= _BV(REFS0);  //wewnętrzne źródło referencyjne 2,56V z zewnętrznym C podpiętym do pinu AREF
  ADMUX |= _BV(REFS1);  //"REFS0" = 1 i "REFS1" = 1
  ADMUX |= _BV(ADLAR);  //zapis wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
  ADCSRA |= _BV(ADEN);  //zezwolenie na konwersję - aktywacja przetwornika ADC "ADEN"
  ADCSRA |= _BV(ADPS0);
  ADCSRA |= _BV(ADPS1); //preskaler 8 "ADPS0 i ADPS1 = 1"
  ADCSRA |= _BV(ADIE);  //włączenie przerwania od zakończenia konwersji
  ADCSRA |= _BV(ADFR);  //free running
  ADMUX &= ~_BV(MUX0);  //wybór wejścia pomiarowego "ADMUX" = 0
  ADCSRA |= _BV(ADSC);  //start konwersji
}


int main(void)
{
  port_init();
  adc_init();

  TCCR1B |= (1 << WGM12);  // Ustawia timer1 w tryb CTC
  OCR1A = 625;             // Ustawia wartość pożądaną na 200Hz dla preskalera 8
  TCCR1B |= (1 << CS11);   // Ustawia timer1 z preskalerem Fcpu/8
  TIMSK |= (1 << OCIE1A);  // Zezwolenie na przerwania dla CTC
  sei();                   // Zezwolenie globalne na przerwania

int i;
  while(1)
  {
    _delay_ms(100);

    temp_current = pomiar;
    _delay_ms(400);

    temp_wysw = temp_current;
    temp_sto = (temp_wysw / 100);
    temp_dzi = (temp_wysw / 10)%10;
    temp_jed = temp_wysw % 10;
  }
}

ISR(ADC_vect)
{
   pomiar = ADCH;
}


ISR(TIMER1_COMPA_vect)  //wywołanie przerwania
{
  switch (wysw)
  {
    case 0:
      PORTB &= ~(1 << 2);     //zeruje bit 2 portu B - włącza wyświetlacz nr 3
      PORTB |= (1 << 1);      //ustawia bit 1 portu B - wyłącza wyświetlacz nr 2
      PORTB |= (1 << 0);      //ustawia bit 0 portu B - wyłącza wyświetlacz nr 1
      PORTD = cyfra(temp_sto);
      wysw++;
    break;

    case 1:
      PORTB |= (1 << 2);      //ustawia bit 2 portu B - wyłącza wyświetlacz nr 3
      PORTB &= ~(1 << 1);     //zeruje bit 1 portu B - włącza wyświetlacz nr 2
      PORTB |= (1 << 0);      //ustawia bit 0 portu B - wyłącza wyświetlacz nr 1
      PORTD = cyfra(temp_dzi);
      wysw++;
    break;

    case 2:
      PORTB |= (1 << 2);      //ustawia bit 2 portu B - wyłącza wyświetlacz nr 3
      PORTB |= (1 << 1);      //ustawia bit 1 portu B - wyłącza wyświetlacz nr 2
      PORTB &= ~(1 << 0);     //zeruje bit 0 portu B - włącza wyświetlacz nr 1
      PORTD = cyfra(temp_jed);
      wysw=0;
    break;
  }
}

Back to top
   
flapo213
Poziom 18
Poziom 18


Joined: 21 Jan 2003
Posts: 549
Location: Rzeszów

Post#8 16 Mar 2010 13:48helpful post - solution   

Re: Atmega8 i zmienne float - problemy


Mała sugestia odnośnie pomiaru i wahania odczytów. Nie tak dawno robiłem odczyt z czujnika temperatury (termistora 5%), irytowała mnie strasznie szalejąca wartość pomiaru. W pierwszej chwili zrobiłem na szybko uśrednianie na podstawie zwykłej średniej arytmetycznej postaci:

wynik = (N_0+N_1+...N_n)/n,

ale nie dało mi to zadowalającego efektu. Aby w tego typu uśrednianiu uzyskać zadowalający efekt trzeba by uśredniać ogromną liczbę pomiarów, co niesie za sobą oczywiście czasochłonność oraz długie oczekiwanie na wynik. Przedstawię Ci prosty sposób na zniwelowanie tego przykrego efektu.

Cały widz polega na tym że z przetwornika otrzymujesz wartości np takie :

0x60, 0x61, 0x68, 0x55, 0x67, 0x60, 0x63, 0x60, 0x,80, 0x76, 0x65, 0x60 itd.

Dla ułatwienia dodam że 0x60 jest wartością poprawną. Jak zastosujesz średnią arytmetyczną to nie będzie ona dla tylu pomiarów równa 0x60 tylko trochę więcej.

Co zrobić w takim razie, odpowiedź jest prosta skoro przetwornik odczytał Ci 4 razy 0x60 to prawdopodobnie jest to wartość oczekiwana. Oczywiście może się zdarzyć identyczna liczba tych samych wartości. Więc napisz sobie funkcyjkę która będzie Ci przeszukiwać zbiór np 20 elementów (czyli 20 odczytów) i wybierze Ci odpowiednią najbardziej powtarzającą się wartość. Ja napisałem taką funkcjkę tylko ze zmienną liczbą próbek bo im więcej tym lepiej, dobry efekt uzyskuje się już przy 30 - 50 próbek. Wiesz zawsze to lepiej niż 1000 uśrednionych wartości. Uzyskałem stabilność lepszą niż DS18x20 (stabilność nie oznacza dokładności,tylko wahania pomiarów).

Niestety dodam że napisanie takiego algorytmu nie jest proste, aby to dobrze zrobić należy wykonać blokowy algorytm najlepiej a później kod w C.

Pozdrawiam i życzę sukcesów
Back to top
   
Kabuto15
Poziom 16
Poziom 16


Joined: 30 Jun 2007
Posts: 339
Location: Rzeszów

Post#9 16 Mar 2010 15:11   

Re: Atmega8 i zmienne float - problemy


A propos uśredniania , filtry medianowe również mogą być przydatne.
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#10 Post from the author of the topic 16 Mar 2010 20:24   

Re: Atmega8 i zmienne float - problemy


Dzięki za sugestie. Może będę musiał tak zrobić, choć nie wiem jak się do tego zabrać, ale nurtuje mnie ten temat, gdyż zmieniające się okresowo pomiary wynikają ewidentnie z wahań napięcia, które obserwuje na mierniku podpiętym do suwaka potencjometru. Tam zmiany są w miliwoltach, ale wartość zasilania VCC waha się bardziej. Problem ustaje po wyłączeniu przetwornika. Początkowo myślałem, że niewydala zasilacz i wahania wynikają ze zmian obciążenia przy różnej liczbie zapalanych segmentów LED, ale dokonywałem zmian wartości wyświetlanych na LEDach poprzez ustawianie zmiennej za pomocą przycisków - docelowo służą one do ustawiania temperatury w piecu - i o dziwo przy wyłączonym przetworniku napięcie było stabilne. Czy praca przetwornika może powodować jakieś zjawisko wzbudzania się układu lub coś podobnego?
Czasami obserwowałem okresy kilku sekundowe bez wahań i wtedy wyświetlacz stabilnie pokazywał jedną wartość.
Co to może być?
Back to top
   
Kabuto15
Poziom 16
Poziom 16


Joined: 30 Jun 2007
Posts: 339
Location: Rzeszów

Post#11 16 Mar 2010 21:25   

Re: Atmega8 i zmienne float - problemy


Może być kilka przyczyn, żeby je wyeliminować można: zastanowić się nad prowadzeniem ścieżek przetwornika, filtracja zasilania - niskoczęstotliwościowa (dodać kondensatorów o sporej pojemności za stabilizatorem), użyć źródła referencyjnego dla przetwornika (np. na TL431).
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#12 Post from the author of the topic 16 Mar 2010 21:38   

Re: Atmega8 i zmienne float - problemy


Kabuto15 wrote:
Może być kilka przyczyn, żeby je wyeliminować można: zastanowić się nad prowadzeniem ścieżek przetwornika, filtracja zasilania - niskoczęstotliwościowa (dodać kondensatorów o sporej pojemności za stabilizatorem), użyć źródła referencyjnego dla przetwornika (np. na TL431).


Na razie jest na płytce stykowej.
Co do kondensatora to o ile wiem, raczej nie jest wskazane pakowanie większej pojemności niż 100µ po stronie wyjściowej 7805.
Tak czy inaczej jeszcze będę robił próby na innym zasilaczu.
Back to top
   
flapo213
Poziom 18
Poziom 18


Joined: 21 Jan 2003
Posts: 549
Location: Rzeszów

Post#13 16 Mar 2010 22:01   

Re: Atmega8 i zmienne float - problemy


Jest jeszcze jedna rzecz którą powinieneś rozważyć przy projektowaniu płytki, mianowicie pamiętaj o tym iż przetwornik ma wewnętrzne podciąganie na liniach ADC więc twój pomiar może być niewiarygodny. Najlepiej zastosuj wzmacniacz operacyjny w funkcji wtórnika a napięcie referencyjne pociągnij z AREF które równa sie 2,56V.

Masz tu kawałek schematu:


Atmega8 i zmienne float - problemy
Back to top
   
Kabuto15
Poziom 16
Poziom 16


Joined: 30 Jun 2007
Posts: 339
Location: Rzeszów

Post#14 16 Mar 2010 22:03   

Re: Atmega8 i zmienne float - problemy


Mnie uczono, że pojemności nigdy za mało. Duże pojemności zmniejszają tętnienia napięcia. I dodatkowo należy pamiętać o 100nF blisko nóżek układu w celu filtracji zakłóceń wysokoczęstotliwościowych. Choć w Twoim przypadku oczywiście może występować inny problem. Napisz jaki masz pobór prądu i ile bierze przetwornik.

I tak jak pisze flapo213 ATmega8 ma skopane AREF (poprawka: VCC) bo wewnętrznie podłączone jest w AVCC (błąd całej serii kontrolerów). Może zamień go na ATmega16.
Back to top
   
atom1477
Poziom 25
Poziom 25


Joined: 14 Jul 2005
Posts: 6360

Post#15 16 Mar 2010 22:07   

Re: Atmega8 i zmienne float - problemy


Kabuto15 wrote:
I tak jak pisze flapo213 ATmega8 ma skopane AREF bo wewnętrznie podłączone jest w AVCC (błąd całej serii kontrolerów). Może zamień go na ATmega16.

1. Nie widzę żeby gdzieś flapo213 coś takiego napisał.
2. O takiej wadzie ATMegi8 nie słyszałem.

PS. O podciąganiu linii ADC też nie słyszałem.
Back to top
   
Google

Google Adsense


Post# 16 Mar 2010 22:07   





Back to top
   
Kabuto15
Poziom 16
Poziom 16


Joined: 30 Jun 2007
Posts: 339
Location: Rzeszów

Post#16 16 Mar 2010 22:16   

Re: Atmega8 i zmienne float - problemy


Sorki za pomyłkę. Chodziło mi o nie odseparowanie AVCC i VCC oczywiście.
Back to top
   
atom1477
Poziom 25
Poziom 25


Joined: 14 Jul 2005
Posts: 6360

Post#17 16 Mar 2010 22:34   

Re: Atmega8 i zmienne float - problemy


No.
A wracając do tematu: Wyniki nie powinny aż tak skakać. Mi zwykle nie skaczą bardziej niż o 1...2LSB (a w układach pracują przetwornice impulsowe, silniki sterowane przez PWM, czy inne cuda).
krzysztofh: masz źle poprowadzona masę pewnie.
Back to top
   
michalko12
Poziom 22
Poziom 22


Joined: 20 Nov 2004
Posts: 1551
Location: Gdzieś koło wawy

Post#18 16 Mar 2010 22:54   

Re: Atmega8 i zmienne float - problemy


atom1477 wrote:
No.
A wracając do tematu: Wyniki nie powinny aż tak skakać. Mi zwykle nie skaczą bardziej niż o 1...2LSB (a w układach pracują przetwornice impulsowe, silniki sterowane przez PWM, czy inne cuda).
krzysztofh: masz źle poprowadzona masę pewnie.


Jestem ciekaw, ile osób zwraca uwagę na impedancję wejścia przetwornika, a może inaczej, zalecaną impedancję źródła sygnału.
Back to top
   
atom1477
Poziom 25
Poziom 25


Joined: 14 Jul 2005
Posts: 6360

Post#19 16 Mar 2010 23:35   

Re: Atmega8 i zmienne float - problemy


Pewnie niewiele.
A po co mnie zacytowałeś?
Ja akurat nie stosuję żadnych wtórników a wyniki mam dobre.
Back to top
   
michalko12
Poziom 22
Poziom 22


Joined: 20 Nov 2004
Posts: 1551
Location: Gdzieś koło wawy

Post#20 17 Mar 2010 00:22   

Re: Atmega8 i zmienne float - problemy


atom1477 wrote:
Pewnie niewiele.
A po co mnie zacytowałeś?
Ja akurat nie stosuję żadnych wtórników a wyniki mam dobre.

To miało się tylko do tego:
Quote:
krzysztofh: masz źle poprowadzona masę pewnie.

i nie chodziło konkretnie o Ciebie tylko o to, że w większości przypadków obwiniane jest zasilanie, a temat jest trochę bardziej złożony.

Podstawą jest zrozumienie działa takiego przetwornika. W parametrach ADC podawana jest rezystancja wejścia na poziomie setek MΩ i tak naprawdę parametr ten na niewiele się zdaje. Dużo mówiącymi są ten rysunek:
Atmega8 i zmienne float - problemy
i ten akapit:
Quote:
The ADC is optimized for analog signals with an output impedance of approximately 10kΩ or
less. If such a source is used, the sampling time will be negligible. If a source with higher imped-
ance is used, the sampling time will depend on how long time the source needs to charge the
S/H capacitor, with can vary widely. The user is recommended to only use low impedant sources
with slowly varying signals, since this minimizes the required charge transfer to the S/H
capacitor.


W tym przypadku może pomóc niewielki kondensator na wejściu (1n) powodujący to, że CS/H będzie miał skąd pobierać ładunek ograniczając przy tym szumy samplowania na wejściu.
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#21 Post from the author of the topic 17 Mar 2010 07:08   

Re: Atmega8 i zmienne float - problemy


Dziękuję wszystkim za podpowiedzi. Jak czas pozwoli to dzisiaj wieczorkiem będą dalsze próby z ustabilizowaniem przetwornika i pomiaru.
O efektach nie omieszkam napisać.

Edit.

Informuję szanowne grono wsparcia, że po poprawieniu jakości zasilania układu oraz dodania C 100n pomiędzy PC0 i GND przetwornik się uspokoił. Cyfry na wyświetlaczu nie skaczą.
Dzięki za pomoc.
Teraz czas na dalsze zmiany w projekcie.
Back to top
   
atom1477
Poziom 25
Poziom 25


Joined: 14 Jul 2005
Posts: 6360

Post#22 20 Mar 2010 20:40   

Re: Atmega8 i zmienne float - problemy


krzysztofh wrote:
Informuję szanowne grono wsparcia, że po poprawieniu jakości zasilania układu oraz dodania C 100n pomiędzy PC0 i GND przetwornik się uspokoił. Cyfry na wyświetlaczu nie skaczą.

To wcześniej nie miałeś tam kondensatora?
Ech. Jak bym wiedział to od razu bym Ci napisał.
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#23 Post from the author of the topic 20 Mar 2010 20:43   

Re: Atmega8 i zmienne float - problemy


Szanowni koledzy proszę znów o pomoc w interpretacji wartości odczytu przetwornika.
Otóż, jak dokonuje pomiaru 8-bitowego (ADCH) wynik wyświetlany jest na wyświetlaczy poprawnie. Np. dla wartości 0,685V zmierzone multimetrem przetwornik pokazuje wartość 0,68 czyli poprawnie gdyż (0,685*256)/2,56. Jeżeli tą wartość pomnożę przez dziesięć, czyli już przestanie się mieścić w zmiennej 8-bitowej wynik jest wyświetlany jako 680 czyli OK, bo zmienne w programie odpowiedzialne za przechowywanie wartości z przetwornika są 16-bitowe.
Jeżeli natomiast zwiększę precyzję odczytu do 10 bitów (ADCW), najstarsza cyfra jest wyświetlana w postaci bliżej nieokreślonej, tzn wyświetlają się segmenty, które nie przypominają cyfr. Dwie młodsze cyfry wyświetlane są poprawnie, choć niewiele mają wspólnego z poprawnym wynikiem. Jak wartość odczytu podzielę przez 100 lub 50 pojawiają się poprawne cyfry, choć sam wynik jest oczywiście dla mnie nie zrozumiały. W przedmiotowym przykładzie powinna się wyświetlić liczba 274, bo (0,685*1024)/2,56.
Bardzo proszę o pomoc bo dalej nie mogę ruszyć z projektem, którym ma być piec z regulacją i stabilizacją temperatury. W załączeniu schemat.
Code:


#define F_CPU 1000000L     //1 Mhz
#include <avr/io.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <wyswietlacze.h>


volatile uint8_t wysw = 0;     // zmienna przechowująca numer aktywnego wyświetlacza
volatile uint8_t temp_sto;     // zmienna przechowująca setki temp
volatile uint8_t temp_dzi;     // zmienna przechowująca dziesiątki temp
volatile uint8_t temp_jed;     // zmienna przechowująca jedności temperatury
int temp_set = 100;           // zmienna przechowująca temp ustawianą
volatile uint16_t temp_wysw = 0; // zmienna przechowująca temp do wyświetlenia
volatile uint16_t pomiar;      //zmienna przechowująca wartość po konwersji
float wynik;
volatile uint16_t temp_current;  // zmienna przechowująca temp zmierzoną po konwersji

void port_init(void)    //inicjalizacja portów
{
DDRD=0xff;     //Port PD0-PD7 jako wyjścia                   /11111111
PORTD=0x7f;    //Port PD0-PD6 podciągnięciem do jedynki      /01111111
DDRB=0x0f;     //Port PB0-PB3 jako wyjścia,                  /001111
PORTB=0x37;    //Port PB0-PB2, PB4-PB5 z podciągnięciem do 1 /110111
DDRC=0x3e;     //Port PC0 jako wejście                       /111110
PORTC=0x20;    //Port PC5 z podciągnięciem do 1              /100000

}

void adc_init(void)
{
  ADMUX |= _BV(REFS0);  //wewnętrzne żródło referencyjne 2,56V z zewnętrznym C podpiętym do pinu AREF
  ADMUX |= _BV(REFS1);  //"REFS0" = 1 i "REFS1" = 1
  ADMUX |= _BV(ADLAR);  //wybór sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
  ADCSRA |= _BV(ADEN);  //zezwolenie na konwersję - aktywacja przetwornika ADC "ADEN"
  ADCSRA |= _BV(ADPS0); //preskaler
  ADCSRA |= _BV(ADPS1); //preskalerem 8 "ADPS0 i ADPS1 = 1"
  ADCSRA |= _BV(ADIE);  //włączenie przerwania od zakończenia konwersji
  ADCSRA |= _BV(ADFR);  //free running
  ADMUX &= ~_BV(MUX0);  //wybór wejścia pomiarowego "ADMUX" = 0
  ADCSRA |= _BV(ADSC);  //start konwersji
}

void led_init(void)
{
  TCCR1B |= (1 << WGM12);  // Ustawia timer1 w tryb CTC
  OCR1A = 625;             // Ustawia wartość pożądaną na 200Hz dla preskalera 8
  TCCR1B |= (1 << CS11);   // Ustawia timer1 z preskalerem Fcpu/8
  TIMSK |= (1 << OCIE1A);  // Zezwolenie na przerwania dla CTC
}


int main(void)
{
  port_init();
  adc_init();
  led_init();
  sei();

  while(1)
  {
    _delay_ms(100);

    temp_current = pomiar;
    temp_wysw = temp_current;
    temp_sto = (temp_wysw / 100);
    temp_dzi = (temp_wysw / 10)%10;
    temp_jed = temp_wysw % 10;


  }
}

ISR(ADC_vect)
{
   pomiar = ADCW;
}


ISR(TIMER1_COMPA_vect)
{
  switch (wysw)
  {
    case 0:
      PORTB &= ~(1 << 2);     //zeruje bit 2 portu B - włącza wyświetlacz nr 3
      PORTB |= (1 << 1);      //ustawia bit 1 portu B - wyłącza wyświetlacz nr 2
      PORTB |= (1 << 0);      //ustawia bit 0 portu B - wyłącza wyświetlacz nr 1
      PORTD = cyfra(temp_sto);
      wysw++;
    break;

    case 1:
      PORTB |= (1 << 2);      //ustawia bit 2 portu B - wyłącza wyświetlacz nr 3
      PORTB &= ~(1 << 1);     //zeruje bit 1 portu B - włącza wyświetlacz nr 2
      PORTB |= (1 << 0);      //ustawia bit 0 portu B - wyłącza wyświetlacz nr 1
      PORTD = cyfra(temp_dzi);
      wysw++;
    break;

    case 2:
      PORTB |= (1 << 2);      //ustawia bit 2 portu B - wyłącza wyświetlacz nr 3
      PORTB |= (1 << 1);      //ustawia bit 1 portu B - wyłącza wyświetlacz nr 2
      PORTB &= ~(1 << 0);     //zeruje bit 0 portu B - włącza wyświetlacz nr 1
      PORTD = cyfra(temp_jed);
      wysw=0;
    break;
  }
}




piec.pdf
 Description:
 n/a

Download
 Filename:  piec.pdf
 Contents:  
 Filesize:  14.05 KB
 Punkty:  0.00

Back to top
   
michalko12
Poziom 22
Poziom 22


Joined: 20 Nov 2004
Posts: 1551
Location: Gdzieś koło wawy

Post#24 21 Mar 2010 00:29   

Re: Atmega8 i zmienne float - problemy


Code:
temp_tys = temp_wysw /1000;
temp_wysw %= 1000;
temp_sto = temp_wysw /100;
temp_wysw %= 100;
temp_dzi = temp_wysw /10;
temp_jed = temp_wysw %10;


I dodatkowo masz błąd w funkcji cyfra(), która nie zabezpiecza się przed argumentem >=10 i stąd te dziwne znaczki na wyświetlaczu.
Jeśli temp_wysw wynosiło >=1000 funkcja cyfra przyjmowała wartości powyżej 9 i prawdopodobnie pobierałeś patern spoza tablicy, domniemam bo nie pokazałeś tej funkcji.
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#25 Post from the author of the topic 21 Mar 2010 17:15   

Re: Atmega8 i zmienne float - problemy


michalko12 - chyba podążamy w dobrym kierunku ale wyników nie potrafię dalej zinterpretować.

poprawiłem kod i teraz jest tak (tylko część główna):
Code:

int main(void)
{
  port_init();
  adc_init();
  led_init();
  sei();

  while(1)
  {
    _delay_ms(100);

    temp_current = pomiar;
    temp_wysw = temp_current;
   
    if (temp_wysw > 999)
    {
      temp_sto = (temp_wysw / 100) % 10;
      temp_dzi = (temp_wysw / 10) % 10;
      temp_jed = temp_wysw % 10;
    }
    else
    {
      temp_sto = (temp_wysw / 100);
      temp_dzi = (temp_wysw / 10)%10;
      temp_jed = temp_wysw % 10;
    }
  }
}



Wyświetlacze są trzy więc nie obsługuje tysięcy. Z resztą nie spodziewam się temperatur większych niż 200°C. Teraz wyświetlane jest oczywiście mierzone przez przetwornik napięcie póki co.

Krzaki z ostatniej cyfry zniknęły i wyświetlane liczby zdają się pokazywać pewną prawidłowość, która jest niestety dla mnie tajemnicą.
Otóż ogrzewam w ręku czujnik (dioda na kawałku radiatora) i obserwuję napięcie na niej (multimetr). Zmiany są w zakresie 0,665V - 0,685V. Tym zmianom odpowiadają liczby na wyświetlaczu (128, 256, 320, 384, 448, 512, 576, 640, 704). Oczywiście cyfry migają wraz ze wzrostem temperatury, ale daje się zaobserwować, że dla określonej temp (napięcia wejściowego) wyświetlana cyfra zachowuje się przez pewien czas stabilnie, co jest zrozumiałe.
Ciekawie wyglądają te cyfry jeżeli przedstawi się je binarnie:
128 - 0000 0000 1000 0000 (najwyższa temp, najniższe napięcie na diodzie)
256 - 0000 0001 0000 0000
320 - 0000 0001 0100 0000
384 - 0000 0001 1000 0000
448 - 0000 0001 1100 0000
512 - 0000 0010 0000 0000
576 - 0000 0010 0100 0000
640 - 0000 0010 1000 0000
704 - 0000 0010 1100 0000 (najwyższe napięcie z podanego wcześniej zakresu)

Po dodaniu warunku rozpoznającego liczbę zapisaną w zmiennej temp_current, cyfry, a właściwie najstarsza cyfra przynajmniej zaczęła wyglądać normalnie, co mogłoby wskazywać na liczbę większą od tysiąca. Ale skąd tam taka liczba, skoro dopiero w okolicy napięcia 2,5V powinna się pojawić wartość 1000, a ja podaję dużo mniejsze wartości na wejście ACD.

Dla jasności podam zawartość pliku wyswietlacze.h
Code:

////////////////////////////////////////////////////////////////////////////////
// wyswietlacze.h - plik nagłówkowy z przydatnymi funkcjami do
//                  obsługi wyświetlaczy 
// wersja: 1.0              data: 7 marca 2008
// zmieniona przez Krzysztof
// autor oryginału: Ravender
////////////////////////////////////////////////////////////////////////////////
// Funkcje
//
// uint8_t cyfra(uint8_t) - zwraca podaną cyfrę z pamięci danych
//
//Plik ten należy umieścić w folderze \avr\include

#include <avr/pgmspace.h>
#include <inttypes.h>

#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define F 5
#define G 6

prog_uint8_t cyfry[11] PROGMEM = {
(1<<G),                                           //0 (PD0-PD6) low
(1<<A)|(1<<D)|(1<<E)|(1<<F)|(1<<G),               //1 (PD1-PD2) low
(1<<C)|(1<<F),                                    //2 (PD0-PD2, PD3-PD4, PD6) low
(1<<E)|(1<<F),                                    //3 (PD0,PD3, PD6) low
(1<<A)|(1<<E)|(1<<D),                                    //4 (PD1-PD2, PD5-PD6) low
(1<<B)|(1<<E),                                    //5 (PD0,PDB2-PD3, PD5-PD6) low
(1<<B),                                           //6 (PD0, PD2-PD6) low
(1<<D)|(1<<E)|(1<<F)|(1<<G),                      //7 (PD0-PD2) low
(0<<A)|(0<<B)|(0<<C)|(0<<D)|(0<<E)|(0<<F)|(0<<G), //8 (PD0-PD6) low
(1<<E),                                           //9 (PD0-PD3, PD5-PD6) low
(1<<A)|(1<<B)|(1<<C)|(1<<D)|(1<<E)|(1<<F)|(1<<G), //  (PD0-PD6) high - wygaszenie wyświetlacza
};

uint8_t cyfra(uint8_t cyfra)
{
  return pgm_read_byte(&cyfry[cyfra]);
}

Back to top
   
Google

Google Adsense


Post# Post from the author of the topic 21 Mar 2010 17:15   





Back to top
   
michalko12
Poziom 22
Poziom 22


Joined: 20 Nov 2004
Posts: 1551
Location: Gdzieś koło wawy

Post#26 21 Mar 2010 17:39   

Re: Atmega8 i zmienne float - problemy


Nie wiem co kombinujesz z diodą i jak masz ją podłączoną. Bez dodatkowych wzmacniaczy nie obejdzie się, a w tym kodzie co podesłałeś był mały błąd. To co poniżej powinno wystarczyć.


Code:
int main(void)
{
  port_init();
  adc_init();
  led_init();
  sei();

  while(1)
  {
    _delay_ms(100);

    temp_current = pomiar;
    temp_wysw = temp_current;
   
      temp_sto = (temp_wysw / 100) % 10;
      temp_dzi = (temp_wysw % 100) / 10;    // temp_dzi = (temp_wysw / 10) % 10;
      temp_jed = temp_wysw % 10;

  }
}

Właśnie zauważyłem schemat, zbyt dobrej rozdzielczości to ty nie uzyskasz przy takim podłączeniu. W każdym bądź razie takie liczby powinny wyświetlać się w zależności od napięcia, nie biorąc pod uwagę błędów konwersji i odchyłki napięcia referencyjnego .

Code:
U(V)      ADC
----------------
0,65       260
0,655      262
0,66       264
0,665      266
0,67       268
0,675      270
0,68       272
0,685      274
0,69       276


i jeszcze jedno, zmień to na wyrównanie do prawej
Quote:
ADMUX |= _BV(ADLAR); //wybór sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)

Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#27 Post from the author of the topic 21 Mar 2010 18:15   

Re: Atmega8 i zmienne float - problemy


Zakładając, że mamy do czynienia z liczba 4-cyfrową to ten kod by wystarczył, ale ja spodziewam się trzycyfrowej.

Swoją drogą dla liczby 4-cyfrowej obie wersje kodu są chyba poprawne np:
1724
temp_dzi = (temp_wysw % 100) / 10;
1724 %100 = 24, 24 / 10 = "2"
temp_dzi = (temp_wysw / 10) % 10;
1724 /10 = 172, 172 %10 - "2"

Sprawa podanych przez Ciebie spodziewanych wyników jest jak najbardziej słuszna, ale jak już podałem na wyświetlaczu widać co innego i z tym nie bardzo mogę sobie poradzić.

A dlaczego do prawej.
W takim razie nie będę mógł odczytać całego rejestru (chyba).
Back to top
   
michalko12
Poziom 22
Poziom 22


Joined: 20 Nov 2004
Posts: 1551
Location: Gdzieś koło wawy

Post#28 21 Mar 2010 18:44helpful post - solution   

Re: Atmega8 i zmienne float - problemy


krzysztofh wrote:
Zakładając, że mamy do czynienia z liczba 4-cyfrową to ten kod by wystarczył, ale ja spodziewam się trzycyfrowej.

Swoją drogą dla liczby 4-cyfrowej obie wersje kodu są chyba poprawne np:
1724
temp_dzi = (temp_wysw % 100) / 10;
1724 %100 = 24, 24 / 10 = "2"
temp_dzi = (temp_wysw / 10) % 10;
1724 /10 = 172, 172 %10 - "2"

Sprawa podanych przez Ciebie spodziewanych wyników jest jak najbardziej słuszna, ale jak już podałem na wyświetlaczu widać co innego i z tym nie bardzo mogę sobie poradzić.

A dlaczego do prawej.
W takim razie nie będę mógł odczytać całego rejestru (chyba).


A co to ma do odczytu rejestru? ADCW to odczyt 16 bitowy niezależnie od tego czy wynik jest dosunięty do prawej czy lewej.
Wynik 260 dosunięty do prawej to 260, a do lewej to 16640
Back to top
   
krzysztofh
Poziom 19
Poziom 19


Joined: 07 Nov 2003
Posts: 630
Location: Warszawa

Post#29 Post from the author of the topic 21 Mar 2010 18:47   

Re: Atmega8 i zmienne float - problemy


Po zmianie tego bitu pojawiły się oczekiwane liczby. Prawie oczekiwane bo obarczone błędem konwersji i odchyłki napięcia referencyjnego, ale to już detal. Mam nadzieję że dalej sobie poradzę.

Wielkie dzięki michalko12, bardzo mi pomogłeś.
Back to top
   
Post new topic  Reply to topic      Main Page -> Forum Index -> Microcontrollers Generally -> AVR Microcontrollers -> Atmega8 i zmienne float - problemy
Page 1 of 1
Similar topics
2 problemy:zmienne, funkcje, klasy (4)
Float na string. Vector <float> tabela. Wyświetlają się śmieci. (2)
ATmega8 - zmienne i ich dzielenie (15)
atmega8 i zmienne volatile (2)
Konwersja char* -> float - problem [avr/atmega8][c/winavr (9)
[atmega8] [c++] konwersja float-->char[] (1)
[C++] int w int i float we float - błąd w kodzie (14)
Problemy z Atmega8 (4)
ATmega8 - drobne problemy (13)
ATmega8 problemy z LCD (7)

Page generation time: 0.168 seconds


FAQ || Administrator || Moderators || Widgets and banners || Contact
elektroda.pl topic RSS feed