Generator sygnału sin i trójkąta
oprogramowanie generatoraCzęść związana z frontpanelem.fgen2_ilu00.jpg
W oprogramowaniu generatora zostały wykorzystane następujące technologie:
Po zaprogramowaniu pamięci FLASH mikrokontrolera ATMEGA można cieszyć się nową zabawką (dla ułatwienia programowania, na panel tylny zostało wyprowadzone jako DB15 złącze programatora, dysponując odpowiednią przejściówką można modyfikować oprogramowanie generatora bez konieczności zdejmowania pokrywy górnej obudowy).
fgen2_ilu01.jpg
Na frontpanelu generatora znajdują się następujące elementy (istotne z punktu widzenia funkcjonalności urządzenia):
- cztery przycisku do operowania funkcjonalnością generatora,
- cztery diody LED (żółte) do sygnalizacji określonych stanów generatora,
- dioda LED (zielona) jako wskaźnik zasilania,
- moduł wyświetlacza LCD (2 wiersze po 16 znaków),
- złącze z sygnałem wyjściowym.
Przyciski spełniają następującą funkcję:
fgen2_ilu02.jpg
- przycisk „←” służy do wybierania poprzedniej pozycji w strukturze menu (jest przyciskiem kontekstowym), używa się go w standardowym trybie (zwyczajowe przyciśnięcie),
- przycisk „→” służy do wybierania następnej pozycji w strukturze menu (jest przyciskiem kontekstowym), używa się go w standardowym trybie (zwyczajowe przyciśnięcie),
- przycisk „Wyb.” służy do wybierania pozycji w strukturze menu i pełni rolę odpowiadającą klawiszowi Enter na klawiaturze (jako zwyczajowe naciśnięcie akceptuje odpowiednią opcję, jako naciśnięcie z przytrzymaniem uruchamia generowanie sygnału o parametrach wynikających z wybranej opcji w strukturze menu),
- przycisk „Zan.” służy do zaniechania, wycofania do poprzedniej pozycji w strukturze menu i pełni rolę odpowiadającą klawiszowi ESC na klawiaturze (jako zwyczajowe naciśnięcie wraca do poprzedniego poziomu w menu, jako naciśnięcie z przytrzymaniem wyłącza generowania sygnału).
Diody LED mają następujące znaczenie:
- dioda „Status” sygnalizuje „rytm serca”,
- dioda „Zdalny” sygnalizuje techniczne połączenie portu szeregowego z zdalnym programem sterującym lub terminalem/emulatorem terminala,
- dioda „Praca” sygnalizuje stan połączenia z zdalnym programem sterującym (lub terminalem/emulatorem terminala)
- dioda „Gener.” sygnalizuje stan generowania sygnału wyjściowego.
Menu do wyboru parametrów sygnału jest zorganizowane jako menu dwupoziomowe. Na pierwszym poziome wybierana jest grupa sygnałów, na drugim poziomie wybierane są określone sygnały w obrębie danej grupy. Taki mechanizm pozwala na optymalizację czynności związanej z wyborem poszukiwanej opcji określającej żądanie generowania sygnału o odpowiednich parametrach. W obecnej wersji programu struktura menu jest następująca:
SIN pojed. Hz   SIN 1 Hz
   SIN 2 Hz
   SIN 5 Hz
SIN dzies. Hz   SIN 10 Hz
   SIN 20 Hz
   SIN 30 Hz
   SIN 40 Hz
   SIN 50 Hz
   SIN 60 Hz
   SIN 70 Hz
   SIN 80 Hz
   SIN 90 Hz
SIN setki Hz   SIN 100 Hz
   SIN 200 Hz
   SIN 300 Hz
   SIN 400 Hz
   SIN 500 Hz
   SIN 600 Hz
   SIN 700 Hz
   SIN 800 Hz
   SIN 900 Hz
SIN pojed. kHz   SIN 1 kHz
   SIN 2 kHz
   SIN 3 kHz
   SIN 4 kHz
   SIN 5 kHz
   SIN 6 kHz
   SIN 7 kHz
   SIN 8 kHz
   SIN 9 kHz
SIN dzies. kHz   SIN 10 kHz
   SIN 20 kHz
   SIN 30 kHz
   SIN 40 kHz
   SIN 50 kHz
   SIN 60 kHz
   SIN 70 kHz
   SIN 80 kHz
   SIN 90 kHz
TROJ pojed. Hz   TROJK. 1 Hz
   TROJK. 2 Hz
   TROJK. 5 Hz
TROJ dzies. Hz   TROJK. 10 Hz
   TROJK. 20 Hz
   TROJK. 30 Hz
   TROJK. 40 Hz
   TROJK. 50 Hz
   TROJK. 60 Hz
   TROJK. 70 Hz
   TROJK. 80 Hz
   TROJK. 90 Hz
TROJ setki Hz   TROJK. 100 Hz
   TROJK. 200 Hz
   TROJK. 300 Hz
   TROJK. 400 Hz
   TROJK. 500 Hz
   TROJK. 600 Hz
   TROJK. 700 Hz
   TROJK. 800 Hz
   TROJK. 900 Hz
TROJ pojed. kHz   TROJK. 1 kHz
   TROJK. 2 kHz
   TROJK. 3 kHz
   TROJK. 4 kHz
   TROJK. 5 kHz
   TROJK. 6 kHz
   TROJK. 7 kHz
   TROJK. 8 kHz
   TROJK. 9 kHz
TROJ dzies. Khz   TROJK. 10 kHz
   TROJK. 20 kHz
   TROJK. 30 kHz
   TROJK. 40 kHz
   TROJK. 50 kHz
   TROJK. 60 kHz
   TROJK. 70 kHz
   TROJK. 80 kHz
   TROJK. 90 kHz
Sygnaly specj.   Nuta C1
   Nuta D1
   Nuta E1
   Nuta F1
   Nuta G1
   Nuta A1
   Nuta H1
   Nuta C2
   Harmon 7.83
   Harmon 432
   Harmon 528
   Harmon 639
   Harmon 963
Zestaw opcji menu można w prosty sposób dowolnie kształtować. Cała struktura menu znajduje się w pliku o nazwie „fgentable.c”. Bieżąca jego postać jest następująca (we fragmentach):
Kod: Zaznacz cały
static MenuElementRecType Traing_10kHzInFlash [ ] PROGMEM =
{
{ "TROJK. 10 kHz " , ( uint32_t ) 1000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 10000.00 Hz
{ "TROJK. 20 kHz " , ( uint32_t ) 2000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 20000.00 Hz
{ "TROJK. 30 kHz " , ( uint32_t ) 3000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 30000.00 Hz
{ "TROJK. 40 kHz " , ( uint32_t ) 4000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 40000.00 Hz
{ "TROJK. 50 kHz " , ( uint32_t ) 5000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 50000.00 Hz
{ "TROJK. 60 kHz " , ( uint32_t ) 6000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 60000.00 Hz
{ "TROJK. 70 kHz " , ( uint32_t ) 7000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 70000.00 Hz
{ "TROJK. 80 kHz " , ( uint32_t ) 8000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 80000.00 Hz
{ "TROJK. 90 kHz " , ( uint32_t ) 9000000 , TriangularWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 90000.00 Hz
{ EndOptions }
} ;
static MenuElementRecType SpecialOptionInFlash [ ] PROGMEM =
{
{ "Nuta C1 " , ( uint32_t ) 26160 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 261.60 Hz
{ "Nuta D1 " , ( uint32_t ) 29370 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 293.70 Hz
{ "Nuta E1 " , ( uint32_t ) 32960 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 329.60 Hz
{ "Nuta F1 " , ( uint32_t ) 34920 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 349.20 Hz
{ "Nuta G1 " , ( uint32_t ) 39190 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 391.90 Hz
{ "Nuta A1 " , ( uint32_t ) 44000 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 440.00 Hz
{ "Nuta H1 " , ( uint32_t ) 49390 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 493.90 Hz
{ "Nuta C2 " , ( uint32_t ) 52320 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 523.20 Hz
{ "Harmon 7.83 " , ( uint32_t ) 783 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 7.83 Hz
{ "Harmon 432 " , ( uint32_t ) 43200 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 432.00 Hz
{ "Harmon 528 " , ( uint32_t ) 52800 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 528.00 Hz
{ "Harmon 639 " , ( uint32_t ) 63900 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 639.00 Hz
{ "Harmon 963 " , ( uint32_t ) 96300 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 963.00 Hz
{ EndOptions }
} ;
GroupOptionsRecType GroupFlashArray [ ] PROGMEM =
{
{ "SIN pojed. Hz " , Sin_1HzInFlash } ,
{ "SIN dzies. Hz " , Sin_10HzInFlash } ,
{ "SIN setki Hz " , Sin_100HzInFlash } ,
{ "SIN pojed. kHz " , Sin_1kHzInFlash } ,
{ "SIN dzies. kHz " , Sin_10kHzInFlash } ,
{ "TROJ pojed. Hz " , Traing_1HzInFlash } ,
{ "TROJ dzies. Hz " , Traing_10HzInFlash } ,
{ "TROJ setki Hz " , Traing_100HzInFlash } ,
{ "TROJ pojed. kHz" , Traing_1kHzInFlash } ,
{ "TROJ dzies. kHz" , Traing_10kHzInFlash } ,
{ "Sygnaly specj. " , SpecialOptionInFlash } ,
{ "***************" , NIL }
} ;Każdy element tablicy (opcji menu pierwszego poziomu) GroupFlashArray opisuje pojedynczą opcję na poziomie wyboru grupy. Zawiera on nazwę grupy i dowiązanie do tablicy zawierającej opis poszczególnych opcji określających określone sygnały (opcje menu drugiego poziomu). Każda opcja zawiera nazwę wyświetlaną na frontpanelu, częstotliwość sygnału wyrażoną w setnych częściach Hz, kształt generowanego sygnału, jego amplitudę oraz wartość składowej stałej (przesunięcie „zera” sygnału).
Kod: Zaznacz cały
static MenuElementRecType Sin_1HzInFlash [ ] PROGMEM =
{
{ "SIN 1 Hz " , ( uint32_t ) 100 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 1.00 Hz
{ "SIN 2 Hz " , ( uint32_t ) 200 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 2.00 Hz
{ "SIN 5 Hz " , ( uint32_t ) 500 , SineWaveFormat , DefaultAmplitude , DefaultDCLevel } , // 5.00 Hz
{ EndOptions }
} ;Powyższa struktura jest łatwa do modyfikacji. Dodanie pozycji w obrębie menu grupy implikuje powołanie całej tablicy opisującej sygnały należące do danej grupy.
Obsługa klawiatury posiłkuje się modułem do obsługi dowolnej małej klawiatury. Sama funkcja do sprzętowego wczytania klawiatury nie zawiera nic nadzwyczajnego.
Kod: Zaznacz cały
static uint8_t HardwareKeybRead ( void )
{
uint8_t KeybData ;
/*----------------------------------------------------------------*/
KeybData = KeybPortInput ;
return ( KeybData ) ;
} /* HardwareKeybRead */Natomiast ze standardowej implementacji przejęta jest obsługa zapisu kodu znaku do bufora cyklicznego. Zawiera ona dodatkowe czynności występujące przy obsłudze klawiatury, do których należą: wygenerowanie sygnału dźwiękowego (beep) przy każdym naciśnięciu przycisku oraz wygenerowaniu „błysku” diody LED podświetlającej dany przycisk. Zrealizowane jest to poprzez włączenie odpowiedniej diody oraz zakolejkowania funkcji odłożonej w czasie przeznaczonej do zgaszenia diody LED. Na podobnej zasadzie zrealizowane jest generowanie dźwięku.
Kod: Zaznacz cały
static void LapmOffSerivice ( void )
{
/*-------------------------------------------------------------------------*/
LEDOff ( L0BacklightBitPosition ) ;
LEDOff ( L1BacklightBitPosition ) ;
LEDOff ( L2BacklightBitPosition ) ;
LEDOff ( L3BacklightBitPosition ) ;
LapmOffSeriviceHandle = NIL ;
} /* LapmOffSerivice */
static void LocalStoreKeyService ( uint8_t NewCh )
{
/*-------------------------------------------------------------------------*/
StoreKey ( NewCh ) ;
KillBeep ( ) ;
SingleToneStartBeep ( PushKeyBeepTime , PushKeyBeepTone ) ;
switch ( NewCh )
{
case StandKey0Code :
case LongKey0Code :
LEDOn ( L0BacklightBitPosition ) ;
break ;
case StandKey1Code :
case LongKey1Code :
LEDOn ( L1BacklightBitPosition ) ;
break ;
case StandKey2Code :
case LongKey2Code :
LEDOn ( L2BacklightBitPosition ) ;
break ;
case StandKey3Code :
case LongKey3Code :
LEDOn ( L3BacklightBitPosition ) ;
break ;
case StandKey01Code :
case LongKey01Code :
LEDOn ( L0BacklightBitPosition ) ;
LEDOn ( L1BacklightBitPosition ) ;
break ;
case StandKey02Code :
case LongKey02Code :
LEDOn ( L0BacklightBitPosition ) ;
LEDOn ( L2BacklightBitPosition ) ;
break ;
case StandKey03Code :
case LongKey03Code :
LEDOn ( L0BacklightBitPosition ) ;
LEDOn ( L3BacklightBitPosition ) ;
break ;
case StandKey12Code :
case LongKey12Code :
LEDOn ( L1BacklightBitPosition ) ;
LEDOn ( L2BacklightBitPosition ) ;
break ;
case StandKey13Code :
case LongKey13Code :
LEDOn ( L1BacklightBitPosition ) ;
LEDOn ( L3BacklightBitPosition ) ;
break ;
case StandKey23Code :
case LongKey23Code :
LEDOn ( L2BacklightBitPosition ) ;
LEDOn ( L3BacklightBitPosition ) ;
break ;
} /* switch */ ;
LapmOffSeriviceHandle = AttachTimer ( LapmOffSerivice , PushKeyBeepTime ) ;
} /* LocalStoreKeyService */Zainicjowanie działania modułu obsługi klawiatury do wymaganej funkcjonalności zawarte jest w funkcji
SoftwareInit :
Kod: Zaznacz cały
static void SoftwareInit ( void )
{
/*-------------------------------------------------------------------------*/
(…)
SoftKeybInit ( KeybMask , HardwareKeybRead ) ;
SetEncodeTable ( (uint16_t ) StandEncodeTabe , EncodeTabeSize ,
(uint16_t ) LongEncodeTabe , EncodeTabeSize ) ;
MountStoreKeyService ( LocalStoreKeyService ) ;
(…)
} /* SoftwareInit */Z obsługą klawiatury związana jest zmienna będąca wskaźnikiem do odpowiedniej funkcji (metoda), której implementacja znajduje się w module
generatormodule.c,
generatormodule.h. Do obsługi menu na poziomie wybory grup wykorzystywana jest funkcja:
Kod: Zaznacz cały
typedef void ( * UserKeybServiceProcT ) ( uint8_t /* KeyCode */ ) ;
UserKeybServiceProcT UserKeybService ;
void GroupSelectionService ( uint8_t KeyCode )
{
/*-------------------------------------------------------------------------*/
switch ( KeyCode )
{
case StandKey0Code :
if ( ! SelectPrevGroup ( ) )
{
SelectLastGroup ( ) ;
} /* if */ ;
DisplayGroup ( ) ;
break ;
case StandKey1Code :
if ( ! SelectNextGroup ( ) )
{
SelectFirstGroup ( ) ;
} /* if */ ;
DisplayGroup ( ) ;
break ;
case StandKey2Code :
SelectFirstOption ( ) ;
DisplayOption ( ) ;
SelectionContext = OptionSelectionMode ;
UserKeybService = OptionSelectionService ;
break ;
} /* switch */ ;
} /* GroupSelectionService */Klawisz „Wyb.” (Enter; wariant StandKey2Code) przenosi funkcję „konsumpcji” znaków klawiatury do funkcji wyboru opcji. Do obsługi menu na poziomie opcji, wykorzystywana jest funkcja:
Kod: Zaznacz cały
void OptionSelectionService ( uint8_t KeyCode )
{
/*-------------------------------------------------------------------------*/
switch ( KeyCode )
{
case StandKey0Code :
if ( ! SelectPrevOption ( ) )
{
SelectLastOption ( ) ;
} /* if */ ;
DisplayOption ( ) ;
break ;
case StandKey1Code :
if ( ! SelectNextOption ( ) )
{
SelectFirstOption ( ) ;
} /* if */ ;
DisplayOption ( ) ;
break ;
case StandKey2Code :
DisplayDetails ( ) ;
UserKeybService = DetailsSelectionService ;
break ;
case StandKey3Code :
DisplayGroup ( ) ;
SelectionContext = GroupSelectionMode ;
UserKeybService = GroupSelectionService ;
break ;
case LongKey2Code :
DisplayDetails ( ) ;
StartWaveGeneration ( MenuElement . Frequency , MenuElement . WaveFormat ,
MenuElement . Amplitude , MenuElement . DCLevel ) ;
UserKeybService = NoOptionSelectionService ;
SelectionContext = NoSelectionMode ;
break ;
} /* switch */ ;
} /* OptionSelectionService */Klawisz „Wyb.” (Enter) przenosi funkcję „konsumpcji” znaków klawiatury do funkcji przeglądania szczegółów (wariant StandKey2Code) lub do uruchomienia generowania sygnału (wariant LongKey2Code). Do obsługi menu na poziomie szczegółów wykorzystywana jest funkcja:
Kod: Zaznacz cały
void DetailsSelectionService ( uint8_t KeyCode )
{
/*-------------------------------------------------------------------------*/
switch ( KeyCode )
{
case StandKey0Code :
if ( ! SelectPrevOption ( ) )
{
SelectLastOption ( ) ;
} /* if */ ;
DisplayDetails ( ) ;
break ;
case StandKey1Code :
if ( ! SelectNextOption ( ) )
{
SelectFirstOption ( ) ;
} /* if */ ;
DisplayDetails ( ) ;
break ;
case StandKey2Code :
break ;
case StandKey3Code :
UserKeybService = OptionSelectionService ;
DisplayOption ( ) ;
break ;
case LongKey2Code :
DisplayDetails ( ) ;
StartWaveGeneration ( MenuElement . Frequency , MenuElement . WaveFormat ,
MenuElement . Amplitude , MenuElement . DCLevel ) ;
UserKeybService = NoOptionSelectionService ;
SelectionContext = NoSelectionMode ;
break ;
} /* switch */ ;
} /* DetailsSelectionService */Uruchomienie generowania sygnału wyjściowego implikuje zmianę metody konsumpcji znaków klawiatury do następującej funkcji:
Kod: Zaznacz cały
void NoOptionSelectionService ( uint8_t KeyCode )
{
/*-------------------------------------------------------------------------*/
if ( KeyCode == LongKey3Code )
{
StopWaveGeneration ( ) ;
UserKeybService = OptionSelectionService ;
SelectionContext = OptionSelectionMode ;
DisplayOption ( ) ;
} /* if */ ;
} /* NoOptionSelectionService */która reaguje jedynie na przycisk żądający zakończenia generowania sygnału wyjściowego.
Załącznik: projekt w AVRSTUDIO:
fgen-avr.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.