Search code examples
cbinarybit-shiftcpu-registerspic

Converting bit-shift operations to specific binary number format (for a PIC microcontroller)


I am working on several home automation projects with PIC12F675. To maximize portability, I am using bit-shift operations to map GPIOs, like this:

// Hardware Mapping
#define pressure_pin  (1<<0)  // Pressue sensor output (analog input) 
#define button_pin    (1<<1)  // Multi-function button (digital input)
#define buzzer_pin    (1<<2)  // NPN transitor to activate buzzer (digital output)
#define pause_pin     (1<<4)  // NPN transistor to pause button (digital output)
#define led_pin       (1<<6)  // Led (digital output)
#define PORT          GPIO    // Port 

To set input pins ('pressure_pin" and 'button_pin'), it is necessary change TRISIO, ANSEL and ADCON0 registers. TRISIO and ANSEL changes are easily done by:

TRISIO |= (button_pin | pressure_pin);  // Output pins 
ANSEL = (0x50 | pressure_pin);          // Fosc/16 and 'pressure_pin' as analog input`

ADCON0 must have bits 7 and 0 setted and bits 3 and 2 must receive the GPIO number used as analog input, as shown in the figure below (extracted from PIC12F675 datasheet)

enter image description here

So, I need ADCON0 to receive one of the following values ​​(according to 'pressure_pin' definition):

pressure_pin ADCON0
(1<<0) 0x81
(1<<1) 0x85
(1<<2) 0x89
(1<<3) 0x8D

My solution was:

ADCON0 = 0x81;  // 0b10000001. ADC value right justified ; ADC turned on
ADCON0 |= (((0x82>>(pressure_pin-1))&0x1)<<2) | (((0x88>>(pressure_pin-1))&0x1)<<3);

This code snippet reproduces my solution in C language:

int main(int, char**)
{
    unsigned char pressure_pin = (1<<3);
    unsigned char ADCON0 = 0x81;
    ADCON0 |= (((0x82>>(pressure_pin-1))&0x1)<<2) | (((0x88>>(pressure_pin-1))&0x1)<<3);   
    return 0;
}

Considering PIC12F675 restrictions,is there a more elegant and/or more efficient solution for this conversion?

Thanks in advance.


Solution

  • Maybe lookup table. No calculations needed.

    const unsigned char data[] = {[1 << 0] = 0x81, [1 << 1] = 0x85, [1 << 2] = 0x89, [1 << 3] = 0x8D};
    unsigned char foo(unsigned pressurepin)
    {
        return data[pressurepin];
    }
    

    I do not have pic compiler but similar 8 bit code generated for AVR shows that it will be much faster (and most likely smaller)

    https://godbolt.org/z/j9aWP3Tqx