//************************************************************ // PIC_METORONOME // // BEAT: 1,2,3,4 Time // TEMPO: 40-200bpm (1bpm step:ROTARY ENCODER) // Rhythm Tone: Wood Block(USED Envelope Contorol Block) // LCD unlook busy : not switch direction (write fixed) // // CPU: dsPIC30F4012 // // Condition: // 7.37MHz Internal RC oscillator, 16x PLL enabled // Fcy=7.37MHzx16/4=29.48MHz, Tcy=33.92ns // // 2012/7/19: N.Ishii // Modify: 2012/8/6 N.Ishii //************************************************************* #include #include // Divice configuration _FWDT(WDT_OFF); _FGS(CODE_PROT_OFF); _FOSC(CSW_FSCM_OFF & FRC_PLL16); //OSC, PLL Setting _FBORPOR(PBOR_OFF & PWRT_64 & MCLR_EN); //------------------------------------------------------------------------- /// message table char msg1[] = {"BEAT :\0"}; char msg2[] = {"TEMPO: [bpm]\0"}; //------------------------------------------------------------------------- /// Envelope Contorol Block Define #define CK1 LATEbits.LATE8 #define CK1_Lo LATEbits.LATE8 = 0 #define UP1_Hi LATDbits.LATD0 = 1 #define UP1_Lo LATDbits.LATD0 = 0 #define DWN1_Hi LATDbits.LATD1 = 1 #define DWN1_Lo LATDbits.LATD1 = 0 //--------------------------------------------------------------------------------------------- /// Rotary ecoder #define RE_A PORTBbits.RB2 #define RE_B PORTBbits.RB3 //----------------------------------------------------------------------------------------- /// LCD Define: R/W_pin= GND (Fixed Write) #define LCD_DATA_WR_MODE LATEbits.LATE5 = 1 // RS_pin = 1 #define LCD_INST_WR_MODE LATEbits.LATE5 = 0 // RS_pin = 0 #define LCD_ENABLE_ON LATEbits.LATE4 = 1 #define LCD_ENABLE_OFF LATEbits.LATE4 = 0 #define LCD_DATA_BIT4 LATEbits.LATE0 #define LCD_DATA_BIT5 LATEbits.LATE1 #define LCD_DATA_BIT6 LATEbits.LATE2 #define LCD_DATA_BIT7 LATEbits.LATE3 //--------------------------------------------------------------------------------------------- /// LCD Instraction Code #define FOUR_BIT_FONT5x7dot 0x28 // + TWO_LINE(1/16Duty), SEG1_50_SEG51_100, COM1_COM16 #define DISP_ON_CURSOR_ON_BLINK_OFF 0x0e #define DISP_CLEAR_CURSOR_HOME 0x01 #define RAM_WR_AFTER_PLUS_1 0x06 // Entory mode set #define DDRAM_START_ADDRESS_SET 0x80 #define DISP_ON_CURSOR_OFF_BLINK_OFF 0x0c //--------------------------------------------------------------------------- unsigned int T3_count = 0; unsigned int beat_count = 0; unsigned char BPM = 60; unsigned int Beat_Period; unsigned int T3_count_MAX = 2000; unsigned char Beat_No = 3; unsigned char start_flag = 0; unsigned char sw1_m0 = 0; // Start/Stop SW unsigned char sw1_m1 = 0; unsigned char sw1_m2 = 0; unsigned char sw2_m0 = 0; // Beat Sel SW unsigned char sw2_m1 = 0; unsigned char sw2_m2 = 0; unsigned char re_b_m0 = 0; // ROTARY ENCODER B-OUT:Clock unsigned char re_b_m1 = 0; unsigned char re_b_m2 = 0; //unsigned char digit[3]; //----------------------------------------------------------------------------------- /// Delay Subrutin void Waitx1ms(int x) // Td = 1mS * x { int i,j; for(i = 0 ; i < x ; ++i) { for(j = 0 ; j < 5000 ; ++j) asm("clrwdt"); //Td=1mS } } void Waitx1us(int x) // Td = 1uS * x { int i,j; for(i = 0 ; i < x ; ++i) { for(j = 0 ; j < 5 ; ++j) asm("clrwdt"); //Td=1uS } } //-------------------------------------------------------------------- /// LCD Subrutin void one_chr_wr(char chr_code) { LCD_DATA_WR_MODE; //RS_pin = 1: select data Reg // A Higher 4bit data out LCD_DATA_BIT7 = (unsigned int)((chr_code & 0x80)>>7); LCD_DATA_BIT6 = (unsigned int)((chr_code & 0x40)>>6); LCD_DATA_BIT5 = (unsigned int)((chr_code & 0x20)>>5); LCD_DATA_BIT4 = (unsigned int)((chr_code & 0x10)>>4); Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; // A Lower 4bit data out LCD_DATA_BIT7 = (unsigned int)((chr_code & 0x08)>>3); LCD_DATA_BIT6 = (unsigned int)((chr_code & 0x04)>>2); LCD_DATA_BIT5 = (unsigned int)((chr_code & 0x02)>>1); LCD_DATA_BIT4 = (unsigned int)(chr_code & 0x01); Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; Waitx1us(50); } void lcd_chr_wr(char *buffer) { while(*buffer != '\0') { one_chr_wr(*buffer); /* calling another function */ /* to write each char to the lcd module */ buffer++; } } void lcd_inst_wr(char inst_code) { LCD_INST_WR_MODE; //RS_pin = 0: select Instruction Reg // A Higher 4bit data out LCD_DATA_BIT7 = (unsigned int)((inst_code & 0x80)>>7); LCD_DATA_BIT6 = (unsigned int)((inst_code & 0x40)>>6); LCD_DATA_BIT5 = (unsigned int)((inst_code & 0x20)>>5); LCD_DATA_BIT4 = (unsigned int)((inst_code & 0x10)>>4); Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; // A Lower 4bit data out LCD_DATA_BIT7 = (unsigned int)((inst_code & 0x08)>>3); LCD_DATA_BIT6 = (unsigned int)((inst_code & 0x04)>>2); LCD_DATA_BIT5 = (unsigned int)((inst_code & 0x02)>>1); LCD_DATA_BIT4 = (unsigned int)(inst_code & 0x01); Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; if ((inst_code >= 0x01) && (inst_code <= 0x03)) Waitx1ms(20); // inst_code is Clear(0x01) or Cursor Home(0x02 or 0x03) Then Wait 20mS else Waitx1us(50); // other code Then Wait 50uS } void lcd_init(void) { // Allow a delay(minimum of 15ms) Waitx1ms(20); //------ 1st step: port_output regster set -------------- // Initialize the data port/control pins to zero LCD_DATA_BIT7 = 0; LCD_DATA_BIT6 = 0; LCD_DATA_BIT5 = 0; LCD_DATA_BIT4 = 0; LCD_INST_WR_MODE; //RS_pin = 0 LCD_ENABLE_OFF; //E_pin = 0 //-------------------------------------------------------- // dsPIC30F4012 //------- 2nd step: port_mode regster set --------------- // Configure the data pins as output TRISEbits.TRISE0 =0; // RE0 is LCD DB4 OUTPUT TRISEbits.TRISE1 =0; // RE1 is LCD DB5 OUTPUT TRISEbits.TRISE2 =0; // RE2 is LCD DB6 OUTPUT TRISEbits.TRISE3 =0; // RE3 is LCD DB7 OUTPUT // Make all control pins as outputs TRISEbits.TRISE4 =0; // RE4 is LCD Enable OUTPUT TRISEbits.TRISE5 =0; // RE5 is LCD RS OUTPUT //------------------------------------------------------- // Initialize stage 1: Set stage 1 only 8-bit Interface // Set Upper 4 Bit Data on RB9 - RB12 LCD_DATA_BIT7 = 0; LCD_DATA_BIT6 = 0; LCD_DATA_BIT5 = 1; LCD_DATA_BIT4 = 1; Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; Waitx1ms(5); // Initialize stage 2: Set stage 2 only 8-bit Interface LCD_DATA_BIT7 = 0; LCD_DATA_BIT6 = 0; LCD_DATA_BIT5 = 1; LCD_DATA_BIT4 = 1; Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; Waitx1ms(1); // Initialize stage 3: Set stage 3 only 8-bit Interface LCD_DATA_BIT7 = 0; LCD_DATA_BIT6 = 0; LCD_DATA_BIT5 = 1; LCD_DATA_BIT4 = 1; Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; Waitx1ms(1); // Initialize stage 4: 4-bit Interface LCD_DATA_BIT7 = 0; LCD_DATA_BIT6 = 0; LCD_DATA_BIT5 = 1; LCD_DATA_BIT4 = 0; Waitx1us(1); LCD_ENABLE_ON; Waitx1us(1); LCD_ENABLE_OFF; Waitx1ms(1); //----- Fixed LCD Setting------------ lcd_inst_wr(FOUR_BIT_FONT5x7dot); // Function Set lcd_inst_wr(DISP_ON_CURSOR_ON_BLINK_OFF); lcd_inst_wr(DISP_CLEAR_CURSOR_HOME); // Set DDRAM Address = 0 lcd_inst_wr(RAM_WR_AFTER_PLUS_1); // Entry mode Set } void const_lcd_disp(void) { // Initialize LCD Disp lcd_inst_wr(0x80); lcd_chr_wr(msg1); // 'BEAT :' const disp1 lcd_inst_wr(0xc0); lcd_chr_wr(msg2); // 'TEMPO: [bpm]' const disp2 } void beat_no_disp(unsigned char Vol, unsigned char loc) { lcd_inst_wr(loc); one_chr_wr(Vol | 0x30); } void tempo_disp(unsigned char Vol, unsigned char loc) { unsigned char i; unsigned char digit[3]; unsigned char ascii[3]; // Bin_to_pacdec digit[0] = Vol%10; digit[1] = (Vol/10)%10; digit[2] = (Vol/100)%10; // Decimal_to_ascii for (i = 0; i <= 2; ++i) {ascii[i] = digit[i] | 0x30;} // LCD Disp lcd_inst_wr(loc); one_chr_wr(ascii[2]); one_chr_wr(ascii[1]); one_chr_wr(ascii[0]); } //----------------------------------------------------------------------------------------- /// SW and ROTARY ENCODER Read Subrutin void Start_Stop_SW_read(void) { sw1_m0 = PORTBbits.RB0; //New SW1 Data sw1_m2 = sw1_m1^(sw1_m0 & sw1_m1); //Neg_Edge Sence SW1 sw1_m1 = sw1_m0; //Chenge New Data to Old Data m1 if (!start_flag) { if (sw1_m2) { // Start start_flag = 1; ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_ON); } } else { if (sw1_m2) { // Stop start_flag = 0; T3_count = 0; beat_count = 0; CK1_Lo; UP1_Lo; DWN1_Lo; // LATDbits.LATD0 = 1; // LED OFF LATBbits.LATB4 = 1; // LED OFF: Mod 120806 ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_OFF); } } } void Beat_No_Sel_SW_read(void) { sw2_m0 = PORTBbits.RB1; //New SW2 Data sw2_m2 = sw2_m1^(sw2_m0 & sw2_m1); //Neg_Edge Sence SW2 sw2_m1 = sw2_m0; //Chenge New Data to Old Data m1 if (sw2_m2) { ++Beat_No; if (Beat_No == 5) Beat_No = 1; if (start_flag) { ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_OFF); T3_count = 0; beat_count = 0; CK1_Lo; UP1_Lo; DWN1_Lo; ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_ON); } } } void Rotary_Encoder_read(void) { //Read ROTARY ENCODER B_Clock re_b_m0 = RE_B; re_b_m2 = re_b_m1^(re_b_m0 & re_b_m1); //Neg_Edge Sence CLOCK re_b_m1 = re_b_m0; //Chenge New Data to Old Data m1 if (re_b_m2 == 1) { //Neg_Edge Sence B_Clock ? if (RE_A == 0) { // A_Data = 0 ? ++BPM; if (BPM >= 201) BPM = 200; } else { // B_Data = 0 --BPM; if (BPM <= 39) BPM = 40; } if (start_flag) { ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_OFF); T3_count = 0; beat_count = 0; CK1_Lo; UP1_Lo; DWN1_Lo; ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_ON); } } } //----------------------------------------------------------------------------------------------------- // Intterrupt routine: T = 0.5ms void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void) { ++T3_count; if (beat_count == 0) { // Top tone is 1kHz if (T3_count <= 160) CK1 = !CK1; } else { // Other tone is 500Hz if ((T3_count <= 160) && ((T3_count - 1) % 2) == 0) CK1 = !CK1; } switch (T3_count) { case 1: LATBbits.LATB4 = 0; // LED ON UP1_Hi; if (beat_count == 0) DWN1_Hi; break; case 21: UP1_Lo; if (beat_count == 0) DWN1_Lo; break; case 25: DWN1_Hi; break; case 125: DWN1_Lo; LATBbits.LATB4 = 1; // LED OFF break; default: break; } if (T3_count == T3_count_MAX) { // 161-xxx: Interval Block T3_count = 0; ++beat_count; if (beat_count == Beat_No) beat_count = 0; } //Intterrupt Timer3 Clear IFS0bits.T3IF = 0; } //-------------------------------------------------------------------- /// Function Main int main(void) { // Set ADPCFG: RB Port is All Digital Pin ADPCFG = 0xFFFF; TRISBbits.TRISB4=0; // RB4 is LED output used debug // Switch Port Set TRISBbits.TRISB0 =1; // RB0 is SW1 input TRISBbits.TRISB1 =1; // RB8 is SW2 input // PAT PORT is ALL OUTPUT TRISDbits.TRISD1 =0; // DWN1 TRISEbits.TRISE8 =0; // CK1 TRISDbits.TRISD0 =0; // UP1 // ROTARY ENCODER PORT TRISBbits.TRISB2 =1; // RB2 is RE_A input TRISBbits.TRISB3 =1; // RB3 is RE_B input LATBbits.LATB4 = 1; // LED OFF // Initialize LCD lcd_init(); lcd_inst_wr(DISP_ON_CURSOR_OFF_BLINK_OFF); const_lcd_disp(); // Inittalize Timer3(2KHz = Fcy /14740) OpenTimer3(T3_ON & T3_GATE_OFF & T3_PS_1_1 & T3_SOURCE_INT, 14740-1); // T3 ON & Enable Interrupt ConfigIntTimer3(T3_INT_PRIOR_5 & T3_INT_OFF); DISICNT = 0x0000; // Enable Interrupt // MAIN LOOP while(1) { Start_Stop_SW_read(); Beat_No_Sel_SW_read(); Rotary_Encoder_read(); Beat_Period = 60000/BPM; T3_count_MAX = Beat_Period * 2; beat_no_disp(Beat_No, 0x86); tempo_disp(BPM, 0xc6); } }