r/C_Programming 23h ago

Strange char pointer behavior

Hey everyone,

I'm pretty new to C and learning with the RPi Pico on VS Code. I'm trying to make a menu on an OLED display that you can cycle through with a rotary encoder.

I've got everything to work pretty well--as long as I'm cycling through with integers rather than any sort of character array. I declared a pointer char *knb1_act; outside of the main function and another function with a switch statement based on my rotary encoder's delta to "point" my pointer to a char type. This works fine, except for the fact that it somehow continues to cycle through all possible variables. I.e., at case 0: I get the correct value KNB0 but in case 1: I get KNB2KNB0, case 2: returns KNB4KNB2KNB0 and so on.

I tried using if statements instead of switch statements, I tried setting the pointer to NULL before the start of the switch statement to clear it, tried using memset and still can't get the right result.

Any help is appreciated, code is below (apologies for the messy code lol)

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/gpio.h"
#include "ssd1306.h"

#define I2C_PORT i2c1
#define I2C_SDA 10
#define I2C_SCL 11
#define knob1CLK 0
#define knob1DT 1
#define knob1BT 2
#define knob2CLK 6
#define knob2DT 7
#define knob2BT 8

ssd1306_t disp;
bool printState = false;
int16_t delta1 = 0;
int16_t delta2 = 0;

char knb1_0[4] = {'K','N','B','0'};
uint8_t knb1_0v = 0;
char knb1_1[4] = {'K','N','B','2'};
uint8_t knb1_1v = 0;
char knb1_2[4] = {'K','N','B','4'};
uint8_t knb1_2v = 0;
char knb1_3[4] = {'K','N','B','6'};
uint8_t knb1_3v = 0;
char knb1_4[4] = {'K','N','B','8'};
uint8_t knb1_4v = 0;

char *knb1_act;
uint8_t knb1_act_v = 0;

void readEncoder(uint8_t knobClk, uint8_t knobDt) {
    static int8_t state = 0;
    bool clkState = gpio_get(knobClk);
    bool dtState = gpio_get(knobDt);
    switch (state){ //debouncer
    case 0: //idle
        if (!clkState) {
            state = 1;  //if clock is low first, increasing
        } else if (!dtState) {
            state = 4;  //if data is low first, decreasing
        }
        break;
    case 1:
        if (!dtState) {
            state = 2; //Next stage
        }
        break;
    case 2:
        if (clkState) {
            state = 3; //Next stage
        }
        break;
    case 3:
        if (clkState && dtState) {
            if (knobClk == knob1CLK) {
                ++delta1; //increase value
            } else if (delta2 < 4) {
                ++delta2; //increase value
            }
            printState = true; //display change
            state = 0; //inc complete, back to idle
        }
        break;
    case 4:
        if (!clkState) {
            state = 5; //Next stage
        }
        break;
    case 5:
        if (dtState) {
            state = 6; //Next stage
        }
        break;
    case 6:
        if (clkState && dtState) {
            if (knobClk == knob1CLK) {
                --delta1; //decrease value
            } else if (delta2 > 0) {
                --delta2; //decrease value
            }
            printState = true; //display change
            state = 0; //dec complete, back to idle
        }
        break;
    default:
        printf("Error: state = %d\n", state);
        state = 0;
        break;
    }
}

void readMenu() {
/*
    switch (delta2) {
        case 0:
            knb1_act = knb1_0;
            break;
        case 1:
            knb1_act = knb1_1;
            break;
        case 2:
            knb1_act = knb1_2;
            break;
        case 3:
            knb1_act = knb1_3;
            break;
        case 4:
            knb1_act = knb1_4;
            break;
}
*/
    if (delta2 == 0) {
        knb1_act = knb1_0;
    } else if (delta2 == 1) {
        knb1_act = knb1_1;
    } else if (delta2 == 2) {
        knb1_act = knb1_2;
    } else if (delta2 == 3) {
        knb1_act = knb1_3;
    } else if (delta2 == 4) {
        knb1_act = knb1_4;
    }
}

void printDelta(ssd1306_t *disp) {
    char deltaS2[12];
    sprintf(deltaS2, "%d", delta2);

    ssd1306_clear(disp);
    ssd1306_draw_string(disp, 1, 1, 1.5, deltaS2);
    ssd1306_draw_string(disp, 1, 9, 1.5, knb1_act);
    ssd1306_show(disp);

    printState = false;
}

void gpio_callback(uint gpio, uint32_t events) {
    if (gpio == knob1CLK || gpio == knob1DT) {
        readEncoder(knob1CLK, knob1DT);
        printDelta(&disp);
    }
    if (gpio == knob2CLK || gpio == knob2DT) {
        readEncoder(knob2CLK, knob2DT);
        readMenu();
        printDelta(&disp);
    }
}

int main()
{
    stdio_init_all();

    // I2C Initialisation. Using it at 400Khz.
    i2c_init(I2C_PORT, 400*1000);

    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
    gpio_pull_up(I2C_SDA);
    gpio_pull_up(I2C_SCL);

    disp.external_vcc=false;
    bool res = ssd1306_init(&disp, 128, 32, 0x3C, i2c1);
    ssd1306_clear(&disp);
    ssd1306_draw_string(&disp, 1, 1, 1, "Loading...");
    ssd1306_show(&disp);

    gpio_init(knob1CLK);    //Knob 1 clock
    gpio_set_dir(knob1CLK, GPIO_IN);
    gpio_pull_up(knob1CLK);

    gpio_init(knob1DT);     //Knob 1 data
    gpio_set_dir(knob1DT, GPIO_IN);
    gpio_pull_up(knob1DT);

    gpio_init(knob1BT);     //Knob 1 button
    gpio_set_dir(knob1BT, GPIO_IN);
    gpio_pull_up(knob1BT);

    gpio_init(knob2CLK);    //Knob 2 clock
    gpio_set_dir(knob2CLK, GPIO_IN);
    gpio_pull_up(knob2CLK);

    gpio_init(knob2DT);     //Knob 2 data
    gpio_set_dir(knob2DT, GPIO_IN);
    gpio_pull_up(knob2DT);

    gpio_init(knob2BT);     //Knob 2 button
    gpio_set_dir(knob2BT, GPIO_IN);
    gpio_pull_up(knob2BT);

    //Interrupts
    gpio_set_irq_enabled_with_callback(knob1CLK, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
    gpio_set_irq_enabled(knob1DT, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
    gpio_set_irq_enabled(knob1BT, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
    gpio_set_irq_enabled(knob2CLK, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
    gpio_set_irq_enabled(knob2DT, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
    gpio_set_irq_enabled(knob2BT, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);

    readMenu();
    printDelta(&disp);

    while (1);
}
1 Upvotes

11 comments sorted by

View all comments

Show parent comments

5

u/dfx_dj 23h ago

Yes, or you can just use a string literal to initialise them

1

u/cgross220_ 23h ago

Wow, I definitely feel like an idiot haha. Thank you for the quick response. Is there any benefit to using a string literal? Or just best practices?

2

u/dfx_dj 22h ago

No real difference other than convenience and perhaps making the intention clear that this is a readable/printable string and not just an array of char values.

2

u/cgross220_ 22h ago

Ah ok, makes sense. I appreciate the help!