Rev 3235 Rev 3255
Line -... Line 1...
-   1 // Melodicky zvonek MB01A_1_00
-   2 //
-   3 // Prohram pro melodicky zvonek s pouzitim knihovny Sound_t1.C
-   4 //
-   5 // (c)miho 2004
-   6 //
-   7 // Historie:
-   8 // 1.00 Uvodni verze
-   9  
-   10 #include <16F819.h> // Definice procesoru
-   11 #fuses HS,NOPROTECT,NOWDT,PUT,NOLVP,NOBROWNOUT,WRT // Definice konfiguracniho slova
-   12  
-   13 #define POWER_386 PIN_A4 // L zapne napajeni pro zesilovac LM386
-   14 #define POWER_PIC PIN_A3 // L pripoji GND pro procesor PIC
-   15  
-   16 #define SOUND_HI PIN_B3 // Akusticky vystup
-   17 #define SOUND_LO PIN_B2 // Akusticky vystup
-   18 #define SOUND_CLOCK 20000000 // Frekvence hodin
-   19 #define SOUND_LowOctave 1 // O oktavu vys protoze mame moc rychly krystal
-   20 #include "Sound_T1.c" // Hudebni knihovna
-   21  
-   22 #include "Data.c" // Datovy blok pro predpripravene skladby
-   23  
-   24 #define RXD PIN_B1 // Port pro RS232
-   25 #use delay(CLOCK=20000000) // Konfigurace pro casovani RS232
-   26 #use rs232(BAUD=9600,RCV=RXD,INVERT,PARITY=N,BITS=8) // Prenosove parametry RS232
-   27  
-   28  
-   29 // Sada globalnich promennych
-   30 // --------------------------
-   31 // Vyuzivame globalni promenne protoze je to vyhodne z hlediska spotreby zdroju. Usetri
-   32 // se vyznmane mnoho pameti programu pri predavani parametru
-   33  
-   34  
-   35 unsigned int16 Adr; // Adresovy ukazatel do pameti skladeb
-   36 unsigned int16 Data; // Prectena data nebo data pro zapis
-   37 unsigned int1 Mode; // 0=rezim testovani, 1=rezim zapisu do FLASH
-   38  
-   39 unsigned int16 Tempo; // Tempo (delka nejkratsi skladby v ms)
-   40 unsigned int16 Pause; // Delka mezery mezi notami v ms
-   41 unsigned int8 Octava; // Posunuti skladby v oktavach
-   42  
-   43 unsigned int8 Beep; // Druh pipnuti pro proceduru SoundSpec
-   44 unsigned int1 Error; // Priznak chyby
-   45  
-   46 unsigned int8 CisloSkladby; // Cislo skladby pro proceduru Find a Play
-   47  
-   48  
-   49 // Zvuky, posloupnost zadaneho poctu tonu
-   50 #define SoundEndOfLine 0x01 // Kratke pipnuti na konci radky
-   51 #define SoundPGM 0x03 // Trilek pri vstupu do rezimu programovani
-   52 #define SoundPostPlay 0x03 // Po ukonceni prehravani
-   53 #define SoundERASE 0x02 // Zvuk pri smazani bloku FLASH pameti
-   54 #define SoundERR 0x05 // Chyba syntaxe
-   55 void SpecBeep()
-   56 // Data - pocet pipnuti, 0 znamena ticho
-   57 {
-   58 int Oct;
-   59  
-   60 if (Error) Beep=SoundERR;
-   61  
-   62 for(Oct=2;Beep!=0;Beep--)
-   63 {
-   64 SoundNote(SOUND_A,Oct++,50);
-   65 }
-   66
-   67 Error=0;
-   68 }
-   69  
-   70  
-   71 // Precti slovo z pameti programu
-   72 int16 ReadData()
-   73 // Adr - adresa ze ktere se cte
-   74 // Data - prectena data
-   75 {
-   76 int8 a,b; // Pomocne promenne
-   77  
-   78 (int8)*EEADR = Adr; // Adresa, spodni cast
-   79 (int8)*EEADRH = Adr >> 8; // Adresa, horni cast
-   80 bit_set(*EECON1,EECON1_EEPGD); // Pamet programu
-   81 bit_set(*EECON1,EECON1_RD); // Operace cteni
-   82 #ASM
-   83 nop; // Povinne nop
-   84 nop;
-   85 #ENDASM
-   86 a = (int8)*EEDATA; // Prevezmi data
-   87 b = (int8)*EEDATAH;
-   88 Data=make16(b,a); // Sestav vysledek ze 2 bajtu
-   89 }
-   90  
-   91  
-   92 // Smazani cele pameti vyhrazene pro skladby
-   93 void Erase()
-   94 {
-   95 for(Adr=STARTMEM; Adr<=ENDMEM; Adr++) // Cela oblast
-   96 {
-   97 ReadData();
-   98 if (Data!=0x3FFF) // Mazu jen bloky, ktere to potrebuji
-   99 {
-   100 if (input(POWER_PIC)!=0) return; // Nezapisuj pokud neni jumper povoleni programovani
-   101 (int8)*EEADR = Adr; // Adresa bloku, spodni cast
-   102 (int8)*EEADRH = Adr >> 8; // Adresa bloku, horni cast
-   103 bit_set(*EECON1,EECON1_EEPGD); // Pamet programu
-   104 bit_set(*EECON1,EECON1_WREN); // Povolit zapis
-   105 bit_set(*EECON1,EECON1_FREE); // Operace mazani
-   106 (int8)*EECON2 = 0x55; // Povinna segvence pro zapis
-   107 (int8)*EECON2 = 0xAA;
-   108 bit_set(*EECON1,EECON1_WR); // Zahajeni mazani
-   109 #ASM
-   110 nop; // Povinne prazdne instrukce
-   111 nop;
-   112 #ENDASM
-   113 bit_clear(*EECON1,EECON1_WREN); // Uz ne zapis
-   114 bit_clear(*EECON1,EECON1_FREE); // Uz ne mazani
-   115 bit_clear(*EECON1,EECON1_EEPGD); // Uz ne pamet programu
-   116 Beep=SoundERASE;
-   117 SpecBeep();
-   118 }
-   119 }
-   120 }
-   121  
-   122  
-   123 // Zapis do pameti programu po jednotlivych slovech.
-   124 // Soucastka vyzaduje zapis vzdy celych osmi slov najednou. Vyuziva se toho, ze pamet FLASH
-   125 // umi zapisovat jen smerem do nuly a tak staci na pozice, ktere zrovna nechceme programovat
-   126 // zapsat same jednicky cimz se stav jejich stav nezmeni.
-   127 void WriteData()
-   128 // Adr - adresa, kam se bude zapisovat
-   129 // Data - data, ktera se budou zapisovat
-   130 {
-   131 int i;
-   132  
-   133 bit_set(*EECON1,EECON1_EEPGD); // Pamet programu
-   134 bit_set(*EECON1,EECON1_WREN); // Zapis
-   135 (int8)*EEADR = Adr & ~3; // Adresa, spodni cast, zaokrouhleno dolu na nasobek 8
-   136 (int8)*EEADRH = Adr >> 8; // Adresa, horni cast
-   137 for (i=0; i<4; i++)
-   138 {
-   139 if ((Adr & 3) == i) // Pokud je adresa slova v bloku totozna s pozadovanou
-   140 {
-   141 (int8)*EEDATA =Data; // Platne slovo, spodni cast
-   142 (int8)*EEDATAH=Data >> 8; // Platne slovo, horni cast
-   143 }
-   144 else // Ostatni bunky nemenime
-   145 {
-   146 (int8)*EEDATA =0xFF; // Zbytek same jednicky
-   147 (int8)*EEDATAH=0xFF;
-   148 }
-   149 (int8)*EECON2 = 0x55; // Povinna sekvence pro zapis
-   150 (int8)*EECON2 = 0xAA;
-   151 bit_set(*EECON1,EECON1_WR); // Zahajeni zapisu
-   152 #ASM
-   153 nop; // Povinne dve prazdne instrukce
-   154 nop;
-   155 #ENDASM
-   156 ((int8)*EEADR) ++; // Dalsi slovo
-   157 }
-   158 bit_clear(*EECON1,EECON1_WREN); // Konec zapisu
-   159 bit_clear(*EECON1,EECON1_EEPGD); // Uz ne pamet programu (bezpecnost)
-   160 }
-   161  
-   162  
-   163 // Zapise data Data na adresu Adr a provede posun na dalsi adresu, zapisuje se jen do
-   164 // dovolene oblasti pameti a jen v pripade, ze je Mode=1
-   165 void WriteDataInc()
-   166 // Data - co se zapisuje
-   167 // Adr - kam se zapisuje, po zapisu se adresa posouva
-   168 {
-   169 if (~Mode) return; // Neni rezim zapisu
-   170 if ( (Adr>=STARTMEM) & (Adr<=ENDMEM) & (input(POWER_PIC)==0) )
-   171 {
-   172 WriteData();
-   173 Adr++;
-   174 }
-   175 else
-   176 {
-   177 Error=1;
-   178 }
-   179 }
-   180  
-   181  
-   182 // Najdi zacatek zadaneho cisla skladby. Promenna Adr ukazuje na zacatek skladby.
-   183 // Neni-li skladba nalezena ukazuje Adr na koncovou znacku (0x3FFF) posledni skladby
-   184 // nebo na konec pameti.
-   185 int1 Find()
-   186 // CisloSkladby - poradove cislo skladby
-   187 // Adr - adresa zacatku skladby
-   188 {
-   189 Adr=STARTMEM-1; // Od zacatku oblasti pro skladby
-   190 for(;1;)
-   191 {
-   192 Adr++;
-   193 ReadData(); // Precti data
-   194 if (Data==ENDOFDATA) return 1; // Priznak konce dat
-   195 if (Adr==ENDMEM+1) return 1; // Uz jsme prosli celou pamet
-   196 if ((Data&MASKBEGIN)==DATABEGIN) // Priznak zacatku skladby
-   197 {
-   198 CisloSkladby--; // Otestuj pocitadlo skladeb
-   199 if (CisloSkladby==0) return 0; // Je to tato skladba
-   200 }
-   201 }
-   202 }
-   203  
-   204  
-   205 // Zahraj jednu notu
-   206 void PlayData()
-   207 // Data = zakodovana nota
-   208 // Tempo, Octava, Pause = parametry hrane noty
-   209 {
-   210 SoundNote((int8)Data&0xF,Octava+(((int8)Data>>4)&0x7),Tempo*((Data>>7)&0x3F)); // Zahraj notu
-   211 SoundNote(SOUND_Space,0,Pause); // Zahraj mezeru mezi notami
-   212 }
-   213  
-   214  
-   215 // Zahraj skladbu od zadane adresy v promenne Adr.
-   216 void Play()
-   217 // CisloSkladby - cislo skladby k hrani
-   218 {
-   219 if (Find()) // Najdi zacatek skladby v pameti skladeb
-   220 {
-   221 return; // Skladba nenalezena
-   222 }
-   223  
-   224 Tempo=100; // Default delka noty
-   225 Pause=100; // Default mezera mezi notami
-   226  
-   227 Octava=Data&~MASKBEGIN; // Posunuti oktav (povinna soucast zacatku skladby)
-   228 Adr++;
-   229  
-   230 for (;1;)
-   231 {
-   232 if (Adr==ENDMEM+1) return; // Konec pametove oblasti
-   233 ReadData(); // Vezmi data
-   234 Adr++; // Posun adresu
-   235 if (Data==ENDOFDATA) return; // Konec dat
-   236 if ((Data&MASKBEGIN)==DATABEGIN) return; // Zacatek dalsi skladby
-   237 if ((Data&MASKTEMPO)==DATATEMPO) Tempo=Data&~DATATEMPO; // Paramter TEMPO
-   238 if ((Data&MASKPAUSE)==DATAPAUSE) Pause=Data&~DATAPAUSE; // Parametr PAUSE
-   239 if ((Data&MASKNOTE)==0) // Nota
-   240 {
-   241 PlayData(); // Zahraj notu
-   242 }
-   243 }
-   244 }
-   245  
-   246  
-   247 // Vycisli cislo z bufferu, posune ukazovatko na prvni nezpracovany znak, preskakuje mezery
-   248 int16 Number(char line[], int *a, len)
-   249 {
-   250 int16 Data;
-   251 char c;
-   252  
-   253 while((line[*a]==' ')&(*a<len)) // Vynech mezery na zacatku
-   254 (*a)++; // Posouvej ukazovatko
-   255  
-   256 Data=0;
-   257 while (1)
-   258 {
-   259 if (*a>=len) return Data; // Konec retezce
-   260 c=line[*a]; // Vezmi znak z pole
-   261 if ((c<'0')|(c>'9')) return Data; // Koncime pokud znak neni cislice
-   262 Data = Data * 10 + (c-'0'); // Pouzij cislici
-   263 (*a)++; // Dalsi znak
-   264 }
-   265 }
-   266  
-   267  
-   268 // Vyhledej klicove slovo a vrat jeho zkraceny kod
-   269 // Pokud slovo neexistuje vraci -1
-   270 // Format definice - retezec ukonceny nulou + zastupny znak, na konci prazdny retezec (nula)
-   271 const char KeyWords[] =
-   272 {
-   273 'P','L','A','Y',0, 'P',
-   274 'E','R','A','S','E',0, 'E',
-   275 'T','E','M','P','O',0, 't',
-   276 'P','A','U','S','E',0, 'p',
-   277 'B','E','G','I','N',0, 'B',
-   278 'T','E','S','T',0, 'b',
-   279 'E','N','D',0, 'Z',
-   280 'C',0. SOUND_C,
-   281 'C','I','S',0, SOUND_Cis,
-   282 'D',0, SOUND_D,
-   283 'D','I','S',0, SOUND_Dis,
-   284 'E',0, SOUND_E,
-   285 'F',0, SOUND_F,
-   286 'F','I','S',0, SOUND_Fis,
-   287 'G',0, SOUND_G,
-   288 'G','I','S',0, SOUND_Gis,
-   289 'A',0, SOUND_A,
-   290 'A','I','S',0, SOUND_Ais,
-   291 'H',0, SOUND_H,
-   292 'S','P','A','C','E',0, SOUND_Space
-   293 };
-   294 signed int Word(char line[], unsigned int8 *a, len)
-   295 {
-   296 unsigned int8 i; // Index do pole klicovych slov
-   297 unsigned int8 j; // index do zpracovavane radky
-   298  
-   299 while((line[*a]==' ')&(*a<len)) // Vynech mezery na zacatku
-   300 (*a)++; // Posouvej ukazovatko
-   301  
-   302 for (i=0;i<sizeof(KeyWords);) // Slova ze slovniku
-   303 {
-   304 for (j=*a;(j<len)&(KeyWords[i]!=0)&(KeyWords[i]==line[j]);i++,j++) // Znaky ze slova
-   305 {
-   306 }
-   307 if ((KeyWords[i]==0)&((line[j]==' ')|(j==len)))
-   308 {
-   309 if (j>=len) j=len-1; // Korekce abychom se nedostali za konec retezce
-   310 *a=j+1; // Posun ukazovatko za zpracovane slovo
-   311  
-   312 return KeyWords[i+1]; // Vrat zastupnou hodnotu z tabulky klicovych slov
-   313 }
-   314 while(KeyWords[i]!=0) i++; // Preskoc zbytek slova v tabulce
-   315 i++; // Preskoc oddelovac
-   316 i++; // Preskoc polozku se zastupnou hodnotou
-   317 }
-   318 return -1; // Prosli jsme cely slovnik a nedoslo ke shode
-   319 }
-   320  
-   321  
-   322 // Programovani pres RS232
-   323 #define LINELEN 40 // Delka radky pro RS232
-   324 #define CR 0x0D // Odradkovani
-   325 #define BS 0x08 // Back Space
-   326 void Download()
-   327 {
-   328 char line[LINELEN]; // Buffer na radku
-   329 unsigned char c; // Znak
-   330 unsigned int8 a; // Ukazovatko do bufferu
-   331 unsigned int8 len; // Delka retezce v radce
-   332 unsigned int8 Oct; // Cislo oktavy u noty
-   333  
-   334 output_low(POWER_386); // Zapni napajeni zesilovace
-   335 SoundNote(SOUND_Space,3,10); // Mezera
-   336 Beep=SoundPGM;
-   337 Error=0;
-   338 SpecBeep(); // Pipni na znameni vstupu do programovani
-   339  
-   340 Tempo=100; // Default hodnoty
-   341 Pause=100;
-   342 Octava=0;
-   343 Mode=0; // Mod hrani
-   344 Oct=0;
-   345 a=0; // Na zacatku je radka prazdna
-   346  
-   347 for(;input(POWER_PIC)==0;) // Opakuj vse dokud je PGM rezim
-   348 {
-   349 Loop:
-   350 c=Getc(); // Vezmi znak ze seriovky
-   351 if (c>=0x80) goto Loop; // Ignoruj znaky nad ASCII
-   352 if (c>=0x60) c=c-0x20; // Preved velka pismena na velka pismena
-   353 if ((c==CR)|(c=='/')) // Konec radky nebo komentar
-   354 {
-   355 while (c!=CR) c=Getc(); // Zpracuj znaky komentare
-   356 len=a; // Zapamatuj si delku radky
-   357 a=0; // Postav se na zacatek radky
-   358 Beep=SoundEndOfLine; // Default zuk na konci radky
-   359 // Zpracovani radky
-   360 while(a<len)
-   361 {
-   362 c=Word(line,&a,len);
-   363 if (c==-1) // Nezname klicove slovo
-   364 {
-   365 if (a<len) // Nejsme uz na konci radky ?
-   366 {
-   367 if ((line[a]>='0')&(line[a]<='9')) // Stojime na cislici -> je to cislo
-   368 {
-   369 // Oct=Number(line,&a,len)&0x7; // tohle nefunguje protoze je chyba v prekladaci
-   370 Oct=Number(line,&a,len); // prekladac prepoklada, z W obsahuje spodni bajt vysledku
-   371 Oct&=0x7; // ale k navratu pouziva RETLW 0 coz smaze W !
-   372 }
-   373 else // Stojime na pismenu nebo oddelovaci
-   374 {
-   375 if (line[a]!=' ') Error=1; // Neni to oddelovac - chyba
-   376 a++; // Preskocim 1 znak (a kdyz to nepomuze dostanu se zase sem)
-   377 }
-   378 }
-   379 }
-   380 else if (c=='P') // Play
-   381 {
-   382 CisloSkladby=Number(line,&a,len);
-   383 Mode=0;
-   384 Play();
-   385 Beep=SoundPGM;
-   386 }
-   387 else if (c=='E') // Erase
-   388 {
-   389 Mode=0;
-   390 Erase();
-   391 Beep=SoundPGM;
-   392 }
-   393 else if (c=='t') // Tempo
-   394 {
-   395 Tempo=Number(line,&a,len)&~MASKTEMPO;
-   396 if (Tempo==0) Tempo=100;
-   397 Data=Tempo|DATATEMPO;
-   398 WriteDataInc(); // Podmineny zapis do FLASH a posun na dalsi adresu
-   399 }
-   400 else if (c=='p') // Pause
-   401 {
-   402 Pause=Number(line,&a,len)&~MASKPAUSE;
-   403 if (Pause==0) Pause=100;
-   404 Data=Pause|DATAPAUSE;
-   405 WriteDataInc(); // Podmineny zapis do FLASH a posun na dalsi adresu
-   406 }
-   407 else if (c=='B') // Begin
-   408 {
-   409 CisloSkladby=~0; // Neplatne cislo skladby
-   410 Find(); // najde konec posledni skladby
-   411 Octava=Number(line,&a,len)&~MASKBEGIN;
-   412 Data=DATABEGIN|Octava; // Zacatecni znacka
-   413 Mode=1; // Mod zapisu do FLASH pameti
-   414 WriteDataInc(); // Podmineny zapis do FLASH a posun na dalsi adresu
-   415 }
-   416 else if (c=='b') // Test
-   417 {
-   418 Octava=Number(line,&a,len)&~MASKBEGIN;
-   419 Mode=0;
-   420 }
-   421 else if (c=='Z') // End
-   422 {
-   423 Mode=0;
-   424 }
-   425 else // Nota
-   426 {
-   427 Data=Number(line,&a,len); // Delka noty (nepovinna)
-   428 Data&=0x3F; // Jen platny rozsah
-   429 if (Data==0) Data++; // Je-li nulova delka - dej jednotkovou
-   430 Data<<=7; // Delka
-   431 Data|=c; // Nota
-   432 Data|=(Oct<<4); // Oktava
-   433 WriteDataInc(); // Podmineny zapis do FLASH a posun na dalsi adresu
-   434 if (~Mode)
-   435 {
-   436 PlayData(); // Zahraj notu
-   437 Beep=0; // Po zahrani noty uz nepipej na konci radky
-   438 }
-   439 }
-   440 }
-   441 a=0; // Radka zpracovana, nuluj jeji delku
-   442 SpecBeep(); // Pipni
-   443 goto Loop;
-   444 }
-   445 if ((c==BS)&(a>0)) {a--;goto Loop;} // Smaz znak
-   446 if ((c==',')|(c<=' ')) c=' '; // Vsechny ostatni ridici znaky i carka jsou oddelovac
-   447 if (a<LINELEN) line[a++]=c; // Zapis znak do bufferu a posun ukazovatko
-   448 }
-   449 }
-   450  
-   451  
-   452 // Tabulka pro prekodovani tlacitek
-   453 const int8 KeyTranslate[16] = {0, 1, 2, 5, 3, 6, 8, 11, 4, 7, 9, 12, 10, 13, 14, 15};
-   454  
-   455 void main()
-   456 {
-   457 Start:
-   458  
-   459 // Inicializace
-   460 port_b_pullups(TRUE); // Zapni pull-up odpory na portu B
-   461 set_tris_a(0b00001000); // Nastav nepouzite vyvody jako vystupy
-   462 set_tris_b(0b11110000); // 1 znamena vstup
-   463 *0x9F = 6; // Vsechny vstupy jsou digitalni
-   464  
-   465 // Test na rezim programovani
-   466 if ((input(POWER_PIC)==0)&(input(RXD)==0)) // Podminka programovani
-   467 Download(); // Pripojen RS232 a propojka na PGM
-   468  
-   469 // Zapnuti napajeni
-   470 output_low(POWER_PIC); // Pripoj GND pro procesor
-   471 SoundNote(SOUND_Space,3,10); // Mezera
-   472 output_low(POWER_386); // Zapni napajeni zesilovace
-   473 SoundNote(SOUND_Space,3,100); // Mezera (jinak se chybne detekuje tlacitko)
-   474  
-   475 // Cteni tlacitek
-   476 #use FAST_IO(B)
-   477 CisloSkladby=(input_b() >> 4) ^ 0xFF & 0xF; // Precti stav tlacitek
-   478 #use STANDARD_IO(B)
-   479 CisloSkladby=KeyTranslate[CisloSkladby]; // Prekoduj je do binarniho kodu
-   480  
-   481 // Prehrani skladby
-   482 Play(); // Zahraj skladbu
-   483  
-   484 // Po odehrani usni a cekej na zmacknuti tlacitka
-   485 #use FAST_IO(B)
-   486 if (input_B()); // Precti stav portu B (vuci tomuto stavu se bude hlidat zmena)
-   487 #use STANDARD_IO(B)
-   488 bit_clear(*0xB,0); // Nuluj priznak preruseni od zmeny stavu portu B
-   489 enable_interrupts(INT_RB); // Povol preruseni od zmeny stavu portu B
-   490  
-   491 output_high(POWER_386); // Vypni napajeni zesilovace
-   492 output_float(POWER_PIC); // Odpoj GND
-   493 Sleep(); // Usni aby byla minimalni klidova spotreba
-   494  
-   495 disable_interrupts(INT_RB); // Zakaz preruseni od portu
-   496 goto Start; // Po probuzeni skoc na zacatek
-   497 }