bitBanging using 745C595N to a 7Seg Display

Hello,
I'm trying to light up a part of the 7 seg display using bit-banging, currently just trying to light up the DP light on and off. It has to be done in a bare metal fashion. Unfortunately, I'm not getting any output whats so ever, I test parts of my code using some LEDs just to check the concept works but I'm fairly sure I have done the bit-banging part wrong.

Any suggestions would be much appreciated.

This is what I've written for that part.

void BitBang(const char b){
  tglLATCH(false);
  int mask = 0x80;
  for(int i = 0; i < 8; i++){
    if(b && mask != 0){
      tglDATA(true);
    }
    else{
      tglDATA(false);
    }
    tglCLOCK(true);
    b<<1;
    tglCLOCK(false);
  }
  tglLATCH(true);
}

This is my full code.

unsigned long lastDTime = 0;
#define HMDelay 320

const byte characters[] = {
  0b00111111,// 0
  0b00000110,// 1
  0b01011011,// 2
  0b01001111,// 3
  0b01100110,// 4
  0b01101101,// 5
  0b01111101,// 6
  0b00000111,// 7
  0b01111111,// 8
  0b01100111,// 9
  0b01110111,// A
  0b01111100,// B
  0b00111001,// C
  0b01011110,// D
  0b01111001,// E
  0b01110001,// F
  0b10001000 // DP
};

void tglCLOCK(bool a) {
  DDRB =  B01000000;
      if(a == true){
    PORTB = B01000000;
  }
  else if(a == false){
  PORTB = B00000000;
  }
}
void tglLATCH(bool a) {
  DDRB = B10000000;
    if(a == true){
    PORTB = B10000000;
  }
  else if(a == false){
  PORTB = B00000000;
  }
}
void tglDATA(bool a) {
  DDRB =  B00000100;
  if(a == true){
    PORTB = B00000100;
  }
  else if(a == false){
  PORTB = B00000000;
  }
}

/*
void shiftingBits(byte B) {
  for (int i = 0; i < 8; i ++) {
    if ((B >> i) & (0x01)) {
      tglDATA();
      tglCLOCK();
    }
    tglLATCH();
  }
}
*/

void BitBang(const char b){
  tglLATCH(false);
  int mask = 0x80;
  for(int i = 0; i < 8; i++){
    if(b && mask != 0){
      tglDATA(true);
    }
    else{
      tglDATA(false);
    }
    tglCLOCK(true);
    b<<1;
    tglCLOCK(false);
  }
  tglLATCH(true);
}

void HeartBeat() {
  lastDTime = millis();
  if ((millis() - lastDTime) > HMDelay) {
    BitBang(characters[16]);
  }
}

void setup() {
  DDRB = B00000001;
  tglCLOCK(false);
  tglLATCH(false);
}

void loop() {
  HeartBeat();
  tglLATCH(true);
}

Thank you very much for looking!

Please post a wiring diagram. Can you get anything to light up, without using the problematic "bit bang" code?

When you say:
PORTB = B00000000;
That turns off ALL of the pins on PORTB.

To turn on Pin 8 (PORTB pin PB0 on an UNO) you should use:
PORTB |= _BV(PB0);
(Note: That's quivalent to PORTB |= 0b0000001;)

To turn off Pin 8 (PORTB pin PB0 on an UNO) you should use:
PORTB &= ~_BV(PB0);
(Note: That's quivalent to PORTB &= 0b11111110;)

What are you doing here ?

So the PB0 = pin 8 or bit 0 from the right side and PB7 would be bit 7 from the right side?
Thanks for the help!

Yeah the wiring is correct as far as I know, I've used it for a previous assignment which was very similar and everything worked fine.

Honestly, I'm not exactly sure, We were given a sort of a guide and I figured that's what they meant by it.

image

If you want bitwise AND then use:

if(b & mask != 0){

Thank you for the advice!

Would this be the correct way to do it, Ive moved the setting of output/input into the setup instead since it doesn't change.

void tglCLOCK(bool a) {
  if (a == true) {
    //PORTB = B01000000;
    PORTB |= _BV(PB4);
  }
  else if (a == false) {
    //PORTB = B00000000;
    PORTB &= ~_BV(PB4);
  }
}
void tglLATCH(bool a) {
  if (a == true) {
    //PORTB = B10000000;
    PORTB |= _BV(PB5);
  }
  else if (a == false) {
    //PORTB = B00000000;
    PORTB &= ~_BV(PB5);
  }
}
void tglDATA(bool a) {
  if (a == true) {
    //PORTB = B00000100;
    PORTB |= _BV(PB0);
  }
  else if (a == false) {
    //PORTB = B00000000;
    PORTB &= ~_BV(PB0);
  }
}

So, there is some case where 'a' is both true and false? No. So if it's not true, why test it to see if it's false?

The read the display with the human eye, it does not need to be microsecond-fast. You can start with normal digitalWrite().
When that is working, then you can (as an educational exercise) convert it piece by piece to direct register addressing.

1 Like

Yeah, I realized that doesn't make sense, and its not really necessary. Changed it to this.

#define CLOCK_HI PORTB |= _BV(PB4)
#define CLOCK_LW PORTB &= ~_BV(PB4)

and this,

void tglCLOCK() {
  CLOCK_HI;
  CLOCK_LW;
}

I believe this should work, right?

Yeah, I believe that would be the best way to do it. Thank you for suggesting that!

This is a Wokwi simulation that I made for you: https://wokwi.com/arduino/projects/315912715095769664.
I hope that I got the connections right :thinking:

Warning: That is the sketch that is not working !
When you show a working sketch, then we can test it in the simulation.

If you log in at Wokwi, then you can "Save a copy" and it will be stored as your own project. Then you can open it from your projects and change things and save them.

Wokwi has a "Logic Analyzer". You can add that to the circuit (via the + button) and record the signals. The signals can be analyzed on your computer in PulseView.

The commented-out part is Bit 6. PB4 is bit 4.

Yeah, after some reading I realized I was counting them wrong, it was supposed to be bit 4. Thanks for the help!

Thank you so much, that is awesome. You really didn't have to put so much work into this but thank you for that, really appreciated!!

I did what you suggested and just started with a normal approach and then changed everything into bare metal and the bit-banging works fine now. Just trying to figure out how to change a bit from one of the bytes (16) in the characters array to on and off without affecting the rest of the bits/keeping them how they were.

The new code,

#define DATA_HI PORTB |= _BV(PB0)
#define DATA_LW PORTB &= ~_BV(PB0)
#define CLOCK_HI PORTB |= _BV(PB4)
#define CLOCK_LW PORTB &= ~_BV(PB4)
#define LATCH_HI PORTB |= _BV(PB5)
#define LATCH_LW PORTB &= ~_BV(PB5)
//#define DP_ON characters[16] |= (1 << 1);
//#define DP_OFF characters[16] &= ~_BV(PB0)

unsigned long lastDelayTime = 0;
#define HMDelay 320
const byte characters[] = {
  0b11111100,//0
  0b01100000,//1
  0b11011010,//2
  0b11110010,//3
  0b01100110,//4
  0b10110110,//5
  0b10111110,//6
  0b11100000,//7
  0b11111110,//8
  0b11100110,//9
  0b11101110,//A 10
  0b00111110,//B 11
  0b10011100,//C 12
  0b01111010,//D 13
  0b10011110,//E 14
  0b10001110,//F 15
  0b00000001 //DP 16
};

void tglCLOCK() {
  CLOCK_HI;
  CLOCK_LW;
}
void tglLATCH() {
  LATCH_HI;
  LATCH_LW;
}

void shiftByteMSF (unsigned char b){
  for (int i = 0 ; i < 8 ; i++){
    if ((b >> i) & (0x01)){
      DATA_HI;
    }
    else{
      DATA_LW;
    }
    tglCLOCK();
  }
  tglLATCH(); // Data finally submitted
}

void HeartBeat() {
  unsigned long currentTime = millis();
  if ((currentTime - lastDelayTime) >= HMDelay) {
    shiftByteMSF(characters[16]);
    lastDelayTime = currentTime;
  }
}

void setup() {
  DDRB = B00110001; //Toggle DATA, LATCH and CLOCK pins to OUTPUT.
}
void loop() {
shiftByteMSF(characters[16]); // BITBANGING WORKING! 
 //HeartBeat();

}

Again, thank you for the help!

With the text editor?