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

[Atmega32][C]monitorowanie solara i sterowanie obw.230V

margas4542 07 Wrz 2010 23:31 7021 45
  • #1 8487388
    margas4542
    Poziom 16  
    ..jest to projekt monitorowania ogniwa foto-galwanicznego z zasilaniem rezerwowym (przetwornica ~230/17V). Ładowanie akumulatora w trybie automatycznym a gdy za mało słońca [ustawione napięcia progowe akumulatora] załączającym rezerwowy prostownik[przetwornica 230V/17V]. Całość zasila obwody niskonapięciowe oświetlenia LED oraz żarówek energooszczędnych na 12V[FOCOS]. Manualne sterowanie 10 obwodami sieciowymi [220V][tablica z niezależnymi obwodami gniazd 230V] poprzez optotriaki.
    Założenia programowe;
    1 - pomiar dwu napięć akumulator i solar
    2 - pomiar prądu ładowania i rozładowania
    3 - pomiar napięcia wyjściowego
    4 - napięcie akumulatora 11V załącz prostownik jeżeli solar daje mniej niż 13V
    5 - napięcie akumulatora 14V wyłącz prostownik - napięcie solara nieistotne
    6 - klawisz w lewo przesuwany w lewo kursor na LCD wiersz 4
    7 - klawisz w prawo przesuwany wprawo kursor na LCD wiersz 4
    8 - klawisz return załącz kanał jeżeli wyłączony lub odwrotnie.
    Schemat;
    [img]
    [Atmega32][C]monitorowanie solara i sterowanie obw.230V [/img]
  • #3 8487413
    margas4542
    Poziom 16  
    ....problemy...to złożony programowo projekt z którym uporać się nie potrafię dlatego wrzuciłem go na forum aby go oceniono i zasugerowano może nawet lepsze rozwiązania niż w przedstawionych założeniach...
  • #4 8487432
    Karol966
    Poziom 31  
    Generalnie nie widzę tu problemów ale zastanawia mnie:

    3 - pomiar napięcia wyjściowego (skąd?) ile łącznie będzie mierzonych zmiennych?
    6 - klawisz w lewo przesuwany w lewo kursor na LCD wiersz 4( taki bajer?)
    7 - klawisz w prawo przesuwany wprawo kursor na LCD wiersz 4( jak wyżej)
    8 - klawisz return załącz kanał jeżeli wyłączony lub odwrotnie. (nie rozumiem tego:P )
  • #5 8487478
    margas4542
    Poziom 16  
    ...wyjściowego z regulatora na odbiorniki [LED żarówki]....mam LCD 4x20 JM204A czterowierszowy i w tym czwartym wierszu ma się za sprawą klawiszy lewo - prawo przesuwać kursor nad numerami kanałów wyświetlanych w wierszu trzecim..po wybraniu kanału klawiszem enter zatwierdzam wybór zmieniając aktualny stan danego wyjścia multiplexera oraz znak na LCD informujący o aktualnym stanie..
  • #6 8489098
    margas4542
    Poziom 16  
    ....mały kłopot z funkcja wykluczająca działanie portu byłbym wdzięczny za sugestie jak ją mądrze sformułować...to ta pomiędzy liniami z gwiazdek...
    
    //------------------------------------------
    //########## A T A M E G A  -  32 ##########
    //------------------------------------------ 
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    //-----
    #define OUT_1         (0x0B + 0xD0) //znak kanał załączony
    #define OUT_0         (0x0A + 0x20) //znak kanał wyłączony
    #define DEVICE_ON     (0x0B + 0x20) //znak załączenia ładowanie
    #define DEVICE_OFF    (0x0D + 0x20) //znak wyłączenia ładowania
    //-----
    volatile uint16_t aku_v;
    volatile uint16_t aku_i;
    volatile uint16_t aku_v_min;
    volatile uint16_t aku_v_max;
    volatile uint16_t solar_v;
    volatile uint16_t solar_i;
    volatile uint16_t solar_v_stat;
    volatile uint16_t pomiar[4] __attribute__((section(".noinit")));
    void inline SetAdcKanal(unsigned char kanal)
    {
     ADMUX = ((ADMUX&0xE0)+ kanal);
    }
    //-----
    int main()
    {
     DDRB=0x1F;
     PORTB=0xE0;
    //----- ADC init
     ADMUX = _BV(REFS0)|_BV(REFS1);
     ADCSRA = _BV(ADEN)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2);             
    //----- LCD init
     LCD_Initalize(); 
     _delay_ms(200);
     LCD_GoTo(0,0);
     LCD_WriteText("                    ");// to jest szybciej od LCD_Clear
     char buffer_n[8];
     uint8_t i;
     while(1)
     {
    //-----pomiary na 4 kanalach
      for(i = 0; i<4; i++){
      SetAdcKanal(i);
      ADCSRA |= (1 << ADSC);
      while(ADCSRA & (1 << ADSC));
      pomiar[i] = ADC;
     }
    //-----
     {
      char aku_v_min=11.00;
      char aku_v_max=14.00;
      char solar_v_min=14.00;
      aku_v = pomiar[0]/41.4;
      aku_i = pomiar[1]/41.4;
      solar_v = pomiar[2]/41.4;
      solar_i = pomiar[3]/41.4;		//
    //**************************************************
      if (aku_v <= aku_v_min)		//załącz zasilacz jeżeli napięcie akumulatora poniżej 11V 
      if (solar_v <= solar_v_stat)	//ale solar ma również poniżej 14V
      PORTB |= _BV(4);				
      if(aku_v >= aku_v_max)		//jeżeli zasilacz załączony to jeżeli solar ma powyżej 13V
      if(solar_v >= solar_v_stat)	//lub akumulator 14V należy go wyłączyć.
      PORTB &=~ _BV(4);						
     }
    //***************************************************
    //-----selektor kanałów
     {
      
     }
    //-----LCD pierwszy wiersz pomiar 1
     {
      LCD_GoTo(0,0);
      LCD_WriteText("AKUM");
      LCD_GoTo(5,0);    
      LCD_WriteText(dtostrf(aku_v=aku_v,5,2,buffer_n));
      LCD_GoTo(10,0);
      LCD_WriteText("V");
    //------LCD pierwszy wiersz pomiar 2
      LCD_GoTo(12,0);
      LCD_WriteText(dtostrf(aku_i=aku_i,5,2,buffer_n));
      LCD_GoTo(17,0);
      LCD_WriteText("A");
      LCD_GoTo(19,0);
      LCD_WriteCommand(char*);  // <<<< wstawić odpowieni znak DEVICE_*
    //-----LCD drugi wiersz pomiar 3
      LCD_GoTo(0,1);
      LCD_WriteText("SOL");
      LCD_GoTo(5,1);    
      LCD_WriteText(dtostrf(solar_v=solar_v,5,2,buffer_n));
      LCD_GoTo(10,1);
      LCD_WriteText("V");
    //------LCD drugi wiersz pomiar4
      LCD_GoTo(12,1);
      LCD_WriteText(dtostrf(solar_i=solar_i,5,2,buffer_n));
      LCD_GoTo(17,1);
      LCD_WriteText("A");
      LCD_GoTo(17,1);
      LCD_WriteCommand(char*);  // <<<< wstawić odpowieni znak DEVICE_*
    //-----LCD trzeci wiersz
      LCD_GoTo(20,0);
      LCD_WriteText("0 1 2 3 4 5 6 7 8 9");
    //----LCD czwarty wiersz
      LCD_GoTo(20,1);
      LCD_WriteCommand(0x14);
      LCD_WriteText("*");
    
    //---------------------- 
     }      
    }
    return 0;
    } 
  • #7 8489500
    janbernat
    Poziom 38  
    
    if ((aku_v <= aku_v_min)&&(solar_v <= solar_v_stat))
     PORTB |= _BV(4); 
       //załącz zasilacz jeżeli napięcie akumulatora poniżej 11V
      //i solar ma również poniżej 14V
    

    itd.
    Masa analogowa MUSI być połączona z masą ogólną przy zasilaczu IC6.
    I tam też powinny być dołączone masy z dzielników.
    I powinny zasilania być odsprzężone przy procesorze kondensatorami 100nF.
    Pomiar prądu na LED nie ma wzmacniacza.
    A opisany jest jako pomiar napięcia na aku.
  • Pomocny post
    #8 8489523
    gaskoin
    Poziom 38  
    btw nie rozumiem po co zakładać dwa tematy...
  • #9 8489995
    margas4542
    Poziom 16  
    ...witam...wielkie podziękowania za cierpliwość i wyrozumiałość dla janbernad i gaskoin....to połączenie mas umknęło mojej uwadze kondensatory odprzęgające również dodałem....co do pomiaru prądu wyjściowego na obciążenia rezystor jest w plusie ponieważ na masie w regulatorze pomiędzy zaciskiem minusowym aku a zaciskiem minusowym wyjścia jest bezpiecznik który mógłbym zewrzeć i dać go w plusie na zewnątrz ale jest jeszcze gwarancja więc na razie zrobić tego nie mogę dlatego zamierzałem zrobić pomiar na zasadzie różnicy napięcie akumulatora a napięcie wyjściowego...schemat jest roboczy więc modyfikacje są dopuszczalne a dołożenie operacyjnych do pomiaru prądu wyjścia to żaden kłopot...więc chyba tak zrobię....
  • #10 8494280
    janbernat
    Poziom 38  
    A ja z uporem maniaka robię kod na przerwaniach:
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    //w Project->configuration option ustawiamy freqency 16000000
    
    #define LICZBA_KANALOW      4 //cztery kanały- tu można zwiększyć ilość kanałów 
    #define NAPIECIE_AKU_MIN	11.0
    #define NAPIECIE_AKU_MAX	14.0
    #define NAPIECIE_SOLAR_MIN  13.0
    #define START_LADOWANIE		PORTB&=~(1 << PORTB0); // clear PORTB0      
    #define STOP_LADOWANIE		PORTB|=(1<<PORTB0);	// set PORTB0
    volatile uint8_t flaga;
    volatile uint16_t napiecie[LICZBA_KANALOW] __attribute__((section(".noinit")));
    
    int main(void)	// tu jest początek main() i tu ustawiamy konfigurację rejestrów
    {   
    	void SetAdcKanal(void);
    	char buffer_nap[LICZBA_KANALOW];
    
        sei();
        DDRB=255;
        PORTB=255;
        TCCR1B=_BV(CS10)|_BV(CS11);//na przerwanie OVF1 co ok.1/4s przy 16 MHz- można zmienić
        ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
        ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
        SFIOR=_BV(ADTS1)|_BV(ADTS2);//ustawienie startu przetwarzania ADC po przerwaniu od OVF Timer1
    
        char *text="Problem z";
        char *text1="przerwaniami";
    
        LCD_Initalize();
        LCD_WriteText(text);
        LCD_GoTo(0,1);
        LCD_WriteText(text1);      
        _delay_ms(300);
        LCD_GoTo(0,0);
        LCD_WriteText("                ");// to jest szybciej niż LCD_Clear
    	LCD_GoTo(0,1);
    	LCD_WriteText("                ");
    
    	double napiecie_aku=0.0;
    	double napiecie_solar=0.0;
    	double napiecie2=0.0;
    	double napiecie3=0.0;
    
      while(1)			//A tu zaczyna się nieskończona pętla
    	{
    	if(flaga)		//Tu sprawdzamy flagę i dlatego ten
    					//fragment wykonuje się co 1/4s- bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER1
    		{			//Przez resztę czasu śpi.LCD też pokazuje co 1s.
    	    flaga=0;	// A tu flagę kasujemy- po 1/4s znowu się ustawi
    		SetAdcKanal();	
    
    		napiecie_aku=napiecie[0];	//NAPIECIE AKU
    	    LCD_GoTo(0,0);
    	    LCD_WriteText("      ");
    		LCD_GoTo(0,0);
    	    LCD_WriteText(dtostrf(napiecie_aku/=50.0,5,2,buffer_nap));// to zamiast utoa.Dzielenie przez 50.0 należy
    	    LCD_GoTo(5,0);											//dopasować do swoich potrzeb
    	    LCD_WriteText("V aku");
    
    		napiecie_solar=napiecie[1];	//NAPIECIE SOLAR
    		LCD_GoTo(0,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(0,1);
    		LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
    		LCD_GoTo(5,1);
    		LCD_WriteText("V solar");
    
    		napiecie2=napiecie[2];
    		LCD_GoTo(20,0);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,0);
    		LCD_WriteText(dtostrf(napiecie2/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,0);
    		LCD_WriteText("V solar1");
    
    		napiecie3=napiecie[3];
    		LCD_GoTo(20,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,1);
    		LCD_WriteText(dtostrf(napiecie3/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,1);
    		LCD_WriteText("V aku1");
    
    		}		//Tu się kończy ten fragment co się wykonuje co 1/4s
    				// a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością 
    
    		if((napiecie_aku<NAPIECIE_AKU_MIN)&&(napiecie_solar<NAPIECIE_SOLAR_MIN))
    			START_LADOWANIE	//ładowanie włączamy stanem niskim
    		if((napiecie_solar>=NAPIECIE_SOLAR_MIN)||(napiecie_aku>=NAPIECIE_AKU_MAX))
    			STOP_LADOWANIE	//a wyłączamy stanem wysokim
    		
    	}
    }
    
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer1 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę której stan sprawdzamy w main()
       flaga=1;
    TIFR |= (1 << TOV1); // a tu nie było przerwania od TIMER1- ale skasować flagę trzeba- no to kasujemy 
    }
    
    void SetAdcKanal(void)// a tu funkcja zmieniająca kanały
    {
    	static uint8_t kanal;	
    	ADMUX = ((ADMUX&0xE0)+ kanal);
    	napiecie[kanal]=ADC;
    	kanal++;	   
        if(kanal>LICZBA_KANALOW)		
    	kanal=0;  
    } 
    

    Mam tę radochę że działa.
    I chyba spełnia te warunki włączania/wyłączania zewnętrznej ładowarki.
    Chociaż te warunki mam wrażenie można by napisać bardziej elegancko.
    Może ktoś będzie miał jakiś pomysł.
  • #11 8494330
    gaskoin
    Poziom 38  
    prototypy funkcji poza mainem.
    Tablice można uzupełniać w przerwaniu


    
    		napiecie_solar=napiecie[1];	//NAPIECIE SOLAR
    		LCD_GoTo(0,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(0,1);
    		LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
    		LCD_GoTo(5,1);
    		LCD_WriteText("V solar");
    
    		napiecie2=napiecie[2];
    		LCD_GoTo(20,0);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,0);
    		LCD_WriteText(dtostrf(napiecie2/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,0);
    		LCD_WriteText("V solar1");
    
    		napiecie3=napiecie[3];
    		LCD_GoTo(20,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,1);
    		LCD_WriteText(dtostrf(napiecie3/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,1);
    		LCD_WriteText("V aku1");
    


    aż się prosi o pętle :)
  • #12 8494435
    janbernat
    Poziom 38  
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    //w Project->configuration option ustawiamy freqency 16000000
    
    #define LICZBA_KANALOW      4 //cztery kanały- tu można zwiększyć ilość kanałów 
    #define NAPIECIE_AKU_MIN	11.0
    #define NAPIECIE_AKU_MAX	14.0
    #define NAPIECIE_SOLAR_MIN  13.0
    #define START_LADOWANIE		PORTB&=~(1 << PORTB0); // clear PORTB0      
    #define STOP_LADOWANIE		PORTB|=(1<<PORTB0);	// set PORTB0
    volatile uint8_t flaga;
    volatile uint16_t napiecie[LICZBA_KANALOW] __attribute__((section(".noinit")));
    void SetAdcKanal(void);	/////////////////////////////////////Czy to jest prototyp?
    int main(void)	// tu jest początek main() i tu ustawiamy konfigurację rejestrów
    {   
    	void SetAdcKanal(void); ///////////////////////////////////czy to jest deklaracja?	
    	char buffer_nap[LICZBA_KANALOW];
    
        sei();
        DDRB=255;
        PORTB=255;
        TCCR1B=_BV(CS10)|_BV(CS11);//na przerwanie OVF1 co ok.1/4s przy 16 MHz- można zmienić
        ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
        ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
        SFIOR=_BV(ADTS1)|_BV(ADTS2);//ustawienie startu przetwarzania ADC po przerwaniu od OVF Timer1
    
        char *text="Problem z";
        char *text1="przerwaniami";
    
        LCD_Initalize();
        LCD_WriteText(text);
        LCD_GoTo(0,1);
        LCD_WriteText(text1);      
        _delay_ms(300);
        LCD_GoTo(0,0);
        LCD_WriteText("                ");// to jest szybciej niż LCD_Clear
    	LCD_GoTo(0,1);
    	LCD_WriteText("                ");
    
    	double napiecie_aku=0.0;
    	double napiecie_solar=0.0;
    	double napiecie2=0.0;
    	double napiecie3=0.0;
    
      while(1)			//A tu zaczyna się nieskończona pętla
    	{
    	if(flaga)		//Tu sprawdzamy flagę i dlatego ten
    					//fragment wykonuje się co 1/4s- bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER1
    		{			//Przez resztę czasu śpi.LCD też pokazuje co 1/4s.
    	    flaga=0;	// A tu flagę kasujemy- po 1/4s znowu się ustawi
    		SetAdcKanal();	
    
    		napiecie_aku=napiecie[0];	//NAPIECIE AKU
    	    LCD_GoTo(0,0);
    	    LCD_WriteText("      ");
    		LCD_GoTo(0,0);
    	    LCD_WriteText(dtostrf(napiecie_aku/=50.0,5,2,buffer_nap));// to zamiast utoa.Dzielenie przez 50.0 należy
    	    LCD_GoTo(5,0);											//dopasować do swoich potrzeb
    	    LCD_WriteText("V aku");
    
    		napiecie_solar=napiecie[1];	//NAPIECIE SOLAR
    		LCD_GoTo(0,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(0,1);
    		LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
    		LCD_GoTo(5,1);
    		LCD_WriteText("V solar");
    
    		napiecie2=napiecie[2];
    		LCD_GoTo(20,0);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,0);
    		LCD_WriteText(dtostrf(napiecie2/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,0);
    		LCD_WriteText("V solar1");
    
    		napiecie3=napiecie[3];
    		LCD_GoTo(20,1);
    		LCD_WriteText("      ");
    		LCD_GoTo(20,1);
    		LCD_WriteText(dtostrf(napiecie3/=50.0,5,2,buffer_nap));
    		LCD_GoTo(25,1);
    		LCD_WriteText("V aku1");
    
    		}		//Tu się kończy ten fragment co się wykonuje co 1/4s
    				// a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością 
    
    		if((napiecie_aku<NAPIECIE_AKU_MIN)&&(napiecie_solar<NAPIECIE_SOLAR_MIN))
    			START_LADOWANIE	//ładowanie włączamy stanem niskim
    		if((napiecie_solar>=NAPIECIE_SOLAR_MIN)||(napiecie_aku>=NAPIECIE_AKU_MAX))
    			STOP_LADOWANIE	//a wyłączamy stanem wysokim
    		
    	}
    }
    
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer1 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę której stan sprawdzamy w main()
       flaga=1;
    TIFR |= (1 << TOV1); // a tu nie było przerwania od TIMER1- ale skasować flagę trzeba- no to kasujemy 
    }
    
    void SetAdcKanal(void)///////////// a tu funkcja zmieniająca kanały- czy to jest definicja?
    {
    	static uint8_t kanal;	
    	ADMUX = ((ADMUX&0xE0)+ kanal);
    	napiecie[kanal]=ADC;
    	kanal++;	   
        if(kanal>LICZBA_KANALOW)		
    	kanal=0;  
    } 
    

    Dlaczego dodanie prototypu nic nie zmienia?
    A z tą pętlą- ja to zmieniam w przerwaniach->kolejny kanał-> co 1/4s.
    Jak dam pętlę- to zupełnie inna koncepcja- tak mi sie wydaje.
  • #13 8494512
    gaskoin
    Poziom 38  
    deklaracja funkcji a jej prototyp to jedno i to samo. Wywal tą linijkę z maina (Setadckanal(void));

    Jeżeli ciało używanej funkcji jest poniżej jej wywołania, to nad jej wywołaniem robi się prototyp.

    O pętlę to chodziło mi o to, że 4 razy w kółko robisz to samo. Niepotrzebnie tam są dwie tablice na napięcie, można wszystko przecież zrobić na tej samej tablicy do której wpisujesz dane wprost z przetwornika. Deklarując ją tylko jako double(czy właściwie tak naprawdę float).

    wtedy w pętli byś wrzucił coś takiego :

    
    napiecie[i] = napiecie[i]/50.0;
    LCD_GoTo(gdziestam);
    LCD_WriteText(zamiana na stringa);
    


    co staje się bardziej czytelne, no i krótsze

    w przerwaniu możesz zrobić coś takiego:

    
    flaga=1;
    TIFR |= (1 << TOV1);
    napiecie[wskaznik_tablicy] = ADC;
    if(++wskaznik_tablicy == LICZBA_KANALOW) wskaznik_tablicy = 0;
    
  • #14 8494623
    janbernat
    Poziom 38  
    Wywaliłem z main (Setadckanal(void));
    A wstawiłem przed main.
    Działa tak samo.
    Potem wstawiłem w main (Setadckanal(void));
    A wywaliłem przed main
    Działa tak samo.
    Napisałeś "deklaracja funkcji a jej prototyp to jedno i to samo."
    Ale czy na pewno jest to tak samo gdy zdeklaruję to wewnątrz jakiejś funkcji czy poza jakąkolwiek funkcją?
    A z tą pętlą to mnie męczyło- ale muszę to rozgryźć.
    No i jeszcze raz muszę przeczytać- czy napiecie[i] = napiecie[i]/50.0;
    da promotion czy demotion.
    Chyba że dasz sobie uciąć.
    P.s.
    To że ciało funkcji zdefiniowane za main wymaga deklaracji/prototypu to wiem.
    Ale nie wiem czy jest różnica gdzie to umieszczę- poza funkcjami czy wewnątrz jakiejś.
  • #15 8494641
    gaskoin
    Poziom 38  
    Cytat:
    No i jeszcze raz muszę przeczytać- czy napiecie[i] = napiecie[i]/50.0;
    da promotion czy demotion.


    nie za bardzo wiem o co Ci tutaj chodziło więc nic mi nie ucinaj.

    Cytat:
    Ale czy na pewno jest to tak samo gdy zdeklaruję to wewnątrz jakiejś funkcji czy poza jakąkolwiek funkcją?


    Funkcji raczej się nie deklaruje w innych funkcjach :)

    A działa tak samo, bo cóż mogło by się zmienić skoro to tylko deklaracja ?
  • #16 8495571
    margas4542
    Poziom 16  
    ..zweryfikowałem schemat...wywaliłem multiplexer bo 8 kanałów w zupełności mi wystarczy w tym kanały sterujące obwodami 220V i oświetleniem nocnym...a i program teraz będzie prostszy w realizacji...
    [img]
    [Atmega32][C]monitorowanie solara i sterowanie obw.230V [/img]
  • #17 8496294
    janbernat
    Poziom 38  
    margas- to po co Ci teraz to przesuwanie - miganie kursora?
    gaskoin- no własnie to " LCD_GoTo(gdziestam); " paskudzi pętlę.
    Za każdym razem inne.
  • #18 8496889
    margas4542
    Poziom 16  
    ...w tym momencie przesuwany kursor na LCD to byłby zwykły szpanerski "bajer" nie mający nic wspólnego z funkcjonalnością....dokładam jeszcze jeden klawisz i tymi czterema obwodami 220V steruje z klawiatury...dwa wejścia adc wykorzystałem jako sensory obecności napięcia sterujące oświetleniem zmierzchowym [adc5] i załączający wyświetlenie komunikatu o załączeniu ładowarki akumulatora[adc6]...zastanawiam się czy pozostałych dwu nie wykorzystać do sterowania wentylatorkiem z termistorem schładzającym radiator ładowarki..

    Dodano po 2 [godziny] 37 [minuty]:

    ....doniesienia z placu boju....tyle uruchomiłem ale mam kłopoty z podstawianiem wartości liczbowo tekstowych i wysłania tego na LCD ..opis w kodzie...
    
    //------------------------------------------
    //########## A T A M E G A  -  32 ##########
    //------------------------------------------ 
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    //-----
    volatile uint16_t aku_v;
    volatile uint16_t aku_v_min;
    volatile uint16_t aku_v_max;
    volatile uint16_t aku_i;
    volatile uint16_t sol_v;
    volatile uint16_t sol_i;
    volatile uint16_t stala;
    volatile uint16_t sensor;
    volatile uint16_t power;
    volatile uint16_t stat;
    int status[];
    volatile uint16_t pomiar[6] __attribute__((section(".noinit")));
    void inline SetAdcKanal(unsigned char kanal)
    {
     ADMUX = ((ADMUX&0xE0)+ kanal);
    }
    //-----
    int main()
    {
     DDRB=0xFF;
     DDRD=0x00;
     PORTD=0x0F;
    //----- ADC init
     ADMUX = _BV(REFS0)|_BV(REFS1)|_BV(ADLAR);
     ADCSRA = _BV(ADEN)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2);             
    //----- LCD init
     LCD_Initalize(); 
     _delay_ms(200);
     LCD_GoTo(0,0);
     LCD_WriteText("                    ");// to jest szybciej od LCD_Clear
     char buffer_n[8];
     uint8_t k;
     while(1)
     {
    //-----pomiary na 6 kanalach
      for(k = 0; k<6; k++)
      {
       SetAdcKanal(k);
       ADCSRA |= (1 << ADSC);
       while(ADCSRA & (1 << ADSC));
       pomiar[k] = ADCH<<2;		
       aku_v = pomiar[0]/40.0;	//ale coś namieszałem bo wyświetla
       aku_i = pomiar[1]/40.0;	//tylko dziesiątki volt,i tylko zera dziesiętne się
       sol_v = pomiar[2]/40.0;	//po przecinku wyświetlają bez zmian 0.1 0.2.?????
       sol_i = pomiar[3]/40.0;	//jak zrobić by po przecinku wyświtlała sie tylko jedna cyfra?
       sensor = pomiar[4]/40.0;	//wystarczy mi dokładność 0,1 Volta
       power = pomiar[5]/40.0;	
      }
    //-----progi przełaczania żródeł zasilania
      {
       char aku_v_min=11.0;
       char aku_v_max=14.0;
       char stala=13.0;
       char stat=10.0;
       if ((aku_v <= aku_v_min)||(sol_v <= stala))
       PORTB &=~_BV(0);		//jeżeli napięcie akumulatora poniżej 11V i napięcie
       						//solara jest poniżej 14V to załącz zasilacz 						
       if ((aku_v >= aku_v_max)||(sol_v >= stala))
       PORTB |= _BV(0);		//jeżeli napięcie akumulatora powyżej 14V lub napięcie solara 
    						//jest wyższe od 13V to wyłącz.zasilacz
    //--------------------oświetlenie nocne - to chodzi
       if (sensor >= stat)
       PORTB &=~ _BV(1);	//załącz 
       LCD_GoTo(20,0); 
       LCD_WriteText("          "); 
       LCD_WriteText("Dziennne");	// jak zmieniać tekst na LCD ????????
       if (sensor <= stat)
       PORTB |= _BV(1);		//wyłącz
       LCD_GoTo(20,0); 
       LCD_WriteText("          "); 
       LCD_WriteText("Nocne");
    //--------------------zasilacz  - to chodzi
       if (power >= stat)
       PORTB &=~ _BV(2);	//załączony
       LCD_GoTo(30,0); 
       LCD_WriteText("Zasilacz");	// jak zmieniać tekst na LCD ???????
       if (power <= stat)
       PORTB |= _BV(2);		//wyłączony 
       LCD_GoTo(30,0); 
       LCD_WriteText("Akumulator");
    //--------------------gniazda 230V kanały z podtrzymaniem - nad tym myślę
       
       if(!(PIND & 0x10))status[1];
       PORTB |= _BV(4);
       LCD_GoTo(20,1); LCD_WriteText("K1-");
    
       if(!(PIND & 0x20))status[2];
       PORTB |= _BV(5);
    
       if(!(PIND & 0x40))status[3];
       PORTB |= _BV(6);
       PORTB |= _BV(7);
       if(!(PIND & 0x80))status[4];
      }   
    //--------------------
     	
    //-----LCD pierwszy wiersz pomiar 1
     {
      LCD_GoTo(0,0);  LCD_WriteText("AKUM");
      LCD_GoTo(5,0);  LCD_WriteText(dtostrf(aku_v=aku_v,5,2,buffer_n));
      LCD_GoTo(10,0); LCD_WriteText("V");
    //------LCD pierwszy wiersz pomiar 2
      LCD_GoTo(12,0); LCD_WriteText(dtostrf(aku_i=aku_i,5,2,buffer_n));
      LCD_GoTo(17,0); LCD_WriteText("A");
      LCD_GoTo(19,0); LCD_WriteData();// znak jeżeli prąd ładowania jest więszy od poboru
    									//lub znak jeżeli pobór jest większy od prądu ładowania
    //-----LCD drugi wiersz pomiar 3
      LCD_GoTo(0,1);  LCD_WriteText("SOL");
      LCD_GoTo(5,1);  LCD_WriteText(dtostrf(sol_v=sol_v,5,2,buffer_n));
      LCD_GoTo(10,1); LCD_WriteText("V");
    //------LCD drugi wiersz pomiar4
      LCD_GoTo(12,1); LCD_WriteText(dtostrf(sol_i=sol_i,5,2,buffer_n));
      LCD_GoTo(17,1); LCD_WriteText("A");
      LCD_GoTo(19,1); LCD_WriteData();// znak jeżeli prąd ładowania jest więszy od poboru
    									//lub znak jeżeli pobór jest większy od prądu ładowania
    //-----LCD trzeci wiersz
    //  LCD_GoTo(20,0); LCD_WriteText("Dzienne");
    //  LCD_GoTo(25,0); LCD_WriteText("Nocne");
    
    //  LCD_GoTo(30,0); LCD_WriteText("Zasilacz");
    //  LCD_GoTo(35,0); LCD_WriteText("Akumulator");
    
    //----LCD czwarty wiersz 
      LCD_GoTo(20,1); LCD_WriteText("K1-");//(x) < znak KANAL_ON lub KANAL_OFF
      LCD_GoTo(25,1); LCD_WriteText("K2-");//(x) < znak KANAL_ON lub KANAL_OFF
      LCD_GoTo(30,1); LCD_WriteText("K3-");//(x) < znak KANAL_ON lub KANAL_OFF
      LCD_GoTo(35,1); LCD_WriteText("K4-");//(x) < znak KANAL_ON lub KANAL_OFF
    //---------------------- 
     }      
    }
    return 0;
    } 
  • #19 8499072
    gaskoin
    Poziom 38  
    Trzeba tak kombinować, żeby nie paskudziło kodu

    Przed:
    napiecie_aku=napiecie[0];   //NAPIECIE AKU
           LCD_GoTo(0,0);
           LCD_WriteText("      ");
          LCD_GoTo(0,0);
           LCD_WriteText(dtostrf(napiecie_aku/=50.0,5,2,buffer_nap));// to zamiast utoa.Dzielenie przez 50.0 należy
           LCD_GoTo(5,0);                                 //dopasować do swoich potrzeb
           LCD_WriteText("V aku");
    
          napiecie_solar=napiecie[1];   //NAPIECIE SOLAR
          LCD_GoTo(0,1);
          LCD_WriteText("      ");
          LCD_GoTo(0,1);
          LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
          LCD_GoTo(5,1);
          LCD_WriteText("V solar");
    
          napiecie2=napiecie[2];
          LCD_GoTo(20,0);
          LCD_WriteText("      ");
          LCD_GoTo(20,0);
          LCD_WriteText(dtostrf(napiecie2/=50.0,5,2,buffer_nap));
          LCD_GoTo(25,0);
          LCD_WriteText("V solar1");
    
          napiecie3=napiecie[3];
          LCD_GoTo(20,1);
          LCD_WriteText("      ");
          LCD_GoTo(20,1);
          LCD_WriteText(dtostrf(napiecie3/=50.0,5,2,buffer_nap));
          LCD_GoTo(25,1);
          LCD_WriteText("V aku1");
    
          }


    Po:

    Po pierwsze:
    
    LCD_GoTo(5,0);                                 //dopasować do swoich potrzeb
    LCD_WriteText("V aku"); 
    


    Po co Ci to w pętli, skoro przez cały program wpisujesz stałą wartość ? Wpisz to przed pętlą główną i już nie ruszaj tego, szkoda czasu procesora.

    
    for(i = 0; i < LICZBA_KANALOW; i++){
          if(i<2){
                LCD_GoTo(0,i);
                LCD_WriteText("      ");
                LCD_GoTo(0,i);
          } else{
                LCD_GoTo(20,i-2);
                LCD_WriteText("      ");
                LCD_GoTo(20,i-2);
          }
          
          LCD_WriteText(dtostrf(napiecie[i]/=50.0,5,2,buffer_nap));
    }
    
    



    Cytat:
    jak zmieniać tekst na LCD ????????


    No tu już trzeba pokombinować, zastąpić stary spacjami i napisać w jego miejsce nowy.
  • #20 8500522
    janbernat
    Poziom 38  
    Co zmieniłem:
    Do startu przetwarzania ADC zamiast TIMER1 wykorzystuję TIMER0- bo ten 16bitowy na coś może się jeszcze przydać.
    Dostawiłem wstępnie flaga_przycisk co 16ms.
    Może zwiększę do 32ms.
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    #include <avr/sfr_defs.h>
    //w Project->configuration option ustawiamy freqency 16000000
    
    #define LICZBA_KANALOW      4 //cztery kanały- tu można zwiększyć ilość kanałów 
    #define NAPIECIE_AKU_MIN	11.0
    #define NAPIECIE_AKU_MAX	14.0
    #define NAPIECIE_SOLAR_MIN  13.0
    #define START_LADOWANIE		PORTB&=~(1 << PORTB0); // clear PORTB0      
    #define STOP_LADOWANIE		PORTB|=(1<<PORTB0);	// set PORTB0
    
    volatile uint8_t flaga_pomiaru;
    volatile uint8_t flaga_przycisku;
    volatile uint16_t napiecie[LICZBA_KANALOW] __attribute__((section(".noinit")));
    
    
    void SetAdcKanal(void);	// prototyp
    uint8_t debounce(uint8_t button_state);
    int main(void)	// tu jest początek main() i tu ustawiamy konfigurację rejestrów
    
    {   
    	char buffer_nap[LICZBA_KANALOW];
    	char *text="Problem z";
        char *text1="przerwaniami";
    	double napiecie_aku=0.0;
    	double napiecie_solar=0.0;
    	double prad_aku=0.0;
    	double prad_solar=0.0;
    //	uint8_t i;	
    
        sei();
        DDRB=255;
        PORTB=255;
    	DDRC=0;
    	PORTC=255; 
     	TCCR0=_BV(CS00)|_BV(CS02);// TIMER0 przepełnia się co 16ms- szkoda TIMER1 na ustawianie flagi
    //    TCCR1B=_BV(CS10)|_BV(CS11);//na przerwanie OVF1 co ok.1/4s przy 16 MHz- można zmienić
        ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
        ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
    //    SFIOR=_BV(ADTS1)|_BV(ADTS2);//ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer1
    	SFIOR=_BV(ADTS2); // ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer0
        LCD_Initalize();
        LCD_WriteText(text);
        LCD_GoTo(0,1);
        LCD_WriteText(text1);      
        _delay_ms(300);
        LCD_GoTo(0,0);
        LCD_WriteText("                ");// to jest szybciej niż LCD_Clear
    	LCD_GoTo(0,1);
    	LCD_WriteText("                ");
    	LCD_GoTo(20,0);
    	LCD_WriteText("  1 2 3 4 5 6 7 8");
    	LCD_GoTo(5,0);											//dopasować do swoich potrzeb
    	LCD_WriteText("V");
    	LCD_GoTo(5,1);
    	LCD_WriteText("V");
    	LCD_GoTo(12,0);
    	LCD_WriteText("A aku");
    	LCD_GoTo(12,1);
    	LCD_WriteText("A solar");
    	LCD_GoTo(22,1);
    	LCD_WriteText("TO");
    
      while(1)			//A tu zaczyna się nieskończona pętla
    	{
    
    
    	if(flaga_pomiaru)		//Tu sprawdzamy flagę i dlatego ten
    					//fragment wykonuje się co 1/4s- bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER0
    		{			//Przez resztę czasu śpi.LCD też pokazuje co 1/4s.
    	    flaga_pomiaru=0;	// A tu flagę kasujemy- po 1/4s znowu się ustawi
    		SetAdcKanal();	
    /*				To jest made by gaskoin- ale nie działa dobrze- próbuje odczytać wszystkie kanały w pętli 
    			for- a przecież one zmieniają się co przerwanie od TIMER0  
    			for(i = 0; i < LICZBA_KANALOW; i++){
    			      if(i<2){
    			            LCD_GoTo(0,i);
    			            LCD_WriteText("      ");
    			            LCD_GoTo(0,i);
    			      } else{
    			            LCD_GoTo(7,i-2);
    			            LCD_WriteText("      ");
    			            LCD_GoTo(7,i-2);
    			      }
         
    			      LCD_WriteText(dtostrf(napiecie[i]/=50.0,5,2,buffer_nap));
    			}
    
    */
    
    
    		napiecie_aku=napiecie[0];	//NAPIECIE AKU
    	    LCD_GoTo(0,0);
    	    LCD_WriteText("     ");
    		LCD_GoTo(0,0);
    	    LCD_WriteText(dtostrf(napiecie_aku/=50.0,5,2,buffer_nap));// to zamiast utoa.Dzielenie przez 50.0 należy
    
    		napiecie_solar=napiecie[1];	//NAPIECIE SOLAR
    		LCD_GoTo(0,1);
    		LCD_WriteText("     ");
    		LCD_GoTo(0,1);
    		LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
    
    		prad_aku=napiecie[2];	//prąd aku
    		LCD_GoTo(7,0);
    		LCD_WriteText("     ");
    		LCD_GoTo(7,0);
    		LCD_WriteText(dtostrf(prad_aku/=50.0,5,2,buffer_nap));
    
    		prad_solar=napiecie[3];//prąd solar
    		LCD_GoTo(7,1);
    		LCD_WriteText("     ");
    		LCD_GoTo(7,1);
    		LCD_WriteText(dtostrf(prad_solar/=50.0,5,2,buffer_nap));
    
    		}		//Tu się kończy ten fragment co się wykonuje co 1/4s
    				
    			if(flaga_przycisku)//ten fragment wykonuje się co 16ms
    			{
    			flaga_przycisku=0;// poczatki debounce- zaczynam coś rozumieć
    				if(bit_is_clear(PINC,0))	
    				PORTB&=~(1 << PORTB2);
    //				PORTB|=(1<<PORTB0);
    			}
    
    			
    // a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością 
    		
    		if((napiecie_aku<NAPIECIE_AKU_MIN)&&(napiecie_solar<NAPIECIE_SOLAR_MIN))
    			START_LADOWANIE	//ładowanie włączamy stanem niskim
    		if((napiecie_solar>=NAPIECIE_SOLAR_MIN)||(napiecie_aku>=NAPIECIE_AKU_MAX))
    			STOP_LADOWANIE	//a wyłączamy stanem wysokim
    		
    	}
    }
    
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer0 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę której stan sprawdzamy w main()
    	static uint8_t liczniczek_pomiaru;//TIMER0 nie starcza na 1/4s- to niech liczniczek to zlicza 
    	liczniczek_pomiaru++;//wydaje mi się że tu jest pętla for()
    	if(liczniczek_pomiaru>=15)//15x16ms- 240ms
    		{
    		liczniczek_pomiaru=0;
    		flaga_pomiaru=1;	//flaga pomiaru ustawia się co 240ms
    		}
    	flaga_przycisku=1;	//flaga przycisku ustawia się co 16ms
    
    	TIFR |= (1 << TOV0); // a tu nie było przerwania od TIMER0- ale skasować flagę trzeba- no to kasujemy 
    }
    
    void SetAdcKanal(void)// a tu funkcja zmieniająca kanały- definicja
    {
    	static uint8_t kanal;	
    	ADMUX = ((ADMUX&0xE0)+ kanal);
    	napiecie[kanal]=ADC;
    	kanal++;	   
        if(kanal>LICZBA_KANALOW)		
    	kanal=0;  
    } 
    
    uint8_t debounce(uint8_t button_state)// a to jest funkcja by Dr_Vee- zaczynam nieśmiało próbować rozumieć
    {
        static uint8_t old_states;
        static uint8_t state;
        old_states = (old_states << 1) | (!!button_state);//!!button_state==(button_state ? 1 : 0);
    
        switch (old_states) {
            case 0x00: state = 0; break;
            case 0xff: state = 1; break;
        }
        return state;
    }
    

    Działa co ma działać- odczytuje pomiar z potencjometrów i włącza/wyłącza zasilacz zależnie od stanu napięcia akumulatora i solar.
    Pętla od gaskoin- nie działa dobrze.
    Ale dzięki- mam nd czym myśleć.
    Wywaliłem stałe ustawienia przed while(1).
    Napisałem co mi się wydaje- kanały zmieniane są co przerwanie od TIMER0- czyli
    od ADC- a pętla chce czytać wszystkie w pętli for().
    Ale może jeszcze coś skopsałem.
    Wpadłem w debounce- trzeba to w końcu zrobić- jeszcze widać mi czubek głowy.
    Ale powoli będę starał się wygrzebać.
    margas- skopiuj to co napisałem, dopasuj porty i to chodzi.
    Jeszcze nie wszystko- ale działa.
    Może wszystkie kanały najpierw odczytać i zapisać w tablicy- a potem odczytać z tablicy w for() i wyswietlić?
    Ale najpierw debounce.
  • #21 8501373
    margas4542
    Poziom 16  
    ...usiłuje podstawiać napisy w zależności od stanu czy załączony jest zasilacz czy solar... poradźcie jak zdefiniować 10 znakowy napis a potem go podmieniać na LCD..
    przerobiłem kilka wariantów ale żaden nie działa poprawnie albo mam jeden napis albo wcale albo cuda....
    
    //----- LCD init stałe napisy nie zmieniane
     LCD_Initalize(); 
     _delay_ms(200);
     LCD_GoTo(0,0);
     LCD_WriteText("                    ");// to jest szybciej od LCD_Clear
     LCD_GoTo(0,0);
     LCD_WriteText("AKUM      V     A");
     LCD_GoTo(0,1);
     LCD_WriteText("SOLAR     V     A");
     LCD_GoTo(20,0);
     LCD_WriteText("Napiecie"); 
     LCD_GoTo(20,1);
     LCD_WriteText("K1   K2   K3   K4");
    //---------------------- 
     {     
      while(1)
      {
       int kan;
    //------------------------pomiary na 6 kanalach
    
    //-------------------------wyświetlanie wyników
    //1
        LCD_GoTo(5,0);
        LCD_WriteText(dtostrf(aku_v=aku_v,5,1,buffer_n));	
        LCD_GoTo(11,0); 
    	LCD_WriteText(dtostrf(aku_i=aku_i,5,1,buffer_n));
        LCD_GoTo(17,0);
        LCD_WriteText(****);
    //2 
        LCD_GoTo(5,1);
    	LCD_WriteText(dtostrf(sol_v=sol_v,5,1,buffer_n));
        LCD_GoTo(11,1); 
    	LCD_WriteText(dtostrf(sol_i=sol_i,5,1,buffer_n));
        LCD_GoTo(17,1);
        LCD_WriteText(****);
    //3
        LCD_GoTo(31,0);
        LCD_WriteText(****);		//wyświetlić tu albo jeden albo drugi 
    //4
    
       }
    //-----progi przełaczania żródeł zasilania
       {
        aku_v_min=11.0;
        aku_v_max=14.0;
        stala=13.0;
        stat=10.0;
        if ((aku_v <= aku_v_min)&&(sol_v <= stala))
    //jeżeli nap. aku. poniżej 11V i nap. solara jest poniżej 14V to załącz zasilacz
    	PORTB &=~0x01;
        zas = znak;//<<<<<<<<<<<<<<<<<<<< tu napis "z zasilacza"
    		
    //jeżeli nap. aku. powyżej 14V lub nap. solara jest wyższe od 13V to wyłącz.zasilacz    
        if ((aku_v >= aku_v_max)||(sol_v >= stala))
        PORTB |= 0x01;
        sol = znak;//<<<<<<<<<<<<<<<<<<<< tu napis "z solara"
    		 
    //------------------------oświetlenie nocne
        if (sensor >= stat)
        PORTB &=~ 0x02;			//załącz   
        if (sensor <= stat)
        PORTB |= 0x02;			//wyłącz 
    //------------------------zasilacz
        if (power >= stat)
        PORTB &=~ 0x04;			//załączony 
        if (power <= stat)
        PORTB |= 0x04;			//wyłączony 
       }   
  • #22 8501521
    gaskoin
    Poziom 38  
    janbarnat napisał:
    pętla chce czytać wszystkie w pętli for().


    A spójrz w swój kod ? po ustawieniu flagi pierwszy raz, w pętli głównej i tak odczytujesz 4 wartości, gdzie w tablicy aktualna jest jedynie jedna (i jedyna bo tablica jest w sekcji noinit)!

    A nie działa to zbyt dobrze bo skopałeś nieco obsługę przerwania, dla Ciebie zagadka - dlaczego? :)

    jeszcze jedno mi się rzuciło w oczy - co jeżeli podczas konwersji napięcia (która jest robiona co określony czas) będziesz zmieniał kanał ? pomiar idzie w krzaki.

    Dlatego w przerwaniu od przetwornika powinieneś robić trzy rzeczy:

    -zmieniać kanał
    -zapisywać pomiar od razu w tablicę
    -kasować flagę overflowa

    ponieważ chcesz czasówki, np do sprawdzania przycisku, to jednak powinieneś uruchomić przerwania od timera i w nim liczyć czas, nie w przetworniku, bo on potrzebuje parę cykli zegarowych po wystąpieniu OVF nim zgłosi przerwanie (czas konwersji). Wszystko się rozjeżdża co około dwudziestu więc koło 2,5 µs (przy taktowaniu 8MHz).


    Ale namieszałem nie? :P







    Co do zmieniania napisów to definiujesz sobie napisy:

    char *napis = "costam";
    char *napis2 = "costam2";


    a potem jakieś ify w kodzie i w zależności od ifa podkładasz odpowiedni napis i tyle


    BTW. Jak się wkurzę to pojadę do tego Mikołowa, najchętniej przez Warszawę.
  • #23 8505699
    margas4542
    Poziom 16  
    ...jak to nie kłopot do do Mikołowa niedaleko a kawy ci u mnie dostatek.....morduje się z tym podstawianiem napisów...padł mi system i kod którym już częściowo chodziło podstawianie napisów jest historią więc musiałem napisać wszystko od nowa ale wszystko chodzi poza podmianką tekstu i wyświetlaniem dziesiętnych jednostek napięcia...
    
    //-----------------------------------napięcia progowe
       char aku_v_min = 11;
       char aku_v_max = 14;
       char sol_v_ref= 13;
       char zas_ref= 10;
    //-----------------------------------zależności
    //jeżeli nap. aku. powyżej 14V lub nap. solara jest wyższe od 13V to wyłącz.zasilacz 
       if ((aku_v >= aku_v_max)||(sol_v >= sol_v_ref))
        PORTB |= 0x01;	 
    //jeżeli nap. aku. poniżej 11V i nap. solara jest poniżej 14V to załącz zasilacz
       if ((aku_v <= aku_v_min)&&(sol_v <= sol_v_ref))
    	PORTB &=~0x01;
    //jeżeli nap. zasiacza poniżej 10V i solara poniżej 13V oraz zasilacz jest "0" zmienna(power)
       if (power<((aku_v <= aku_v_min)&&(sol_v <= sol_v_ref)))
        napis3 = napis0;	//napis1 = "Brak zasilania";
    //-----------------------------------
       if (aku_i >= sol_i)
        napis5 = napis0;	// napis5 = "<<" pobór mniejszy od prądu ładowania
        PORTB &=~0x02;
       if (aku_i <= sol_i)
       napis6 = napis0;		// napis6 = ">>" pobór większy od prądu ładowania
    	PORTB |=0x02;
    //-----------------------------------
       if(sol_v >= sol_v_ref)
        napis3 = napis0;	//napis3 = "Zasilanie z solara";
    //-----------------------------------włącza wentylator zasilacza
       if(power>zas_ref)
        napis2 = napis0;	//napis2 = "Zasilanie  z sieci";
    	PORTB &=~0x04;
       if(power<zas_ref)
    	PORTB |=0x04;
    //-----------------------------------czujnik zmierzchowy tylko wł/wył kanał
       if(sensor>zas_ref)
    	PORTB &=~0x08;
       if(sensor<zas_ref)
    	 PORTB |=0x08;
    //-----------------------------------info zdeklarowane zmienne
    //char *napis0 = " Atmega Home System";
    //char *napis1 = " Brak zasilania";
    //char *napis2 = " Zasilanie  z sieci";
    //char *napis3 = " Zasilanie z solara";
    //char *napis5 = "<<";
    //char *napis6 = ">>";
    //-----------------------------------wyświetlanie wyników
    //-----LCD pierwszy wiersz pomiar 1
       LCD_GoTo(0,0);  LCD_WriteText("AKUM");
       LCD_GoTo(6,0);  LCD_WriteText(dtostrf(aku_v=aku_v,4,1,buffer_n));
       LCD_GoTo(10,0); LCD_WriteText("V");
    //------LCD pierwszy wiersz pomiar 2
       LCD_GoTo(12,0); LCD_WriteText(dtostrf(aku_i=aku_i,4,1,buffer_n));
       LCD_GoTo(16,0); LCD_WriteText("A");
       LCD_GoTo(18,0); LCD_WriteText(napis5);
    //-----LCD drugi wiersz pomiar 3
       LCD_GoTo(0,1);  LCD_WriteText("SOLAR");
       LCD_GoTo(6,1);  LCD_WriteText(dtostrf(sol_v=sol_v,4,1,buffer_n));
       LCD_GoTo(10,1); LCD_WriteText("V");
    //------LCD drugi wiersz pomiar4
       LCD_GoTo(12,1); LCD_WriteText(dtostrf(sol_i=sol_i,4,1,buffer_n));
       LCD_GoTo(16,1); LCD_WriteText("A");
       LCD_GoTo(18,1); LCD_WriteText(napis6);
    //-----LCD trzeci wiersz
       LCD_GoTo(20,0); LCD_WriteText(napis0);
    //----LCD czwarty wiersz
       LCD_GoTo(20,1); LCD_WriteText("K1-");
       LCD_GoTo(25,1); LCD_WriteText("K2-");
       LCD_GoTo(30,1); LCD_WriteText("K3-");
       LCD_GoTo(35,1); LCD_WriteText("K4-");
    //------------------------------------
  • #24 8507228
    janbernat
    Poziom 38  
    gaskoin- czy jesteś pewien że for w main dobrze działa?
    Kombinuję jak koń pod górę żeby tę pętle wstawić- i jakaś sieczka mi wychodzi.
    Jakieś migające cyfry- coś wyświetla ale nie można tego odczytać- i dziwnie reaguje na sprawdzanie napięcia akumulatora.
    Jakieś przełączenia- ale nie widać przy jakim napięciu.
    Dużo zakomentowane.
    W tej wersji działa:
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    #include <avr/sfr_defs.h>
    //w Project->configuration option ustawiamy freqency 16000000
    
    #define LICZBA_KANALOW      4 //cztery kanały- tu można zwiększyć ilość kanałów 
    #define NAPIECIE_AKU_MIN	11.0
    #define NAPIECIE_AKU_MAX	14.0
    #define NAPIECIE_SOLAR_MIN  13.0
    #define START_LADOWANIE		PORTB&=~(1 << PORTB0); // clear PORTB0      
    #define STOP_LADOWANIE		PORTB|=(1<<PORTB0);	// set PORTB0
    
    volatile uint8_t flaga_pomiaru;
    volatile uint8_t flaga_przycisku;
    volatile double napiecie[LICZBA_KANALOW];//to wywaliłem-jeszcze za słabo ogarniam: __attribute__((section(".noinit")));
    
    void SetAdcKanal(void);	// prototyp
    uint8_t debounce(uint8_t button_state);// to też prototyp funkcji na razie słabo używanej
    
    int main(void)	// tu jest początek main() i tu ustawiamy konfigurację rejestrów
    
    {   
    	
    	char buffer_nap[LICZBA_KANALOW];
    	char *text="Problem z";
        char *text1="przerwaniami";
    	double napiecie_aku=0.0;
    	double napiecie_solar=0.0;
    	double prad_aku=0.0;
    	double prad_solar=0.0;
    //	uint8_t i;	
    	
        sei();
        DDRB=255;
        PORTB=255;
    	DDRC=0;
    	PORTC=255; 
     	TCCR0=_BV(CS00)|_BV(CS02);// TIMER0 przepełnia się co 16ms- szkoda TIMER1 na ustawianie flagi
    //    TCCR1B=_BV(CS10)|_BV(CS11);//na przerwanie OVF1 co ok.1/4s przy 16 MHz- można zmienić
        ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
        ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
    //    SFIOR=_BV(ADTS1)|_BV(ADTS2);//ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer1
    	SFIOR=_BV(ADTS2); // ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer0
        LCD_Initalize();
        LCD_WriteText(text);
        LCD_GoTo(0,1);
        LCD_WriteText(text1);      
        _delay_ms(300);
        LCD_GoTo(0,0);
        LCD_WriteText("                ");// to jest szybciej niż LCD_Clear
    	LCD_GoTo(0,1);
    	LCD_WriteText("                ");
    	LCD_GoTo(20,0);
    	LCD_WriteText("  1 2 3 4 5 6 7 8");
    	LCD_GoTo(5,0);											//dopasować do swoich potrzeb
    	LCD_WriteText("V");
    	LCD_GoTo(5,1);
    	LCD_WriteText("V");
    	LCD_GoTo(12,0);
    	LCD_WriteText("A aku");
    	LCD_GoTo(12,1);
    	LCD_WriteText("A solar");
    	LCD_GoTo(22,1);
    	LCD_WriteText("T");
    
      while(1)			//A tu zaczyna się nieskończona pętla
    	{
    
    
    	if(flaga_pomiaru)		//Tu sprawdzamy flagę i dlatego ten
    					//fragment wykonuje się co 1/4s- bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER0
    		{			//Przez resztę czasu śpi.LCD też pokazuje co 1/4s.
    	    flaga_pomiaru=0;	// A tu flagę kasujemy- po 1/4s znowu się ustawi
    
    //				To jest made by gaskoin- ale nie działa dobrze- próbuje odczytać wszystkie kanały w pętli 
    //			for- a przecież one zmieniają się co przerwanie od TIMER0
    //		Na wyświetlaczu- migotanie- coś wyświetla ale nie można odczytać  
    /*					for(i = 0; i < LICZBA_KANALOW; i++){
    			      if(i<2){
    			            LCD_GoTo(0,i);
    			            LCD_WriteText("     ");
    			            LCD_GoTo(0,i);
    			      } else{
    			            LCD_GoTo(7,i-2);
    			            LCD_WriteText("     ");
    			            LCD_GoTo(7,i-2);
    			      }
         
    			      LCD_WriteText(dtostrf(napiecie[i]/=50.0,5,2,buffer_nap));
    		}
    */		
    
    
    
    		napiecie_aku=napiecie[0];	//NAPIECIE AKU
    	    LCD_GoTo(0,0);
    	    LCD_WriteText("     ");
    		LCD_GoTo(0,0);
    	    LCD_WriteText(dtostrf(napiecie_aku/=50.0,5,2,buffer_nap));// to zamiast utoa.Dzielenie przez 50.0 należy
    
    		napiecie_solar=napiecie[1];	//NAPIECIE SOLAR
    		LCD_GoTo(0,1);
    		LCD_WriteText("     ");
    		LCD_GoTo(0,1);
    		LCD_WriteText(dtostrf(napiecie_solar/=50.0,5,2,buffer_nap));
    
    		prad_aku=napiecie[2];	//prąd aku
    		LCD_GoTo(7,0);
    		LCD_WriteText("     ");
    		LCD_GoTo(7,0);
    		LCD_WriteText(dtostrf(prad_aku/=50.0,5,2,buffer_nap));
    
    		prad_solar=napiecie[3];//prąd solar
    		LCD_GoTo(7,1);
    		LCD_WriteText("     ");
    		LCD_GoTo(7,1);
    		LCD_WriteText(dtostrf(prad_solar/=50.0,5,2,buffer_nap));
    
    		}		//Tu się kończy ten fragment co się wykonuje co 1/4s
    				
    			if(flaga_przycisku)//ten fragment wykonuje się co 16ms
    			{
    			static uint8_t powtorzenie;
    			powtorzenie++;
    			flaga_przycisku=0;// poczatki debounce- zaczynam coś rozumieć
    			if(bit_is_clear(PINC,0))	
    
    			PORTB&=~(1 << PORTB2);
    			
    			}
    
    
    			
    // a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością 
    		
    		if((napiecie_aku<NAPIECIE_AKU_MIN)&&(napiecie_solar<NAPIECIE_SOLAR_MIN))
    			START_LADOWANIE	//ładowanie włączamy stanem niskim
    		if((napiecie_solar>=NAPIECIE_SOLAR_MIN)||(napiecie_aku>=NAPIECIE_AKU_MAX))
    			STOP_LADOWANIE	//a wyłączamy stanem wysokim
    
    	}
    }
    
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer0 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę której stan sprawdzamy w main()
    //	static uint8_t wskaznik_tablicy;
    	static uint8_t liczniczek_pomiaru;//TIMER0 nie starcza na 1/4s- to niech liczniczek to zlicza 
    	liczniczek_pomiaru++;
    	if(liczniczek_pomiaru>=15)//15x16ms- 240ms
    		{
    		liczniczek_pomiaru=0;
    		SetAdcKanal();//ta funkcja zmienia kanal i zapisuje w tablicę napiecie[kanal]
    		flaga_pomiaru=1;	//flaga pomiaru ustawia się co 240ms
    //		napiecie[wskaznik_tablicy] = ADC;
    //		if(++wskaznik_tablicy == LICZBA_KANALOW) wskaznik_tablicy = 0; 
    
    
    		}
    
    	flaga_przycisku=1;	//flaga przycisku ustawia się co 16ms
    
    	TIFR |= (1 << TOV0); // a tu nie było przerwania od TIMER0- ale skasować flagę trzeba- no to kasujemy 
    }
    
    void SetAdcKanal(void)// a tu funkcja zmieniająca kanały- definicja
    {
    	static uint8_t kanal;	
    	ADMUX = ((ADMUX&0xE0)+ kanal);//zmienić kanał
    	napiecie[kanal]=ADC;			// zapisać pomiar w tablicę
    	kanal++;	   
        if(kanal>LICZBA_KANALOW)		
    	kanal=0;  
    } 
    
    uint8_t debounce(uint8_t button_state)// a to jest funkcja by Dr_Vee- zaczynam nieśmiało próbować rozumieć
    {
        static uint8_t old_states;
        static uint8_t state;
        old_states = (old_states << 1) | (!!button_state);//!!button_state==(button_state ? 1 : 0);
    
        switch (old_states) {
            case 0x00: state = 0; break;
            case 0xff: state = 1; break;
        }
        return state;
    }
    
  • #25 8507410
    margas4542
    Poziom 16  
    ..janbernat to jest poprzedni listing nad który trochę podumałem i nieco naprawdę odrobinkę zmodyfikowałem...chodzi ok no może poza moją wstawką ze switch która chodzi w testowym programie ale nie w tym bo gryzie się z przerwaniami...no i LCD jest na porcie C...
    
    //##############################################################
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    #include <avr/sfr_defs.h>
    
    #define LICZBA_KANALOW       6 	//ilość kanałów
    #define NAPIECIE_AKU_MIN    11.0
    #define NAPIECIE_AKU_MAX    14.0
    #define NAPIECIE_SOLAR_MIN  13.0
    #define START_LADOWANIE     PORTB&=~(1 << PORTB0); // clear PORTB0     
    #define STOP_LADOWANIE      PORTB|=(1<<PORTB0);    // set PORTB0
    #define NAPIECIE_VREF		10.0
    volatile uint8_t flaga_pomiaru;
    volatile uint8_t flaga_przycisku;
    volatile uint16_t napiecie[LICZBA_KANALOW] __attribute__((section(".noinit")));
    
    void SetAdcKanal(void);   // prototyp
    uint8_t debounce(uint8_t button_state);
    //----- MAIN
    int main(void)
    {   
     char buffer_nap[LICZBA_KANALOW];
     char *text=" konflikt przerwan";
     double napiecie_aku=0.0;
     double napiecie_solar=0.0;
     double prad_aku=0.0;
     double prad_solar=0.0;
     double power=0.0;
     double sensor=0.0;
    //   uint8_t i;
     sei();  
     DDRB=0xFF;
    // PORTB=0xFF;
     DDRD=0xF0;
     PORTD=0x0F;
     TCCR0=_BV(CS00)|_BV(CS02);		// TIMER0 przepełnia się co 16ms
     ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
     ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
     SFIOR=_BV(ADTS2); 				//start przetwarzania ADC po przepełnieniu OVF Timer0
     LCD_Initalize();
     LCD_GoTo(20,0);
     LCD_WriteText(text);     
     _delay_ms(100);
    //-----1
     LCD_GoTo(0,0);
     LCD_WriteText("Akum");
     LCD_GoTo(10,0);
     LCD_WriteText("V");
     LCD_GoTo(16,0);
     LCD_WriteText("A");
    //2
     LCD_GoTo(0,1);
     LCD_WriteText("Solar");
     LCD_GoTo(10,1);
     LCD_WriteText("V");
     LCD_GoTo(16,1);
     LCD_WriteText("A");
    //3
    
    //4
     LCD_GoTo(20,1);
     LCD_WriteText("L1   L2   L3   L4");
    //----- LOOP
     while(1)
     {
      if(flaga_pomiaru)		//sprawdzamy flagę i ten fragment wykonuje się co 1/4s- 
                       		//bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER0
       {               		//przez resztę czasu śpi.LCD też pokazuje co 1/4s.
        flaga_pomiaru=0;	//tu flagę kasujemy- po 1/4s znowu się ustawi
        SetAdcKanal();   
    //--
        napiecie_aku=napiecie[1];   //akumulator napięcie
        LCD_GoTo(6,0);
        LCD_WriteText("    ");
        LCD_GoTo(6,0);
        LCD_WriteText(dtostrf(napiecie_aku/=41.3,4,1,buffer_nap));
    //--
        prad_aku=napiecie[2];   //akumulator prąd
        LCD_GoTo(12,0);
        LCD_WriteText("    ");
        LCD_GoTo(12,0);
        LCD_WriteText(dtostrf(prad_aku/=41.3,4,1,buffer_nap));
        LCD_GoTo(18,0);
        LCD_WriteText(">>");
    //--
        napiecie_solar=napiecie[3];  //solar napięcie
        LCD_GoTo(6,1);
        LCD_WriteText("    ");
        LCD_GoTo(6,1);
        LCD_WriteText(dtostrf(napiecie_solar/=41.3,4,1,buffer_nap));
    //--
        prad_solar=napiecie[4];//solar prąd
        LCD_GoTo(12,1);
        LCD_WriteText("    ");
        LCD_GoTo(12,1);
        LCD_WriteText(dtostrf(prad_solar/=41.3,4,1,buffer_nap));
        LCD_GoTo(18,1);
        LCD_WriteText(">>");
    //--
        LCD_GoTo(20,0);
     	LCD_WriteText(napis0);
        power=napiecie[5]/41.3;
    	sensor=napiecie[6]/41.3;
    
    //----------------------
       }//Tu się kończy ten fragment co się wykonuje co 1/4s
      if(flaga_przycisku)//ten fragment wykonuje się co 16ms
       {
        flaga_przycisku=0;
        if(bit_is_clear(PIND,0))   
        PORTB&=~(1 << PORTB2);
    //            PORTB|=(1<<PORTB0);
       }   
       if((napiecie_aku<NAPIECIE_AKU_MIN)&&(napiecie_solar<NAPIECIE_SOLAR_MIN))
         START_LADOWANIE   //ładowanie włączamy stanem niskim
       if((napiecie_solar>=NAPIECIE_SOLAR_MIN)||(napiecie_aku>=NAPIECIE_AKU_MAX))
         STOP_LADOWANIE   //a wyłączamy stanem wysokim
    //--
       if(power> NAPIECIE_VREF)
         PORTB &=~ 0x02;
       if(power< NAPIECIE_VREF)
         PORTB |= 0x02;
    //--
       if(sensor> NAPIECIE_VREF)
         PORTB &=~ 0x04;
       if(sensor< NAPIECIE_VREF)
         PORTB |= 0x04;
    //--
    // a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością
       unsigned char key;		  
       for(key=3; key<8; key++)	
       if(!(PIND & _BV(key)))	
       {	 
        switch(key)
        {
    	 case 3:
          PORTC ^=_BV(0);
    	  _delay_ms(400);
          break;
    	 case 4:
          PORTB ^=_BV(4);
    	  _delay_ms(400);
          break;
         case 5:
          PORTB ^=_BV(5);
    	  _delay_ms(400);
    	  break;
         case 6:
          PORTB ^=_BV(6);
    	  _delay_ms(400);
          break;
         case 7:
          PORTB ^=_BV(7);
    	 _delay_ms(400);
    	  break;
         default:
    	  break;
        }
     }
    }
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer0 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę a stan sprawdzamy w main()
     static uint8_t liczniczek_pomiaru;//TIMER0 nie starcza na 1/4s- to niech liczniczek to zlicza
     liczniczek_pomiaru++;//wydaje mi się że tu jest pętla for()
     if(liczniczek_pomiaru>=15)//15x16ms- 240ms
      {
       liczniczek_pomiaru=0;
       flaga_pomiaru=1;   //flaga pomiaru ustawia się co 240ms
      }
     flaga_przycisku=1;   //flaga przycisku ustawia się co 16ms
     TIFR |= (1 << TOV0); //tu nie było przerwania od TIMER0- ale skasować flagę trzeba
    }
    void SetAdcKanal(void)// a tu funkcja zmieniająca kanały- definicja
    {
     static uint8_t kanal;   
     ADMUX = ((ADMUX&0xE0)+ kanal);
     napiecie[kanal]=ADC;
     kanal++;      
     if(kanal>LICZBA_KANALOW)      
     kanal=0; 
    }
    uint8_t debounce(uint8_t button_state)// a to jest funkcja by Dr_Vee- zaczynam nieśmiało próbować rozumieć
    {
     static uint8_t old_states;
     static uint8_t state;
     old_states = (old_states << 1) | (!!button_state);//!!button_state==(button_state ? 1 : 0);
     switch (old_states) {
      case 0x00: state = 0; break;
      case 0xff: state = 1; break;
    }
    return state;
    } 
    //##########################################
    
  • #26 8507581
    gaskoin
    Poziom 38  
    Nie mam już do was siły.... Wody, wody ... :D

    Janku - ta pętla robi to samo co Twój zapis przyjrzyj się :)
    Źle jest trochę obsługa przerwania z przetwornika - nie powinno się tam naliczać czasu. Zauważ że 15 pomiarów idzie bezsensu w krzaki.

    Ogólnie trochę zła koncepcja jest w kilku miejscach, ale to Ci napisałem wcześniej
  • #27 8508025
    janbernat
    Poziom 38  
    Będzie następna powódź.
    Ta pętla robi to samo co mój zapis- tak chyba jest.
    Ale bardzo szybko.
    W jednym przejściu pętli przy 16MHz.
    I traci 15 pomiarów.
    I odczytuje ADC co 240ms.
    I w zasadzie ma czytać z ADC co 240ms- bo po co częściej- to jest tylko akumulator.
    I ma tracić te 15 pomiarów- chyba że czytać do tablicy dwuwymiarowej i uśredniać odczyty.
    Jak czyta w pętli for to chyba nie nadąża z przetwarzaniem- nie wiem jeszcze.
    W Twojej wersji gaskoin ładnie się kompiluje i przy pewnej dbałości o kod mam 0 warningów.
    Ale ma tę wadę że źle działa.
    Słabo potrafię korzystać z symulatora i zwykle zanim odpowiem to sprawdzam w realu.
    A pułapki robię zwykle ustawiając porty.
    Potem oscyloskop i pomiar czasu.
    Zmontowałem układ margasa na płytce z propoxu i potencjometry na stykowej.
    Z wyświetlaczem na cztery linijki.
    I mam prawie taki sam układ jak margas.
    Oczywiście wiem że robię błędy.
    Ale gdybyś zechciał przerobić mój ostatni program i dać mi "gotowca" z pętlą for to mógłybym to sprawdzić w układzie.
  • #28 8508044
    gaskoin
    Poziom 38  
    janbernat napisał:

    Ale gdybyś zechciał przerobić mój ostatni program i dać mi "gotowca" z pętlą for to mógłbym to sprawdzić w układzie.


    Napiszę Wam to w sobotę, bo teraz mam 10 tysięcy rzeczy na głowie :), jutro cały dzień mnie nie ma, a na piątek jakiemuś zdesperowanemu studentowi program w C# trzeba napisać
  • #29 8510235
    margas4542
    Poziom 16  
    Witam....kłopot z podmianą napisów na LCD oraz wyświetlania cyfr dziesiętnych po przecinku zastał rozwiązany pozytywnie....pozostało mi jeszcze do przedefiniowania kilka zależności pomiędzy pomiarami aby po wystąpieniu określonych parametrów napięć wykonywał zdefiniowane polecenia równocześnie wyświetlając odpowiedni komunikat...
  • #30 8511319
    janbernat
    Poziom 38  
    "A nie działa to zbyt dobrze bo skopałeś nieco obsługę przerwania, dla Ciebie zagadka - dlaczego?" :D
    A teraz gaskoin działa z Twoją petlą for.
    I z moim przerwaniem.
    A teraz dla Ciebie zagadka- co dziwnie działa? :D
    Dodam dla ułatwienia że w zupełnie nieoczekiwanym miejscu.
    To miałem na początku uczenia się pisania tego programiku- ale zlekceważyłem.
    A niesłusznie.
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "HD44780.h"
    #include <avr/sfr_defs.h>
    //w Project->configuration option ustawiamy freqency 16000000
    
    #define LICZBA_KANALOW      4 //cztery kanały- tu można zwiększyć ilość kanałów 
    #define NAPIECIE_AKU_MIN	800.0
    #define NAPIECIE_AKU_MAX	1000.0
    #define NAPIECIE_SOLAR_MIN  900.0
    #define START_LADOWANIE		PORTB&=~(1 << PORTB0); // clear PORTB0      
    #define STOP_LADOWANIE		PORTB|=(1<<PORTB0);	// set PORTB0
    
    volatile uint8_t flaga_pomiaru;
    volatile uint8_t flaga_przycisku;
    double napiecie[LICZBA_KANALOW];
    
    void SetAdcKanal(uint8_t);	// prototyp
    
    int main(void)	// tu jest początek main() i tu ustawiamy konfigurację rejestrów
    
    {   
    	
    	char buffer_nap[LICZBA_KANALOW];
    	char *text="Problem z";
        char *text1="przerwaniami";
    	double napiecie_aku=0.0;
    	double napiecie_solar=0.0;
    //	double prad_aku=0.0;
    //	double prad_solar=0.0;
    	uint8_t i;	
    	
        sei();
        DDRB=255;
        PORTB=255;
    	DDRC=0;
    	PORTC=255; 
     	TCCR0=_BV(CS00)|_BV(CS02);// TIMER0 przepełnia się co 16ms- szkoda TIMER1 na ustawianie flagi
    //  TCCR1B=_BV(CS10)|_BV(CS11);//na przerwanie OVF1 co ok.1/4s przy 16 MHz- można zmienić
        ADMUX = _BV(REFS0)|_BV(REFS1) ;//|_BV(ADLAR)   
        ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADATE)|_BV(ADPS0)|_BV(ADPS1)|_BV(ADPS2)|_BV(ADSC);   
    //  SFIOR=_BV(ADTS1)|_BV(ADTS2);//ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer1
    	SFIOR=_BV(ADTS2); // ustawienie startu przetwarzania ADC po przepełnieniu OVF Timer0
        LCD_Initalize();
        LCD_WriteText(text);
        LCD_GoTo(0,1);
        LCD_WriteText(text1);      
        _delay_ms(300);
        LCD_GoTo(0,0);
        LCD_WriteText("                ");// to jest szybciej niż LCD_Clear
    	LCD_GoTo(0,1);
    	LCD_WriteText("                ");
    	LCD_GoTo(20,0);
    	LCD_WriteText("  1 2 3 4 5 6 7 8");
    	LCD_GoTo(5,0);											//dopasować do swoich potrzeb
    	LCD_WriteText("V");
    	LCD_GoTo(5,1);
    	LCD_WriteText("V");
    	LCD_GoTo(12,0);
    	LCD_WriteText("A aku");
    	LCD_GoTo(12,1);
    	LCD_WriteText("A solar");
    	LCD_GoTo(22,1);
    	LCD_WriteText("T");
    
      while(1)			//A tu zaczyna się nieskończona pętla
    	{
    
    
    	if(flaga_pomiaru)		//Tu sprawdzamy flagę i dlatego ten
    					//fragment wykonuje się co 1/4s- bo co 1/4s jest wyzwalany ADC- po przepełnieniu TIMER0
    		{			//Przez resztę czasu śpi.LCD też pokazuje co 1/4s.
    
    			for(i = 0; i < LICZBA_KANALOW; i++)
    				{
    			      if(i<2)
    				  {
    			            LCD_GoTo(0,i);
    			            LCD_WriteText("     ");
    			            LCD_GoTo(0,i);
    			      } 
    				  else
    				  {
    			            LCD_GoTo(8,i-2);
    			            LCD_WriteText("     ");
    			            LCD_GoTo(8,i-2);
    			      }
         
    			      LCD_WriteText(dtostrf(napiecie[i],4,1,buffer_nap));
    				}
        flaga_pomiaru=0;	// A tu flagę kasujemy- po 1/4s znowu się ustawi
    
    		}		//Tu się kończy ten fragment co się wykonuje co 1/4s
    				
    			
    // a tu można wsadzić resztę programu która się bedzie wykonywała z pełną prędkością 
    		
    		if(((napiecie_aku=napiecie[0])<NAPIECIE_AKU_MIN)&&((napiecie_solar=napiecie[1])<NAPIECIE_SOLAR_MIN))
    			START_LADOWANIE	//ładowanie włączamy stanem niskim
    		if(((napiecie_solar=napiecie[1])>=NAPIECIE_SOLAR_MIN)||((napiecie_aku=napiecie[0])>=NAPIECIE_AKU_MAX))
    			STOP_LADOWANIE	//a wyłączamy stanem wysokim
    
    	}
    }
    
    ISR(ADC_vect)//a tu przerwanie od ADC- jak wystartował po OVF Timer0 i skończył
    {            //przetwarzanie to tu jest i ustawia flagę której stan sprawdzamy w main()
    	static uint8_t kanal;
    	static uint8_t liczniczek_pomiaru;//TIMER0 nie starcza na 1/4s- to niech liczniczek to zlicza 
    	liczniczek_pomiaru++;
    	if(liczniczek_pomiaru>=15)//15x16ms- 240ms
    		{
    		liczniczek_pomiaru=0;
    //SetAdcKanal(kanal);//ta funkcja zmienia kanal i zapisuje w tablicę napiecie[kanal]- nieużywana chwilowo
    //kanal++;  
    //  if(kanal>=LICZBA_KANALOW)		
    //	kanal=0; 
    		flaga_pomiaru=1;	//flaga pomiaru ustawia się co 240ms
    		ADMUX = ((ADMUX&0xE0)+ kanal);
    		napiecie[kanal] = ADC;
    		kanal++;
    		if(kanal == LICZBA_KANALOW) kanal = 0; 
    		}
    
    	TIFR |= (1 << TOV0); // a tu nie było przerwania od TIMER0- ale skasować flagę trzeba- no to kasujemy 
    }
    
    void SetAdcKanal(uint8_t kanal)// a tu funkcja zmieniająca kanały- definicja- nieużywana chwilowo
    {
    //	static uint8_t kanal=0;
    	ADMUX = ((ADMUX&0xE0)+ kanal);//zmienić kanał
    	napiecie[kanal]=ADC;			// zapisać pomiar w tablicę
    //	kanal++;  
    //    if(kanal>=LICZBA_KANALOW)		
    //	kanal=0;  
    } 
    
    
REKLAMA