Atmega16 - podtrzymanie Goldcapem

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Atmega16 - podtrzymanie Goldcapem

Post autor: malina555 » 20 kwie 2012, 16:10

Witam. Jestem w trakcie budowy zegara opartego o uC Atmega16. Chciałbym kolegów zapytać w jaki sposób wydłużyć czas pracy układu na kondensatorze Goldcap(podtrzymującym) 3F/5,5V. Obecnie układ wytrzymuje tylko kilka minut po odłączeniu napięcia 12V. Przetwornik A/C mierzy napięcie zasilania i wyłącza sterowanie wyjściami uC po zaniku tego napięcia. Można coś jeszcze zrobić aby ograniczyć pobór prądu układu???? Jeśli tak to w jaki sposób???

Schemat układu w załączniku.

Oto kod programu:

Plik main.c

Kod: Zaznacz cały

[/quote]#include <avr/io.h>
#include <util/delay.h>
#include "display.h"
#include <avr/interrupt.h>

#include "keyb.h"
#include "czas.h"
  
#define Uref        5               //definicja napiecia referencyjnego
#define R1			10000			// Dzielnik napieciowy - R1 10k ohm
#define R2			6800			// Dzielnik napieciowy - R2 6k8  ohm


void fv_Tryby_Pracy(void);
unsigned char  wart1, wart2;
unsigned char  uc_display_enable; 


SIGNAL(SIG_OUTPUT_COMPARE1A)
{
	licz_czas();
}


int main(void)
{

   
    unsigned int napiecie; // zmienna do obliczeń wartości ADC i napięcia  



  //Kierunki portów:
	DDRA=0b11111110;
	DDRB=0b11111111;
	DDRC=0b11111111;
	DDRD=0b00111111;


  //Podciągnięcie wejść przycisków do Vcc
	PORTD |=0b01000000;
	PORTD |=0b10000000;

  //Inicjalizacja ADC 
	ADMUX |=  (1<<REFS0); // REFS1:0: wybór napięcia odniesienia ADC  
                        		     //na wewnętrzne źródło 2,56V  
                                     //z zewnętrznym kondensatorem na pinie AREF  
  
    ADCSRA |= (1<<ADEN);  // Odblokowanie przetwornika, Bit rozpoczęcia konwersji
    ADCSRA |= (1<<ADPS2) | (1<<ADPS0); // Dzielnik częstotliwości ADC przez 32 (131 kHz)

  // Inicjalizacja Timer1
   TCCR1B |= (1<<WGM12) | (1<<CS10);// tryb CTC, prescaler /1024 
   OCR1A = 41943; // wartość porównania
   TIMSK |= (1<<OCIE1A); // zezwolenie na przerwanie 

 
	sei(); 


	while(1)
	{

  
    napiecie = 0;

	 // pomiar wartosci ADC0 - napiecie zasilania LED
       
       
       ADCSRA |= (1<<ADSC);// Uruchomienie pojedynczej konwersji 
       while(ADCSRA & (1<<ADSC)); ////czeka na zakończenie konwersji
       //Uin = (Uref*ADC)/1024; //przeliczenie wartości na napięcie
	   napiecie = (ADC*50)/42;

  	 wart1 = napiecie / 100; 
	 wart2 = napiecie % 100; 
	     
       if( napiecie < 800)
       {
         uc_display_enable = 0;
	   }
	   else
	   {
	     uc_display_enable = 1;
       }



       
     

		fv_HAL_keyb_100ms();


		fv_Tryby_Pracy();


		fv_HAL_Display_100ms();

		_delay_ms(100);
	}
}


void fv_Tryby_Pracy(void)
{

	static unsigned char uc_Tryb = 0;
	static unsigned char uc_licz_zmiane = 0;

	switch (uc_Tryb)
	{
	 case(0):	//Wyświetlanie godzin i minut
	 	{
			str_Display.uc_D12_Tryb = c_LIGHT;
			str_Display.uc_D34_Tryb = c_LIGHT;
			str_Display.uc_Dots_Tryb = c_BLINK;

			str_Display.uc_D12_Wart = uc_godziny;
			str_Display.uc_D34_Wart = uc_minuty;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 3;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_Tryb = 1;
		
			break;
		}

	 case(1):  //Wyświetlanie minut i sekund
	 	{

			str_Display.uc_D12_Tryb = c_LIGHT;
			str_Display.uc_D34_Tryb = c_LIGHT;
			str_Display.uc_Dots_Tryb = c_LIGHT;

			str_Display.uc_D12_Wart = uc_minuty;
			str_Display.uc_D34_Wart = uc_sekundy;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 8;
			if(uc_key_state[KEY_SET]==PUTTED1) uc_Tryb = 2;

			break;
		}

	 case(2): //Wyświetlanie daty
	 	{
			str_Display.uc_D12_Tryb = c_LIGHT;
			str_Display.uc_D34_Tryb = c_LIGHT;
			str_Display.uc_Dots_Tryb = c_DARK;

			str_Display.uc_D12_Wart = uc_dni;
			str_Display.uc_D34_Wart = uc_mies;
			
			if(uc_key_state[KEY_SET]==PUTTED1) uc_Tryb = 0;

			break;
		}

	 case(3):	//ustawianie godzin
	 	{
			if(uc_key_state[KEY_SET]!=NOTHING) str_Display.uc_D12_Tryb = c_LIGHT;
			else  str_Display.uc_D12_Tryb = c_BLINK;
			str_Display.uc_D34_Tryb = c_LIGHT;
			

			str_Display.uc_D12_Wart = uc_godziny;
			str_Display.uc_D34_Wart = uc_minuty;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 4;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_godziny++;
			if(uc_godziny>23) uc_godziny=0;
		
		
			break;
		}

	 case(4): //ustawianie minut
	 	
		
	 	{
			str_Display.uc_D12_Tryb = c_LIGHT;
		 	if(uc_key_state[KEY_SET]!=NOTHING) str_Display.uc_D34_Tryb = c_LIGHT;
			else  str_Display.uc_D34_Tryb = c_BLINK;

			str_Display.uc_D12_Wart = uc_godziny;
			str_Display.uc_D34_Wart = uc_minuty;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 5;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_minuty++;
			if(uc_minuty>59) uc_minuty=0;
			
			break;
		}

		case(5): //ustawianie sekund
	 	
		
	 	{
			str_Display.uc_D12_Tryb = c_LIGHT;
		 	if(uc_key_state[KEY_SET]!=NOTHING) str_Display.uc_D34_Tryb = c_LIGHT;
			else  str_Display.uc_D34_Tryb = c_BLINK;

			str_Display.uc_D12_Wart = uc_minuty;
			str_Display.uc_D34_Wart = uc_sekundy;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 6;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_sekundy=0;
			
			break;
		}





	 case(6): // ustawianie dni
	 	{

			if(uc_key_state[KEY_SET]!=NOTHING) str_Display.uc_D12_Tryb = c_LIGHT;
			else  str_Display.uc_D12_Tryb = c_BLINK;
			str_Display.uc_D34_Tryb = c_LIGHT;
			

			str_Display.uc_D12_Wart = uc_dni;
			str_Display.uc_D34_Wart = uc_mies;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 7;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_dni++;
			if(uc_dni>31) uc_dni=0;
		
		
			break;
		}

	 	case(7): // ustawianie miesięcy
	 	{
			

			str_Display.uc_D12_Tryb = c_LIGHT;
			if(uc_key_state[KEY_SET]!=NOTHING) str_Display.uc_D34_Tryb = c_LIGHT;
			else  str_Display.uc_D34_Tryb = c_BLINK;
			

			str_Display.uc_D12_Wart = uc_dni;
			str_Display.uc_D34_Wart = uc_mies;
			
			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 0;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_mies++;
			if(uc_mies>12) uc_mies=0;

			break;
		}

		case(8): // wyświetlanie automatyczne
	 	{
			
			
			if( (uc_licz_zmiane++) > 150 ) uc_licz_zmiane=0;
			
			if(uc_licz_zmiane <= 100)
			 {
				str_Display.uc_D12_Tryb = c_LIGHT;
				str_Display.uc_D34_Tryb = c_LIGHT;
				str_Display.uc_Dots_Tryb = c_BLINK;

				str_Display.uc_D12_Wart = uc_godziny;
				str_Display.uc_D34_Wart = uc_minuty;
			 }
			else
			 {
				str_Display.uc_D12_Tryb = c_LIGHT;
				str_Display.uc_D34_Tryb = c_LIGHT;
				str_Display.uc_Dots_Tryb = c_DARK;

				str_Display.uc_D12_Wart = uc_dni;
				str_Display.uc_D34_Wart = uc_mies;
			 }
			

			if(uc_key_state[KEY_MODE]==PUTTED1) uc_Tryb = 0;

			if(uc_key_state[KEY_SET]==PUTTED1) uc_Tryb = 1;
		
			break;
		}



	}


}
Plik display.c

Kod: Zaznacz cały

#include "hal.h"
#include "display.h"





void fv_BcdTo7seg(void)
  {


	switch(str_Display_BCD.uc_D1_Wart)
	{
		case(0): {str_Display_7seg.uc_Digit1=ZERO;	break;}
		case(1): {str_Display_7seg.uc_Digit1=JEDEN;	break;}
		case(2): {str_Display_7seg.uc_Digit1=DWA;	break;}
		case(3): {str_Display_7seg.uc_Digit1=TRZY;	break;}
		case(4): {str_Display_7seg.uc_Digit1=CZTERY;break;}
		case(5): {str_Display_7seg.uc_Digit1=PIEC;	break;}
		case(6): {str_Display_7seg.uc_Digit1=SZESC;	break;}
		case(7): {str_Display_7seg.uc_Digit1=SIEDEM;break;}
		case(8): {str_Display_7seg.uc_Digit1=OSIEM;	break;}
		case(9): {str_Display_7seg.uc_Digit1=DZIEWIEC;break;}
	};
    
	switch(str_Display_BCD.uc_D2_Wart)
	{
		case(0): {str_Display_7seg.uc_Digit2=ZERO;	break;}
		case(1): {str_Display_7seg.uc_Digit2=JEDEN;	break;}
		case(2): {str_Display_7seg.uc_Digit2=DWA;	break;}
		case(3): {str_Display_7seg.uc_Digit2=TRZY;	break;}
		case(4): {str_Display_7seg.uc_Digit2=CZTERY;break;}
		case(5): {str_Display_7seg.uc_Digit2=PIEC;	break;}
		case(6): {str_Display_7seg.uc_Digit2=SZESC;	break;}
		case(7): {str_Display_7seg.uc_Digit2=SIEDEM;break;}
		case(8): {str_Display_7seg.uc_Digit2=OSIEM;	break;}
		case(9): {str_Display_7seg.uc_Digit2=DZIEWIEC;break;}
	};

	switch(str_Display_BCD.uc_D3_Wart)
	{
		case(0): {str_Display_7seg.uc_Digit3=ZERO;	break;}
		case(1): {str_Display_7seg.uc_Digit3=JEDEN;	break;}
		case(2): {str_Display_7seg.uc_Digit3=DWA;	break;}
		case(3): {str_Display_7seg.uc_Digit3=TRZY;	break;}
		case(4): {str_Display_7seg.uc_Digit3=CZTERY;break;}
		case(5): {str_Display_7seg.uc_Digit3=PIEC;	break;}
		case(6): {str_Display_7seg.uc_Digit3=SZESC;	break;}
		case(7): {str_Display_7seg.uc_Digit3=SIEDEM;break;}
		case(8): {str_Display_7seg.uc_Digit3=OSIEM;	break;}
		case(9): {str_Display_7seg.uc_Digit3=DZIEWIEC;break;}
	};

	switch(str_Display_BCD.uc_D4_Wart)
	{
		case(0): {str_Display_7seg.uc_Digit4=ZERO;	break;}
		case(1): {str_Display_7seg.uc_Digit4=JEDEN;	break;}
		case(2): {str_Display_7seg.uc_Digit4=DWA;	break;}
		case(3): {str_Display_7seg.uc_Digit4=TRZY;	break;}
		case(4): {str_Display_7seg.uc_Digit4=CZTERY;break;}
		case(5): {str_Display_7seg.uc_Digit4=PIEC;	break;}
		case(6): {str_Display_7seg.uc_Digit4=SZESC;	break;}
		case(7): {str_Display_7seg.uc_Digit4=SIEDEM;break;}
		case(8): {str_Display_7seg.uc_Digit4=OSIEM;	break;}
		case(9): {str_Display_7seg.uc_Digit4=DZIEWIEC;break;}
	};

	
  }



void fv_HAL_Display_100ms(void)
{



if (uc_display_enable == 0)
{
str_Display.uc_D12_Tryb = c_DARK;
str_Display.uc_D34_Tryb = c_DARK;
str_Display.uc_Dots_Tryb = c_DARK;

}

        //migacz wyświetlaczy

	unsigned char uc_Migaj;
	static unsigned char uc_Licz_Okres;
     	
	 uc_Licz_Okres++;

	 if( uc_Licz_Okres >= MIG_OKRES ) uc_Licz_Okres = 0;
	 if( uc_Licz_Okres > MIG_WYPEL ) uc_Migaj = 0; else uc_Migaj = 1;
	 
	   // Podział liczby na cyfry
str_Display_BCD.uc_D1_Wart = str_Display.uc_D12_Wart / 10;
str_Display_BCD.uc_D2_Wart = str_Display.uc_D12_Wart % 10;
str_Display_BCD.uc_D3_Wart = str_Display.uc_D34_Wart / 10;
str_Display_BCD.uc_D4_Wart = str_Display.uc_D34_Wart % 10;

str_Display_BCD.uc_Dots_Tryb = str_Display.uc_Dots_Tryb;

		fv_BcdTo7seg(); //zamiana liczb BCD na kody dla wyświetlaczy

		

str_Display_BCD.uc_D1_Tryb = str_Display.uc_D12_Tryb;
str_Display_BCD.uc_D2_Tryb = str_Display.uc_D12_Tryb;
str_Display_BCD.uc_D3_Tryb = str_Display.uc_D34_Tryb;
str_Display_BCD.uc_D4_Tryb = str_Display.uc_D34_Tryb;


	 //Realizacja trybów świecenia wyświetlaczy (ciemny, migajacy, świecący)

		switch(str_Display_BCD.uc_D1_Tryb)
		{
			case(c_DARK): str_Display_7seg.uc_Digit1 = 0;
			case(c_BLINK): if(uc_Migaj == 0) str_Display_7seg.uc_Digit1 = 0;
		}

		switch(str_Display_BCD.uc_D2_Tryb)
		{
			case(c_DARK): str_Display_7seg.uc_Digit2 = 0;
			case(c_BLINK): if(uc_Migaj == 0) str_Display_7seg.uc_Digit2 = 0;
		}

		switch(str_Display_BCD.uc_D3_Tryb)
		{
			case(c_DARK): str_Display_7seg.uc_Digit3= 0;
			case(c_BLINK): if(uc_Migaj == 0) str_Display_7seg.uc_Digit3 = 0;
		}

		switch(str_Display_BCD.uc_D4_Tryb)
		{
			case(c_DARK): str_Display_7seg.uc_Digit4 = 0;
			case(c_BLINK): if(uc_Migaj == 0) str_Display_7seg.uc_Digit4 = 0;
		}
		


		str_Display_7seg.uc_Dots = 1;
		switch(str_Display_BCD.uc_Dots_Tryb)
		{
			case(c_DARK): {str_Display_7seg.uc_Dots = 0; break;}
			case(c_BLINK): {if(uc_Migaj == 0) str_Display_7seg.uc_Dots = 0; break;}
		}



		//Cyfra 1 (dziesiątki godzin:
        if( (str_Display_7seg.uc_Digit1 & 0x01) == 0 ) out_D1a_OFF; else out_D1a_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x02) == 0 ) out_D1b_OFF; else out_D1b_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x04) == 0 ) out_D1c_OFF; else out_D1c_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x08) == 0 ) out_D1d_OFF; else out_D1d_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x10) == 0 ) out_D1e_OFF; else out_D1e_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x20) == 0 ) out_D1f_OFF; else out_D1f_ON;
		if( (str_Display_7seg.uc_Digit1 & 0x40) == 0 ) out_D1g_OFF; else out_D1g_ON;

        if( (str_Display_7seg.uc_Digit2 & 0x01) == 0 ) out_D2a_OFF; else out_D2a_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x02) == 0 ) out_D2b_OFF; else out_D2b_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x04) == 0 ) out_D2c_OFF; else out_D2c_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x08) == 0 ) out_D2d_OFF; else out_D2d_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x10) == 0 ) out_D2e_OFF; else out_D2e_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x20) == 0 ) out_D2f_OFF; else out_D2f_ON;
		if( (str_Display_7seg.uc_Digit2 & 0x40) == 0 ) out_D2g_OFF; else out_D2g_ON;

        if( (str_Display_7seg.uc_Digit3 & 0x01) == 0 ) out_D3a_OFF; else out_D3a_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x02) == 0 ) out_D3b_OFF; else out_D3b_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x04) == 0 ) out_D3c_OFF; else out_D3c_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x08) == 0 ) out_D3d_OFF; else out_D3d_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x10) == 0 ) out_D3e_OFF; else out_D3e_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x20) == 0 ) out_D3f_OFF; else out_D3f_ON;
		if( (str_Display_7seg.uc_Digit3 & 0x40) == 0 ) out_D3g_OFF; else out_D3g_ON;
 
        if( (str_Display_7seg.uc_Digit4 & 0x01) == 0 ) out_D4a_OFF; else out_D4a_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x02) == 0 ) out_D4b_OFF; else out_D4b_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x04) == 0 ) out_D4c_OFF; else out_D4c_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x08) == 0 ) out_D4d_OFF; else out_D4d_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x10) == 0 ) out_D4e_OFF; else out_D4e_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x20) == 0 ) out_D4f_OFF; else out_D4f_ON;
		if( (str_Display_7seg.uc_Digit4 & 0x40) == 0 ) out_D4g_OFF; else out_D4g_ON;

        if(str_Display_7seg.uc_Dots) out_Dwukropek_ON; else out_Dwukropek_OFF;
}

Plik display.h

Kod: Zaznacz cały

//Wartości dla cyfr i dwukropka:
#define c_DARK  0
#define c_LIGHT 1
#define c_BLINK 2


#define MIG_OKRES	10 // okres migania wyświetlacza
#define MIG_WYPEL	5 // okres świecenia w trakcie migania


 


//kształty cyfr 7-segmentowego wyświetlacza:

//				    gfedcba
#define	ZERO	 0b00111111
#define	JEDEN	 0b00000110
#define	DWA 	 0b01011011
#define	TRZY	 0b01001111
#define	CZTERY	 0b01100110
#define	PIEC	 0b01101101
#define	SZESC	 0b01111101
#define	SIEDEM	 0b00000111
#define	OSIEM	 0b01111111
#define	DZIEWIEC 0b01101111


unsigned char  uc_display_enable;  // zmienna trybu wyświetlania



struct def_str_Display
   {
	unsigned char uc_D12_Wart;
	unsigned char uc_D34_Wart;
	unsigned char uc_D12_Tryb;
	unsigned char uc_D34_Tryb;
	unsigned char uc_Dots_Tryb;
   } str_Display;




struct def_str_Display_BCD
   {
	unsigned char uc_D1_Wart;
	unsigned char uc_D2_Wart;
	unsigned char uc_D3_Wart;
	unsigned char uc_D4_Wart;
	unsigned char uc_D1_Tryb;
	unsigned char uc_D2_Tryb;
	unsigned char uc_D3_Tryb;
	unsigned char uc_D4_Tryb;
	unsigned char uc_Dots_Tryb;
   } str_Display_BCD;


struct def_str_Display_7seg
   {
	unsigned char uc_Digit1;
	unsigned char uc_Digit2;
	unsigned char uc_Digit3;
	unsigned char uc_Digit4;
	unsigned char uc_Dots;
   } str_Display_7seg;



void fv_BcdTo7seg(void);
void fv_HAL_Display_100ms(void);

Plik czas.c

Kod: Zaznacz cały

#include <avr/interrupt.h>
#include "czas.h"


void licz_czas (void)
{
  uc_setne++;
 
  if(uc_setne>=100)
    {
    uc_setne=0;
    uc_sekundy++;
    }
  
  if(uc_sekundy>=60)
    {
    uc_sekundy=0;
    uc_minuty++;
    }
  
  if(uc_minuty>=60)
    {
    uc_minuty=0;
    uc_godziny++;
    }

  if(uc_godziny>=25)
    {
    uc_godziny=0;
    uc_dni++;
    }
  
  switch(uc_mies)
   {
     case 1:
      {
	  if(uc_dni>=32)
	    {
		uc_dni=0;
		uc_mies++;
		}
      }
    
	 case 2:
	 {
	 if(uc_dni>=30)
	   {
	   uc_dni=0;
	   uc_mies++;
	   }
     }

	 case 3:
	 {
	 if(uc_dni>=29)
	   {
	   uc_dni=0;
	   uc_mies++;
	   }
     }

	 default:
	 {
	  if(uc_dni>=31)
	    {
		uc_dni=0;
		uc_mies++;
		}
     }
   }

   switch(uc_lata)
    {

	 case 1:
	 {
	 if(uc_dni>=367)
	   {
	   uc_dni=0;
	   uc_lata++;
	   }
     }

	 default:
	 {
	 if(uc_dni>=366)
	   {
	   uc_dni=0;
	   uc_lata++;
	   }
     }
    }
}

Plik hal.h

Kod: Zaznacz cały

#include <avr/io.h>

#define out_D1a_ON	PORTB |= 0b00100000
#define out_D1a_OFF	PORTB &=~0b00100000
#define out_D1b_ON	PORTB |= 0b00010000
#define out_D1b_OFF	PORTB &=~0b00010000
#define out_D1c_ON	PORTD |= 0b00000100
#define out_D1c_OFF	PORTD &=~0b00000100
#define out_D1d_ON	PORTD |= 0b00000010
#define out_D1d_OFF	PORTD &=~0b00000010
#define out_D1e_ON	PORTD |= 0b00000001
#define out_D1e_OFF	PORTD &=~0b00000001
#define out_D1f_ON	PORTB |= 0b01000000
#define out_D1f_OFF	PORTB &=~0b01000000
#define out_D1g_ON	PORTB |= 0b10000000
#define out_D1g_OFF	PORTB &=~0b10000000

#define out_D2a_ON	PORTB |= 0b00000010
#define out_D2a_OFF	PORTB &=~0b00000010
#define out_D2b_ON	PORTB |= 0b00000001
#define out_D2b_OFF	PORTB &=~0b00000001
#define out_D2c_ON	PORTD |= 0b00100000
#define out_D2c_OFF	PORTD &=~0b00100000
#define out_D2d_ON	PORTD |= 0b00010000
#define out_D2d_OFF	PORTD &=~0b00010000
#define out_D2e_ON	PORTD |= 0b00001000
#define out_D2e_OFF	PORTD &=~0b00001000
#define out_D2f_ON	PORTB |= 0b00000100
#define out_D2f_OFF	PORTB &=~0b00000100
#define out_D2g_ON	PORTB |= 0b00001000
#define out_D2g_OFF	PORTB &=~0b00001000

#define out_D3a_ON	PORTA |= 0b00001000
#define out_D3a_OFF	PORTA &=~0b00001000
#define out_D3b_ON	PORTA |= 0b00010000
#define out_D3b_OFF	PORTA &=~0b00010000
#define out_D3c_ON	PORTC |= 0b00000100
#define out_D3c_OFF	PORTC &=~0b00000100
#define out_D3d_ON	PORTC |= 0b00000010
#define out_D3d_OFF	PORTC &=~0b00000010
#define out_D3e_ON	PORTC |= 0b00000001
#define out_D3e_OFF	PORTC &=~0b00000001
#define out_D3f_ON	PORTA |= 0b00000100
#define out_D3f_OFF	PORTA &=~0b00000100
#define out_D3g_ON	PORTA |= 0b00000010
#define out_D3g_OFF	PORTA &=~0b00000010

#define out_D4a_ON	PORTA |= 0b10000000
#define out_D4a_OFF	PORTA &=~0b10000000
#define out_D4b_ON	PORTC |= 0b01000000
#define out_D4b_OFF	PORTC &=~0b01000000
#define out_D4c_ON	PORTC |= 0b00100000
#define out_D4c_OFF	PORTC &=~0b00100000
#define out_D4d_ON	PORTC |= 0b00010000
#define out_D4d_OFF	PORTC &=~0b00010000
#define out_D4e_ON	PORTC |= 0b00001000
#define out_D4e_OFF	PORTC &=~0b00001000
#define out_D4f_ON	PORTA |= 0b01000000
#define out_D4f_OFF	PORTA &=~0b01000000
#define out_D4g_ON	PORTA |= 0b00100000
#define out_D4g_OFF	PORTA &=~0b00100000


#define out_Dwukropek_ON  PORTC |= 0b10000000
#define out_Dwukropek_OFF PORTC &=~0b10000000

Plik keyb.h

Kod: Zaznacz cały

//Podpięcie przycisków do portów

#define in_S1 PIND & 0b01000000
#define in_S2 PIND & 0b10000000


#define KEYS_NR 2 //ilośc klawiszy systemu
#define KEY_MODE 0 //definicja nazw przycisków w systemie
#define KEY_SET 1 //definicja nazw przycisków w systemie


//czasy:* 100ms:
#define T_PUTTED 		2	//Po tym czasie stan przycisku będzie PUTED
#define T_LONG_PUT 		20	//Po tym czasie stan przycisku będzie LONG_PUT
#define T_AUTO		 	10	//Po tym czasie będzie automatyczne klikanie
#define T_CLICK		 	2	//Czas pomięczy kliknięciami


//stany perzycisków:
#define NOTHING 	0
#define PUTTED1 	1
#define PUTTED2 	2
#define LONG_PUT	3


unsigned char uc_key_in[KEYS_NR];
unsigned char uc_key_state[KEYS_NR];


void fv_HAL_keyb_100ms (void);
unsigned char fuc_Klawisz_100ms(unsigned char uc_numer, unsigned char uc_in );



Plik keyb.c

Kod: Zaznacz cały

#include <avr/io.h>
#include "keyb.h"

//unsigned char uc_key_in[KEYS_NR];
//unsigned char uc_key_state[KEYS_NR];
 

void fv_HAL_keyb_100ms (void)

{

 unsigned char i;


	if(in_S1) uc_key_in[KEY_MODE] = 0; else uc_key_in[KEY_MODE] = 1;
	if(in_S2) uc_key_in[KEY_SET] = 0; else uc_key_in[KEY_SET] = 1;
	

	for(i=0;i<KEYS_NR;i++)
	{

      uc_key_state[i] = fuc_Klawisz_100ms( i, uc_key_in[i]);
	}
	

}

//uc_numer - numer przycisku, uc_in - stan wejścia do którego podłączony jest przycisk
unsigned char fuc_Klawisz_100ms(unsigned char uc_numer, unsigned char uc_in )
{

 static unsigned char uc_stan[KEYS_NR];			//pamięć akutalnych stanów poszczególnych przycisków
 static unsigned char uc_licz[KEYS_NR];			//liczniki czasów naciśnięcia
 static unsigned char uc_licz_long[KEYS_NR];    //licznik czasów długiego naciśnięcia
 unsigned char uc_key_out;



  switch( uc_stan[uc_numer] )
  {
	//Bez naciśnięcia:
	case(0):
	{
		uc_licz[uc_numer]=0;
		uc_licz_long[uc_numer]=0;
		uc_key_out = NOTHING;
		if( uc_in > 0 ) {uc_stan[uc_numer] = 1; uc_key_out = PUTTED1;}
		break;
	}

	//Naciśniecie:
	case(1):
	{
		uc_licz[uc_numer]++;
		uc_licz_long[uc_numer]++;
		uc_key_out = PUTTED2;
		if(uc_licz[uc_numer] > T_AUTO) {uc_key_out = PUTTED1; uc_stan[uc_numer] = 2; uc_licz[uc_numer]=0;}
		if( uc_in == 0 ) {uc_stan[uc_numer] = 0; uc_key_out = NOTHING;}
		break;
	}


	//Automatyczne klikanie::
	case(2):
	{
		uc_licz[uc_numer]++;
		uc_licz_long[uc_numer]++;
		if( uc_licz[uc_numer] >= T_CLICK ) {uc_key_out = PUTTED1; uc_licz[uc_numer]=0;}
		else uc_key_out = PUTTED2;

		if( uc_in == 0 ) {uc_stan[uc_numer] = 0; uc_key_out = NOTHING;}
		break;
	}


  }

  if( uc_licz_long[uc_numer] > T_LONG_PUT && uc_key_out == PUTTED2)	uc_key_out = LONG_PUT;

  return uc_key_out;
}
Załączniki
zegar.rar
(55.1 KiB) Pobrany 476 razy

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 20 kwie 2012, 17:19

Na forum zdecydowanie przydało by się kolorowanie składni kodów programów, ale nie będę zbaczać z tematu.

Miło że wysłałeś całe kody źródłowe, zapodaj jeszcze do kompletu schemat, może masz jakieś elementy pożerające energię. Taki np. 7805 jak nie ma napięcia na wejściu to przepuszcza napięcie z wyjścia na wejście.

Co do programu, to poczytaj w dokumentacji procesora (tak, ten pdf 350 stron po angielsku) o zarządzaniu energią i trybach uśpienia. Niektóre zbędne peryferia (np. ADC, komparator analogowy) można wyłączyć już na wstępnie, a samo jądro procka (taktowanie rdzenia, rezonator, zasilanie RAMu, ...) nożna wyłączyć i okresowo wybudzać jakimś przerwaniem lub co kilka sekund reset poprzez watchdog.

Jeśli peryferiów we/wy nie wyłączysz poprzez odcięcie zasilania, to staraj się nie ustawiać ich na brak podłączenia. Ustaw 1/0/podciągnięcie, bo obwody wejściowe cmos pobierają zadziwiająco dużo prądu jeśli napięcie na wejściu jest w okolicach progu przełączania (a z niewiadomych przyczyn jak ustawisz porty jako niepodłączone, to napięcie na nich samo stabilizuje się na około 2-3V).

Na koniec policz: 1F to zmiana o 1V napięcia na kondensatorze w ciągu 1s pod wpływem prądu rzędu 1A.
C * delta V = I * T.
Przy spadku 5V->4V, pojemności 3F i prądzie 10mA (0.01A) wychodzi równo 5 minut.

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 20 kwie 2012, 17:29

Witam. Dziękuje za odpowiedź. Porty ustawione na 0, schemat jest w załączniku.

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 20 kwie 2012, 18:18

A więc to tak, a spodziewałem się źródeł w załączniku.
Na przyszłość: file -> export -> image, nie każdy ma eagla.

Co do oszczędzania energii, to jak mówiłem, wyłączyć ADC (i inne zbędne peryferia też). A właściwie, po co z niego korzystasz? Mierzysz napięcie 12V czy co z nim robisz?
Dobierz właściwie dzielnik napięcia R31-R32 tak, żeby przy napięciu znamionowym na wejściu uC było ponad 4V (stan logiczny 1), a po zaniku napięcia żeby na wejściu procka było coś koło zera (stan logiczny zero). Odczytujesz stan jednego pinu jak przycisk i wiesz co dalej z tym robić.

Drugie to uśpienie. Wyświetlaczy nie sterujesz multiplekserowo tylko statycznie (wreszcie wiszę projekt zegarka który nie miga wyświetlaczami z częstotliwością ok. 50hz) więc poza cyklicznym sprawdzaniem przycisków i liczeniem czasu procek nic twórczego nie robi. Jeśli dobrze widzę, to przerwanie masz 100hz, więc generalnie możesz z pętli głównej wywalić waity i zamiast nich wstawić instrukcję sleep poprzedzoną wyborem odpowiedniego trybu.
Działa to tak, że po wykonaniu tej instrukcji procek po prostu przestaje działać. Jeśli ustawiłeś odpowiedni tryb uśpienia, to po wygenerowaniu przerwania timera procek wznawia działalność, wykonuje przerwanie i wraca do programu zaraz po instrukcji sleep. Oznacza to przejście pętli głównej i znowu sleep.

Trzecia sprawa to taktowanie. Przy tak wymagającym zadaniu jak zegarek, możesz zmienić kwarc na tzw. zegarkowy (32 768hz), co powinno zmniejszyć prąd pobierany przez procesor o przynajmniej połowę.
Uwaga: trzeba przestawić fusy, do tego musisz mieć później programator który zaprogramuje procka z taktowaniem 32khz (usbasp nie daje rady), obowiązkowo trzeba wyłączyć dzielnik taktowania przez 8 i dobrze mieć pod ręką awaryjny generator zegarowy z 1Mhz prostokąt.

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 20 kwie 2012, 20:08

Wyłączyłem komparator analogowy i ADC. Wyłączenie ADC niewiele pomogła napięcie na kondensatorze po zaniku napięcia zasilania bardzo szybko spada do wartości 2,4V i "powoli" spada coraz bardziej.

Mógłby kolega powiedzieć w jaki sposób dokładnie uspać procka ??? I potem obudzić.

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 20 kwie 2012, 23:33

Szybko to znaczy w jakim czasie?
Minuta czy sporo mniej? Naładuj kondensator do 5V i odłącz go od układu, sprawdź jakie będzie napięcie zaraz po odłączeniu a jakie po kilkudziesięciu minutach leżenia.

A jak usypiać procka już mówiłem, odpowiedzi szukaj w dokumentacji producenta.
http://www.atmel.com/Images/doc2466.pdf strona 34 +/-3.

Jeśli masz możliwość, to zmierz prąd jaki płynie przez duży kondensator i rezystor 10 omów (właściwie to możesz mierzyć napięcie na tym rezystorze) podczas pracy z sieci (ładowanie kondensatora) oraz podczas braku zasilania (procek zasilany z kondensatora).
Uważam że 20mA to absolutne maksimum ile może pobierać procesor, jak ciągnie więcej to może być uszkodzony albo coś innego kradnie prąd.
Prąd ładowania kondensatora powinien spaść do podobnej wartości w ciągu kilkunastu minut ładowania, jak nie będzie chciał spaść to kondensator ma upływność.

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 21 kwie 2012, 12:16

Mierzone bez procka po godzinie ładowania:
Maksymalne napięcie naładowania wynosi: 4,89V (bo dioda zabezpieczająca)
Napięcie na rezystorze w czasie ładowania: 1,8mV

Napięcie na kondensatorze po wyłączeniu zasilania(bez procka): 4,89 V
Napięcie na rezystorze po wyłączeniu zasilania (bez procka): 0 mV

Napięcie na kondensatorze po 10 minutach (bez procka): 4,83 V
Napięcie na rezystorze po 10 minutach (bez procka): 0 mV

Napięcie na kondensatorze po 30 minutach (bez procka): 4,80 V
Napięcie na rezystorze po 30 minutach (bez procka): 0 mV



Mierzone z prockiem po godzinie ładowania:
Maksymalne napięcie naładowania wynosi: 4,80V (bo dioda zabezpieczająca)
Napięcie na rezystorze w czasie ładowania: 1,2mV

Napięcie na kondensatorze po wyłączeniu zasilania(z prockiem): 4,53 V
Napięcie na rezystorze po wyłączeniu zasilania(z prockiem): 51 mV

Napięcie na kondensatorze po 10 minutach (z prockiem): 3,51 V
Napięcie na rezystorze po 10 minutach (z prockiem): 35,1 mV

Napięcie na kondensatorze po 30 minutach (z prockiem): 2,45 V
Napięcie na rezystorze po 30 minutach (z prockiem): 22,0 mV

Co do trybu Uśpienia. Można by to zrobić tak żeby zastosować tryb Standby na czas tych 100ms???Jeśli tak to w jaki sposób mam go teraz wybudzić, przerwanie od Timera1 który liczy czas wybudzi procka?????


Plik main.c

Kod: Zaznacz cały

#include <avr/io.h>
#include <util/delay.h>
#include "display.h"
#include <avr/interrupt.h>
#include <avr/sleep.h>

#include "keyb.h"
#include "czas.h"
  
void fv_Tryby_Pracy(void);
unsigned char  uc_display_enable; 


SIGNAL(SIG_OUTPUT_COMPARE1A)
{
	licz_czas();
}


int main(void)
{

  //Kierunki portów:
	DDRA=0b11111110;
	DDRB=0b11111111;
	DDRC=0b11111111;
	DDRD=0b00111111;


  //Podciągnięcie wejść przycisków do Vcc
	PORTD |=0b01000000;
	PORTD |=0b10000000;

  // Inicjalizacja Timer1
   TCCR1B |= (1<<WGM12) | (1<<CS10);// tryb CTC, prescaler /1024 
   OCR1A = 41943; // wartość porównania
   TIMSK |= (1<<OCIE1A); // zezwolenie na przerwanie 

   //Wyłacznie komparatora analogowego
	ACSR |= (1<<ACD);
 
   //Ustawienie trybu Standby
        MCUCR |= (1<<SM2) | (1<<SM1)

	sei(); 


	while(1)
	{

       if(!(PINA & 1<<0))
       {
         uc_display_enable = 0;
	   }
	   else
	   {
	     uc_display_enable = 1;
       }

		fv_HAL_keyb_100ms();


		fv_Tryby_Pracy();


		fv_HAL_Display_100ms();

		sleep_mode();
	}
}


void fv_Tryby_Pracy(void)
{
}

Ostatnio zmieniony 21 kwie 2012, 16:46 przez malina555, łącznie zmieniany 1 raz.

Awatar użytkownika
timo66
Moderator
Posty: 1807
Rejestracja: 20 maja 2006, 19:15
Lokalizacja: 66'15" M.a.R.s.
Kontakt:

Post autor: timo66 » 21 kwie 2012, 13:28

W stanie bezczynności procek powinien pobierać 350µA, co daje spadek o 2V po 4h i 45minutach. Wszystko fajnie i można by powiedzieć czego chcieć więcej. Nie podałeś firmy tego kondensatora. Patrząc losowo na to co oferują w tme i przeglądając pdf to nadciągają czarne chmury. Upływność może być na poziomie 2mA co daje spadek napięcia o 2,4V po godzinie.
Można by było jeszcze zmniejszyć ten rezystor do 1Ω, ale nie wiem jaki maksymalny dopuszczalny prąd ma ten kondensator.

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 21 kwie 2012, 14:54

Kondensator 3F/5,5V firmy FORECON...jakoś nie mogę znaleźć informacji o nim :/

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 21 kwie 2012, 17:07

Jaką wartość ma rezystor R33 włączony szeregowo z kondensatorem C4 3F?
Jeśli jest to 10 omów zgodnie ze schematem, to zgodnie z prawem oma:
1.2mV podczas ładowania oznacza prąd rzędu 10mA co wydaje mi się wartością dość dużą
51mV po odłączeniu zasilania i z włożonym procesorem oznacza prąd 0.5A co jest stanowczo za duże!

Jeśli ten rezystor ma wartość 1 om, to prąd ładowania (upływność kondensatora) jest ok, natomiast 50mA na zasilanie procesora dalej jest wartością zbyt dużą.

Wybudzenie procesora ze stanu uśpienia następuje w momencie wystąpienia jakiegoś przerwania, u ciebie przerwanie timera 1 (liczenie do 1/100 sekundy) powinno wybudzić procesor, woęc sprawdzenie przycisków nastąpi co 10ms.
Jeśli chcesz żeby wywołanie tych funkcji następowało co 100ms to musisz wstawić w tym miejscu licznik do 10 (tak jak liczenie do 60 sekund żeby zwiększyć minutę).

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 21 kwie 2012, 17:19

10 Ohm. Chyba kolega pomylił prawo Ohma z tego co widzę: I=U/R to przy 1,2mV mamy prąd 120uA a przy 51mV mamy 5mA.

Spróbowałem zmienić program i użyć trybu Standby potem na Extended Standby...wyświetlacze nie świecą wogóle :/ Zadziałał tylko tryb Idle. Ale wyświetlacze bardzo szybko migają.
Ostatnio zmieniony 21 kwie 2012, 17:34 przez malina555, łącznie zmieniany 1 raz.

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 21 kwie 2012, 17:34

Ale wtopa, pomyliło mi się z U=R*I :oops:

Jeśli rezystor ma te 10 om, to 5mA na procka to dobry wynik, a spadek napięcia o 1V na 10 minut nawet się zgadza i kondensator wydaje się zachowywać tak jak trzeba.

Teraz zostaje walczyć z usypianiem procka. Może ta strona coś pomoże: http://www.nongnu.org/avr-libc/user-man ... sleep.html
Jak nie, to zostaje wertowanie dokumentacji procesora (tam naprawdę wszystko jest, tylko czasem trzeba się dobrze wczytać) lub szukanie jakiejś ogólnej instrukcji o oszczędzaniu energii na stronie Atmela.


EDIT:
Na pewno żadnych dużych opóźnień. sleep (nieważne w jakiej formie) jest od tego żeby procesor czekał na przerwania, jak mu dasz instrukcję wait/delay to procesor marnuje energię na nicnierobieniu zamiast w uśpieniu czekać na przerwanie.
Zależnie od użytego trybu uśpienia, procesor można wybudzić różnymi zdarzeniami, patrz tabela 14/strona 34. Jak włączyłeś tryb w którym timery są wyłączone, to procka można wybudzić tylko przez zmianę stanu na pinie INT.
Możesz spróbować taktować procesor z wbudowanego oscylatora RC, a kwarc wymienić na zegarkowy. Wtedy timer2 liczy czas i co sekundę budzi procesor. Jeśli natomiast zasilanie jest, to masz pętlę z delay i nie usypiasz procesora.

malina555
-
Posty: 53
Rejestracja: 11 lut 2011, 20:54
Lokalizacja: Warszawa

Post autor: malina555 » 21 kwie 2012, 17:53

Żadnego trybu oprócz idla chyba nie się tu użyć...Jak zastosować to opóźnienie od drugiego licznika????

Awatar użytkownika
kayron
Użytkownik
Posty: 2088
Rejestracja: 21 wrz 2008, 12:53
Lokalizacja: Poland
Kontakt:

Post autor: kayron » 21 kwie 2012, 21:07

Po pierwsze taktować procesor jak najmniejszym zegarem. Tutaj wewnętrznym RC = 1MHz.
Jeżeli jest zewnętrzny układ RTC w postaci np. PCF8583, to budzić procesor przerwaniem od niego. Da się chyba ustawić aby było częściej niż co 1sek. Wtedy można wejść w głębokie uśpienie.

Awatar użytkownika
timo66
Moderator
Posty: 1807
Rejestracja: 20 maja 2006, 19:15
Lokalizacja: 66'15" M.a.R.s.
Kontakt:

Post autor: timo66 » 21 kwie 2012, 21:33

kayron, właśnie jak teraz tak piszesz o PCF'ie to gdzieś już widziałem takie rozwiązanie, że był zegarek i dane pobierał z PCF'a. Podtrzymanie miał na akumulatorku 150mAh. Takie rozwiązanie chyba jest dużo bardziej wydajne.

ODPOWIEDZ