Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: AppleRemoteController_copy_Production_Version AppleRemoteController_Reference_Only
main.cpp
- Committer:
- andrewcrussell
- Date:
- 2015-11-16
- Revision:
- 1:bb881a434906
- Parent:
- 0:83d4a20e7bc7
- Child:
- 2:674e2dd56e7d
File content as of revision 1:bb881a434906:
/****************************** RC5 Decoder and Preamp Controller V1.0 *************************/ /* AndrewR written in 2015 */ /* This RC5 decoder works by reading in the RC5 stream from one of the serial port lines */ /* and saving the incoming stream into an array called stream, after which it is decoded and */ /* the command executed. A Marantz RC-68PM IR R/C was used to develop this program - it */ /* should work with any controller complying with the Philips RC5 standard. */ /* See the rc5codes.h header for the codes used. */ /* The following audio preamplifier facilities are catered for:- */ /* 1. Manual volume control adjustment via ALPS RK27 motorized potentiometer */ /* 2. Input select via rotary encoder */ /* 3. Output mute via push button actuation */ /* 4. Record loop via push button actuation */ /* 5. Power ON output to drive the /standby input of a system power supply */ /* Facilities 1,2,3 and 5 are supported by an RC5 compliant remote control for preamplifiers */ /* The program can be used with either the LPC11U24 or the LPC1114 - just use the appropriate */ /* Pindfefxxxx.h file */ #include "mbed.h" #include "rc5codes.h" // Philips RC5 code definitions #include "Pindef1114.h" // all microcontroller I/O pin assignments defined here #define TRUE 1 #define FALSE 0 #define HIGH 1 #define LOW 0 #define rc5_bitcount 14 // number of RC5 bits #define tick 444 // quarter bit time in us #define tock 1778 // one bit time in us #define VUP_timeout 10 // defines max number of R/C cycles before the vol ctrl mtr drive stops #define VDWN_timeout 10 // as above but for volume decrease. Needed to ensure the motor is not burnt out //#define PHONO_IN 1 // these are the input assignments - not used in V1.0 of the //#define CD_IN 2 // controller since the input select is just stepped //#define TUN_IN 4 // through from PHONO_IN to REC_IN and back again //#define AUX1_IN 8 //#define MSERV_IN 16 //define REC_IN 32 int startbit; int toggle; int toggle1; int toggle2; int standby; int address; int command; int FLAG1; // this is used in the remote control input processing int FLAG2; // this is used in the select input processing int FLAG3; // this is for the mute pushbutton int FLAG4; // this is for the standby pushbutton int FLAG5; // this is the recloop flag int RCFLAG = FALSE; // used to determine if the select command came via R/C int standbyflag; // used to save the standby condition int relay; int key_press = 1; // keeps track of key presses int toggle_press = 1; //stores value of toggle for key_press routine // delcarations below are all for the input select proceses int select = 0; int select_save = 1; // we save the status of select drive here. Initial value is 1 int select_rot = 1; // rotary encoder pulse counter // declare function prototypes here void select_out (void); void rc5isr(void); void mute_isr(void); void recloop_isr(void); void select_isr(void); void standby_out(void); /****************************** volume increase ***********************************/ void vol_up (void) { if ((standbyflag == TRUE) && (key_press < VUP_timeout)) { FWD1 = HIGH; // FWD2 = HIGH; wait(.1); //drive the motors for a short while FWD1 = LOW; // FWD2 = LOW; } if (toggle1 != toggle) { key_press = 0; // user released the button, so reset counter } else if (toggle1 == toggle) { key_press++; // button remained depressed, so increment counter } toggle1 = toggle; wait_ms(1); } /******************************* volume decrease **********************************/ void vol_dwn (void) { if ((standbyflag == TRUE) && (key_press < VDWN_timeout)) { REV1 = HIGH; // REV2 = HIGH; wait(.1); //drive the motors for a short while REV1 = LOW; // REV2 = LOW; } if (toggle1 != toggle) { key_press = 0; // user released the button, so reset counter } else if (toggle1 == toggle) { key_press++; // button remained depressed, so increment counter } toggle1 = toggle; wait_ms(1); } /********************************** stdby_isr *************************************/ void stdby_isr (void) { FLAG4 = TRUE; } /*********************************** standby **************************************/ /* this will require supporting hardware functionality to power down the */ /* analog board, LED's etc. Best option here is to use regulators with a */ /* shutdown option. for now, all the LED's are just turned off. */ void standby_out(void) // both p/button and R/C come in here { stdby_int.fall(NULL); // on first power up cycle NO interuppts are accepted // and neither any while this function is executed in any case wait_ms(20); // a very simple debounce do { // that waits for the depressed button to be released (1); } while (stdby !=1); if (standbyflag == TRUE) { // was ON so we will turn it OFF // turn off all interrupts except the standby and rc5int select_int.fall(NULL); mute_int.fall(NULL); recloop_int.fall(NULL); muteind = LOW; muteout = LOW; recloop_out = LOW; select_save = select_drv; // save the status of select_drv select_drv = 0; // turn all input select realys OFF //power_ind = LOW; // this is the regulator shutdown control. HIGH = ON wait(1); muteind = HIGH;` standbyflag = FALSE; // set it up for the next power cycle } else if (standbyflag == FALSE) { // was OFF so we will turn it ON //printf("i should be here!\n"); //power_ind = HIGH; muteind = LOW; rc5int.rise(&rc5isr); // trigger int on rising edge - go service it at rc5dat select_int.fall(&select_isr); // input from rotary encoder or input select mute_int.fall(&mute_isr); recloop_int.fall(&recloop_isr); wait(2); select_drv = select_save; // recall the input select setting wait(2); muteind = HIGH; // let things settle a bit muteout = HIGH; standbyflag = TRUE; } //printf("STDB ISR\n"); wait_ms(5); stdby_int.fall(&stdby_isr); // re-enable the standby interrupt } /********************************** record loop isr *******************************/ void recloop_isr(void) { FLAG5 = TRUE; } /************************** recloop - just a simple toggle ************************/ void recloop() { recloop_int.fall(NULL); // to prevent re-entrance when coming here from the R/C wait_ms(20); // simple debounce for when mute is via the f/p p/b switch do { (1); // wait here until the button is released } while (recloop_in!=1); recloop_out = !recloop_out; wait_ms(20); recloop_int.fall(&recloop_isr); } /************************************ mute_isr ************************************/ void mute_isr(void) { FLAG3 = TRUE; toggle2 = !toggle2; // so the p/button input is recognized in mute_out() if(muteout = HIGH) {muteind = LOW;} } /*************************** mute - just a simple toggle **************************/ void mute_out() { mute_int.fall(NULL); // to prevent re-entance when coming here from the R/C if ((standbyflag == TRUE) && (toggle != toggle2)) { // only toggle mute if the preamp is ON wait_ms(20); //simple debounce for when mute is via the f/p p/b switch do { (1); //wait here until the button is released } while (mute != 1); muteout = !muteout; wait_ms(20); } toggle2 = toggle; mute_int.fall(&mute_isr); } /************************************ rc5isr **************************************/ /* Interrupt triggered by a rising edge on p21 of the cont which is R/C data in */ void rc5isr(void) { FLAG1 = TRUE; } /***************** save rc5 bit stream from remote controller *********************/ /* This function reads the input data on pin rc5dat at 1778us ('tock')intervals */ /* and saves the data into an array stream[i]. */ /* This function only looks at the second half of the bit position, since if that */ /* is a 1 then it is assumed the first half of the bit position is a zero. Note */ /* that in Manchester encoding, you cannot (should not) have both the 0 half-bit */ /* position and the 1 half-bit position both HIGH or LOW in the same bit time - */ /* a simplification exploited in this function. */ void save_stream(void) { bool stream[15];// the array is initialized each time its used and is local only int bitloop; // number of bit positions int i = 0; // counter int k = 0; // temp storage startbit = 0; address = 0; command = 0; toggle = 0; wait_us(tick); // locate read point in middle of 1st half bit time of the 1st start bit for (bitloop = 0; bitloop <15; bitloop++) { stream[bitloop] = rc5dat; //read the data and save it to array position [i] wait_us(tock); //wait here until ready to read the next bit in // now have 14 bits loaded into stream[i] } /* now put data in the array into the start, toggle, address and command variables - array counts from stream[0] */ for (i=0; i<2; i++) { // first 2 bit positions are start bits = 3; will use this later for basic error checking k = stream[i]; startbit = (startbit << 1); startbit = startbit|k; } toggle = stream[2]; // 3rd bit position is the toggle bit - 1 bit for (i = 3; i <8; i++) { // bit positions 3 to 7 are the address (or 'system') - 5 bit positions in total k = stream[i]; address = (address << 1); address = address|k; } for (i = 8; i <14; i++) { // bit positions 8 to 13 are the command - 6 bit positions k = stream[i]; command = (command << 1); command = command|k; } } /********************************* process_stream() *******************************/ /* handles commands coming in from the remote controller only */ void process_stream (void) { if ((address == PREAMP) && (startbit == 3)) { // basic error checking - must be preamp + startbit ok to get executed otherwise skip completly switch (command) { case VUP: vol_up(); break; case VDOWN: vol_dwn(); break; case MUTE: mute_out(); break; case SELECT_R: select_out(); break; case STANDBY: standby_out(); break; } } } /*********************************** select_isr ***********************************/ void select_isr(void) { FLAG2 = TRUE; } /********************************* select_process *********************************/ /* used for selecting the input source. This function is used by both the */ /* rotary encoder and the remote control */ void select_process(void) { if (RCFLAG == FALSE) { // if used R/C skip to select below wait_ms(5); // debounce select = 0; // flush select select = (select | sela) <<1; // read the two port lines associated with the select rotary encoder select = (select | selb); } switch (select) { case 1: // select encoder is being rotated CW select_rot <<= 1; if (select_rot > 32) { select_rot = 1; } break; case 0: select_rot >>= 1; // encoder is being rotated CCW if (select_rot < 1) { select_rot = 32; } break; case 2: {} break; // indeterminate fall through values - ignore case 3: {} break; } select_drv = select_rot; // write the value out to the bus } /********************* input select from remote controller only *******************/ void select_out (void) { if (toggle != toggle1) { // if the R/C button is held down, skip the increment RCFLAG = TRUE; // this indicates command came in through the remote select = 1; select_process(); RCFLAG = FALSE; } toggle1 = toggle; } /************************************ main() ***************************************/ int main(void) { disable_irq(); // just to make sure we can set up correctly without problems muteind = LOW; muteout = LOW; // mute the output while we go through power-up sequence recloop_out = LOW; // make sure initial recloop condition is delected //power_ind = LOW; // power control; HIGH = power up wait(.2); //Serial pc(USBTX, USBRX); // for debuging only - comment out on production FLAG1 = FALSE; FLAG2 = FALSE; FWD1=0; // FWD2=0; REV1=0; // REV2=0; //make sure the volume control motor is OFF // set up the ISR's we will be using rc5int.rise(&rc5isr); // trigger int on rising edge - go service it at rc5dat select_int.fall(&select_isr); // input from rotary encoder or input select mute_int.fall(&mute_isr); // mute push button interrupt recloop_int.fall(&recloop_isr); // record loop push button interrupt stdby_int.fall(&stdby_isr); // the system power/standby switch //now disable them, leaving only the stand by p/button and rc5int interrupts active select_int.fall(NULL); mute_int.fall(NULL); recloop_int.fall(NULL); //printf("diable ISR\n"); standbyflag = TRUE; // preamp will be set-up first time for OFF standby_out(); // go through standby_out for initial set-up select_save = 2; // CD will be selected when power is first turned on muteind = HIGH; __enable_irq(); // all ready and in standby from this point forward LOOP: // this is the main operating loop //printf("WFI\n"); __WFI(); // wait here until interrupt if (FLAG1 == TRUE) { // FLAG1 indicates remote control was used __disable_irq(); save_stream(); if (startbit == 3) { process_stream(); } FLAG1 = FALSE; __enable_irq(); } if (FLAG2 == TRUE) { __disable_irq(); select_process(); //select process FLAG2 = FALSE; __enable_irq(); } if (FLAG3 == TRUE) { __disable_irq(); mute_out(); //mute FLAG3 = FALSE; __enable_irq(); } //printf("B4stdby\n"); if (FLAG4 == TRUE) { __disable_irq(); standby_out(); // standby FLAG4 = FALSE; // printf("back from isr\n"); __enable_irq(); //printf("renable isr\n"); } //printf("finished with STBY\n"); if (FLAG5 == TRUE) { __disable_irq(); recloop(); //recloop FLAG5 = FALSE; __enable_irq(); } wait_us(5); //printf("loop to WFI\n"); goto LOOP; }