logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[tiny26][c]problem z czytaniem i porownywaniem tablic

markli 20 Sie 2009 09:35 2253 6
REKLAMA
  • #1 6912348
    markli
    Poziom 2  
    Próbuję przepisać program który kiedyś napisałem w asemblerze na C. Program to prosty woltomierz - pomiar przez przetwornik a/c, następnie porównanie zmierzonego napięcia z pierwszą tablicą 16 bitową w której są umieszczone przedziały napięć a następnie odczytanie z drugiej liczby kroków odpowiadającej pomiarowi, która ma być wysłana do funkcji sterującej ruchem silnika krokowego. Tablica ma być czytana dotąd az zmienna odczytana z tablicy nie będzie większa lub równa zmierzonemu napięciu. Symulowałem ten kod w AVRStudio i przy czytaniu z tablicy, gdy wartość napięcia jest większa od zera, program nie wychodzi z pętli do - while. Ktoś może wskazać co jest nie tak? Dodam że testowałem różne warunki i różne kombinacje przy while i za każdym razem program nie wychodził z tej pętli.

    //wlaczone pliki
    #include<avr\io.h>
    #include<inttypes.h>
    #include<util\delay.h>
    #include<avr\signal.h>
    #include <avr\interrupt.h>
    #include<avr\pgmspace.h>
    ///definicje wyprowadzen
    
    #define LED 1
    #define Reset 4
    #define Kierunek 6
    #define ClockDriver 5
    #define F_CPU 1000000
    ////////////////////////////
    
    /////tablice i zmienne ktore mozna zmieniac
    
    prog_uint16_t g_TablicaPomiar[62] = {61, 133, 141, 149, 157, 163, 172, 180, 188, 196, 204, 212, 219, 227, 235, 243,
    									251, 260, 268, 276, 282, 290, 299, 307, 315, 323, 331, 337, 346, 354, 362, 370,
    									378, 387, 393, 401, 409, 417, 425, 434, 442, 450, 456, 497, 1023, 1023, 1023,
    									1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
    									1023, 1023};
    prog_uint16_t g_TablicaKrokow[62] = {0, 300, 660, 732, 804, 876, 948, 1020, 1092, 1164, 1236, 1308, 1380, 1452, 1524,
    									1596, 1668, 1740, 1812, 1884, 1956, 2028, 2100, 2172, 2244, 2316, 2460, 2532, 
    									2604, 2676, 2748, 2820, 2892, 2964, 3036, 3108, 3180, 3252, 3324, 3396, 3468,
    									3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540,
    									3540, 3540, 3540, 3540, 3540, 3540, 3540};
    
    
    //////zmienne ktorych nie mozna zmieniac
    
    uint16_t g_Pomiar=0;
    uint16_t g_PomiarTablica;
    uint16_t	g_WskaznikTablicy=0;
    uint16_t g_KrokiTablica = 0;
    
    
    
    
    /////////program///////////////
    int main(void)
    {
    	for(;;)
    	{
    		//////pomiar
    		ADCSR |=(1<<ADEN);	//wlaczenie pzetwornika
    		ADCSR |=(1<<ADSC);	//wlaczenie konwersji
    		
    		while(!(ADCSR & 1<<ADIF)){}
    		g_Pomiar = ADC;
    
    		//////koniec pomiaru
    		g_WskaznikTablicy=0;
    		/////poczatek porownania
    		do
    		{
    			g_PomiarTablica &= pgm_read_word (&g_TablicaPomiar[g_WskaznikTablicy]);	
    			g_WskaznikTablicy++;
    		}
    	
    		while(g_PomiarTablica<g_Pomiar);
    		g_KrokiTablica &=pgm_read_word(&g_TablicaKrokow[g_WskaznikTablicy]);
    	}
    	return 0;
    }
    
  • REKLAMA
  • REKLAMA
  • #3 6912642
    tmf
    VIP Zasłużony dla elektroda
    Jeszcze tylko przy okazji dodam, ze zapomniales ustawic w rejestrze ADMUX numer kanalu ADC i zrodlo referencyjne. Oczywiscie mozna przyjac wartosci defaultowe jakie sa po resecie, tylko czy na pewno tego chcesz?
  • REKLAMA
  • #4 6912734
    markli
    Poziom 2  
    Dzięki za podpowiedź - teraz już działa. Błąd spowodowało bezmyślne skopiowanie polecenia czytania z tablicy z jakiegoś kursu C.
    Co do ustawienie tych bitów w rejestrze a/c to nie muszę ich ustawiać ponieważ przetwornik chodzi na ustawieniach standardowych - bodajże kanał 0 i referencja zewnętrzna.
  • REKLAMA
  • #5 6915240
    markli
    Poziom 2  
    No i połączyłem to z resztą kodu i nie działa. W przerwaniu jest sterownie ruchem wskazówki - w zależności od stosunku zmiennych g_KrokiSilnika i g_KrokiZTablicy silnik krokowy porusza się do przodu lub do tyłu lub stoi w miejscu. Jeżeli deklaruję zmienną g_KrokiSilnika ręcznie silnik porusza się odpowiednią stronę i zatrzymuje się w odpowiednim miejscu (pomiar z a/c i czytanie z pamięci wyłączone). Jeżeli zostawiam włączony ten fragment kodu to silnik stoi w miejscu przy zmianach napięcia. Może ktoś rzucić okiem jeszcze na ten kod?
    //wlaczone pliki
    #include<avr\io.h>
    #include<inttypes.h>
    #include<util\delay.h>
    #include <avr\interrupt.h>
    #include<avr\pgmspace.h>
    ///definicje wyprowadzen
    
    #define LED 1
    #define Reset 4
    #define Kierunek 6
    #define ClockDriver 5
    
    ////////////////////////////
    
    /////tablice i zmienne ktore mozna zmieniac
    
    prog_uint16_t g_TablicaPomiar[62] = {61, 133, 141, 149, 157, 163, 172, 180, 188, 196, 204, 212, 219, 227, 235, 243,
    									251, 260, 268, 276, 282, 290, 299, 307, 315, 323, 331, 337, 346, 354, 362, 370,
    									378, 387, 393, 401, 409, 417, 425, 434, 442, 450, 456, 497, 1023, 1023, 1023,
    									1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
    									1023, 1023};
    prog_uint16_t g_TablicaKrokow[62] = {0, 300, 660, 732, 804, 876, 948, 1020, 1092, 1164, 1236, 1308, 1380, 1452, 1524,
    									1596, 1668, 1740, 1812, 1884, 1956, 2028, 2100, 2172, 2244, 2316, 2460, 2532, 
    									2604, 2676, 2748, 2820, 2892, 2964, 3036, 3108, 3180, 3252, 3324, 3396, 3468,
    									3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540, 3540,
    									3540, 3540, 3540, 3540, 3540, 3540, 3540};
    
    #define ZakresRuchuReset1	3744	//wartosc do 3700
    #define PreskalerReset1		0x003f //wartosc 16 bitowa	ruch szybki
    #define ZakresRuchuReset2 	200   //
    #define PreskalerReset2		0x01ff	//wartosc 16 bitowa ruch wolny
    
    #define PoczatkowaPozycja 	200	//pozycja poczatkowa
    #define PreskalerReset3		0x01ff	//wartosc 16 bitowa ruch do przodu zaraz po resecie
    
    #define zliczanie 128	//zlicznie od 0 do 255
    
    //////zmienne ktorych nie mozna zmieniac
    
    uint16_t g_Pomiar=400;
    uint16_t g_PomiarTablica;
    uint16_t g_WskaznikTablicy=0;
    uint16_t g_KrokiZTablicy=0;
    volatile uint16_t g_KrokiSilnika = PoczatkowaPozycja;
    volatile uint8_t g_ZmianaKroku	= 1;
    
    
    /////////program///////////////
    int main(void)
    {
    	//inicjacja portow
    	DDRB = 0x22;
    	DDRA = 0xfe;
    	PORTA |=(1<<Reset);	//jedynka na reset
    	PORTA &= ~(1<<Kierunek);	//0 na kierunek - do przodu
    	PORTA &= ~(1<<ClockDriver); //0 na clock	
    
    	//reset wyswietlacza
    	PORTB |=(1<<LED);	//LED_ON
    
    	/////// petla resetu /////
    	//najpierw w tyl//
    	PORTA |=(1<<Kierunek);	//1 na kierunek - do tylu
    	
    	///szybki ruch
    	for(uint16_t ResetRuch1 = 0; ResetRuch1<ZakresRuchuReset1; ResetRuch1++)
    	{
    		PORTA |=(1<<ClockDriver);	//LED_ON	
    		_delay_loop_2(PreskalerReset1);	//petla opoznienia
    		PORTA &= ~(1<<ClockDriver);
    		_delay_loop_2(PreskalerReset1);	//petla opoznienia
    	}
    	//wolny ruch zeby wskazowka sie nie odbijala
    	for (uint16_t ResetRuch2 = 0; ResetRuch2<ZakresRuchuReset2; ResetRuch2++)
    	{
    		PORTA |=(1<<ClockDriver);	//LED_ON	
    		_delay_loop_2(PreskalerReset2);	//petla opoznienia
    		PORTA &= ~(1<<ClockDriver);
    		_delay_loop_2(PreskalerReset2);	//petla opoznienia
    	}
    	
    	////teraz do przodu//
    	PORTA &= ~(1<<Kierunek);	//0 na kierunek - do przodu
    	for (uint16_t ResetRuch3 = 0; ResetRuch3<PoczatkowaPozycja; ResetRuch3++)
    	{
    		PORTA |=(1<<ClockDriver);	//LED_ON	
    		_delay_loop_2(PreskalerReset3);	//petla opoznienia
    		PORTA &= ~(1<<ClockDriver);
    		_delay_loop_2(PreskalerReset3);	//petla opoznienia
    	}
    
    
    	PORTB &= ~(1<<LED);	//LED_OFF
    
    /////koniec resetu
    /////inicjacja timera
    		TCCR0 |=1<<CS00;	//preskaler na 1
    		TIMSK |=1<<TOIE0;	//wlaczenie przerwan
    		TCNT0 = zliczanie;	//wpisanie od ilu ma liczyc
    		sei(); 
    
    	for(;;)
    	{
    	//////pomiar
    		ADCSR |=(1<<ADEN);	//wlaczenie pzetwornika
    		ADCSR |=(1<<ADSC);	//wlaczenie konwersji
    		
    		while(!(ADCSR & 1<<ADIF));
    		g_Pomiar = ADC;
    
    		//////koniec pomiaru
    		g_WskaznikTablicy=0;
    		/////poczatek porownania
    		do
    		{
    			g_PomiarTablica = pgm_read_word(&g_TablicaPomiar[g_WskaznikTablicy]);	
    			g_WskaznikTablicy++;
    		}
    		while(g_PomiarTablica<g_Pomiar);
    		g_KrokiZTablicy = pgm_read_word(&g_TablicaKrokow[g_WskaznikTablicy]);	
    		_delay_loop_2(0x000f);
    
    	}
    	return 0;
    }
    
    /////przerwanie/////
    SIGNAL(TIMER0_OVF0_vect)
    {
    
    if(g_KrokiSilnika!=g_KrokiZTablicy)
    {	if(g_ZmianaKroku==0)	//jezeli 0 to na Clock Driver na jedynke i ruch
    	{	
    		//jesli pozycja jest mniejsza 
    		if(g_KrokiSilnika<g_KrokiZTablicy)
    		{
    			//silnik do przodu
    			PORTA &= ~(1<<Kierunek);	//0 na kierunek - do przodu
    			g_KrokiSilnika++;
    
    		}
    		if(g_KrokiSilnika>g_KrokiZTablicy)
    		{
    			//silnik do tylu
    			PORTA |=(1<<Kierunek);	//1 na kierunek - do tylu
    			g_KrokiSilnika--;
    		}
    		PORTA |=(1<<ClockDriver);	//na 1 
    	}
    	if(g_ZmianaKroku==1)	//jezeli 1 to Clockdriver na 0 i ruch
    	{
    		PORTA &= ~(1<<ClockDriver);	//na 0
    	}
    	g_ZmianaKroku++;
    	if(g_ZmianaKroku>1)
    		g_ZmianaKroku=0;
    }
    TCNT0 = zliczanie;	//wpisanie od ilu ma liczyc
    }
    
    
  • #6 6915382
    Freddie Chopin
    Specjalista - Mikrokontrolery
    g_KrokiZTablicy powinno być zadeklarowane jako volatile. Dwie zmienne ktore juz masz jako volatile wcale takie nie musza byc.

    slowko volatile potrzebne jest do zmiennych ktore sa WSPOLDZIELONE. Jesli jakies zmienne sa tylko do przerwania, to nie musza byc volatile, co wiecej - moga byc zmiennymi statycznymi wewnatrz funkcji przerwania.

    A tak w ogole:

    g_ZmianaKroku++; 
       if(g_ZmianaKroku>1) 
          g_ZmianaKroku=0;


    mozna skompresowac do jednej linijki:

    g_ZmianaKroku ^= 1;

    4\/3!!
  • #7 6916187
    tmf
    VIP Zasłużony dla elektroda
    Jeszcze dodalbym, ze poniewaz np. g_KrokiZTablicy sa zadeklarowane jako uint16_t i sa volatile i porownywane w przerwaniu to ich modyfikacje w glownej petli nalezy wykonac z zablokowanymi przerwaniami - np. za pomoca macro ATOMIC_BLOCK. Przerwanie moze wystapic pomiedzy operacjami zmiany tej zmiennej, zmieniony bedzie tylko jeden bajt i w przerwaniu wystapi kaszana.
    Poza tym niepotrzebnie niektore zmienne sa zadeklarowane jako 2 bajtowe, te wskazniki do tablic spokojnie moga byc jako uint8_t.
REKLAMA