scanning 25 bcd switches - wrong reading?

I am missing something stupid here, I am using 3 cascaded CD4017 decade counters to feed ( up to ) 25 bcd switches.

(I am posting here as it is multiplexing )

The 4 outputs of the switches are fed via diodes to 4 data inputs ( SW0 - 3 ) of the micro, each input has a pull down resistor.

The following code is supposed to send the data from the switches via virtualwire , but with no connections to the data inputs - just the pull down resistors I get all 1000 when the ISR is triggered. i.e :-

TX setup
Sleep
data for switchbank 0 = 1000
data for switchbank 1 = 1000
blah blah
data for switchbank 18 = 1000
data for switchbank 19 = 1000
Sleep

actually I think its trying to tell me something, its 4 am and I should have some rest :cold_sweat:
can anyone see my blonde moment here?

Incidentally, with another chip for the scanning that has zero going outputs to the switches, I inverted the data with the commented out line
// address |= digitalRead(SW*) << i; and this gives 1111 as expected...............*
my code is
```
*//  FIRST TRY SCANNING USING 4017

#include <VirtualWire.h>    // Wireless transmitter/receiver library
#include <avr/sleep.h>      // powerdown library
#include <avr/interrupt.h>  // interrupts library

// ***********************************************************************

uint8_t SW[4]; // assign four data pins from bcd switches

int SW0 = 3;               // bits to read in unique address - LSB
int SW1 = 4;               // bits to read in unique address
int SW2 = 5;               // bits to read in unique address
int SW3 = 6;               // bits to read in unique address - MSB

int address = 0;          
int add0;
int add1;
int add2;
int add3;

int reset = 7;
int clock = 8;

int dpin0 = 0;              // apparently redefined by Serial as Serial Monitor works
int dpin1 = 1;              // apparently redefined by Serial as Serial Monitor works
int pin2 = 2;               // Int0 interrupt pin

// create an array to store data to be sent out
// ***********************************************************************
int switchbanks = 19; // CHANGE TO NUMBER OF SWITCHES max 25
char msg [20]; // includes msg 0  which is PIN number from dip switches
// ***********************************************************************

// *  Name:        pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
 /* This brings us back from sleep. */
}

//***************************************************
// *  Name:        enterSleep
void enterSleep()
{
 /* Setup pin2 as an interrupt and attach handler. */
 attachInterrupt(0, pin2Interrupt, LOW);
 delay(50); // need this?

set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // setting up for sleep ...
 sleep_enable();                       // setting up for sleep ...
 ADCSRA &= ~(1 << ADEN);
 PRR = 0xFF;
 sleep_mode();                         // now goes to Sleep and waits for the interrupt
 /* The program will continue from here after the interrupt. /
 
 detachInterrupt(0);                 //disable interrupts while we get ready to read the keypad
 // Power up functions
 PRR = 0x00;
 /
First thing to do is disable sleep. */
 sleep_disable();
}

// ***********************************************************************

void setup()
{

Serial.begin(9600);

pinMode(pin2, INPUT);                 // our sleep interrupt pin
 digitalWrite(pin2, HIGH);  //  sets pull up res

pinMode ( reset, OUTPUT );  //  resets the external cd4017 counters to 0
 digitalWrite(reset, HIGH);

pinMode ( clock, OUTPUT );  // starts the clock to the CD4017s to zero so first out = PIN number
 digitalWrite(clock, LOW);

//***************************************************************************

//  all data inputs SW0-3 have pull down 22k resistors
 pinMode(SW0, INPUT); // LSB of remote Address
 byte add0 = 0;
 pinMode(SW1, INPUT); // LSB+1
 byte add1= 0;
 pinMode(SW2, INPUT);  // LSB+2
 byte add2 = 0;
 pinMode(SW3, INPUT);  // MSB of address
  byte add3 = 0;

// *************************************************************************
 Serial.begin(9600);              
 Serial.println("TX setup");              // for debug only

// ***********************************************************************t
 // Initialise the IO and ISR for VirtualWire

vw_set_ptt_pin(10); //  should be set as default ?
 vw_setup(4000);                      // Bits per sec

}                                            // end of void Setup()

// *******************************************************************************************

void loop()
{
digitalWrite(reset, HIGH);

Serial.println("Sleep");               // for debug only
 
 enterSleep();                             // call Sleep function to put us out
 //  THE PROGRAM CONTINUEs FROM HERE after waking up in enterSleep()
 
digitalWrite(reset, LOW);

scan ();

vw_send((uint8_t *)msg, switchbanks);     // send the character out

vw_wait_tx();                             // Wait until the whole message is gone
 delay (10);
 
}                                             // end of void loop

//********************************************************************************************
void scan ()
{
 for ( int x=0; x<= switchbanks; x++ )
 {
digitalWrite(clock, LOW );

delay ( 50 );
   address=0;
 
   for (uint8_t i = 0; i < 4; i++) {  //    read inputs from bcd switches sequenced by CD4017s
    // address |= digitalRead(SW[i]) << i;
     address = digitalRead(SW[i]) << i;
    }
   digitalWrite(clock, HIGH);  //   advances CD4017s ready for next read
 
   Serial.print("data for switchbank ");  
   Serial.print(x);  
   Serial.print(" =    ");
   Serial.println(address, BIN);
   msg [switchbanks]  = address;

} // end of  for ( int x=2; x<= switchbanks; x==)

}  // end of scan function*
```

John,
Can you post a schematic? Kinda late here, I am not seeing what the diodes are doing for you; somehow providing isolation between the switches? And what are the counters doing?
Bob

This line:
vw_setup(4000); // Bits per sec
I had to use 4000 with my 8MHz Promini running at 3.7V for this to look like 2000 to a 16 MHz Promini at 5V. What speeds are you running?

These lines:
int add0;
int add1;
int add2;
int add3;

You then go on to call them bytes in Setup; you can probably ditch these also.

Hi Robert

here's a link to the basic cct for one CD4017 giving 10 switches. I cant just add the picture as it looks like flikr wants people to go there and look.....

I am using a 16M xtal, and the 4000 baudrate seems to be working fine on all the other projects ( though I slow it to 2400 for the new cheapy transmit / receive pair I have been experimenting with )

Imgur

The 4017 is the wrong chip to use here. You need a signal that has only one pin high with all the others low. I can't see all the code at e moment as my iPad doesn't do the scrolling boxes correctly so I can't be sure but it looks like you are addressing all the switches at once. Put them all to 8, is there any difference?

Hi Mike

The outputs of the 4017 have only one high at a time, each output goes to the common of a bcd thumbwheel switch, the 4 switched outputs of the switches have steering diodes so that they don't short out the 4 data lines.
I have used this circuit extensively, but with a cd4514 chip to feed the switches, but that would need 2 of them to do 32 switches, and take 5 pins of the micro for their bcd address, so I want to try it this way with just 2 pins to control as many switches as I like ( I am keeping it down to 25 switches as thats all that the 4017 can cascade, and the VirtualWire can handle only 27 messages.

I think this bit is wrong:-
address = digitalRead(SW*) << i;*
You have commented out
// address |= digitalRead(SW*) << i;*
Which is closer
I would put:-
address |= ( ( digitalRead(SW*) & 0x1) << i);*

Thanks

I will play around with that and actually hook up a bcd switch to see whats happening.

It seemed to be working with the commented out bit, but of course inverted ( 1111 for all switches off ) but I can always invert it at the RX end anyway.

when I try that I get:-

invalid conversion from 'uint8_t*'to 'uint8_t'

Now I am really confused, when I connect a binary switch, the data stays the same, and also the clock signal doesnt change....

I think I must strip it down to bare bones and try it

OK, with hindsight and a couple of hours sleep I sorted out why I was getting 1000 reading from the switches when scanned - one of the pull-down resistor leads had become open circuit ( read bad soldering by me )

But meantime I still had to go back to the longer "or" ing each bit to get it to work for some reason.

What does " invalid conversion from 'uint8_t*'to 'uint8_t' " mean?

is the * a pointer ? or should I leave that closet closed until I have time to learn more?

The reason I want to only have two micro pins controlling the CD4017 counting, is that I want to later use another 7 pins for a 3x4 keyboard.

I should still have some spare pins for flexibility.

I hope to be able to send in one packet :- the selected decimal number from up to 25 BCD switches, and one of 12 keypresses, plus a security number ( which I call PIN ) all in one 27 byte burst using VirtualWire.

Tonight I am on the receiver decoder, I love VirtualWire, with literally one wire ( the usb plugs do the ground ) I don't have to run the RF link for testing, which is a blessing for all my neighbours who are trying to open the complex gate with their remotes ( also on 433 Mhz )

Sorry I didn't use the # icon and the board scrambled my code, what I put was:-

      address |= ( ( digitalRead(SW[i]) & 0x1) << i);

As posted you were using an array without an in index, hence the pointer error message.

Thanks Mike I will try that.
I have got the receiver listing all 19 switches, plus the PIN nunmber checking, next stage is to build it on veroboard, and shiftout to 19 displays.
I know shiftout is not that fast, but this project is to replace the Holtek chips I was using that took about 2 seconds to update.

OK I finally got the 25 BCD switch scanner going, I am only using 19 switches for this project, see photo testsetup | remote box top left, testing remote jig top righ… | Flickr of the test setup ( and the remote control box with all its filed rectangular holes and half the wiring done.)

I am using an Arduino board ( top right ) with only 3 switches connected to test it. The receiver has only little 3 displays for testing. The 19 chips are TPIC6B595 daisychained shift registers with high current sinking for large common anode LED displays

The 3 x CD4017 decade counters are on the vero/perf board in the middle of the pic, they are cascaded to give up to 25 outputs to the switchbanks.

I am running the RF link at 2400 , and all 19 displays update in less than half a second .

Hopefully I can get it all boxed up by the weekend.

Here's a link to the circuit of the 4017 cascade part of the circuit. I have used simple diode gating to save the AND gate suggested on the datasheet for cascading.

Imgur

I always use BAT85 schottky diodes as they only have about 250mV across them when on, as opposed to 650mV for a 1N4148.

You can repeat the middle chip as many times as you want, getting 8 more outputs for every chip.

I reset the chips with the first reset rather than the last 0 in the datasheet, so have 9 outputs from that chip as well.

This gives 26 outputs, I am using the first ( 0 ) for the PIN number on my system, and the other 25 are available for the BCD switches.

I have everything working fine, the radio range is brilliant, I walked two blocks away and the signal got through 4 houses and about 200 meters before I couldn't walk any more ( a dead end road )

But now and again, when the system has been on a time and I have been randomly checking it, It throws up a wrong display, sometimes all the displays go off and when I checked the Tx, I found that it was just sending zeros.

It is very intermittent though. most times its fine.

Is there anything in the code below that might be filling up some memory or whatever ? I am basically scanning the outputs of the 4017 to read 20 bcd switches, as in the sketch linked in a message above, and transmitting it via VirtualWire....

//  FIRST TRY SCANNING USING 4017  serialprints commented out to speed up

#include <VirtualWire.h>    // Wireless transmitter/receiver library
#include <avr/sleep.h>      // powerdown library
#include <avr/interrupt.h>  // interrupts library

// ***********************************************************************

uint8_t SW[4]; // assign four data pins from bcd switches

int SW0 = 3;               // bits to read in unique address - LSB
int SW1 = 4;               // bits to read in unique address
int SW2 = 5;               // bits to read in unique address
int SW3 = 6;               // bits to read in unique address - MSB
int address = 0;          

int reset = 18;
int clock = 16;
int pwrup = 19;   // for powering cd4017 counters,  left hi in this example

int dpin0 = 0;              // apparently redefined by Serial as Serial Monitor works
int dpin1 = 1;              // apparently redefined by Serial as Serial Monitor works
int pin2 = 2;               // Int0 interrupt pin


// create an array to store data to be sent out
// ***********************************************************************
int switchbanks = 20; // CHANGE TO NUMBER OF SWITCHES +1 for pin dipswitch max 25 
char msg [20]; // includes msg 0  which is PIN number from dip switches
// ***********************************************************************

// *  Name:        pin2Interrupt, "ISR" to run when interrupted in Sleep Mode
void pin2Interrupt()
{
  /* This brings us back from sleep. */
}
//   ********************************************************************                                                                                                                                                                                                                                                                                             66 
void enterSleep()
{
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(50); // need this?

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // setting up for sleep ...
  sleep_enable();                       // setting up for sleep ...
  ADCSRA &= ~(1 << ADEN);
  PRR = 0xFF;
  sleep_mode();                         // now goes to Sleep and waits for the interrupt
  /* The program will continue from here after the interrupt. */
  
  detachInterrupt(0);                 //disable interrupts while we get ready to read the keypad 
  // Power up functions
  PRR = 0x00;

  sleep_disable();   /* First thing to do is disable sleep. */
}

// ***********************************************************************

void setup()
{
  Serial.begin(9600);
 
  pinMode(pin2, INPUT);                 // sleep interrupt pin
  digitalWrite(pin2, HIGH);  //  sets pull up res

  pinMode ( clock, OUTPUT );  // starts the clock to the CD4017s to zero so first out = PIN number
  digitalWrite(clock, LOW); 
  
    pinMode ( reset, OUTPUT );  //  resets the external cd4017 counters to 0
  digitalWrite(reset, HIGH); 

 pinMode ( pwrup, OUTPUT ); 
   digitalWrite(pwrup, HIGH);  //  leave high for testing
 
//***************************************************************************

//  all data inputs SW0-3 have pull down 22k resistors
  pinMode(SW0, INPUT); // LSB of remote Address
  byte add0 = 0; 
  pinMode(SW1, INPUT); // LSB+1
  byte add1= 0;
  pinMode(SW2, INPUT);  // LSB+2
  byte add2 = 0;
  pinMode(SW3, INPUT);  // MSB of address
   byte add3 = 0;

// *************************************************************************
  Serial.begin(9600);	               
  Serial.println("TX setup");              // for debug only 

  // ***********************************************************************t
  // Initialise the IO and ISR for VirtualWire
  
vw_set_tx_pin(9);
  vw_set_ptt_pin(11); //  should be set as default ?
  vw_setup(2400);	                      // Bits per sec 

}                                            // end of void Setup()

// *******************************************************************************************

void loop()
{
digitalWrite(reset, HIGH);
  Serial.println("Sleep");               // for debug only
    enterSleep();                             // call Sleep function to put us out
  //  THE PROGRAM CONTINUEs FROM HERE after waking up in enterSleep()
  
digitalWrite(reset, LOW);

  scan ();

   vw_send((uint8_t *)msg, switchbanks);     // send the character out
   vw_wait_tx();                             // Wait until the whole message is gone
}                                             // end of void loop

//********************************************************************************************
void scan ()
{
    for ( int r=0; r<= switchbanks; r++ ) 
  {
 digitalWrite(clock, LOW );

    address=0;

   add3 = digitalRead(SW3); 
   add3 = add3 << 3;
   add2 = digitalRead(SW2);
   add2 = add2 << 2;
   add1 = digitalRead(SW1);
    add1 = add1 << 1;
   add0 = digitalRead(SW0);
   // now OR it together
   address = address|add3;
   address = address|add2;
   address = address|add1;
   address = address|add0;
  
        msg [r]  = address;

digitalWrite(clock, HIGH );  // move 4017 on to next switch
delay ( 20 );
  } // end of  for ( int x=2; x<= switchbanks; x==) 
}  // end of scan function

I don't see anything unreasonable; but I'm not really a programmer, I just play one on TV 8)

Nice one Bob, like with the remote control ! :slight_smile:

I think I have inadvertently fixed the problem ( I hate to say that too soon but it has been ok for the last 8 hours when I try it )

Just before I posted the code, I forgot I had tried putting in a delay right at the end of the scan function, so that the clock pulse to the cascaded counters had a bit of time at a high level.

Without it the next instruction was to take it low again. I don't know how to work out how long that takes, but the data sheet for the 4017 says the clock pulse at 5v should be minimum 200nS. 3.2 clock pulses @ 16Mhz?

The wiring to the perf board and the 3 chips clock inputs has quite a bit of capacitance too, and there is a 22k resistor feeding each counter for the diode "anding"

I guess it was tripping over its own feet ? I will test it again in the morning, and perhaps reduce the delay to a couple of milliseconds, I can see it is noticeably slower with 20mS x 20 loops. nearly half a second.

Well the remote is still working, but now the decoder has frozen, its getting data from the receiver OK, but not responding, no output scoped on the data out from the micro.

I reset the power and now it works again.....

Can anyone see in my code why it should hang up?

It reads the switch data, compares the PIN numbers ( a security address ) then I sort out the displays that need leading zero blanking, plus I check to see if switches 7 and 8 are set to 0, ( which is how I put the displays into standby ) and then it shiftsout to the 19 shift registers.

I put the flushing bit in when I had the previous problem, I dont think it can do any harm ?

There is a shift register clear pin on the TPIC display chips, but I am not using that ( or the notG pin for blanking ) due to pcb layout simplicity. heres the code:-

//  19 digit receiver
// tile order set by old pcb layout of plugs  HGDABCEFSRQPONMLKJI link across gap data inout
// try flushing SR before sending new lot to get rid of intermittent wrong displays

#include <VirtualWire.h>
#define latchPin 19  // rck
#define clockPin 18  // sck
#define dataPin 16   // ser in
int Rxpin;
int PIN;
int tile [19];

int SW0Pin = 3;               // bits to read in unique address - LSB
int SW1Pin = 4;               // bits to read in unique address
int SW2Pin = 5;               // bits to read in unique address
int SW3Pin = 6;               // bits to read in unique address - MSB
int address = 0;            // bits put together afteer reading switches
int add0;
int add1;
int add2;
int add3;

const byte digitTable [10] = { 
  B01111110, B00110000, B01101101, B01111001, B00110011,      // orig without text switching
  B01011011, B01011111, B01110000, B01111111, B01111011};

const byte blank = B00000000;

void setup()
{

  pinMode(SW0Pin, INPUT); // LSB of remote Address
  digitalWrite(SW0Pin, HIGH);
  byte add0 = 0; // read the value of SW0
  pinMode(SW1Pin, INPUT); // LSB+1
  digitalWrite(SW1Pin, HIGH);
  byte add1= 0;
  pinMode(SW2Pin, INPUT);  // LSB+2
  digitalWrite(SW2Pin, HIGH);
  byte add2 = 0;
  pinMode(SW3Pin, INPUT);  // MSB of address
  digitalWrite(SW3Pin, HIGH);
  byte add3 = 0;

  add3 = !digitalRead(SW3Pin); 
  add3 = add3 << 3;
  add2 = !digitalRead(SW2Pin);
  add2 = add2 << 2;
  add1 = !digitalRead(SW1Pin);
  add1 = add1 << 1;
  add0 = !digitalRead(SW0Pin);
  address = address|add3;
  address = address|add2;
  address = address|add1;
  address = address|add0;

  Rxpin = address;
  Serial.println("Rx PIN is: ");
  Serial.println(Rxpin, BIN);
  Serial.println("testing");
  Serial.begin(9600);	// Debugging only
  Serial.println("setup");

  pinMode ( latchPin, OUTPUT);
  pinMode ( clockPin, OUTPUT);
  pinMode ( dataPin, OUTPUT);

  vw_set_rx_pin(9);        // set Rx
  vw_setup(2400);	 // Bits per sec
  vw_rx_start();    
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loop () 
{

  //        CHECK FOR INCOMING MESSAGE
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  
  delay (20);
  if (vw_get_message(buf, &buflen)) // Non-blocking
  {
    Serial.println("Got: ");  // Show on PC for debugging

    //            CHECK IF PIN NUMBERS MATCH

    PIN = buf[0];   // read Tx PIN number from buffer 0
    if ( PIN == Rxpin ) {   //  everything below only runs if PINs match 

      Serial.println(" PINs match ") ; 
      
      for ( int t =1 ;t<=19;t++ ) { 
        tile [t] = buf [t];
          show ();
      } 
    } // end of if PINs match
  }//  end of if message received 
}  //  end of loop


void show ()

{   //   display numbers generated depending on leading zero blanking requirements of each group of displays
  int dnumber = digitTable [ tile [3] ];  // single digit , no LZblanking
  /////////////////////////////////////////////////////
  int gnumber = (tile [2]) ? digitTable [ tile [2]] : 0; // leading zero blanking

  int  hnumber = digitTable [tile [1]];
  ////////////////////////////////////////////////////
  int enumber = (tile [7]) ? digitTable [ tile [7]] : 0; // leading zero blanking

  int  fnumber = digitTable [tile [8]];
  ////////////////////////////////////////////////////
  int rnumber = (tile [10]) ? digitTable [ tile [10]] : 0; // leading zero blanking

  int  snumber = digitTable [tile [9]];
  ////////////////////////////////////////////////////

  int anumber = (  tile [4]) ? digitTable [ tile [4] ] : 0;
  int bnumber = ( tile [4]|| tile [5]) ? digitTable [ tile [5]] : 0; // leading zero blanking
  int  cnumber = digitTable [tile [6]];

  ///////////////////////////////////////////////////////
  int onumber = (  tile [13]) ? digitTable [ tile [13] ] : 0;
  int pnumber = ( tile [13]|| tile [12]) ? digitTable [ tile [12]] : 0; // leading zero blanking
  int  qnumber = digitTable [tile [11]];

  ////////////////////////////////////////////////////

  int lnumber = (  tile [16]) ? digitTable [ tile [16] ] : 0;
  int mnumber = ( tile [16]|| tile [15]) ? digitTable [ tile [15]] : 0; // leading zero blanking
  int  nnumber = digitTable [tile [14]];

  ////////////////////////////////////////////////////

  int inumber = (  tile [19]) ? digitTable [ tile [19] ] : 0;
  int jnumber = ( tile [19]|| tile [18]) ? digitTable [ tile [18]] : 0; // leading zero blanking
  int  knumber = digitTable [tile [17]];

  ////////////////////////////////////////////////////

if ( tile [7] || tile [8] ) {     // if switches 7 and 8  set to 00 blanks all displays
  
   ///////////////////////////////////////////////////
    digitalWrite(latchPin, LOW); 
    
   for ( int k=0; k<=20; k++ ){                            // flush out shift register
    shiftOut(dataPin, clockPin, LSBFIRST, blank); 
   }
    delay (20);

    shiftOut(dataPin, clockPin, LSBFIRST, hnumber);  
   // delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, gnumber);
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, dnumber); 
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, anumber);
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, bnumber);   
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, cnumber);
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, enumber); 
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, fnumber); 
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, snumber);  
   // delay (5); 
    shiftOut(dataPin, clockPin, LSBFIRST, rnumber);
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, qnumber); 
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, pnumber);
   // delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, onumber);  
    //delay (5); 
    shiftOut(dataPin, clockPin, LSBFIRST, nnumber);
    //delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, mnumber); 
   // delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, lnumber);
   // delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, knumber); 
   // delay (5);  
    shiftOut(dataPin, clockPin, LSBFIRST, jnumber);
   // delay (5);
    shiftOut(dataPin, clockPin, LSBFIRST, inumber); 
    delay (5);

    digitalWrite(latchPin, HIGH); 
  }
  else {

    digitalWrite(latchPin, LOW);      // blanking all displays
   for ( int k=0; k<=20; k++ ){
    shiftOut(dataPin, clockPin, LSBFIRST, blank); 
   }
  digitalWrite(latchPin, HIGH); 
 }
}  // end of showT function