Skip to content

Instantly share code, notes, and snippets.

@Kazu-zamasu
Created June 16, 2015 15:57
Show Gist options
  • Save Kazu-zamasu/2a72c675bb9be726b42e to your computer and use it in GitHub Desktop.
Save Kazu-zamasu/2a72c675bb9be726b42e to your computer and use it in GitHub Desktop.
Platforms
Components
Handbook
Cookbook
Code
Questions
Forum
Compiler
Dashboard
ARM mbed
Hi, Profile kazu_zamasu
[Beta]
Logout Logout
Users » andrewcrussell » Code » RC5_AndrewR
Andrew R / [This repository is a program] RC5_AndrewR
An RC5 decoder and preamp controller. Written on the LPC11U24, Ported to LPC1114, but it seems that version is a bit unstable.
Dependencies: mbed
Home History Graph API Documentation Wiki Pull Requests
file
revisions
annotate
diff
raw
main.cpp
Committer:
Andrew R
Date:
about 5 hours ago
Revision:
0:83d4a20e7bc7
File content as of revision 0:83d4a20e7bc7:
/* **************************** RC5 Decoder and Preamp Controller V1.0 *************************/
/* Andrew C. Russell (c) 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 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. Note the address is 16 which is for a preamp. */
/* 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 */
#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 */
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);
muteout = LOW;
wait(1);
recloop_out = LOW;
select_save = select_drv; // save the status of select_drv
select_drv = 0; // turn all input select realys OFF
wait(1);
power_ind = LOW; // this is the regulator shutdown control. HIGH = ON
standbyflag = FALSE; // set it up for the next power cycle
} else if (standbyflag == FALSE) { // was OFF so we will turn it ON
power_ind = HIGH;
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); // let things settle a bit
muteout = HIGH;
standbyflag = TRUE;
}
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()
}
/*************************** 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
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);
standbyflag = HIGH; // preamp will be set-up first time for OFF
standby_out(); // go through standby_out for initial set-up
select_save = 1; // phono will be selected when power is first turned on
__enable_irq();
// all ready and in standby from this point forward
LOOP: // this is the main operating loop
__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();
}
if (FLAG4 == TRUE) {
__disable_irq();
standby_out(); // standby
FLAG4 = FALSE;
__enable_irq();
}
if (FLAG5 == TRUE) {
__disable_irq();
recloop(); //recloop
FLAG5 = FALSE;
__enable_irq();
}
wait_us(5);
goto LOOP;
}
Ask a question Start a discussion
Repository toolbox
Embed:
Import this program
Export to desktop IDE
Build repository
Follow
Clone repository to desktop:
Repository details
Type: Program
Created: about 5 hours ago
Imports: 4
Forks: 0
Commits: 1
Dependents: 0
Dependencies: 1
Followers: 1
Software licencing information
The code in this repository is Apache licensed.
© mbed blog we're hiring! support service status privacy policy terms and conditions Language: en ja es de
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment