Created
September 4, 2014 14:23
-
-
Save spirilis/1d53a65c7ebc040f9d8d to your computer and use it in GitHub Desktop.
Remote control illustrating Graycode incremental encoder interpretation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* nRFDMX Remote Control implementation to send 3-letter RGB values based | |
* on a user-adjusted HSV colorspace system. | |
* Value adjusted by sliding potentiometer | |
* Hue adjusted by rotating a Rotary Encoder | |
* Saturation flipped between 1.0 and 0.1 by the rotary encoder pushbutton | |
*/ | |
#include <msp430.h> | |
#include <stdint.h> | |
#include <sys/cdefs.h> | |
#include <string.h> | |
#include "msprf24.h" | |
#include "dmx512.h" | |
#include "packet_processor.h" | |
#include "misc.h" | |
#include "hsv2rgb.h" | |
volatile uint16_t sleep_counter; | |
volatile int16_t rotenc, rotenc_old; | |
volatile uint8_t gc_old, rotbtn; | |
volatile uint16_t pot, pot_old; | |
volatile float saturation; | |
int8_t graycode_interpret(uint8_t, uint8_t); | |
int main() | |
{ | |
WDTCTL = WDTPW | WDTHOLD; | |
DCOCTL = CALDCO_16MHZ; | |
BCSCTL1 = CALBC1_16MHZ; | |
BCSCTL2 = DIVS_1; // SMCLK = 8MHz | |
BCSCTL3 = LFXT1S_2; | |
while (BCSCTL3 & LFXT1OF) | |
; | |
// Initialize Rotary Encoder | |
P2DIR &= ~(BIT4 | BIT5); | |
P2REN |= BIT4 | BIT5; | |
P2OUT |= BIT4 | BIT5; | |
__delay_cycles(100000); // Time for hardware debounce RC network to charge | |
P2IES = (P2IES & ~(BIT4 | BIT5)) | (P2IN & (BIT4 | BIT5)); /* Preload P2IES with current | |
* values since we can't interrupt | |
* on any change, but must track | |
* rising vs. falling transitions. | |
*/ | |
P2IFG &= ~(BIT4 | BIT5); | |
gc_old = (P2IN & (BIT4 | BIT5)) >> 4; | |
P2IE |= BIT4 | BIT5; | |
// Initialize rotary encoder pushbutton | |
P2DIR &= ~BIT7; | |
P2SEL &= ~BIT7; | |
P2SEL2 &= ~BIT7; | |
P2REN |= BIT7; | |
P2OUT |= BIT7; | |
P2IES |= BIT7; | |
P2IFG &= ~BIT7; | |
P2IE |= BIT7; | |
rotbtn = 0; | |
// Initialize LEDs | |
P2OUT &= ~(LED_ROTGREEN | LED_ROTRED | LED_POT); | |
P2DIR |= LED_ROTGREEN | LED_ROTRED | LED_POT; | |
P2REN &= ~(LED_ROTGREEN | LED_ROTRED | LED_POT); | |
P2SEL &= ~(LED_ROTGREEN | LED_ROTRED | LED_POT); | |
P2SEL2 &= ~(LED_ROTGREEN | LED_ROTRED | LED_POT); | |
// Initialize S1+S2 address setting scheme | |
P2DIR &= ~(BIT0 | BIT1); | |
P2REN &= ~(BIT0 | BIT1); /* ^ No interrupts necessary since we just read P2IN for this information | |
* as we need it. Also no debounce circuitry; the switches go hard to Vcc or GND. | |
*/ | |
// Initialize analog input port & VeREF+ output for potentiometer | |
P1DIR &= ~(BIT3 | BIT4); | |
P1REN &= ~(BIT3 | BIT4); | |
P1IE &= ~(BIT3 & BIT4); | |
pot = 0; | |
// Configure Nordic nRF24L01+ | |
rf_crc = RF24_EN_CRC | RF24_CRCO; // CRC enabled, 16-bit | |
rf_addr_width = 5; | |
rf_speed_power = RF_SPEED | RF24_POWER_MAX; // RF_SPEED from tcsender.h | |
rf_channel = RF_CHANNEL; // This #define is located in tcsender.h | |
msprf24_init(); | |
msprf24_open_pipe(0, 0); | |
msprf24_set_pipe_packetsize(0, 0); | |
packet_init_tasklist(); | |
dmx512_init(); | |
sleep_counter = ADC_SLEEP_INTERVAL; | |
WDTCTL = WDT_ADLY_16; | |
IE1 |= WDTIE; | |
saturation = 1.0; | |
while(1) { | |
// Handle RF acknowledgements | |
if (rf_irq & RF24_IRQ_FLAGGED) { | |
msprf24_get_irq_reason(); | |
// Handle TX acknowledgements | |
if (rf_irq & RF24_IRQ_TX) { | |
// Acknowledge | |
msprf24_irq_clear(RF24_IRQ_TX); | |
msprf24_powerdown(); | |
P2OUT &= ~LED_POT; | |
} | |
if (rf_irq & RF24_IRQ_TXFAILED) { | |
msprf24_irq_clear(RF24_IRQ_TXFAILED); | |
flush_tx(); | |
msprf24_powerdown(); | |
P2OUT &= ~LED_POT; | |
} | |
if (rf_irq & RF24_IRQ_RX) { | |
// Really no reason we should be receiving anything. | |
flush_rx(); | |
msprf24_irq_clear(RF24_IRQ_RX); | |
} /* rf_irq & RF24_IRQ_RX */ | |
} /* rf_irq & RF24_IRQ_FLAGGED */ | |
if (rotbtn) { | |
// Process rotary encoder button press | |
if (saturation == 1.0) | |
saturation = 0.2; | |
else | |
saturation = 1.0; | |
// Do update | |
if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) { | |
HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) ); | |
dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3); | |
} | |
rotbtn = 0; | |
} | |
if (!sleep_counter) { // ADC conversion timer | |
ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFBURST | REFON | REFOUT | ADC10ON; | |
ADC10CTL1 = INCH_3 | ADC10DIV_1; | |
ADC10AE0 |= BIT3; | |
ADC10CTL0 |= ENC | ADC10SC; | |
while (ADC10CTL1 & ADC10BUSY) | |
; | |
pot = ADC10MEM >> 3; | |
ADC10CTL1 &= ~ENC; | |
ADC10CTL0 &= ~(ADC10ON | ADC10IFG); | |
if (pot != pot_old) { | |
// Do update | |
if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) { | |
HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) ); | |
dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3); | |
pot_old = pot; | |
} | |
} | |
sleep_counter = ADC_SLEEP_INTERVAL; | |
} | |
if (rotenc != rotenc_old) { | |
// Do update | |
if (msprf24_queue_state() & RF24_QUEUE_TXEMPTY) { | |
HSV_to_RGB(dmx512_buffer, (float)rotenc, saturation, (float) (pot / POT_UPPER_VALUE) ); | |
dmx512_output_channels(P2IN & 0x03, 1, dmx512_buffer, 3); | |
rotenc_old = rotenc; | |
} | |
} | |
if (packet_task_next() != NULL) { | |
packet_process_txqueue(); | |
P2OUT |= LED_POT; | |
} | |
LPM3; | |
} /* while(1) */ | |
return 0; // Should never reach here | |
} | |
// WDT overflow/timer | |
#pragma vector=WDT_VECTOR | |
__interrupt void WDT_ISR(void) | |
{ | |
IFG1 &= ~WDTIFG; | |
if (sleep_counter) | |
sleep_counter--; | |
else | |
__bic_SR_register_on_exit(LPM3_bits); | |
} | |
// Port 2 ISR - Rotary Encoder, rotary encoder pushbutton | |
#pragma vector=PORT2_VECTOR | |
__interrupt void P2ISR(void) | |
{ | |
uint8_t gc, p2in; | |
p2in = P2IN; | |
// Rotary encoder gray code | |
if (P2IFG & (BIT4 | BIT5)) { | |
gc = (p2in & (BIT4 | BIT5)) >> 4; | |
rotenc += graycode_interpret(gc, gc_old); | |
if (rotenc < 0) | |
rotenc = 359; | |
if (rotenc > 359) | |
rotenc = 0; | |
if (rotenc != rotenc_old) | |
__bic_SR_register_on_exit(LPM3_bits); | |
gc_old = gc; | |
P2IES = (P2IES & ~(BIT4 | BIT5)) | (p2in & (BIT4 | BIT5)); | |
P2IFG &= ~(BIT4 | BIT5); | |
} | |
if (P2IFG & BIT7) { | |
P2IFG &= ~BIT7; | |
rotbtn = 1; | |
__bic_SR_register_on_exit(LPM3_bits); // Wake the CPU to process this one. | |
} | |
} | |
// LSB = A, MSB = B -- graycode lookup table | |
const uint8_t graycode_cw[4] = {2, 0, 3, 1}; | |
const uint8_t graycode_ccw[4] = {1, 3, 0, 2}; | |
int8_t graycode_interpret(uint8_t newgc, uint8_t oldgc) | |
{ | |
if (graycode_cw[oldgc] == newgc) | |
return 1; | |
if (graycode_ccw[oldgc] == newgc) | |
return -1; | |
return 0; // should never get here, but, ya never know. | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment