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

[ATMEGA16][C]problem z mnożeniem/dzieleniem uint przez uint.

Ałek Art. 06 Kwi 2009 22:08 1796 7
  • #1 6382694
    Ałek Art.
    Poziom 11  
    Witam,

    Pojawił się ostatnio u mnie taki problem. Otóż odczytuję z przetwornika ADC ATmegi16, z kanału ADC0 wartość napięcia (od 0 do 5VDC). Wyświetlam sobie wynik konwersji na LCD i wszystko ładnie działa (liczba na LCD zmienia się w zakresie od 0 do 1023, jak kręcę potencjometrem). Chciałem sterować tym napięciem podłączonym do ADC0 obrotami silnika prądu stałego. W tym celu postanowiłem wykorzystać PWM na Timer/Counter1.
    PWM chodzi napewno. Konwersja ADC również. Problem polega na tym, że potrzebuję do OCR1A/ OCR1B wpisywać wartość z przedziału 0 do 100 (moc wyjściowa w %).
    Dokonuję sobie przeliczenia mojego wyniku z przetwornika ADC takim sposobem:

    i = ((AI1_REG) * 100 / 1023);

    gdzie: AI1_REG - rejestr, do którego przepisuję wartość ADC po skończonej konwersji.

    Wartość tak obliczonej zmiennej "i" także wyświetlam sobie na moim LCD i tutaj, o dziwo jak dla mnie, czary się dzieją, ponieważ dla zerowego napięcia na wejściu ADC0 wartość wyświetlacz pokazuje mi wartość 0 (z przetwornika) oraz 0 (% mocy PWM) i tak łądnie sobie liczy aż do 63% mocy. Potem wynik zmiennej "i" skacze na zero i znowu liniowo rośnie wraz ze wzrostem napięcia na ADC0 do wartości 37%.

    Skąd te czary??? Przecież od razu widać, że suma tych skrajnych wartości mocy daje 100% (czyli tyle, ile powinienem uzyskać dla maksymalnego napięcia wejściowego na ADC0)...

    Pisząc wyżej podaną linijkę kodu pomyślałem w taki sposób: "Liczby są typu całkowitego, więc jeśli wynik dzielenia wyjdzie jakiś niecałkowity i będzie coś po przecinku, to i tak to co po przecinku zostanie "obcięte" do wyniku całkowitego".

    Czy moje myślenie było już na wejściu błędne? (Dodam, że moje początki z C były jakieś 3 lata temu, potem przerwa aż dotąd, więc może jakiegoś babola strzeliłem...)

    Czy ktoś jest mi w stanie pomóc???

    Poniżej kod programu głównego wraz z przerwaniami:
    
    #include <stdlib.h>
    #include <avr/io.h>
    #include <avr/pgmspace.h>
    #include <sterownik_deklaracje.h>
    #include <lcd.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    
    /*************************************************************************************************
    **************************************************************************************************
    ***************                       PĘTLA GŁÓWNA PROGRAMU                       ****************
    **************************************************************************************************
    *************************************************************************************************/
    
    
    int main(void)
    {
    
    config_function();
    
    lcd_init(LCD_DISP_ON);
    
    
    uint8_t i,i_pop;
    char dupa[10];
     
    while(1)
    	{
    	i = ((AI1_REG) * 100 / 1023);
    
    	if(i != i_pop)
    		{
    		 h_bridge_pwm(LEWO,i);
    		 i_pop = i;
    		 lcd_clrscr();
    		 itoa( AI1_REG , dupa, 10);
    		 lcd_puts(dupa);
    		 lcd_gotoxy(0,1);
    		 itoa( i , dupa, 10);
    		 lcd_puts(dupa);
    		}
    	}
    }
    
    
    
    /*************************************************************************************************
    **************************************************************************************************
    ***************                    PROCEDURY OBSŁUGI PRZERWAŃ                     ****************
    **************************************************************************************************
    *************************************************************************************************/
    
    
    //=================================================================================
    //przerwanie od przepełnienia licznika TC0 - obsługuje klawiaturę i wejścia cyfrowe
    //=================================================================================
    void TIMER0_OVF_vect(void)
    {
    
    
    TCNT0 = 99;								//odtworzenie wartości początkowej licznika TC0
    
    
    static	uint8_t	przycisk_pop_SW1;		//zmienne do obsługi klawiszy
    static	uint8_t	przycisk_pop_SW2;		//
    static	uint8_t	przycisk_pop_SW3;		//
    static	uint8_t	przycisk_temp_SW1;		//
    static	uint8_t	przycisk_temp_SW2;		//
    static	uint8_t	przycisk_temp_SW3;		//
    
    static	uint8_t	temp_DI1;				//zmienne do obsługi wejść DI1-4
    static	uint8_t	temp_DI2;				//
    static	uint8_t	temp_DI3;				//
    static	uint8_t	temp_DI4;				//
    static	uint8_t	pop_DI1;				//
    static	uint8_t	pop_DI2;				//
    static	uint8_t	pop_DI3;				//
    static	uint8_t	pop_DI4;				//
    
    static	uint8_t	licz_odczyt;			//liczniki odczytów klawiatury i wejść DI
    
    
    
    	//Obsługa klawiszy funkcyjnych KLAW_PLUS, KLAW_MINUS, KLAW_MODE
    	//oraz wejść cyfrowych DI1, DI2, DI3, DI4
    
    	przycisk_temp_SW1 = 0;				//domyślnie klawisze wciśnięte
    	przycisk_temp_SW2 = 0;
    	przycisk_temp_SW3 = 0;
    	temp_DI1 = 0;
    	temp_DI2 = 0;
    	temp_DI3 = 0;
    	temp_DI4 = 0;
    
    	if((SW_PIN & _BV(SW1)) == 0)		//test przycisku KLAW_MODE
     		przycisk_temp_SW1 = 1;
    
    	if((SW_PIN & _BV(SW2)) == 0)		//test przycisku KLAW_MINUS
    		przycisk_temp_SW2 = 1;
    
    	if((SW_PIN & _BV(SW3)) == 0)		//test przycisku KLAW_PLUS
     		przycisk_temp_SW3 = 1;
    
    	if((DI_PIN & _BV(DI1)) == 1)		//test wejścia DI1
     		temp_DI1 = 1;
    
    	if((DI_PIN & _BV(DI2)) == 1)		//test wejścia DI2
     		temp_DI2 = 1;
    
    	if((DI_PIN & _BV(DI3)) == 1)		//test wejścia DI3
     		temp_DI3 = 1;
    
    	if((DI_PIN & _BV(DI3)) == 1)		//test wejścia DI4
     		temp_DI4 = 1;
     
    
     	if(pop_DI1 == temp_DI1 && pop_DI2 == temp_DI2 && pop_DI3 == temp_DI3 && pop_DI4 == temp_DI4 \
    		&& przycisk_temp_SW1 == przycisk_pop_SW1 && przycisk_temp_SW2 == przycisk_pop_SW2 \
    		&& przycisk_temp_SW3 == przycisk_pop_SW3)
    		licz_odczyt--;
     	else
     		{
    	 	 przycisk_pop_SW1 = przycisk_temp_SW1;
    		 przycisk_pop_SW2 = przycisk_temp_SW2;
    		 przycisk_pop_SW3 = przycisk_temp_SW3;
    		 pop_DI1 = temp_DI1;
    		 pop_DI2 = temp_DI2;
    		 pop_DI3 = temp_DI3;
    		 pop_DI4 = temp_DI4;
     	 	 licz_odczyt = LICZ_ODCZYT_START_VALUE;
    		}
    
    
     	if(licz_odczyt == 0)
    		{
     		 KLAW_MODE = przycisk_temp_SW1;
    		 KLAW_MINUS = przycisk_temp_SW2;
    		 KLAW_PLUS = przycisk_temp_SW3;
    		 WE_DI1 = temp_DI1;
    		 WE_DI2 = temp_DI2;
    		 WE_DI3 = temp_DI3;
    		 WE_DI4 = temp_DI4;
    		 licz_odczyt = LICZ_ODCZYT_START_VALUE;
    		}
    }
    
    
    //==================================================================
    //przerwanie od przepełnienia licznika TC2 - liczy czas w sterowniku
    //==================================================================
    void TIMER2_OVF_vect(void)
    {
    	LICZ_PRZERW --;
    	if(LICZ_PRZERW == 0)
    		{
    			LICZ_PRZERW = 250;					//odtwórz wartość pierwotną LICZ_PRZERW
    			LICZ_SEK ++;
    
    			if(LICZ_SEK == 60)
    				{
    					LICZ_SEK = 0;
    					LICZ_MIN ++;
    				}
    			if(LICZ_MIN == 60)
    				{
    					LICZ_MIN = 0;
    					LICZ_GODZ ++;
    				}
    			if(LICZ_GODZ == 24)
    				{
    					LICZ_GODZ = 0;
    				}
    		}
    }
    
    
    //==============================
    //przerwanie od przetwornika ADC
    //==============================
    
    void ADC_vect(void)
    {
    	//przerwanie obsługujące przetwornik ADC
    
    static uint8_t zrodlo_adc;
    
    	ADCSRA &= ~_BV(ADIF);					//na wszelki wypadek wyzeruj flagę przerwania
    
    	zrodlo_adc = ADMUX & 0b00000111;		//sprawdź wybrane wejście przetwornika ADC
    
    	switch (zrodlo_adc)
    	{
    		case 0:
    			{
    			 AI1_REG = ADCW;
    			}
    		case 1:
    			{
    			 AI2_REG = ADCW;
    			}
    		case 2:
    			{
    			 AI3_REG = ADCW;
    			}
    		case 3:
    			{
    			 AI4_REG = ADCW;
    			}
    		case 4:
    			{
    			 H_FB_REG = ADCW;
    			}
    	}
    
    	zrodlo_adc += 1;
    	if(zrodlo_adc == 5)
    		zrodlo_adc = 0;
    
    		ADMUX &= 0b11111000;				//zmień kanał przetwornika
    		ADMUX |= zrodlo_adc;
    
    	ADCSRA |= _BV(ADSC);					//Start nowej konwersji
    }
    


    Dodatkowo umieszczam również plik z deklaracjami:
    
    /****************************************************************************************************
    *****************************************************************************************************
    **** BIBLIOTEKA Z ZADEKLAROWANYMI NAZWAMI REJESTRÓW I STAŁYCH UŻYWANYCH W PROGRAMIE GŁÓWNYM ORAZ ****
    ****                                       W PRZERWANIACH                                        ****
    *****************************************************************************************************
    *****************************************************************************************************
    **** AUTOR: AŁEK ART. *******************************************************************************
    *****************************************************************************************************
    ****************************************************************************************************/
    
    
    #define LICZ_ODCZYT_START_VALUE	2		//Ilość zgodnych odczytów stanu klawiszy
    
    volatile	uint8_t	LICZ_SEK;							//
    volatile	uint8_t LICZ_MIN;							//
    volatile	uint8_t LICZ_GODZ;							//do użycia w przerwaniu od TC2
    volatile	uint8_t	LICZ_PRZERW;						//co tyle przerwań wejdzie do obsł. czasu
    
    
    
    //**************************************
    // Nazwy wejść analogowych i cyfrowych:
    //**************************************
    
    #define		AI_PORT		PORTA			//Port procka, na którym wiszą wejścia analogowe
    
    #define		AI1			0				//Pierwsze wejście analogowe (pin nr 0 w porcie A)
    #define		AI2			1				//Drugie wejście analogowe (pin nr 1 w porcie A)
    #define		AI3			2				//Trzecie wejście analogowe (pin nr 2 w porcie A)
    #define		AI4			3				//Czwarte wejście analogowe (pin nr 3 w porcie A)
    
    
    #define		DI_PORT		PORTC			//Port procka, na którym wiszą wejścia cyfrowe
    #define		DI_PIN		PINC			//fizyczne stany wejść DI
    
    #define		DI1			0				//Pierwsze wejście cyfrowe (pin nr 0 w porcie C)
    #define		DI2			1				//Drugie wejście cyfrowe (pin nr 1 w porcie C)
    #define		DI3			2				//Trzecie wejście cyfrowe (pin nr 2 w porcie C)
    #define		DI4			3				//Czwarte wejście cyfrowe (pin nr 3 w porcie C)
    
    volatile uint8_t	WE_DI1;				//znacznik stanu wejścia DI1
    volatile uint8_t	WE_DI2;				//znacznik stanu wejścia DI2
    volatile uint8_t	WE_DI3;				//znacznik stanu wejścia DI3
    volatile uint8_t	WE_DI4;				//znacznik stanu wejścia DI4
    
    
    //************************************************************************
    //Nazwy rejestrów przechowujących odczytane wartości z wejść analogowych:
    //************************************************************************
    //Konwersja 10-bitowa -> potrzebne rejestry 16-bitowe (typu "int")
    
    volatile uint16_t	AI1_REG;				//Rejestr z wartością odczytaną z wejścia AI1
    volatile uint16_t	AI2_REG;				//Rejestr z wartością odczytaną z wejścia AI2
    volatile uint16_t	AI3_REG;				//Rejestr z wartością odczytaną z wejścia AI3
    volatile uint16_t	AI4_REG;				//Rejestr z wartością odczytaną z wejścia AI4
    
    
    //**********************************************************************
    //Nazwy klawiszy na klawiaturze i nazwy znaczników wciśnięcia klawisza:
    //**********************************************************************
    
    #define		SW_PORT		PORTB			//Port procka, na którym wiszą klawisze
    #define		SW_PIN		PINB			//fizyczne stany klawiszy
    
    #define		SW1			0				//Pierwszy klawisz od lewej (pin 0 portu B)
    #define		SW2			1				//Środkowy klawisz (pin 1 portu B)
    #define		SW3			2				//Pierwszy klawisz od prawej (pin 2 portu B)
    
    volatile uint8_t		KLAW_PLUS;		//Znacznik wcisniętego klawisza SW1
    volatile uint8_t		KLAW_MINUS;		//Znacznik wciśniętego klawisza SW2
    volatile uint8_t		KLAW_MODE;		//znacznik wciśniętego klawisza SW3
    
    
    //***************************************
    //Nazwy wyjść cyfrowych przekaźnikowych:
    //***************************************
    
    #define		RO_PORT		PORTD			// "RO_PORT" znaczy "RELAY OUTPUT PORT"
    
    #define		RO1			7				//Pierwsze wyjście przekaźnikowe (pin 7 portu D)
    #define		RO2			2				//Drugie wyjście przekaźnikowe (pin 2 portu D)
    										//jest jednocześnie jednym z wyjść przekaźnikowego
    										//mostka H
    #define		RO3			3				//Trzecie wyjście przekaźnikowe (pin 3 portu D)
    										//jest jednocześnie jednym z wyjść przekaźnikowego
    										//mostka H
    
    //**********************************************************************
    //Nazwy wyjść cyfrowych do i wejścia analogowego ze scalonego mostka H:
    //**********************************************************************
    
    #define		HO_PORT		PORTD			//Port procka, na którym wiszą wejścia scalonego mostka H
    
    #define		H_ENABLE	6				//Pin portu D sygnału "ENABLE" mostka H
    #define		H_IN1		5				//Pin portu D sygnału "IN1" mostka H
    #define		H_IN2		4				//Pin portu D sygnału "IN2" mostka H
    
    
    #define		HI_PORT		PORTA			//Port procka, na którym wisi wyjście pomiaru prądu mostka H
    
    #define		H_FB		4				//Pin portu A sygnału "FEEDBACK" mostka H.
    										//Wartość sygnału równa 1V/1A.
    
    volatile uint8_t WARTOSC_MOCY;			//rejestr zawierający wartość PWM scalonego mostka H
    
    volatile uint8_t	KIERUNEK;			//kierunek kręcenia silnikiem w mostku H (umownie)
    
    #define		STOP		0				//zatrzymany
    #define 	PRAWO		1				//kierunek "w prawo"
    #define		LEWO		2				//kierunke "w lewo"
    
    
    //**************************************************************************
    //Nazwa rejesru przechowującego odczytaną wartość prądu scalonego mostka H:
    //**************************************************************************
    
    volatile uint16_t	H_FB_REG;				//konwersja 10-bitowa -> potrzebny rejestr 16-bitowy.
    
    
    //******************************
    //Liczniki/Czasomierze - stałe:
    //******************************
    
    
    
    
    //*******************************************************************************************
    //*************************         Deklaracje funkcji:            **************************
    //*******************************************************************************************
    
    //====================
    //deklaracje przerwań:
    //====================
    
    extern void TIMER0_OVF_vect(void) __attribute__ ((interrupt));
    extern void TIMER2_OVF_vect(void) __attribute__ ((interrupt));
    extern void ADC_vect(void) __attribute__((interrupt));
    
    //===========================
    //koniec deklaracji przerwań:
    //===========================
    
    
    
    //==========================
    //deklaracje innych funkcji:
    //==========================
    extern void config_function(void);
    extern void h_bridge_pwm(uint8_t KIERUNEK, uint8_t WARTOSC_MOCY);
    extern void przekaznik_on(uint8_t nr_przekaznika);
    extern void przekaznik_off(uint8_t nr_przekaznika);
    


    No i jeszcze na koniec plik z dodatkowymi funkcjami:
    
    /****************************************************************************************************
    *****************************************************************************************************
    **** BIBLIOTEKA ZAWIERAJĄCA FYUNKCJE WYKORZYSTYWANE W PROGRAMOWANIU STEROWNIKA. ZAWIERA TEŻ      ****
    **** FUNKCJE KONFIGURACYJNE I WYKONYWANE NIEZALEŻNIE OD PROGRAMU GŁÓWNEGO (NP. W PRZERWANIACH).  ****
    *****************************************************************************************************
    **** FUNKCJE TE UŻYWAJĄ NAZW ZMIENNYCH ZADEKLAROWANYCH W PLIKU "sterownik_deklaracje.h"          ****
    *****************************************************************************************************
    *****************************************************************************************************
    **** AUTOR: AŁEK ART. *******************************************************************************
    *****************************************************************************************************
    ****************************************************************************************************/
    
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/delay.h>
    #include <lcd.h>
    #include <sterownik_deklaracje.h>
    
    
    
    //**************************************************************************************
    //Funkcja konfigurująca bebechy mikroklocka. Ustawia odpowiednie tryby pracy liczników,
    //konfiguruje przerwania i ustawia wartości początkowe zmiennych dla programu głównego.
    //Do funkcji nie są przekazywne żadne parametry, ani funkcja nic nie zwraca.
    //Przeznaczona jest do użycia na samym początku programu głównego.
    //**************************************************************************************
    
    void config_function(void)
    {
    
    	//cli();								//na wszelki wypadek wyłączenie wszystkich przerwań
    
    	KLAW_MODE = 0;
    	KLAW_PLUS = 0;
    	KLAW_MINUS = 0;
    
    
    	//****************************************************************
    	//ustawienie odpowiednich portów/pinów procka jako wejścia/wyjścia
    	//****************************************************************
    
    	DDRD = 0b11111110;				//PORTD: 7-0 wyjścia
    	RO_PORT = _BV(RO3);				//OD RAZU WYŁĄCZ NAPIĘCIE NA PRZEKAŹNIKOWYM MOSTKU H!!!
    									//(przeoczenie przy projektowaniu obwodu drukowanego).
    									//ustawi jedynkę na jednym z wejść mostka;
    									//reszta wyjść na zerach.
    
    	DDRC = 0b11110000;				//PORTC: 7-4 wyjścia, 3-0 wejścia
    	PORTC = 0b00000000;				//3-0: Pull-Up wyłączony na wszystkich pinach
    
    	DDRB = 0b11111000;				//PORTB: 2-0 wejścia na klawisze
    	PORTB = 0b00000111;				//2-0: Pull-Up włączony na tych pinach
    
    	DDRA = 0b11100000;				//PORTA: 7-5 wyjścia, 4-0 wejścia
    	PORTA = 0b00000000;
    
    
    	//********************************
    	//Ustawienie trybu pracy liczników
    	//********************************
    
    	//==============================================================
    	//LICZNIK TC0 - używany do kontroli klawiatury i wejść cyfrowych
    	//==============================================================
    
    	TCCR0 = 0b00000101;				//Timer TC0: ftakt=fcpu/1024, tryb "NORMAL"
    	TCNT0 = 99;						//przerwanie co 10ms
    
    
    	//=======================================================
    	//LICZNIK TC2 - używany do odmierzania czasu w sterowniku
    	//=======================================================
    
    	TCCR2 |= (_BV(WGM21) | _BV(CS22) | _BV(CS21));	//Timer TC2: ftakt=fcpu/256, tryb "CTC"
    	TCNT2 = 249;						//Wartość początkowa licznika TC2 - przerwanie co 4ms
    										//Liczba zliczanych impulsów: 250.
    
    
    	//=========================================================
    	//LICZNIK TC1 - odpowiada za PWM (na wyjściach OC1A i OC1B)
    	//=========================================================
    
    	TCCR1A = 0b10100010;				//Tryb: FAST PWM
    	TCCR1B = 0b00011000;				//licznik na dzień dobry zatrzymany
    	ICR1 = 100;							//rozdzielczość PWM: 7-bit
    
    	
    	//************************************************
    	//Konfiguracja modułu przetwornika ADC mikroklocka
    	//************************************************
    
    	ADCSRA = 0b00000111;			//preskaler: 1/128 (125kHz) -> fs = 9.6kHz/5 = 1.9kHz
    	ADCSRA |= 0b10001000;			//włączony przetwornik i przerwanie po konwersji
    	ADMUX = 0b01000000;				//Vref = AVCC; wynik naturalny; kanał ADC0
    	_delay_us(130);					//poczekaj 130us
    									//Wszystko już zrobione. Start konwersji później.
    
    	ADCSRA |= _BV(ADSC);			//Start konwersji
    
    	TIMSK = 0b00000001;				//przerwania od TC1 - nieaktywne
    	sei();							//Włączenie wszystkich przerwań
    
    }
    
    //*******************************************************************************************
    //                               Koniec funkcji konfiguracyjnej
    //*******************************************************************************************
    
    
    
    
    
    
    //************************************************************************************************
    //Funkcja włączająca scalony mostek H. Steruje mocą obwodu wyjściowego (zmienna WARTOSC_PWM)
    //oraz polaryzacją napięcia wyjściowego (zmienna KIERUNEK).
    //Można podać następujące wartości parametrów wejściowych:
    //
    //	KIERUNEK:
    //		*STOP
    //		*PRAWO
    //		*LEWO
    //
    //	WARTOSC_PWM: dowolna liczba int (procenty) z przedziału <0;100> - im większa, tym większa moc.
    //************************************************************************************************
    
    void h_bridge_pwm(uint8_t KIERUNEK, uint8_t WARTOSC_PWM)
    {
    	if(KIERUNEK == STOP)							//Gdy ma być zatrzymany, to:
    		{
    			HO_PORT &= ~_BV(H_ENABLE);				//wyłączy mostek H
    			TCCR1B &= ~(_BV(CS12) | _BV(CS10));		//zatrzyma licznik TC1
    			OCR1A = 0;								//wyzeruje oba PWMy
    			OCR1B = 0;								//
    		}
    	if(KIERUNEK == PRAWO)							//Gdy ma się kręcić w prawo, to:
    		{	
    			HO_PORT &= ~_BV(H_ENABLE);				//zatrzyma mostek H
    			TCCR1B &= ~(_BV(CS12) | _BV(CS10));		//wyłączy licznik TC1
    			OCR1A = WARTOSC_PWM;					//załaduje odpowiednie wartości do OCR1x
    			OCR1B = 0;								//
    			TCCR1B |= (_BV(CS12) | _BV(CS10));		//włączy licznik TC1
    			HO_PORT |= _BV(H_ENABLE);				//włączy mostek H
    		}
    	if(KIERUNEK == LEWO)							//Gdy ma się kręcic w lewo, to:
    		{
    			HO_PORT &= ~_BV(H_ENABLE);				//zatrzyma mostek H
    			TCCR1B &= ~(_BV(CS12) | _BV(CS10));		//wyłączy licznik TC1
    			OCR1A = 0;								//załaduje odpowiednie wartości do OCR1x
    			OCR1B = WARTOSC_PWM;					//
    			TCCR1B |= (_BV(CS12) | _BV(CS10));		//włączy licznik TC1
    			HO_PORT |= _BV(H_ENABLE);				//włączy mostek H
    		}
    
    }
    
    //*******************************************************************************************
    //                               Koniec funkcji sterującej PWM
    //*******************************************************************************************
    
    
    
    
    
    //*******************************************************************************************
    //Funkcja włączająca przekaźnik wyjściowy o numerze "nr_przekaznika"
    //możliwe wartości parametru wejściowego:
    //	*RO1
    //	*RO2
    //	*RO3
    //*******************************************************************************************
    
    void przekaznik_on(uint8_t nr_przekaznika)
    {
    	RO_PORT |= _BV(nr_przekaznika);
    }
    
    
    
    
    //*******************************************************************************************
    //Funkcja wyłączająca przekaźnik wyjściowy o numerze "nr_przekaznika"
    //możliwe wartości parametru wejściowego:
    //	*RO1
    //	*RO2
    //	*RO3
    //*******************************************************************************************
    
    void przekaznik_off(uint8_t nr_przekaznika)
    {
    	RO_PORT &= ~_BV(nr_przekaznika);
    }
    


    Pliku z funkcjami do LCD nie będę zamieszczał, bo działają napewno. W tych moich funkcjach również nic się nie sypało. Problem jest jedynie z przeliczaniem odczytu z ADC na % mocy wyjściowej PWM.

    Pozdrawiam wszystkich, którym się chciało czytać i liczę na jakąkolwiek pomoc.
  • #2 6382746
    Freddie Chopin
    Specjalista - Mikrokontrolery
    liczba 16-bitowa ma max wartość 2^16=65535. (1023*63%)*100 to ile będzie?

    Twoje założenie o tym, że do rejestru PWM musisz wpisywać wartość z przedziału 0-100 jest bzdurą. Równie dobrze może to być wartość z przedziału 0-12 jak i 0-93412 jak i 0-255, co tak się składa jest równe wartościom 0-1023 przesuniętym w prawo o 2 pozycje. Można nawet zrezygnować z odczytu całej wartości z przetwornika, ustawić justowanie do lewej i odczytywać tylko ADCH.

    4\/3!!
  • #3 6382931
    Ałek Art.
    Poziom 11  
    Freddie Chopin napisał:
    liczba 16-bitowa ma max wartość 2^16=65535. (1023*63%)*100 to ile będzie?

    Twoje założenie o tym, że do rejestru PWM musisz wpisywać wartość z przedziału 0-100 jest bzdurą. Równie dobrze może to być wartość z przedziału 0-12 jak i 0-93412 jak i 0-255, co tak się składa jest równe wartościom 0-1023 przesuniętym w prawo o 2 pozycje. Można nawet zrezygnować z odczytu całej wartości z przetwornika, ustawić justowanie do lewej i odczytywać tylko ADCH.

    4\/3!!


    Wynik Twojego działania to: 64449, czyli mieści się w zakresie i nie powinno być problemu.
    Poza tym muszę mieć przetwarzanie z 10-bitową precyzją.
    Oprócz tego nie wykonuję działania takiego, jak napisałeś, lecz: (1023 * 100)/1023 (i to przy maksymalnym napięciu na wejściu przetwornika), więc wynik działania MUSI się zmieścić w 1 bajcie (bo maksymalnie może wyjść właśnie wartość 100).
    Wartość 100, którą chcę ładować do OCR1A/OCR1B wynika z wygody użytkowania funkcji "h_bridge_pwm();" i intuicyjności obsługi (bo program piszę nie dla siebie, lecz dla kumpla, który poprosił o podawanie wartości mocy w % od 0 do 100).

    Pozdrawiam.
  • #4 6383023
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Ałek Art. napisał:

    Wynik Twojego działania to: 64449, czyli mieści się w zakresie i nie powinno być problemu.

    I właśnie dlatego 63 jest ostatnią wartością którą widzisz. Powinieneś widzieć jeszcze 64, ale pewnie nie ma wystarczającej precyzji potencjometru i od razu przeskakujesz na (teoretyczne) 65.

    Cytat:

    Poza tym muszę mieć przetwarzanie z 10-bitową precyzją.

    Ciekawe po co, skoro potem przycinasz wynik do mniej niż 7 bitów. Jak dla mnie 3 najmłodsze bity są TRACONE, a nie używane do czegokolwiek.

    Cytat:

    Oprócz tego nie wykonuję działania takiego, jak napisałeś, lecz: (1023 * 100)/1023 (i to przy maksymalnym napięciu na wejściu przetwornika), więc wynik działania MUSI się zmieścić w 1 bajcie (bo maksymalnie może wyjść właśnie wartość 100).

    Owszem - wynik końcowy zawsze mieścić się będzie w 1 bajcie, ale czemu zakładasz, że obliczenia pośrednie realizowane są na liczbach o nieskończonej precyzji? Pierwszą operacją jaką wykonujesz jest pomnożenie wartości 0-1023 przez 100. 63% z 1023 * 100 to będzie...? Bez sprecyzowania typu (rzutowania) obliczenia tego typu są wykonywane na typie int, który w avr-gcc ma 16-bitów.

    Cytat:

    Wartość 100, którą chcę ładować do OCR1A/OCR1B wynika z wygody użytkowania funkcji "h_bridge_pwm();" i intuicyjności obsługi (bo program piszę nie dla siebie, lecz dla kumpla, który poprosił o podawanie wartości mocy w % od 0 do 100).

    Przekonaj więc kumpla, że nie ma to najmniejszego sensu.

    4\/3!!
  • #5 6383101
    Ałek Art.
    Poziom 11  
    Freddie Chopin napisał:
    Ałek Art. napisał:

    Wynik Twojego działania to: 64449, czyli mieści się w zakresie i nie powinno być problemu.

    I właśnie dlatego 63 jest ostatnią wartością którą widzisz. Powinieneś widzieć jeszcze 64, ale pewnie nie ma wystarczającej precyzji potencjometru i od razu przeskakujesz na (teoretyczne) 65.

    Cytat:

    Poza tym muszę mieć przetwarzanie z 10-bitową precyzją.

    Ciekawe po co, skoro potem przycinasz wynik do mniej niż 7 bitów. Jak dla mnie 3 najmłodsze bity są TRACONE, a nie używane do czegokolwiek.

    Cytat:

    Oprócz tego nie wykonuję działania takiego, jak napisałeś, lecz: (1023 * 100)/1023 (i to przy maksymalnym napięciu na wejściu przetwornika), więc wynik działania MUSI się zmieścić w 1 bajcie (bo maksymalnie może wyjść właśnie wartość 100).

    Owszem - wynik końcowy zawsze mieścić się będzie w 1 bajcie, ale czemu zakładasz, że obliczenia pośrednie realizowane są na liczbach o nieskończonej precyzji? Pierwszą operacją jaką wykonujesz jest pomnożenie wartości 0-1023 przez 100. 63% z 1023 * 100 to będzie...? Bez sprecyzowania typu (rzutowania) obliczenia tego typu są wykonywane na typie int, który w avr-gcc ma 16-bitów.

    Cytat:

    Wartość 100, którą chcę ładować do OCR1A/OCR1B wynika z wygody użytkowania funkcji "h_bridge_pwm();" i intuicyjności obsługi (bo program piszę nie dla siebie, lecz dla kumpla, który poprosił o podawanie wartości mocy w % od 0 do 100).

    Przekonaj więc kumpla, że nie ma to najmniejszego sensu.

    4\/3!!


    1) Konwersja ADC będzie używana nie tylko do sterowania PWMem, lecz także do innych rzeczy, w których zażyczył sobie 10-bitowej precyzji.
    2) Wartości 0 do 100% mocy PWM wykorzystałem tak sobie dla wygody, żebym fizycznie mógł obserwować, co się dzieje i czy działa.
    3) Ostatecznie wartość ADC po konwersji i tak będzie musiała być przeliczona na liczby z zakresu 0 do 100% ( żeby to wyświetlać na LCD - oczywiście dla pewnych zastosowań wymyślonych przez tegoż właśnie kumpla).

    A wracając do tematu, to zdaje mi się, że podsunąłeś mi chyba co nieco. Czy dobrze myślę, że pomogłoby wprowadzenie jakiejś dodatkowej zmiennej typu uint32_t i wykonanie obliczenia:

    uint32_t z;
    z = AI1_REG * 100;

    a potem podzielenie "z" przez 1023?
    Jeśli tak, to jak potem ten wynik 32-bitowy wpisać do liczby 8-bitowej (bo domyślam się, że wynik powyższych obliczeń zmieści się na najmłodszym oktecie zmiennej "z")?
  • #6 6383164
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Tak naprawde nie jest ci potrzebna dodatkowa zmienna - wystarczy zrzutować którąś ze zmiennych w działaniu.

    Albo tak:

    (((uint32_t)adc)*100)/1023

    Albo tak:

    (adc*100ul)/1023

    Przy przepisywaniu zmiennej x-bitowej do zmiennej y-bitowej kompilator sam dokona niejawnego rzutowania, więc tym się nie martw.

    4\/3!!
  • #7 6383209
    Ałek Art.
    Poziom 11  
    Dziękuję za tak szybką odpowiedź. Niestety dopiero jutro sprawdzę, czy zadziała - dzisiaj już nadszedł mój czas na sen ;) Pozdrawiam serdecznie.
  • #8 6384887
    Ałek Art.
    Poziom 11  
    Działa wyśmienicie!!! :) Dziękuję za pomoc - sam nigdy w życiu bym się chyba nie domyślił, że tak można... Pozdrawiam i zamykam temat.
REKLAMA