328pb Stuck on 2x2 shift register (74hc595) and c++ (control 39 butons, 23 leds, 8 7segment displays)

Hi, i have a machines electronics card, shematic and software. I'm new to company and don't used shift registers and c++.
The engineer who designed these left the company and the job was left to me. I worked day and night, but the card did not work as expected. The engineer before me was also a good engineer and built a lot of machines for the company. But we cannot reach him.
Purpose and problems;
1-) When the electronic card is powered on, the DS305 indicator should read 15. It currently says 19.
2-) S232 and S224 will be used to increase or decrease the value written in DS305 by one. Now when you press s224 it becomes 18, when you press s224 it becomes 17, when you press s3 it becomes 18, when you press s224 it becomes 19, when you press it it becomes 28.
3-) When the electronic card is powered on, no segments light up. This is OK.
4-) When the electronic card is powered on, D421-422-423 and DS412-413-414 are off, all other LEDs are on.
5-) When the buttons on the far right are pressed, the 7-segment on that line should be opened and the power and speed values should be written in the segment with the buttons on the left. For example, when I press S208, all LEDs except D412-413-414 are on, but no segment is on.

D2 led work fine and i can change time it works as i command.

The combinations change a lot when you press the buttons. There are many more problems, but maybe someone with experience will understand the problem, I think the shift registers are working incorrectly. I suspect ui.ino 19. line. Because code was not compiling when i start, then i added timer and arx container lib. code was arx::map<.... and i added arx::stdx::map<...

I am adding the schematics and software. ;
328pb.ino

#include <arduino-timer.h>
#include <ArxContainer.h>

#define TOOL_STATE_OFF 0
#define TOOL_STATE_ON 1
#define TOOL_STATE_RUNNING 2

#define RED 0
#define GREEN 1

//milisecond resolution timer
Timer<10, millis> timer;
//microsecond resolution timer, used for ui and io
Timer<2, micros> himer;

void setup() {
  io_setup();
  ui_setup();
  buzzer_setup();
  led_setup();
  timer_setup();

  brush_setup();
  drdc_setup();
  hammer_setup();
  vacuum_setup();
  hifreq_setup();
  sonic_setup();

  buzzer_bep();
}

void loop() {
  himer.tick<void>();
  timer.tick<void>();
}

void tool_stop_all() {
  brush_stop();
  drdc_stop();
  hammer_stop();
  vacuum_stop();
  hifreq_stop();
  sonic_stop();
}

void tool_off_all() {
  brush_off();
  drdc_off();
  hammer_off();
  vacuum_off();
  hifreq_off();
  sonic_off();
}

io.ino

#define PIN_SRIO_OE PORTC5
#define PIN_SRIO_CLR PORTE1
#define PIN_SRIO_LOAD PORTE0
#define PIN_SRIO_DATA PORTE3
#define PIN_SRIO_CLK PORTE2


uint16_t io_data;
uint8_t io_elapsed;
uint8_t io_duty_map[16];

void io_setup() {
  //initial io data,
  io_data = 0b0000000000000000U;
  io_elapsed = 0U;
  memset(&io_duty_map[0], 0, 16 * sizeof(uint8_t));

  //shift register control lines outputs
  DDRC |= _BV(PIN_SRIO_OE);
  DDRE |= _BV(PIN_SRIO_CLR) | _BV(PIN_SRIO_LOAD) | _BV(PIN_SRIO_DATA) | _BV(PIN_SRIO_CLK);

  //disable shift register
  PORTC |= _BV(PIN_SRIO_OE);
  //initial control signals
  PORTE &= ~_BV(PIN_SRIO_CLR) & ~_BV(PIN_SRIO_LOAD) & ~_BV(PIN_SRIO_DATA) & ~_BV(PIN_SRIO_CLK);
  //clear SR
  PORTE |= _BV(PIN_SRIO_CLR);
  PORTE &= ~_BV(PIN_SRIO_CLR);
  //shift out data, all zeros
  PORTE &= ~_BV(PIN_SRIO_DATA);
  for (uint8_t i = 0; i < 16; i++) {
    PORTE |= _BV(PIN_SRIO_CLK);
    PORTE &= ~_BV(PIN_SRIO_CLK);
  }
  //load
  PORTE |= _BV(PIN_SRIO_LOAD);
  PORTE &= ~_BV(PIN_SRIO_LOAD);
  //enable shift register
  PORTC &= ~_BV(PIN_SRIO_OE);

  himer.every(1000, __io_shift);
}

bool __io_shift(void*) {
  uint8_t i = 16U, val;
  uint16_t data = io_data;
  //clear SR
  PORTE |= _BV(PIN_SRIO_CLR);
  PORTE &= ~_BV(PIN_SRIO_CLR);
  //shift out msb first
  while (i--) {
    if (io_duty_map[i] != 0U) {
      val = io_elapsed < io_duty_map[i];
    } else {
      val = (data & 0x8000U) == 0x8000U;
    }
    //set the bit
    if (val) PORTE |= _BV(PIN_SRIO_DATA);
    else PORTE &= ~_BV(PIN_SRIO_DATA);
    //clk out
    PORTE |= _BV(PIN_SRIO_CLK);
    PORTE &= ~_BV(PIN_SRIO_CLK);
    data = data << 1;
  }
  //load
  PORTE |= _BV(PIN_SRIO_LOAD);
  PORTE &= ~_BV(PIN_SRIO_LOAD);
  io_elapsed = (io_elapsed + 1) % 20U;
  return true;
}

void io_digitalWrite(uint8_t pin, uint8_t state) {
  io_duty_map[pin] = 0;  //cancle pwm
  if (state) {
    io_data |= 0x0001U << pin;
  } else {
    io_data &= ~(0x0001U << pin);
  }
}

uint8_t io_digitalRead(uint8_t pin) {
  return io_data & (0x0001U << pin);
}

//val 0-7
void io_analogWrite(uint8_t val) {
  //only first tree bits is meaningfull A0,A1,A2
  bitWrite(io_data, 6, bitRead(val, 0));
  bitWrite(io_data, 5, bitRead(val, 1));
  bitWrite(io_data, 4, bitRead(val, 2));
}

//pwm 0-100; @50Hz
void io_pwm(uint8_t pin, uint8_t duty) {
  io_duty_map[pin] = duty / 5;
}

iu.ino

#define PIN_SRUI_OE PORTC5
#define PIN_SRUI_CLR PORTB3
#define PIN_SRUI_LOAD PORTB2
#define PIN_SRUI_DATA PORTB5
#define PIN_SRUI_CLK PORTB4

#define PIN_KBDR0 PINC0
#define PIN_KBDR1 PINC1
#define PIN_KBDR2 PINC2
#define PIN_KBDR3 PINC3
#define PIN_KBDR4 PINC4

uint8_t ui_cur_seg;
/////////////////////////// 0  , 1   , 2   , 3    ,4,    ,5    ,6    ,7   ,8     ,9//
const uint8_t bcd_mat[] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10 };
const uint8_t bcd_mal[] = { 0xFF, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0xFF };
uint8_t ui_7seg_buffer[14];
uint8_t ui_key_code, ui_last_key_code;
**arx::stdx::map<uint8_t, void (*)(void), 20> ui_key_map;**
**//std::map<uint8_t, void (*)(void), 20> ui_key_map;**
/*

*/
void ui_setup() {
  ui_cur_seg = 0;
  ui_key_code = ui_last_key_code = 0xFFU;
  memset(&ui_7seg_buffer[0], 0xFFU, 14 * sizeof(uint8_t));

  //shift register control lines outputs
  DDRC |= _BV(PIN_SRUI_OE);
  DDRB |= _BV(PIN_SRUI_CLR) | _BV(PIN_SRUI_LOAD) | _BV(PIN_SRUI_DATA) | _BV(PIN_SRUI_CLK);



  //keyboard 5 rows input pullups
  MCUCR &= ~_BV(PUD);  //pull ups
  PORTC |= _BV(PIN_KBDR0) | _BV(PIN_KBDR1) | _BV(PIN_KBDR2) | _BV(PIN_KBDR3);
  DDRC &= ~_BV(PIN_KBDR0) & ~_BV(PIN_KBDR1) & ~_BV(PIN_KBDR2) & ~_BV(PIN_KBDR3);

  //seven seg driver pins outputs
  DDRD = 0xFFU;
  PORTD = 0xFF;

  //disable shift register
  PORTC |= _BV(PIN_SRUI_OE);

  //initial control signals
  PORTB &= ~_BV(PIN_SRUI_CLR) & ~_BV(PIN_SRUI_LOAD) & ~_BV(PIN_SRUI_DATA) & ~_BV(PIN_SRUI_CLK);
  //clear SR
  PORTB |= _BV(PIN_SRUI_CLR);
  PORTB &= ~_BV(PIN_SRUI_CLR);
  //shift out all one's
  PORTB |= _BV(PIN_SRUI_DATA);
  for (uint8_t i = 0; i < 16; i++) {
    //clk out
    PORTB |= _BV(PIN_SRUI_CLK);
    PORTB &= ~_BV(PIN_SRUI_CLK);
  }
  //load
  PORTB |= _BV(PIN_SRUI_LOAD);
  PORTB &= ~_BV(PIN_SRUI_LOAD);
  //enable shift register
  PORTC &= ~_BV(PIN_SRUI_OE);

  himer.every(1000, __ui_scan);
}

/*
 * walks thru all the segments
*/
static bool __ui_scan(void*) {
  //first read-in the key code from previous cycle
  //this way, it allows the signals settle out
  //keypad colums are seg0 to seg7
  if ((ui_cur_seg > 0) && (ui_cur_seg < 9)) {
    uint8_t key_row = PINC & 0x1FU;  //filter row pins
    if (key_row != 0x1FU) {
      //if any key pressed in current column
      //key code structure: MSB 3 bits -> column number, LSB 5 bits -> row number
      ui_key_code = (((ui_cur_seg - 1) & 0x07U) << 5) | key_row;  //construct key code
    }
  }

  if (ui_cur_seg == 0) {
    //handle key presses, onece every 14 segments scanned
    //hence on multiple presses, last key counts
    if (ui_key_code == 0xFFU) {
      //key released
      ui_last_key_code = 0xFFU;
    } else if (ui_key_code != ui_last_key_code) {
      //new key pressed
      ui_last_key_code = ui_key_code;
      //buzzer_beep();
      ui_handle_key(ui_key_code);
    }
    ui_key_code = 0xFFU;
    //clear SR
    PORTB &= ~_BV(PIN_SRUI_CLR);
    PORTB |= _BV(PIN_SRUI_CLR);
    //scan from beginning, put a zero into shift register
    PORTB &= ~_BV(PIN_SRUI_DATA);
  }
  //shift out, data should be 1 except when cur_seg = 0;
  //1111111111111110, shifted in repeadetly, zero walks from LSB to MSB
  PORTB |= _BV(PIN_SRUI_CLK);
  PORTB &= ~_BV(PIN_SRUI_CLK);
  //make sure data line is high for the next cycle
  PORTB |= _BV(PIN_SRUI_DATA);
  //before loading register. turn off all leds,
  //otherwise it might bleed to next segment
  PORTD = 0xFFU;
  //load the register
  PORTB |= _BV(PIN_SRUI_LOAD);
  PORTB &= ~_BV(PIN_SRUI_LOAD);
  //light up the new leds
  PORTD = ui_7seg_buffer[ui_cur_seg];
  //goto next segment in the next cycle
  ui_cur_seg = (ui_cur_seg + 1) % 14;
  return true;
}

/*
 * writes 1-8 to a 7segment display, 0 and 9 turns off the display
 * this is for power level singel digit 7segment sdisplays
*/
void ui_7segWrite(uint8_t seg, uint8_t lvl, uint8_t dp) {
  ui_7seg_buffer[seg] = bcd_mal[lvl] | (dp ? 0x00U : 0x80U);
}

/*
 * write two digit time value
*/
void ui_7segWriteTime(uint8_t min, uint8_t dp) {
  uint8_t bcd0 = 0xFFU;
  uint8_t bcd1 = 0xFFU;
  bcd1 = min / 10 ? bcd_mat[min / 10] : 0xFFU; //turn off if zero
  bcd0 = bcd_mat[min - ((min / 10) * 10)];// do not turn off if zero
  ui_7seg_buffer[7] = bcd1 | 0x80U; //filter dp
  ui_7seg_buffer[8] = bcd0 | (dp ? 0x00 : 0x80U); //place dp if active
}

/*
 * contols leds,
 * leds numbered from 0-23
 * 0-7  : only red, color parameter ignored, seg9
 * 8-15 : red/green, red is segment 10, green is segment 11
 * 16-23 : red green, red is segment 12, green is segment 13
 */
void ui_ledWrite(uint8_t led, uint8_t val, uint8_t color) {
  uint8_t seg_on, seg, seg_off, dat;
  if (led < 8) {
    seg = seg_off = 9;
  } else if (led < 16) {
    seg = (color == RED) ? 10 : 11;
    seg_off = (color == RED) ? 11 : 10;
    led -= 8;
  } else if (led < 24) {
    seg = (color == RED) ? 12 : 13;
    seg_off = (color == RED) ? 13 : 12;
    led -= 16;
  }
  //turn off other color
  dat = ui_7seg_buffer[seg_off] | (0x01U << led);
  ui_7seg_buffer[seg_off] = dat;
  //light up this color, depending on new value
  dat = val ? ui_7seg_buffer[seg] & ~(0x01U << led) : ui_7seg_buffer[seg] | (0x01U << led);
  ui_7seg_buffer[seg] = dat;
}

/*
 * registes a callback function as a key code handler
*/
void ui_registerKey(uint8_t key, void (*handler)(void)) {
  ui_key_map.insert(key, handler);
}

/*
 * calls the handler callback function when key pressed
*/
static void ui_handle_key(uint8_t key) {
  if (ui_key_map.find(key) != ui_key_map.end()) {
    ui_key_map[key]();
  }
}

ui 02 - Kopya.pdf (204.4 KB)

Hi
Are you expect that somebody will try to figure out all this problems that to do your job for you?
The size and complexity of the work task clearly exceeds what can be expected for free help on the forum. I think this should be moved to the paid consultation category

i'm just honest, i could cover this on another subject. i not worrying about my job, i only wonder why it makes this. and there is just one problem shift registers not working properly.

Your code does not compile. E.g. the function buzzer_setup() is nowhere to be found. There might be a lot of other functions that are missing, I did not check.

They are below, my bad apologies.
timer

#define KEY_TIMER_DEC 0b00001111
#define KEY_TIMER_INC 0b00010111

#define TIMER_DEFAULT_TIME (15 * 60 - 1)
#define TIMER_STATE_STOPPED 0
#define TIMER_STATE_RUNNING 1
uint16_t remaining_time;
uint8_t timer_state;
uint8_t timer_blink;

void timer_setup() {
  ui_7segWriteTime(TIMER_DEFAULT_TIME / 60 + 1, LOW);
  remaining_time = TIMER_DEFAULT_TIME;
  timer_state = TIMER_STATE_STOPPED;
  timer_blink = LOW;

  ui_registerKey(KEY_TIMER_DEC, timer_dec);
  ui_registerKey(KEY_TIMER_INC, timer_inc);

  timer.every(1000, __timer_timeout);
  timer.every(250, [](void*) -> bool {
    //update display every 250ms
    timer_blink = (timer_state == TIMER_STATE_RUNNING) ? !timer_blink : LOW;
    ui_7segWriteTime((remaining_time > 99) ? remaining_time / 60 + 1 : remaining_time, timer_blink);
    return true;
  });
}

void timer_start() {
  timer_state = TIMER_STATE_RUNNING;
}

void timer_stop() {
  timer_state = TIMER_STATE_STOPPED;
}

void timer_reset() {
  timer_state = TIMER_STATE_STOPPED;
  remaining_time = TIMER_DEFAULT_TIME;
}

void timer_inc(void) {
  remaining_time = (remaining_time + 60);
  if (remaining_time > 99 * 60 - 1) {
    remaining_time = 99 * 60 - 1;
    buzzer_beep();
  } else buzzer_bep();
}

void timer_dec(void) {
  if (remaining_time > 60) {
    remaining_time -= 60;
    buzzer_bep();
  } else {
    remaining_time = 0;
    buzzer_beep();
  }
}

bool __timer_timeout(void*) {

  switch (timer_state) {
    case TIMER_STATE_RUNNING:
      if (remaining_time > 0) {
        remaining_time--;
      }
      break;
    case TIMER_STATE_STOPPED:
      break;
  }
  if (remaining_time == 0) {
    //time expired, stop all running tools
    buzzer_beep();
    timer_state = TIMER_STATE_STOPPED;
    remaining_time = TIMER_DEFAULT_TIME;
    tool_stop_all();
  } else if (remaining_time < 10) {
    //notify user last 10 seconds
    buzzer_bep();
  }
  return true;
}

buzzer

#define PIN_BUZZER PORTB1

void buzzer_setup() {
  DDRB |= _BV(PIN_BUZZER); // pin buzzer çıkış
  PORTB |= _BV(PIN_BUZZER); // pin buzzer 1
}

void buzzer_bep() {
  PORTB &= ~_BV(PIN_BUZZER);
  timer.in(100, [](void*) -> bool {
    PORTB |= _BV(PIN_BUZZER);
    return false;
  });
}

void buzzer_beep(){
  PORTB &= ~_BV(PIN_BUZZER);
  timer.in(500, [](void*) -> bool {
    PORTB |= _BV(PIN_BUZZER);
    return false;
  });  
}

Led (just pin_led d2 on shematics, please ignore pin_io_led because not on pcb)

#define PIN_LED     PORTB0
#define PIN_IO_LED  1 /*C2*/

void led_setup() {
  DDRB |= _BV(PIN_LED);
  PORTB |= _BV(PIN_LED);
  io_digitalWrite(PIN_IO_LED, HIGH);

  timer.every(500, [](void*) -> bool {
    PINB |= _BV(PIN_LED);//toggle
    io_digitalWrite(PIN_IO_LED, !io_digitalRead(PIN_IO_LED));
    return true;
  });
}

Brush
This is tool like drdc sonic etc. please ignore the other tools they are same

#define PIN_BRUSH 10 /*B1*/
#define SEG_BRUSH 3
#define LED_BRUSH 4
#define KEY_BRUSH_ON  0b10011110
#define KEY_BRUSH_DEC 0b10001111
#define KEY_BRUSH_INC 0b10010111

uint8_t brush_state;
uint8_t brush_lvl;

void brush_setup() {
  io_digitalWrite(PIN_BRUSH, LOW);
  io_analogWrite(0);
  ui_7segWrite(SEG_BRUSH, 0, 0);
  ui_ledWrite(LED_BRUSH, LOW, RED);
  ui_registerKey(KEY_BRUSH_ON, brush_toggle);
  ui_registerKey(KEY_BRUSH_DEC, brush_level_dec);
  ui_registerKey(KEY_BRUSH_INC, brush_level_inc);
  brush_state = TOOL_STATE_OFF;
  brush_lvl = 0;
}

void brush_toggle(void) {

  switch (brush_state) {
    case TOOL_STATE_OFF:
      tool_off_all();
      ui_7segWrite(SEG_BRUSH, brush_lvl + 1, 0);
      ui_ledWrite(LED_BRUSH, HIGH, RED);
      io_digitalWrite(PIN_BRUSH, LOW);
      io_analogWrite(0x07);
      brush_state = TOOL_STATE_ON;
      timer_reset();
      buzzer_bep();
      break;
    case TOOL_STATE_ON:
      ui_7segWrite(SEG_BRUSH, brush_lvl + 1, 1);
      ui_ledWrite(LED_BRUSH, HIGH, RED);
      io_digitalWrite(PIN_BRUSH, HIGH);
      io_analogWrite(0x07-brush_lvl);
      brush_state = TOOL_STATE_RUNNING;
      timer_start();
      buzzer_bep();
      break;
    case TOOL_STATE_RUNNING:
      ui_7segWrite(SEG_BRUSH, brush_lvl + 1, 0);
      ui_ledWrite(LED_BRUSH, HIGH, RED);
      io_digitalWrite(PIN_BRUSH, LOW);
      io_analogWrite(0x07);
      brush_state = TOOL_STATE_ON;
      timer_stop();
      buzzer_bep();
      break;
    default:
      break;
  }
}

void brush_stop() {
  if (brush_state == TOOL_STATE_RUNNING) {
    ui_7segWrite(SEG_BRUSH, brush_lvl + 1, 0);
    ui_ledWrite(LED_BRUSH, HIGH, RED);
    io_digitalWrite(PIN_BRUSH, LOW);
    io_analogWrite(0x07);
    brush_state = TOOL_STATE_ON;
  }
}

void brush_off() {
  ui_7segWrite(SEG_BRUSH, 0, 0);
  ui_ledWrite(LED_BRUSH, LOW, RED);
  io_digitalWrite(PIN_BRUSH, LOW);
  io_analogWrite(0);
  timer_reset();
  brush_state = TOOL_STATE_OFF;
}

void brush_level_dec() {
  if ((brush_lvl > 0) && (brush_state != TOOL_STATE_OFF)) {
    brush_lvl--;
    ui_7segWrite(SEG_BRUSH, brush_lvl + 1, brush_state == TOOL_STATE_RUNNING);
    if(brush_state==TOOL_STATE_RUNNING) io_analogWrite(0x07-brush_lvl);
    buzzer_bep();
  } else {
    buzzer_beep();
  }
}

void brush_level_inc() {
  if ((brush_lvl < 7) && (brush_state != TOOL_STATE_OFF)) {
    brush_lvl++;
    ui_7segWrite(SEG_BRUSH, brush_lvl + 1, brush_state == TOOL_STATE_RUNNING);
    if(brush_state==TOOL_STATE_RUNNING)  io_analogWrite(0x07-brush_lvl);
    buzzer_bep();
  } else {
    buzzer_beep();
  }
}

I do not understand that. To be able to have a look at your project, someone that is interested in helping needs every single function that is used somewhere in your code.

That's definite crap that never compiles.
The same for the copy named buzzer_beep().

I think that you are cheating. Not worth to spend any more time on your problem.

This snippet compiles fine for me (on Arduino Uno)

But in general the project contains a lot of intentionally obfuscated code, so I think whoever will fix this code can ask for a very good fee :slight_smile:

A void function returning a value is nonsense. Too bad if the compiler only flags it as a warning.

I don't think that the boid function returns anything. There is something called inside that void function that retuns false. It's however far (and I mean FAR) outside my knowledge.

Some form of callback?

Was he made redundant (laid off)? Replaced by someone younger and cheaper? I would not want to be reached either.

1 Like

it is lambda function

1 Like

Even no warning in that case. This void is not a return type, it is a parameter.
The return type of the function is bool.

The lambda syntax:

[ capture clause ] (parameters) -> return-type  
{   
   definition of method   
} 

i'm out.

Kindly I have no intention of offending or making fun of you or anyone else who takes the time. I really appreciated you all, thanks a lot guys.

@sterretje tools are machine's actuators. they are works fine, Since the codes I posted were already too long, I did not post them in order not to waste your time, but when I put them in comments, the problems I wrote above continue. I just threw the brush code as an example. Please don't linger buzzer.

It's my fault to upset and confuse you all, apoligies.

Friends, I don't want to take up too much of your time anyway. I'm very close to being lynched :slight_smile: Can you answer just two of my questions?

1-) I have never worked with Shift registars before. I'm not an expert. Could you please check if there is any problem or illogicality in the codes related to the shift register? For example, I changed arx::map< to arx::stdx::map< in line 19 in ui.ino because I could not compile it. Then I added the arxcontainer library, but I didn't find the code included this in the first place.

2-) There was a topic like this on a site I came across while doing research: [ATmega328PB Arduino Pin Mappings - Development Platforms - PlatformIO Community](https://It is here) Could these confusions be due to such a problem? I using mini core and some people in another topics said that there is no problem with mini core but please give your opinion.

I didn't work with arxcontainer library before, but as far I see it used to map a control codes to handler functions or callbacks. Despite the fact that the buttons are controlled by shift registers, the container library code itself has nothing to do with shift registers.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.