Skocz do zawartości

Zwieszanie się atmegi8 , przy ifach


Pomocna odpowiedź

Napisano

Witam wszystkich, to mój pierwszy post na forum.

Mam pewien problem, mój zestaw to atmega8 + czujnik nacisku + wyświetlacz.

Chciałbym go zaprogramować tak, aby na wyświetlaczy pokazywała się siła nacisku, czujnik ma wyjście rezystancyjne, korzystając z charakterystyki wyznaczyłem wzory opisujące siłę, dla trzech interesujących mnie przedziałów rezystancji. Zaznaczam od razu że pomiar rezystancji i jej wyświetlanie na wyświetlaczu działa poprawnie. Problem pojawia się, gdy chcę przekształcić rezystancję w siłę, korzystając z wyznaczonych wzorów.

Fragment kodu:

R=((VREF*10-adc*10)/adc);


if(R>=20)
	F=((-0.043)*R)+21.3;
else if(R<20 && R>=10)
	F=((-1.5)*R)+64.78;
else if(R<10)
	F=((-12.5)*R)+175;

Atmega zawiesza się , lub przestaje działać w momencie dodania tego kodu, tzn. na wyświetlaczu nie chcą się wyświetlać żadne wartości, cały czas są same zera, bez ifów samo R jest obliczane i wyświetlane prawidłowo, więc podejrzewam że problem jest z ifami, tylko nie wiem o co może chodzić.

Może ktoś ma jakiś pomysł .

Pozdrawiam

rozumiem że mógłbym wykraczać po za zakres, ale R ( liczone bez względu na zakres) które bez tych ifów wyświetla się normalnie po dodaniu ich również przestaje się wyświetlać. stąd moja myśl że coś się zwiesza, no ale spróbuje z tym elsem jeszcze.

edit. sprawdziłem i ten else na końcu niczego nie zmienia .

A próbowałeś uprościć i dać samego if'a, bez else'ów?

Ciężko uwierzyć, że taki kawałek mógłby coś zepsuć. No chyba, że F przyjmuje jakąś kosmiczną wartość i to ma wpływ na działanie uC. Aczkolwiek wątpię.

@UP

Jest część z mnożeniem *R, ale jest też część dodająca stałą wartość. Więc coś będzie i tak.

R na pewno nigdy nie przyjmuje wartości zera, bo im mniejszy nacisk tym większe R.

Bez elsów, samymi ifami również próbowałem, ale niczego to nie zmienia.

Teraz tak się zastanawiam, może wychodzą za duże liczby po przecinku, a atmega nie jest w stanie ich przetworzyć.

Czasami zdarza się tak że przez chwilę wszystko działa okej a dopiero później następuje zwieszenie, więc mój drugi pomysł to może jakiś bufor się zapycha czy coś.

Nie wiem nie znam się na uC , to mój pierwszy projekt i nie mogę tego ogarnąć .

Może wykraczasz jednak poza zakres?

Dodaj na końcu samo else, dla wszystkich innych przypadków.

Podane warunki obejmują dowolną wartość R. Nawet gdyby było poza zakresem, to po prostu F nie byłoby zdefiniowane.
Inna sprawa to czy R może przyjąć wartość 0 i co się wtedy stanie ?
Stałoby się to, że zaistnieje warunek (R<10).

kuba3d6, zapodaj deklaracją zmiennych, wykorzystaniem F oraz okolicznym kodem (jak nie jest długi, to całym).

okej wstawiam cały kod, wykorzystałem już istniejący z bloga gdzie było pokazana jak wykorzystać adc, trochę go przerobiłem na swoje potrzeby :

//Pomiar napięcia przetwornikiem A/C i prezentacja wyniku na LCD 2x16 HD44780  
#include <avr/io.h>  
#include <util/delay.h>  
#include <stdio.h>
#include <avr/interrupt.h>     
#include "HD44780.h"  



//definicja napiecia referencyjnego  
#define VREF 5.05  
//definicja ADCIN (wejście ADC)  
#define ADCIN PC5   

volatile double adc;//zmienna do obliczeń napięcia  
volatile double F;
volatile double R;

int main(void)  
{  
  char wynik[]="           ";//bufor tekstowy, wyczyszczenie bufora  
  char sila[]="           ";

  LCD_Initalize();   //inicjalizacja LCD  

  //Inicjalizacja ADC  
  ADCSRA = (1<<ADEN) //włączenie ADC  
           |(1<<ADFR) //włączenie trybu Free run  
           |(1<<ADIE) //uruchomienie zgłaszania przerwań  
           |(1<<ADSC) //rozpoczęcie konwersji  
           |(1<<ADPS0)   //ADPS2:0: ustawienie preskalera na 128  
           |(1<<ADPS1)  
           |(1<<ADPS2);  


  ADMUX  =    (1<<REFS0) //VCC jako napięcie referencyjne  
           |(1<<MUX2) | (1<<MUX0); //wybór kanału pomiarowego ADC5  

  DDRC &=~ (1<<ADCIN); //ustawienie wejścia ADC  

  sei(); //Globalne uruchomienie przerwań   

 while(1)
 {  
	sprintf(wynik,"R=%1.3f [kOm]",R);   //konwersja na łańcuch znakowy       
	LCD_GoTo(0, 0);         //Ustawienie kursora w pozycji (1,1)  
	LCD_WriteText(wynik);   //Wyświetlenie wyniku 
	sprintf(sila,"F=%1.3f [g]",F);  //konwersja na łańcuch znakowy       
	LCD_GoTo(0, 1);         //Ustawienie kursora w pozycji (1,1)  
	LCD_WriteText(sila);
	_delay_ms(500);  //opóźnienie  
	LCD_Clear();
 }  
}  



ISR(ADC_vect)//obsługa przerwania po zakończeniu konwersji ADC  
{  
 adc=ADC*VREF/1024;      //przeliczenie wartości na napięcie 
 R=((VREF*10-adc*10)/adc);
F=((-0.043)*R)+21.3;

if(R>=20)
	F=((-0.043)*R)+21.3;
if(R<20 && R>=10)
	F=((-1.5)*R)+64.78;
if(R<10)
	F=((-12.5)*R)+175;


}  

Po dopasowaniu kodu do megi32, na której mam płytkę testową, kod się nie zawiesza, ale na wyświetlaczu obie wartości mam jako "?".

Nie widzę powodu, dla których te ify miałyby zawieszać program.

a masz coś podpięte pod wejście przetwornika a/c ? w mnie wszystko działa normalnie do czasu aż dodam w programie te ify, więc to chyba musi być ich wina.

Ok, sprawdziłem. Rzeczywiście, u mnie też się wiesza. Na to wygląda, że przerwanie wykonuje się za długo.

Zmieniłem to na taki kod:

double adc;
double F;
double R;
volatile uint16_t vADC;
//(...)
while(1) {

adc=vADC*VREF/1024;      //przeliczenie wartości na napięcie
R=((VREF*10-adc*10)/adc);
//	F=((-0.043)*R)+21.3;//tfu, to zbędne przecież, poniżej liczymy to samo

if(R>=20)
	F=((-0.043)*R)+21.3;
if(R<20 && R>=10)
	F=((-1.5)*R)+64.78;
if(R<10)
	F=((-12.5)*R)+175;
}
//(...)
ISR(ADC_vect) {
vADC = ADC;
}

I śmiga. Czyli przerwanie trwa parę taktów, a obliczenia robisz w pętli głównej.

Pamiętaj, że AVRy nie mają koprocesora, więc operacje na liczbach zmiennoprzecinkowych robione są software'owo co znaacznie wydłuża te obliczenia. Może uda Ci się wykorzystać tablicowanie i operacje na liczbach całkowitych.

  • Lubię! 1

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...