Skocz do zawartości

Zdobądź Proxxona FBS 240/E - #4 - Uniwersalna funkcja


Pomocna odpowiedź

OldSkull, muszę Cię zmartwić, ale Bobby ma 100% racji.

Po pierwsze kod:

#ifndef _ADC_CALC_H_ 
#define _ADC_CALC_H_ 

#endif 

Nie ma najmniejszego sensu. Jest to kompilacja warunkowa pustego bloku. Czyli za pierwszym razem ta pusta linijka zostanie dołączona do kodu, za kolejnym razem już nie. Definicja klasy, jak i pozostała zawartość pliku nagłówkowego powinna być między define, a endif.

Jeszcze ciekawiej jest z kodem dla konstruktora w pliku nagłówkowym. Zasada jest taka, że treść metod / funkcji powinna być w plikach c/cpp/cc, a nie nagłówkowych. Czasem niestety konieczne jest odejście od tej reguły. Przyczyny to: użycie szablonów (template), optymalizacja (funkcje rozwijane w miejscu wywołania, include). W Twoim przypadku nie ma żadnego uzasadnienia na włączanie konstruktora do nagłówka. Tym bardziej, że pozostałem metody są w pliku .cpp.

Najciekawsze jest jednak coś innego - dwa błędy, które popełniłeś, ale nie chcesz się przyznać, sprawiają, że nawet kompilator je wychwyci. Otóż nie działa zabezpieczenie przed dwukrotnym włączaniem pliku nagłówkowego AdcCalc.hpp. Gdybyś nie wstawił konstruktora do tego pliku, kompilator by to przeżył. Ale ponieważ w nagłówku jest treść konstruktora, pojawią się dwie implementacje tej samej metody oraz błąd kompilacji.

Jak nie wierzysz, sprawdź:

#include "AdcCalc.hpp"
#include "AdcCalc.hpp"

error: redefinition of 'AdcCalc'

Tu masz rację. Aczkolwiek dalej uważam, że błąd był w bloku ifdef, a nie w klasie. W każdym razie dziękuję za zwrócenie uwagi - już poprawiłem.

A nie przyznaję się, gdyż są to rozwiązania dopuszczalne, nawet jeśli nie zalecane. To tak jak z instrukcjami skoku - niektóre są dobre, a niektóre złe - goto złe, a break i continue dobre. Wszystko zależy od sytuacji. Tutaj ciała funkcji są w miejscach, które nie ograniczają czytelności kodu, a nawet ją zwiększają - tym samym jako dozwolony zapis, można go stosować.

  • 2 tygodnie później...

Witam!

Ja z kolei chciałbym przedstawić gotową funkcję, ale dla użytkownikó STM'ów32. Ustawia ona najwyższe taktowanie dla mikrokontrolerów z serii f103(72Mhz), ale po kilku małych zmiannach również dla wielu innych. Odróżnia się ona od reszty tym, że jest napisana na rejestrach i można po kolei zobaczyć co jest ustawiane, oraz (co ja lubię najbardziej) obserwować zmiany bitów w debugerze.

void RCC_cfg(void)
{
RCC->CR |= RCC_CR_HSEON;													//włączamy HSE

 while(((RCC->CR) & RCC_CR_HSERDY) == 0){}									//oczekiwanie na HSE

 RCC->CR |= RCC_CR_CSSON;													// włączamy Clock security system

 RCC->CFGR |= RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV1; // ustawiamy taktowania dla szyn AHB, APB1 i APB2
 //HCLK = SYSCLK/1- 72Mhz;    PCLK1 = HCLK/2 - 36Mhz;       PCLK1 = HCLK/1- 72mhz;
 RCC->CFGR |= RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC;                          // ustawienie mnożnika dla PLL (8MHz * 9 = 72MHz) , oraz wejciowego sygnału taktującego dla PLL)

 RCC->CR |= RCC_CR_PLLON;													//włączamy PLL

 while(((RCC->CR) & RCC_CR_PLLRDY)==0){}									//oczekiwanie na włącznie pll

 FLASH->ACR|=FLASH_ACR_LATENCY_2; 											//opóźnienie dla pamięci flash

 RCC->CFGR|=RCC_CFGR_SW_PLL;												// PLL jako źródło taktowania SYSCLK

 while( ((RCC->CFGR) & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL){}                 //oczekiwanie na ustawielnie PLL jako źródła SYSCLK

 RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;	//AFIO WŁ									//włączamy taktowanie dla kolejnych peryferiów kontrolera
 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //GPIOC WŁ

}

Dodam, że nie chcę wszczynać dyskusji na temat SPL'a czy rejestrów, bo to jak widać na polskich forach jest wszechobecna walka. Jest to tylko przykład gdyby ktoś był zaciekawiony.

Pozdrawiam.

Przypominam, że tylko do końca dnia można zgłaszać propozycje swoich funkcji.

Jutro startuje kolejne zadanie!

Witam,

dla początkujących programujących swoje pierwsze roboty, przydatna może być funkcja odbierania danych z modułu Bluetooth ( np. HC-05) poprzez interfejs USART. Dane można wysyłać np. z smartfona z systemem Android, a aplikację mobilną, która będzie się komunikowała z modułem Bluetooth umieszonym w robocie można z łatwością napisać dzięki AppInventorowi. Funkcja ta umożliwia w robotach typu Line Follower szybkie i wygodne zmiany nastaw regulatora, podczas testów. Dzięki tej funkcji możemy także zbudować robota zdalnie sterowanego z smartfona.

#define  BUF_MAX 16
volatile uint8_t Bufor[BUF_MAX];
volatile uint8_t status;


void uart_init()
{
#define BAUD 9600
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
UCSR0A = (1<<RXC0);//Przerwanie po odebraniu bajtu danych
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); //8 bitów danych + 1 bit stopu
UCSR0B = (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0); //bez parzystości
}

int main()
{
   uart_init();
   sei();
       while(1){

       if(status){

            if(Bufor[0]==1){
                     //skręć w lewo
            }else if(Bufor[0]==2){
                     //skręć w prawo
            }/*
              itp
               */ 
        status=0;
}
}
}

ISR(USART_RX_vect){

static uint8_t bufpos, n;
if(status) return; //Błąd poprzednia ramka jeszcze nieobsłużona

if(n == 0){		//Pierwszy bajt danych jest informacją jak długa będzie ramka danych, zapisujemy tą liczbę do zmiennej n
	n = UDR0;
	bufpos = 0;
	return;
}
if(bufpos < n){				//Zapisujemy kolejne bajty do tablicy buforu, nastepnie zwiększamy indeks tablicy
	Bufor[bufpos] = UDR0;
	bufpos++;
}

if(bufpos >= n){	//Gdy indeks buforu będzie równy wysłanej wczesniej informacji o długosci ramki
	status = 1;		//przypisujemy 1 do zmiennej globalnej status, konczymy odbieranie i w mainie obsługujemy Bufor
	n = 0;
}
}


Jak widać w programie został zastosowany pewien protokół komunikacyjny. Aby komunikacja przebiegała poprawnie należy się trzymać dwóch zasad:

- pierwszy wysłany bajt musi być liczbą, która informuje ile bajtów wysyłamy,
- aby poprawnie wykonać pożądaną przez nas akcję po wysłaniu ramki, zalecane jest wysłanie jako drugiego bajtu jakiejś cyfry, która zostanie zapisana w Bufor[0], a następnie w mainie Bufor[0] wykorzystać jako element do porównywania w instrukcji warunkowej (Patrz na kod).

Program został napisany na mikrokontroler ATMega88p.

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...