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

[atmega32][c]multipleksowanie wyświetlacza LED

margas4542 20 Gru 2010 14:08 6846 15
REKLAMA
  • #1 8891869
    margas4542
    Poziom 16  
    Witam. Potrzebny mi jest zegar wyświetlający równocześnie czas lokalny i czas Greenwich. W tym celu próbuje napisać odpowiedni program ale mam problem z multipleksowaniem dwu wyświetlaczy LED każdy po sześć cyfr. Podstawą czasu jest PCF8583 a że mam akurat atmegę32 więc ją wykorzystam. Od razu mówię że orłem w programowaniu nie jestem i bardzo możliwe że źle się do tego zabrałem. Poszukiwania podobnego programu który mógłby posłużyć za pomoc dydaktyczna to istna mordęga bo w C znaleźć cokolwiek nie jest łatwo a jak jest to kod jest wyższych lotów w 70% dla mnie nie zrozumiały z powodu zastosowania funkcji których nie rozumie. Segmenty podłączone do portu A, pierwsze 6-cyfr podłączyłem do portu B a drugie 6-cyfr do C, klawisze na porcie D. Wkleję cały kod aby było to w pełni dla was czytelne;
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h> 
    //********** funcje obsługi TWI dla PCF
    #define zegar 0xA2 				// A0 PCF do plusa
    #define ACK 1
    #define NOACK 0
    static void TWI_start(void)
    {
    	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    	while (!(TWCR & (1<<TWINT)));
    }
    static void TWI_stop(void)
    {
    	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    }
    void TWI_write(unsigned char scalak,unsigned char adres_rejestru,unsigned char liczba)
    {
    	TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =scalak;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =adres_rejestru;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =liczba;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);
    } 
    unsigned char TWI_read(unsigned char scalak,unsigned char adres_rejestru)
    {
    	unsigned char odczyt;     	
    	TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =scalak;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =adres_rejestru;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWCR =(1 << TWINT) | (1 << TWSTA) | ( 1 << TWEN );
    	while(!(TWCR & (1 << TWINT)));	
    	TWDR =scalak | 0x01;	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	TWCR =(1 << TWINT) | (1 << TWEN);
    	while(!(TWCR & (1 << TWINT)));	
    	odczyt =TWDR;	
    	TWCR =(1 << TWINT) | (1<<TWEN) | (1<<TWSTO);
    	return(odczyt);
    }
    //********** funkcje konwersji	
    char dec_na_bcd(char num)	{return ((num/10 * 16) + (num % 10));}	//set = dec_na_bcd(set);		
    char bcd_na_dec(char num)	{return ((num/16 * 10) + (num % 16));}	//set = bcd_na_dec(set);
    //********** definicje zmiennych dla zegara
    unsigned char PCF,PCF_dzien,dec_dzien,m,d,y;
    unsigned char buffer_t[16];
    unsigned char PCF_dmc,PCF_jmc,PCF_ddni,PCF_jdni;						//odczyt daty
    unsigned char PCF_dg,PCF_jg,PCF_dm,PCF_jm,PCF_ds,PCF_js,PCF_sds,PCF_sjs;//odczyt czasu
    unsigned char dec_dg,dec_jg,dec_dm,dec_jm,dec_ds,dec_js;	//czas bierzący po konwersji na dec
    //********** definicje zmiennych dla menu
    unsigned char led_display;
    unsigned char set_g1,set_m1,set_g2,set_m2,set_g3,set_m3,set_g4,set_m4;
    //********** define segmentów wyświetlacza
    unsigned char nr_wysw;
    const unsigned char cyfra[10]={
    				0x3F,/*cyfra 0		  A   		*/
    				0x06,/*cyfra 1		 ---		*/
    				0x5B,/*cyfra 2		|	|		*/
    				0x4F,/*cyfra 3	  F |	| B		*/
    				0x66,/*cyfra 4		|	|		*/
    				0x6D,/*cyfra 5	  G  ---		*/
    				0x7D,/*cyfra 6		|	|		*/
    				0x07,/*cyfra 7	  E |	| C		*/
    				0x7F,/*cyfra 8		|	|		*/
    				0x6F,/*cyfra 9		 ---		*/
    				0x80 /*kropka		  D	  #	H	*/
    				};
    //***** MAIN
    int main()
    {
     DDRA=0xFF;		//wyjścia - segmenty wyświetlaczy wyś_1 oraz wyś_2
     DDRB=0xFF;		//wyjścia - cyfry wyświetlacza czasu lokalnego
     DDRC=0xFC;		//wyjścia - cyfry wyświetlacza daty oraz wejścia - SCL SDA układu PCF8583
     PORTC=0x03;	//pull-up - dla SCL SDA INT1 układu PCF8583
     DDRD=0x00;		//wejścia - klawiatura
     PORTD=0xF8;	//pull-up - klawiatura
    //----- TWI init
     TWSR=0x00;		
     TWBR=0x48; //preskaler I2C - ((F_CPU / 100000UL - 16) - inicjacja przerwań
     sei();	
    //-----pętla główna progranu
     while(1)
     {	//odczyt czasu i daty 
    		//-----
    	PCF=TWI_read(zegar,0x06);	PCF_dmc=PCF >>4;	PCF_jmc=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x05);	PCF_ddni=PCF >>4;	PCF_jdni=PCF & 0x0F;
        PCF=TWI_read(zegar,0x04);	PCF_dg=PCF >>4;		PCF_jg=PCF & 0x0F;
        PCF=TWI_read(zegar,0x03);	PCF_dm=PCF >>4;		PCF_jm=PCF & 0x0F;
        PCF=TWI_read(zegar,0x02);	PCF_ds=PCF >>4;		PCF_js=PCF & 0x0F;
    	//-----
    	dec_dg=bcd_na_dec(PCF_dg);	dec_jg=bcd_na_dec(PCF_jg);//konwersja na dec godziny
    	dec_dm=bcd_na_dec(PCF_dm);	dec_jm=bcd_na_dec(PCF_jm);//konwersja na dec minuty
    
    	for( nr_wysw=0; nr_wysw<12; nr_wysw++)
    	{
    		switch(nr_wysw)
    		{
    			case 0://wyśw_1_dziesiątki godzin
    			PORTB &=~ _BV(1);
    			cyfra[dec_dg];
    			PORTB |= _BV(1);
    			break;
    			case 1://wyśw_1_jednostki godzin
    			PORTB &=~ _BV(2);
    			cyfra[dec_jg];
    			PORTB |= _BV(2);
    			break;
    			case 2://wyśw_1_dziesiątki minut
    			PORTB &=~ _BV(3);
    			cyfra[dec_dm];
    			PORTB |= _BV(3);
    			break;
    			case 3://wyśw_1_jednostk minut
    			PORTB &=~ _BV(4);
    			cyfra[dec_jm];
    			PORTB |= _BV(4);
    			break;
    			case 5://wyśw_1_dziesiątki sekund
    			PORTB &=~ _BV(5);
    			cyfra[dec_ds];
    			PORTB |= _BV(5);
    			break;
    			case 6://wyśw_1_jednostk sekund
    			PORTB &=~ _BV(6);
    			cyfra[dec_js];
    			PORTB |= _BV(6);
    			break;
    			//----------------czas 2 GMT
    			case 7://wyśw_2_dziesiątki godzin
    			PORTC &=~ _BV(1);
    			cyfra[dec_dg];
    			PORTC |= _BV(1);
    			break;
    			case 8://wyśw_2_jednostki godzin
    			PORTC &=~ _BV(2);
    			cyfra[dec_jg];
    			PORTC |= _BV(2);
    			break;
    			case 9://wyśw_2_dziesiątki minut
    			PORTC &=~ _BV(3);
    			cyfra[dec_dm];
    			PORTC |= _BV(3);
    			break;
    			case 10://wyśw_2_jednostk minut
    			PORTC &=~ _BV(4);
    			cyfra[dec_jm];
    			PORTC |= _BV(4);
    			break;
    			case 11://wyśw_2_dziesiątki sekund
    			PORTC &=~ _BV(5);
    			cyfra[dec_ds];
    			PORTC |= _BV(5);
    			break;
    			case 12://wyśw_2_jednostk sekund
    			PORTC &=~ _BV(6);
    			cyfra[dec_js];
    			PORTC |= _BV(6);
    			break;
    			default:
    			break;
    		}
    	}
    }
    return;		
    }
    //********** END MAIN **********
  • REKLAMA
  • #2 8892000
    tmf
    VIP Zasłużony dla elektroda
    Źle do tego podchodzisz. Całe multipleksowanie zrób w przerwaniu timera, który określi dokładnie jak długo wyświetlana będzie każda cyfra. Teraz to robisz w pętli idącej z max szybkością proca, w efekcie piekielnie szybko multipleksujesz LCD, co pomniejsza ich jasność, a dwa, że jak program się na czymś na chwilę zatrzyma (czyli odczycie PCF) to całość szlag trafia. Swoją drogą zamiast PCFa, nie prościej byłoby zrobić programowy RTC, albo programowo/sprzętowy, wykorzystując asynchroniczny timer?
  • REKLAMA
  • #3 8892349
    margas4542
    Poziom 16  
    Chyba niezbyt dokładnie przeczytałeś mój post nie korzystam z LCD tylko z dwu 6-cyfrowych wyświetlaczy LED. Mam parę PCF-ów więc je wykorzystuje są stabilniejsze i dokładniejsze a o miejsce na płytce nie muszę się martwić. Fakt że multiplex będzie szedł z prędkością proca ale to nie działa i w tym kłopot.
  • #4 8892414
    mirekk36
    Poziom 42  
    margas4542 -->

    tmf napisał:
    , w efekcie piekielnie szybko multipleksujesz LCD, co pomniejsza ich jasność, ?


    toż w tym przypadku LCD to tylko literówka, więc nic się nie pomyliło bo z kontekstu całej wypowiedzi jasno przecież wynika że chodzi o LED a nie LCD. A uwagi zawarte w tej wypowiedzi są akurat bardzo słuszne odnośnie tego jak robisz multipleksowanie i co robisz źle.

    Co do RTC to ja akurat też wolę takie rozwiązanie niż robienie tego na procku ale jednak nie zgodzę się z tobą, że:

    margas4542 napisał:
    więc je wykorzystuje są stabilniejsze i dokładniejsze


    Bo nie chodzi o to które rozwiązanie jest dokładniejsze czy stabilniejsze - oba są porównywalne. Bardziej chodzi o rozwiązywanie sposobów podtrzymywania zasilania w czasie gdy układ jest wyłączony. Dla RTC wystarczy tylko dać maleńką bateryjkę przez jakąś diodę a w przypadku procka już trzba troszkę pokombinować na zewnątrz jak i w samym kodzie. No ale każdy zrobi tak jak lubi i co mu wygodniej.


    margas4542 napisał:
    Fakt że multiplex będzie szedł z prędkością proca ale to nie działa i w tym kłopot.


    Dlatego zrób tak jak radził kolega, i tak jak się należy to robić czyli w oparciu o jakiejś przerwanie dowolnego timera ze ściśle dobranym czasem odświeżania.
  • #5 8893124
    margas4542
    Poziom 16  
    Mam niewielkie a raczej bardzo małe doświadczenie z licznikami i przerwaniami i nie za bardzo wiem jak się do tego zabrać,który i jak skonfigurować licznik i gdzie użyć przerwań...
  • #6 8895358
    margas4542
    Poziom 16  
    Dziękuje za linki...próbowałem coś wskórać tłumacząc manualna atmegi ale teraz mogę spróbować napisać potrzebny kod....co z tego wyjdzie zobaczymy
    OK mam ustawiony Timer i funkcję switch przełączającą cyfry wyświetlacza ale w jaki sposób jest zwiększana wartość zmiennej (wysw) z przykładu [linki poprzedni post] ?..
    
    //********** define segmentów wyświetlacza
    volatile uint8_t led_display;
    const unsigned char cyfra[10]={
    				0xC0,/*cyfra 0		  A   		*/
    				0xF9,/*cyfra 1		 ---		*/
    				0xA4,/*cyfra 2		|	|		*/
    				0xB0,/*cyfra 3	  F |	| B		*/
    				0x99,/*cyfra 4		|	|		*/
    				0x92,/*cyfra 5	  G  ---		*/
    				0x82,/*cyfra 6		|	|		*/
    				0xF8,/*cyfra 7	  E |	| C		*/
    				0xC0,/*cyfra 8		|	|		*/
    				0x90,/*cyfra 9		 ---		*/
    				0x7F /*kropka		  D	  #	H	*/
    				};
    //***** MAIN
    int main()
    {
     DDRA=0xFF;		//wyjścia - segmenty wyświetlaczy wyś_1 oraz wyś_2
     DDRB=0xFF;		//wyjścia - cyfry wyświetlacza czasu lokalnego
     DDRC=0xFC;		//wyjścia - cyfry wyświetlacza daty oraz wejścia - SCL SDA układu PCF8583
     PORTC=0x03;	//pull-up - dla SCL SDA INT1 układu PCF8583
     DDRD=0x00;		//wejścia - klawiatura
     PORTD=0xF8;	//pull-up - klawiatura
    //----- TWI init
     TWSR=0x00;		
     TWBR=0x48; //preskaler I2C - ((F_CPU / 100000UL - 16) - inicjacja przerwań
    //----- 
     TCCR1B |= (1 << WGM12); 	//ustawia timer1 w tryb CTC
     OCR1A = 160000; 			//ustawia wartość pożądaną na 100Hz dla preskalera 1
     TCCR1B |= (1 << CS10); 	//ustawia timer z preskalerem Fcpu/1
     TIMSK |= (1 << OCIE1A); 	//zezwolenie na przerwania dla CTC
     sei(); 					//zezwolenie globalne na przerwania
    //-----pętla główna progranu
     while(1)
     {	//odczyt czasu i daty 
    	PCF=TWI_read(zegar,0x06);	PCF_dmc=PCF >>4;	PCF_jmc=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x05);	PCF_ddni=PCF >>4;	PCF_jdni=PCF & 0x0F;
        PCF=TWI_read(zegar,0x04);	PCF_dg=PCF >>4;		PCF_jg=PCF & 0x0F;
        PCF=TWI_read(zegar,0x03);	PCF_dm=PCF >>4;		PCF_jm=PCF & 0x0F;
        PCF=TWI_read(zegar,0x02);	PCF_ds=PCF >>4;		PCF_js=PCF & 0x0F;
    	//-----
    	dec_dg=bcd_na_dec(PCF_dg);	dec_jg=bcd_na_dec(PCF_jg);//konwersja na dec godziny
    	dec_dm=bcd_na_dec(PCF_dm);	dec_jm=bcd_na_dec(PCF_jm);//konwersja na dec minuty
     	{
    	//
    	}
    }
    return 0;
    }
    
    ISR(TIMER1_COMPA_vect)
    {
    	switch(led_display)
    	{
    		case 0://wyśw_1_dziesiątki godzin
    		PORTB &=~ 0x00;
    		cyfra[dec_dg];
    		_delay_ms(500);
    		PORTB |= 0x00;
    		break;
    		case 1://wyśw_1_jednostki godzin
    		PORTB &=~ 0x01;
    		cyfra[dec_jg];
    		_delay_ms(500);
    		PORTB |= 0x01;
    		break;
    		case 2://wyśw_1_dziesiątki minut
    		PORTB &=~ 0x02;
    		cyfra[dec_dm];
    		_delay_ms(500);
    		PORTB |= 0x02;
    		break;
    		case 3://wyśw_1_jednostk minut
    		PORTB &=~ 0x04;
    		cyfra[dec_jm];
    		_delay_ms(500);
    		PORTB |= 0x04;
    		break;
    		case 4:
    		PORTB &=~ 0x08;
    		PORTA=0xC0;
    		_delay_ms(500);
    		PORTB |= 0x08;
    		break;
    	}
    }
    //********** END MAIN **********
  • REKLAMA
  • #7 8896330
    MichalXY
    Poziom 11  
    W obsłudze przerwania zupełnie niepotrzebnie dałeś opóźnienie _delay_ms(500)

    A jeśli chodzi o zwiększanie wartości zmiennej led_display to przed instrukcją break;
    zwiększasz wartość zmiennej przez instrukcję (ta instrukcja to inkramentacja czyli zwiekszanie zmiennej o 1).
    Dopiero gdy jesteś w ostatniej instrukcji case np case 3 to do zmiennej led_display przypisujesz wartość 0 aby nastąpił "skok" do pierwszego case'a.




    Mam tylko jeszcze jedną uwagę - o co chodzi w tym fragmencie kodu:
    
    case 4:
          PORTB &=~ 0x08;
          PORTA=0xC0;
          _delay_ms(500);
          PORTB |= 0x08;
          break; 
    


    Moim skromnym zdaniem ten fragment jest niepotrzebny.

    Pozdrawiam i życzę wesołych świąt! :)
  • #8 8896716
    margas4542
    Poziom 16  
    Wiem to pokłosie prób...OK zmieniłem zgodnie z sugestią i dalej mam NIC...a właściwie zmiany tylko na ostatniej cyfrze jak gdyby kolejne cyfry nakładały się na siebie....ale co robi teraz timer bo chyba nic ?......
    
    //********** define segmentów wyświetlacza
    volatile uint8_t led_display;
    const unsigned char cyfra[]={
    				0xC0,/*cyfra 0		  A   		*/
    				0xF9,/*cyfra 1		 ---		*/
    				0xA4,/*cyfra 2		|	|		*/
    				0xB0,/*cyfra 3	  F |	| B		*/
    				0x99,/*cyfra 4		|	|		*/
    				0x92,/*cyfra 5	  G  ---		*/
    				0x82,/*cyfra 6		|	|		*/
    				0xF8,/*cyfra 7	  E |	| C		*/
    				0xC0,/*cyfra 8		|	|		*/
    				0x90,/*cyfra 9		 ---		*/
    				0x7F /*kropka		  D	  #	H	*/
    				};
    //***** MAIN
    int main()
    {
     DDRA=0xFF;		//wyjścia - segmenty wyświetlaczy wyś_1 oraz wyś_2
     DDRB=0xFF;		//wyjścia - cyfry wyświetlacza czasu lokalnego
     DDRC=0xFC;		//wyjścia - cyfry wyświetlacza daty oraz wejścia - SCL SDA układu PCF8583
     PORTC=0x03;	//pull-up - dla SCL SDA INT1 układu PCF8583
     DDRD=0x00;		//wejścia - klawiatura
     PORTD=0xF8;	//pull-up - klawiatura
    //----- TWI init
     TWSR=0x00;		
     TWBR=0x48; //preskaler I2C - ((F_CPU / 100000UL - 16)
    //----- 
     TCCR1B |= (1 << WGM12); 	//ustawia timer1 w tryb CTC
     OCR1A = 160000; 			//ustawia wartość pożądaną na 100Hz dla preskalera 1
     TCCR1B |= (1 << CS10); 	//ustawia timer z preskalerem Fcpu/1
     TIMSK |= (1 << OCIE1A); 	//zezwolenie na przerwania dla CTC
     sei(); 					//zezwolenie globalne na przerwania
    //-----pętla główna progranu
     while(1)
     {   //odczyt czasu i daty
    	PCF=TWI_read(zegar,0x06);   PCF_dmc=PCF >>4;   PCF_jmc=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x05);   PCF_ddni=PCF >>4;   PCF_jdni=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x04);   PCF_dg=PCF >>4;      PCF_jg=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x03);   PCF_dm=PCF >>4;      PCF_jm=PCF & 0x0F;
    	PCF=TWI_read(zegar,0x02);   PCF_ds=PCF >>4;      PCF_js=PCF & 0x0F;
    	//-----
    	dec_dg=bcd_na_dec(PCF_dg);   dec_jg=bcd_na_dec(PCF_jg);//konwersja na dec godziny
    	dec_dm=bcd_na_dec(PCF_dm);   dec_jm=bcd_na_dec(PCF_jm);//konwersja na dec minuty
    	dec_ds=bcd_na_dec(PCF_ds);   dec_js=bcd_na_dec(PCF_js);//konwersja na dec minuty
    }
    return 0;
    }
    
    ISR(TIMER1_COMPA_vect)
    {
    	switch(led_display)
    	{
    		case 0://wyśw_1_dziesiątki godzin
    		PORTB &=~ 0x00;
    		PORTA=cyfra[dec_dm];
    		PORTB |= 0x00;
    		led_display++;
    		break;
    		case 1://wyśw_1_jednostki godzin
    		PORTB &=~ 0x01;
    		PORTA=cyfra[dec_jm];
    		PORTB |= 0x01;
    		led_display++;
    		break;
    		case 2://wyśw_1_dziesiątki minut
    		PORTB &=~ 0x02;
    		PORTA=cyfra[dec_ds];
    		PORTB |= 0x02;
    		led_display++;
    		break;
    		case 3://wyśw_1_jednostk minut
    		PORTB &=~ 0x04;
    		PORTA=cyfra[dec_js];
    		PORTB |= 0x04;
    		led_display=0;
    		break;
    	}
    }
    //********** END MAIN **********
  • REKLAMA
  • #9 8899396
    margas4542
    Poziom 16  
    Teraz dla ułatwienia multiplex chcę uruchomić na wyświetlaczach LED ale docelowo będą dwie lampy VFD typ IW-18 łącznie wyświetlanych 12-cyfr...czy nie ma na tym forum nikogo kto potrafi wytłumaczyć jak poprawnie powinno się zrobić taki multiplex ?..dołączam schemat;
    [img]
    [atmega32][c]multipleksowanie wyświetlacza LED[/img]
  • #10 8899539
    tmf
    VIP Zasłużony dla elektroda
    Raczej nie ma nikogo, komu chce się tłumaczyć takie podstawy, tym bardziej, że na googlach znajdziesz gotowce na ten temat w pare sekund. Poza tym kolega MichalXY dał ci już linki do materiałów.
    Co do twojego programu to zastanów się po co masz te wszystkie switch/case? Są niepotrzebne, od tego masz zmienną led_display, aby nią indeksować dane. Tak samo po co ją zwiększać w każdym case? Nie lepiej ją zwiększać na samym końcu tylko raz? Te instrukcje PORTB &=~ 0x04; są niepotrzebne, po prostu wpisz 0 na ten port, chyba, że inne linie tego portu wykorzystujesz do czegoś innego, to wtedy je zamaskuj, ale też tylko raz. Pokaż też jak są zadeklarowane twoje zmienne dec_costam, zapewne bez volatile?
    Kolejna rzecz - po co na około czytasz czas z PCFa, skoro wyświetlasz go z dokładnością do minuty? To lepiej już czytać co minutę. A najlepiej wykorzystać do tego celu wyjście przerwania z PCFa. Kolejna rzecz to atomowość - zastanó się co będzie, jeśli w trakcie zmiany np. minut z 59 na 00 przerwanie LED wystąpi pomiędzy odczytem pierwszej i drugiej cyfry? Przez chwilę będziesz miał 50, co będzie wyglądać dziwnie. Co prawda to będzie ułamek sekundy, ale to wystarczy, żeby widzieć nieprzyjemne mignięcie.
  • #11 8899670
    margas4542
    Poziom 16  
    To mój drugi program ale nie robiłem jeszcze niczego na przerwaniach...każdy pisze po swojemu a nawet mając doświadczenie nawet wam trudno taki program przeanalizować....wszyscy odwołujcie się do google twierdząc że wszystkiego tam jest w bród a to nie jest tak różowo...może dla kolegi to banalne podstawy podając za przykład linki a potem te same procedury krytykuje doprowadzając do sytuacji że ta procedura multiplexu nie jest już tak banalnie prosta...
    Na razie uzyskałem wyświetlanie na 2-3-4 pozycji wyświetlacza ale tą samą cyfrę..
    
    //********** funkcje konwersji   
    char dec_na_bcd(char num)   {return ((num/10 * 16) + (num % 10));}   //set = dec_na_bcd(set);      
    char bcd_na_dec(char num)   {return ((num/16 * 10) + (num % 16));}   //set = bcd_na_dec(set);
    //********** definicje zmiennych dla zegara
    unsigned char rtc_tmp;
    unsigned char rtc[12];//odczyt daty i czasu
    unsigned char dec[12];//czas po konwersji na dec
    // dziesiątki -> [0] miesięcy,[2] dni,[4] godzin,[6] minut,[8] sekund
    // jednostki  -> [1] miesięcy,[3] dni,[5] godzin,[7] minut,[9] sekund
    //********** definicje zmiennych dla menu
    unsigned char licznik_1,licznik_2,cyfra_nr;
    unsigned char set_g1,set_m1,set_g2,set_m2,set_g3,set_m3,set_g4,set_m4;
    //********** define segmentów wyświetlacza
    volatile uint8_t led_display;
    const unsigned char cyfra[10]={
                0xC0,/*cyfra 0        A       		*/
                0xF9,/*cyfra 1       ---      		*/
                0xA4,/*cyfra 2      |   |     		*/
                0xB0,/*cyfra 3    F |   | B   		*/
                0x99,/*cyfra 4      |   |     		*/
                0x92,/*cyfra 5    G  ---      		*/
                0x82,/*cyfra 6      |   |     		*/
                0xF8,/*cyfra 7    E |   | C   		*/
                0xC0,/*cyfra 8      |   |     		*/
                0x90,/*cyfra 9       ---      		*/
                0x7F /*kropka         D     #   H   */
                }; 
    //***** MAIN
    int main()
    {
     DDRA=0xFF;		//wyjścia - segmenty wyświetlaczy wyś_1 oraz wyś_2
     DDRB=0xFF;		//wyjścia - cyfry wyświetlacza czasu lokalnego
     DDRC=0xFC;		//wyjścia - cyfry wyświetlacza daty oraz wejścia - SCL SDA układu rtc8583
     PORTC=0x03;	//pull-up - dla SCL SDA INT1 układu rtc8583
     DDRD=0x00;		//wejścia - klawiatura
     PORTD=0xF8;	//pull-up - klawiatura
    //----- TWI init
     TWSR=0x00;      
     TWBR=0x48;					//preskaler I2C - ((F_CPU / 100000UL - 16)
     TCCR1B |= (1 << WGM12);    //ustawia timer1 w tryb CTC
     OCR1A = 160000;          	//ustawia wartość pożądaną na 100Hz dla preskalera 1
     TCCR1B |= (1 << CS10);    	//ustawia timer z preskalerem Fcpu/1
     TIMSK |= (1 << OCIE1A);    //zezwolenie na przerwania dla CTC 
     sei();   
    //-----pętla główna progranu
     while(1)
     {
     	cyfra_nr=0;
     	rtc_tmp=TWI_read(zegar,0x01);	rtc[10]=rtc_tmp >>4;	rtc[11]=rtc_tmp & 0x0F;//odczyt setnych sekund
    	dec[10]=bcd_na_dec(rtc[10]);   dec[11]=bcd_na_dec(rtc[11]);		//konwersja na dec setne sekundy
    
    	if(dec[11]==0)
    	{
    		rtc_tmp=TWI_read(zegar,0x06);	rtc[0]=rtc_tmp >>4;	rtc[1]=rtc_tmp & 0x0F;//odczyt miesięcy
    		rtc_tmp=TWI_read(zegar,0x05);	rtc[2]=rtc_tmp >>4;	rtc[2]=rtc_tmp & 0x0F;//odczyt dni
    		rtc_tmp=TWI_read(zegar,0x04);	rtc[4]=rtc_tmp >>4;	rtc[5]=rtc_tmp & 0x0F;//odczyt godzin
    		rtc_tmp=TWI_read(zegar,0x03);	rtc[6]=rtc_tmp >>4;	rtc[7]=rtc_tmp & 0x0F;//odczyt minut
    		rtc_tmp=TWI_read(zegar,0x02);	rtc[8]=rtc_tmp >>4;	rtc[9]=rtc_tmp & 0x0F;//odczyt sekund
    	//-----
    		dec[0]=bcd_na_dec(rtc[0]);   dec[1]=bcd_na_dec(rtc[1]);//konwersja na dec miesięcy
    		dec[2]=bcd_na_dec(rtc[2]);   dec[3]=bcd_na_dec(rtc[3]);//konwersja na dec dni
    		dec[4]=bcd_na_dec(rtc[4]);   dec[5]=bcd_na_dec(rtc[5]);//konwersja na dec godziny
    		dec[6]=bcd_na_dec(rtc[6]);   dec[7]=bcd_na_dec(rtc[7]);//konwersja na dec minuty
    		dec[8]=bcd_na_dec(rtc[8]);   dec[9]=bcd_na_dec(rtc[9]);//konwersja na dec sekundy
    	}
    }
    return;      
    }
    ISR(TIMER1_COMPA_vect)
    {
       switch(cyfra_nr)			//na razie testuje na czterech cyfrach bo tylko taki mam wyświetlacz.
       							//docelowo lampa VFD IW-18
       {
    		case 0:				//wyśw_1_cyfra_1
    		PORTB &=~ 0x00;
    		PORTA=cyfra[dec[6]];
    		PORTB |= 0x00;
    		cyfra_nr++;
    		break;
    		case 1:				//wyśw_1_cyfra_2
    		PORTB &=~ 0x01;
    		PORTA=cyfra[dec[7]];
    		PORTB |= 0x01;
    		cyfra_nr++;
    		break;
    		case 2:				//wyśw_1_cyfra_3
    		PORTB &=~ 0x02;
    		PORTA=cyfra[dec[8]];
    		PORTB |= 0x02;
    		cyfra_nr++;
    		break;
    		case 3:				//wyśw_1_cyfra_4
    		PORTB &=~ 0x04;
    		PORTA=cyfra[dec[9]];
    		PORTB |= 0x04;
    		cyfra_nr++;
    		break;
    		case 4:				//wyśw_1_cyfra_5
    		cyfra_nr++;
    		break;
    		case 5:				//wyśw_1_cyfra_6
    		cyfra_nr++;
    		break;
    		case 6:				//wyśw_2_cyfra_1
    		cyfra_nr++;
    		break;
    		case 7:				//wyśw_2_cyfra_2
    		cyfra_nr++;
    		break;
    		case 8:				//wyśw_2_cyfra_3
    		cyfra_nr++;
    		break;
    		case 9:				//wyśw_2_cyfra_4
    		cyfra_nr++;
    		break;
    		case 10:			//wyśw_2_cyfra_5
    		cyfra_nr++;
    		break;
    		case 11:			//wyśw_2_cyfra_6
    		cyfra_nr++;
    		break;
    
       }
    }
    //********** END MAIN **********
  • Pomocny post
    #12 8900769
    MichalXY
    Poziom 11  
    margas4542 linki które podałem zawierają naprawdę dobre materiały na temat timerow, przerwań i multipleksowania wyświetlaczy LED.

    Poniżej jest uproszczony schemat podłączenia wyświetlaczy LED i kod programu do obsługi multipleksowania wyświetlaczy LED.

    [atmega32][c]multipleksowanie wyświetlacza LED

    Poniżej znajduje się program do obsługi multipleksowania wyświetlaczy LED ze wspólną anodą i dla częstotliwości procesora 1MHz


    /*
     * multipleksowanie.c
     *
     *  Created on: 21-12-2010
     *      Author: Michał
     */
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    int wyswietlacz;
    
    unsigned char cyfra[10]={
               0xC0,/*cyfra 0        A         */
               0xF9,/*cyfra 1       ---      */
               0xA4,/*cyfra 2      |   |      */
               0xB0,/*cyfra 3     F |   | B      */
               0x99,/*cyfra 4      |   |      */
               0x92,/*cyfra 5     G  ---      */
               0x82,/*cyfra 6      |   |      */
               0xF8,/*cyfra 7     E |   | C      */
               0xC0,/*cyfra 8      |   |      */
               0x90,/*cyfra 9       ---      */
               0x7F /*kropka        D     #   H   */
               };
    
    
    
    ISR(TIMER1_COMPA_vect)
    {
    	switch(wyswietlacz)
    	{
    	case 0: PORTB |= _BV(3);  /* USTAWIENIE BITU 3 PORTU B wyłączenie wyswietlacza nr 4*/
    	        PORTB |= _BV(2);  /* USTAWIENIE BITU 2 PORTU B wyłączenie wyswietlacza nr 3*/
    	        PORTB |= _BV(1);  /* USTAWIENIE BITU 1 PORTU B wyłączenie wyswietlacza nr 2*/
    	        PORTB &= ~_BV(0); /* WYZEROWANIE BITU 0 PORTU B włączenie wyswietlacza nr 1*/
    	        PORTA = cyfra[1];
    	        wyswietlacz++;
    	        break;
    	case 1: PORTB |= _BV(0);  /* USTAWIENIE BITU 0 PORTU B wyłączenie wyswietlacza nr 1*/
    	        PORTB |= _BV(3);  /* USTAWIENIE BITU 3 PORTU B wyłączenie wyswietlacza nr 4*/
    	        PORTB |= _BV(2);  /* USTAWIENIE BITU 2 PORTU B wyłączenie wsywietlacza nr 3*/
    	        PORTB &= ~_BV(1); /* WYZEROWANIE BITU 1 PORTU B włączenie wyswietlacza nr 2*/
    	        PORTA = cyfra[2];
    	        wyswietlacz++;
    	        break;
    	case 2: PORTB |= _BV(1);  /* USTAWIENIE BITU 1 PORTU B wyłączenie wyswietlacza nr 2*/
    	        PORTB |= _BV(3);  /* USTAWIENIE BITU 3 PORTU B wyłączenie wyswietlacza nr 4*/
    	        PORTB |= _BV(0);  /* USTAWIENIE BITU 0 PORTU B wyłączenie wsyweietlacza nr 1*/
    	        PORTB &= ~_BV(2); /* WYZEROWANIE BITU 2 PORTU B włączenie wyswietlacza nr 3*/
    	        PORTA = cyfra[3];
    	        wyswietlacz++;
    	        break;
    	case 3: PORTB |= _BV(2);  /* USTAWIENIE BITU 2 PORTU B wyłączenie wyswietlacza nr 3*/
    	        PORTB |= _BV(1);  /* USTAWIENIE BITU 1 PORTU B wyłączenie wyswietlacza nr 2*/
    	        PORTB |= _BV(0);  /* USTAWIENIE BITU 0 PORTU B wyłączenie wyswietlacza nr 1*/
    	        PORTB &= ~_BV(3); /* WYZEROWANIE BITU 3 PORTU B włączenie wyswietlacza nr 4*/
    	        PORTA = cyfra[4];
    	        wyswietlacz=0;
    	        break;
    
    
    
    
    	}
    }
    
    int main(void)
    {
    	DDRB = 0xff;
    	PORTB = 0xff;
    	DDRA = 0xff;
    	TCCR1B |= (1<<WGM12);
    	TCCR1B |= (1<<CS10);
    	TIMSK |= (1<<OCIE1A);
    	OCR1A = 5000;
    	sei();
    	while(1);
    
    
    }


    Udostępniam również wsad do procesora ATMEGA32 z powyższym programem
  • #13 8900862
    margas4542
    Poziom 16  
    Ooo wielkie dzięki ruszyło z kopyta...teraz mogę się temu na spokojnie przyjrzeć i przeanalizować...ustawiłeś OCR1A = 5000/3200Hz ja miałem 160000/100Hz ale chodzi przy jednym i drugim parametrze tak samo czy jest jakaś różnica której nie dostrzegam ?...
    dodano; załapałem...to multiplex po modyfikacji
    
    ISR(TIMER1_COMPA_vect)
    {
    	switch(wyswietlacz)
    	{
    		case 0: 
    		PORTB = 0xFE; 			//włączenie wyswietlacza nr 1
    		PORTA = cyfra[dec[6]];
    		wyswietlacz++;
    		break;
    		case 1: 
    		PORTB = 0xFD; 			//włączenie wyswietlacza nr 2
    		PORTA = cyfra[dec[7]];
    		wyswietlacz++;
    		break;
    		case 2: 
    		PORTB = 0xFB; 			//włączenie wyswietlacza nr 3
    		PORTA = cyfra[dec[8]];
    		wyswietlacz++;
    		break;
    		case 3: 
    		PORTB = 0xF7; 			//włączenie wyswietlacza nr 4
    		PORTA = cyfra[dec[9]];
    		wyswietlacz=0;
    		break;
    	}
    }
    
  • Pomocny post
    #14 8901159
    MichalXY
    Poziom 11  
    margas4542 zaopatrz się w program TimerCycles ze tej strony:
    http://www.wkretak.pl/downloads.php?cat_id=1

    Dzięki temu obliczysz liczbę cykli czyli to co zapisuję się do rejestru OCR1A.

    Jeśli chodzi o timery to po pierwsze preskaler(czyli część obwodu timera który dzieli impuls zegarowy tj. zmienia rozdzielczość timera) jest ustawiony na 1 mówi o tym ten fragment kodu:
    TCCR1B |= (1<<CS10) czyli ustawienie bitu CS10 rejestru TCCR1B.

    Timer1 (TCCR1B) zlicza tak długa aż jego wartość będzie równa wartości wpisanej do rejestru OCR1A. Gdy wartość timera i rejestru OCR1A będą równe następuje przerwanie i automatyczne wyzerowanie timera i zliczanie na nowo.
    Takie porównywanie jest umożliwione dzięki trybowi CTC timera czyli porównania wartości timera z wartością pożądaną czyli tą którą wpisujemy do rejestru OCR1A w tym wypadku i gdy wartości będą równe timer zostaję wyzerowany i zostaje w tym momencie wywołane przerwanie.
    Fragment kodu który ustawia timer w tryb CTC
    TCCR1B |= (1<<WGM12);

    Samo przerwanie uzyskujemy dzięki ustawieniu bitu OCIE1A rejestru TIMSK
    czyli zezwolenie na przerwanie dla CTC.
    Fragment:
    TIMSK |= (1<<OCIE1A);


    Ah, bym zapomniał, wogóle każde przerwanie jest odblokowywane poleceniem a blokowane poleceniem

    Odnośnie częstotliwości multipleksowania przyjmuję 50Hz odświerzania dla jednego wyświetlacza co dla 4 wyświetlaczy daje 200Hz.

    Pozdrawiam! :)
  • #15 8901240
    margas4542
    Poziom 16  
    Jeszcze raz dziękuje za cierpliwość i zrozumiałe wytłumaczenie tematu. Aż miło popatrzeć jak cyferki się wyświetlają...programik mam ale policzyłem na kalkulatorku i wszystko pasuje.
    A Z OKAZJI ŚWIĄT CHCIAŁBYM WSZYSTKIM FORUMOWICZOM ORAZ ADMINISTRATOROM PORTALU ELEKTRODA ŻYCZYĆ SPOKOJNYCH BEZTROSKICH ŚWIĄT, POMYŚLNOŚCI , ZDROWIA , SPEŁNIENIA MARZEŃ ORAZ UDANYCH KONSTRUKCJI I DAJĄCYCH SATYSFAKCJĘ PROGRAMÓW.
  • #16 8928080
    margas4542
    Poziom 16  
    Witam. Napisałem i uruchomiłem część zegarka a mianowicie odczyt z PCF-a czasu i daty oraz multipleksowanie wyświetlaczy LED ale mam kłopot z koncepcją jego programowania. Po kilku nieudanych próbach napisania sensownej obsługi klawiszy zmuszony jestem poprosić was o pomoc...to działający kod reszta w malinach :-(
    
    //********** funkcje konwersji   
    char dec_na_bcd(char num)   {return ((num/10 * 16) + (num % 10));}   //set = dec_na_bcd(set);     
    char bcd_na_dec(char num)   {return ((num/16 * 10) + (num % 16));}   //set = bcd_na_dec(set);
    //********** definicje zmiennych dla zegara
    unsigned char rtc_tmp;
    unsigned char rtc[12];//odczyt daty i czasu
    unsigned char dec[12];//czas po konwersji na dec
    unsigned char gmt[12];//czas GMT
    // dziesiątki -> [0] miesięcy,[2] dni,[4] godzin,[6] minut,[8] sekund
    // jednostki  -> [1] miesięcy,[3] dni,[5] godzin,[7] minut,[9] sekund
    //********** definicje zmiennych dla menu
    unsigned char wyswietlacz,funkcja;
    unsigned char set,set_plus,set_minus;
    //********** define segmentów wyświetlacza
    const unsigned char cyfra[11]={
                0xC0,/*cyfra 0        A             */
                0xF9,/*cyfra 1       ---            */
                0xA4,/*cyfra 2      |   |           */
                0xB0,/*cyfra 3    F |   | B         */
                0x99,/*cyfra 4      |   |           */
                0x92,/*cyfra 5    G  ---            */
                0x82,/*cyfra 6      |   |           */
                0xF8,/*cyfra 7    E |   | C         */
                0xC0,/*cyfra 8      |   |           */
                0x90,/*cyfra 9       ---            */
                0x7F,/*kropka         D     #   H   */
    			0xFF /*segmenty wygaszone*/
                };
    //***** MAIN
    int main()
    {
     DDRA=0xFF;      	//wyjścia - segmenty wyświetlaczy wyś_1 oraz wyś_2
     DDRB=0xFF;      	//wyjścia - cyfry wyświetlacza czasu lokalnego
     DDRC=0xFC;      	//wyjścia - cyfry wyświetlacza daty oraz wejścia - SCL SDA układu rtc8583
     PORTC=0x03;   		//pull-up - dla SCL SDA układu rtc8583
     DDRD=0x00;      	//wejścia - klawiatura
     PORTD=0xF8;   		//pull-up - klawiatura
    //----- TWI init
     TWSR=0x00;     
     TWBR=0x48;					//preskaler I2C - ((F_CPU / 100000UL - 16)
     TCCR1B |= (1 << WGM12);	//ustawia timer1 w tryb CTC
     OCR1A = 26666;				//ustawia wartość 50Hz na segment wyświetlacza
     TCCR1B |= (1 << CS10);		//ustawia timer z preskalerem Fcpu/1
     TIMSK |= (1 << OCIE1A);	//zezwolenie na przerwania dla CTC
     sei();
    //-----pętla główna progranu
     while(1)
     {
    	rtc_tmp=TWI_read(zegar,0x06);   rtc[0]=rtc_tmp >>4;   rtc[1]=rtc_tmp & 0x0F;//odczyt miesięcy
    	rtc_tmp=TWI_read(zegar,0x05);   rtc[2]=rtc_tmp >>4;   rtc[2]=rtc_tmp & 0x0F;//odczyt dni
    	rtc_tmp=TWI_read(zegar,0x04);   rtc[4]=rtc_tmp >>4;   rtc[5]=rtc_tmp & 0x0F;//odczyt godzin
    	rtc_tmp=TWI_read(zegar,0x03);   rtc[6]=rtc_tmp >>4;   rtc[7]=rtc_tmp & 0x0F;//odczyt minut
    	rtc_tmp=TWI_read(zegar,0x02);   rtc[8]=rtc_tmp >>4;   rtc[9]=rtc_tmp & 0x0F;//odczyt sekund
    	//-----
    	dec[0]=bcd_na_dec(rtc[0]);   dec[1]=bcd_na_dec(rtc[1]);//konwersja na dec miesięcy
    	dec[2]=bcd_na_dec(rtc[2]);   dec[3]=bcd_na_dec(rtc[3]);//konwersja na dec dni
    	dec[4]=bcd_na_dec(rtc[4]);   dec[5]=bcd_na_dec(rtc[5]);//konwersja na dec godziny
    	dec[6]=bcd_na_dec(rtc[6]);   dec[7]=bcd_na_dec(rtc[7]);//konwersja na dec minuty
    	dec[8]=bcd_na_dec(rtc[8]);   dec[9]=bcd_na_dec(rtc[9]);//konwersja na dec sekundy
    }
    return;     
    }
    ISR(TIMER1_COMPA_vect)
    {
    	switch(wyswietlacz)//docelowo dwie lampy VFD IW-12
    	{
    		case 0://------cyfra nr 1 port PB2
    		PORTC=0xFC;
    		PORTB = 0xFB; 	PORTA = cyfra[dec[4]];	wyswietlacz++;
    		break;
    		case 1://------cyfra nr 2 port PB3
    		PORTB = 0xF7; 	PORTA = cyfra[dec[5]];	wyswietlacz++;
    		break;
    		case 2://------cyfra nr 3 port PB4
    		PORTB = 0xEF; 	PORTA = cyfra[dec[6]];	wyswietlacz++;
    		break;
    		case 3://------cyfra nr 4 port PB5
    		PORTB = 0xDF; 	PORTA = cyfra[dec[7]];	wyswietlacz++;
    		break;
    		case 4://------cyfra nr 5 port PB6
    		PORTB = 0xBF; 	PORTA = cyfra[dec[8]];	wyswietlacz++;
    		break;
    		case 5://------cyfra nr 6 port PB7
    		PORTB = 0x7F; 	PORTA = cyfra[dec[9]];	wyswietlacz++;
    		break;//----------------------------------------------
    		case 6://------cyfra nr 7 port PC2
    		PORTB=0xFF;
    		PORTC = 0xFB; 	PORTA = cyfra[dec[2]];	wyswietlacz++;
    		break;
    		case 7://------cyfra nr 8 port PC3
    		PORTC = 0xF7; 	PORTA = cyfra[dec[3]];	wyswietlacz++;
    		break;
    		case 8://------cyfra nr 9 port PC4
    		PORTC = 0xEF; 	PORTA = cyfra[dec[0]];	wyswietlacz++;
    		break;
    		case 9://------cyfra nr 10 port PC5
    		PORTC = 0xDF; 	PORTA = cyfra[dec[1]];	wyswietlacz++;
    		break;
    		case 10://------cyfra nr 11 port PC6
    		PORTC = 0xBF;	PORTA = 0xF9;	wyswietlacz++;
    		break;
    		case 11://-----cyfra nr 12 port PC
    		PORTC = 0x7F;	PORTA = 0xF9;	wyswietlacz=0;
    		break;
    	}
    }
REKLAMA