/* * File: PWM-Glosniczek-main.c * Author: elektronikawsrode.pl * Program: Odtwarza game C-Dur na buzzerze pasywnym uzywajac modulu PWM3. */ // Bity konfiguracyjne // CONFIG1 #pragma config FOSC = INTOSC // (INTOSC oscillator; I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PLLEN = OFF // PLL Enable (4x PLL disabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LPBOREN = OFF // Low Power Brown-out Reset enable bit (LPBOR is disabled) #pragma config DEBUG = OFF // In-Circuit Debugger Mode (In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #define _XTAL_FREQ 4000000 // Ustawiamy wewnetrzny oscylator na 4 MHz #include void SYSTEM_Initialize(void) { ANSELA = 0; // Ustaw wszystkie piny jako cyfrowe TRISAbits.TRISA2 = 0; // Ustawienie pinu RA2 jako wyjscie TRISAbits.TRISA4 = 0; TRISAbits.TRISA5 = 0; // 1. Konfiguracja Oscylatora // Ustawienie HFINTOSC na 4 MHz // IRCF<3:0> = 1101 (4 MHz) // SCS<1:0> = 00 (Zegar systemowy z FOSC) OSCCON = 0b01101000; // 2. Konfiguracja Timera PWM3 PWM3CLKCONbits.CS = 0b00; // Zegar PWM z FOSC PWM3CLKCONbits.PS = 0b100; // Prescaler 1:16 // Ustawienie okresu PWM (dla Fosc=4MHz i preskalera 1:16, wartosc 250 daje f ~ 1kHz) PWM3PRH = 250 >> 8; // 00000011 PWM3PRL = 250 & 0xFF; // 10000100 // Poczatkowe ustawienie wypelnienia (Duty Cycle) PWM3DCH = 0; // Wyjscie 0% (cisza) na starcie PWM3DCL = 0; // Ustawienie fazy i offsetu na 0 PWM3PHH = 0; PWM3PHL = 0; PWM3OFH = 0; PWM3OFL = 0; // Aktywowanie PWM3 PWM3CONbits.PWM3POL = 0; // Aktywny stan wyjscia: wypelnienie stan wysoki PWM3CONbits.PWM3MODE = 0; // Tryb standardowy PWM // Wlaczenie modulu PWM3 PWM3CONbits.PWM3OE = 1; // Wlacz wyjscie PWM3 na pin PWM3CONbits.PWM3EN = 1; // Wlacz modul PWM3 } // NOWA FUNKCJA do obslugi zmiennego czasu opoznienia void delay_ms_zmienna(unsigned int milliseconds) { while (milliseconds > 0) { __delay_ms(1); milliseconds--; } } /* * Odtwarza nute o danej czestotliwosci i czasie trwania. * czestotliwosc Czestotliwosc nuty w Hz (0 = cisza) * czas_trwania Czas trwania nuty w milisekundach */ //void zagraj_nute(unsigned int czestotliwosc, unsigned int czas_trwania, unsigned int ktora_dioda) { void zagraj_nute(unsigned int czestotliwosc, unsigned int czas_trwania) { unsigned int pr = 0; // Wartosc rejestru okresu unsigned int dc = 0; // Wartosc rejestru wypelnienia if (czestotliwosc > 0) { // Oblicz wartosc rejestru okresu // Zegar PWM = FOSC / Prescaler = 4,000,000 / 16 = 250,000 Hz // PWM3PR = (250000 / Czestotliwosc) - 1 pr = (unsigned int)(250000UL / czestotliwosc) - 1; // Ustaw wypelnienie na 50% dla buzzera pasywnego dc = pr / 2; } // Jesli czestotliwosc == 0, pr i dc pozostaja 0, co oznacza cisze (wypelnienie 0%) // Zaladuj nowe wartosci do rejestrow buforujacych PWM3PRH = (pr >> 8); PWM3PRL = (pr & 0xFF); PWM3DCH = (dc >> 8); PWM3DCL = (dc & 0xFF); // Uzbroj rejestry do zaladowania w nastepnym cyklu PWM (Load Arm) PWM3LDCONbits.LDA = 1; // if (ktora_dioda == 0){ // LATAbits.LATA4 = 0; // LATAbits.LATA5 = 0; // } // if (ktora_dioda == 1){ // LATAbits.LATA4 = 1; // LATAbits.LATA5 = 0; // } // if (ktora_dioda == 2){ // LATAbits.LATA4 = 0; // LATAbits.LATA5 = 1; // } // Poczekaj okreslony czas trwania nuty if (czas_trwania > 0) { delay_ms_zmienna(czas_trwania); } } //// Definicja pauzy //#define PAUZA 0 // //// Ustawienia czasu trwania //unsigned int czas_nuty = 500; // Czas trwania nuty w ms //unsigned int czas_pauzy = 50; // Czas pauzy miedzy nutami // //void main(void) { // // Inicjalizacja systemu (w tym PWM) // SYSTEM_Initialize(); // // // Petla odtwarzajaca dwa dzwieki na zmiane // while(1) { // // Zagraj 1000 Hz // zagraj_nute(500, czas_nuty, 1); // // Pauza // zagraj_nute(PAUZA, czas_pauzy, 0); // //zagraj_nute(unsigned int czestotliwosc, unsigned int czas_trwania) // // Zagraj 2000 Hz // zagraj_nute(1000, czas_nuty, 2); // // Pauza // zagraj_nute(PAUZA, czas_pauzy, 0); // } //} // Definicje nut (czestotliwosci w Hz) #define C4 262 #define D4 294 #define E4 330 #define F4 349 #define G4 392 #define A4 440 #define B4 494 #define C5 523 #define PAUZA 0 // Tablica z nutami gamy C-dur unsigned int gama[] = {C4, D4, E4, F4, G4, A4, B4, C5}; unsigned int czas_nuty = 350; // Czas trwania nuty w ms unsigned int czas_pauzy = 50; // Czas pauzy miedzy nutami void main(void) { // Inicjalizacja systemu (w tym PWM) SYSTEM_Initialize(); // Petla odtwarzajaca game while(1) { // Odtworz game w gore for (int i = 0; i < 8; i++) { zagraj_nute(gama[i], czas_nuty); zagraj_nute(PAUZA, czas_pauzy); // Pauza miedzy nutami /* zagraj_nute(unsigned int czestotliwosc, unsigned int czas_trwania) */ } // Dluzsza pauza zagraj_nute(PAUZA, 500); // Odtworz game w dol for (int i = 7; i >= 0; i--) { zagraj_nute(gama[i], czas_nuty); zagraj_nute(PAUZA, czas_pauzy); } // Dluzsza pauza przed powtorzeniem zagraj_nute(PAUZA, 1000); } }