Components and supplies
5 mm LED: Red
Breadboard (generic)
74HC595 IC Shift Register
7 Segment LED Display, InfoVue
Arduino UNO
Resistor 220 ohm
Jumper wires (generic)
Apps and platforms
Arduino IDE
Project description
Code
SIPO8 library cpp file, ez_SIPO8.cpp
c_cpp
SIPO8 library cpp file, ez_SIPO8.cpp
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 SIPO8 v1-00 5 6 Serial/Parallel IC (SIPO) library supporting banking of multiple SIPOs 7 of same/different bit sizes. 8 Supports maximum of up to 255 8bit SIPOs (2040 individual output pins) 9 and up to 255 indivual timers. 10 11 This example and code is in the public domain and 12 may be used without restriction and without warranty. 13 14*/ 15 16 17#include <Arduino.h> 18#include <ez_SIPO8_lib.h> 19 20// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21// This function will be called when the class is initiated. 22// The parameter is the maximum number of SIPOs that will be configured 23// in the sketch. 24// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 25SIPO8::SIPO8(uint8_t max_SIPO_ICs, uint8_t Max_timers ) { 26 // Setup the SIPO_banks control data struture sized for the maximum number of 27 // SIPO banks that could be defined 28 SIPO_banks = (SIPO_control *) malloc(sizeof(SIPO_control) * max_SIPO_ICs); 29 if (SIPO_banks == NULL) { 30 SIPO_lib_exit(0); 31 } 32 // Determine how may pin_status_bytes of 'pins_per_SIPO' bit length are 33 // needed to map the number of bank SIPOs defined 34 _max_pins = max_SIPO_ICs * pins_per_SIPO; 35 max_pins = _max_pins; 36 _num_pin_status_bytes = max_SIPO_ICs; 37 num_pin_status_bytes = _num_pin_status_bytes; 38 pin_status_bytes = (uint8_t *) malloc(sizeof(pin_status_bytes) * _num_pin_status_bytes); // 1 byte per 8-bit SIPO 39 if (pin_status_bytes == NULL) { 40 SIPO_lib_exit(1); 41 } 42 // clear down pin_status_bytes to LOW (0) 43 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 44 pin_status_bytes[pin_status_byte] = 0; 45 } 46 // create timer struct(ure) of required size 47 if (Max_timers > 0){ 48 timers = (timer_control *) malloc(sizeof(timer_control) * Max_timers); 49 if (timers == NULL) { 50 SIPO_lib_exit(2); 51 } 52 } 53 _max_timers = Max_timers; 54 max_timers = Max_timers; 55 // initialise other working variables, private and user accessible 56 for (uint8_t timer = 0; timer < max_timers; timer++) { 57 timers[timer].timer_status = not_active; 58 timers[timer].start_time = 0; // elapsed time 59 } 60 _num_active_pins = 0; // no pins yet declared 61 num_active_pins = 0; 62 _max_SIPOs = max_SIPO_ICs; 63 max_SIPOs = _max_SIPOs; 64 _bank_SIPO_count = 0; 65 bank_SIPO_count = 0; 66 _next_bank = 0; 67 num_banks = 0; 68} 69 70// 71// General error reporting routine with termination 72// 73void SIPO8::SIPO_lib_exit(uint8_t reason) { 74 Serial.begin(9600); 75 switch (reason) { 76 case 0: 77 Serial.println(F("Exit:out of memory for setup-SIPO banks")); 78 break; 79 case 1: 80 Serial.println(F("Exit:out of memory for setup-status bytes")); 81 break; 82 case 2: 83 Serial.println(F("Exit:out of memory for setup-timers")); 84 break; 85 default: 86 Serial.println(F("Exit:unspecified")); 87 break; 88 } 89 Serial.flush(); 90 exit(reason); 91} 92 93// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94// The function will try to create a bank of SIPOs if possible. The create process 95// will fail if the more SIPOs for a bank are requested than remain unallocated. 96// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97int SIPO8::create_bank(uint8_t data_pin, uint8_t clock_pin, uint8_t latch_pin, 98 uint8_t num_SIPOs) { 99 if (_bank_SIPO_count + num_SIPOs <= _max_SIPOs && num_SIPOs > 0) { 100 // still enough free SIPOs available to assign to a new bank 101 pinMode(data_pin, OUTPUT); 102 digitalWrite(data_pin, LOW); 103 pinMode(clock_pin, OUTPUT); 104 digitalWrite(clock_pin, LOW); 105 pinMode(latch_pin, OUTPUT); 106 digitalWrite(latch_pin, LOW); 107 SIPO_banks[_next_bank].bank_data_pin = data_pin; 108 SIPO_banks[_next_bank].bank_clock_pin = clock_pin; 109 SIPO_banks[_next_bank].bank_latch_pin = latch_pin; 110 SIPO_banks[_next_bank].bank_num_SIPOs = num_SIPOs; 111 SIPO_banks[_next_bank].bank_low_pin = _num_active_pins; 112 uint16_t num_pins_this_bank = num_SIPOs * pins_per_SIPO; 113 SIPO_banks[_next_bank].bank_high_pin = _num_active_pins + num_pins_this_bank - 1;// inclusive pin numbers 114 _num_active_pins = _num_active_pins + num_pins_this_bank; 115 num_active_pins = _num_active_pins; 116 _bank_SIPO_count = _bank_SIPO_count + num_SIPOs; 117 bank_SIPO_count = _bank_SIPO_count; 118 _next_bank++; // next bank struct(ure) entry 119 num_banks = _next_bank; // user accessible number of banks defined 120 return _next_bank - 1; // return the bank number of this bank in the SIPOs struct(ure) 121 } 122 return create_bank_failure; // cannot provide number of SIPOs asked for, for this bank request 123} 124 125// 126// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 127// Function will set the entire array of pins to the given status value. Note that 128// this function operates on an entire array basis rather than bank by bank. 129// The parameter pin_status should be HIGH or LOW 130// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 131void SIPO8::set_all_array_pins(bool pin_status) { 132 uint8_t mask = pin_status * 255; // either 0 (all pins set low), or 255 (all pins set high) 133 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 134 pin_status_bytes[pin_status_byte] = mask; 135 } 136} 137 138// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 139// Function will invert the status of each pin the the array. Note that 140// this function operates on an entire array basis rather than bank by bank. 141// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 142void SIPO8::invert_all_array_pins() { 143 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 144 pin_status_bytes[pin_status_byte] = ~pin_status_bytes[pin_status_byte]; 145 } 146} 147 148// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 149// Function sets the given pin (absolute pin reference) to the given status value. 150// The success or otherwise of the process may be tested by the calling code using 151// the return function value. 152// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153int SIPO8::set_array_pin(uint16_t pin, bool pin_status) { 154 if (pin < _num_active_pins) { 155 // pin is in the defined pin range 156 uint8_t pin_status_byte = pin / pins_per_SIPO; 157 uint8_t pin_bit = pin % pins_per_SIPO; 158 bitWrite(pin_status_bytes[pin_status_byte], pin_bit, pin_status); 159 return pin; 160 } 161 return pin_set_failure; 162} 163 164// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 165// Function inverts the existing pin status. Note that pin is given as an absolute 166// pin reference. 167// The success or otherwise of the process may be tested by the calling code using 168// the return function value. 169// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 170int SIPO8::invert_array_pin(uint16_t pin) { 171 if (pin < _num_active_pins) { 172 // pin is in the defined pin range 173 uint8_t pin_status_byte = pin / pins_per_SIPO; 174 uint8_t pin_bit = pin % pins_per_SIPO; 175 bool inverted_status = !bitRead(pin_status_bytes[pin_status_byte], pin_bit); 176 bitWrite(pin_status_bytes[pin_status_byte], 177 pin_bit, 178 inverted_status); 179 return inverted_status; // high or low status 180 } 181 return pin_invert_failure; 182} 183 184// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 185// Funcion will read the status value of the specified pin and return to the calling 186// code. Note that pin is given as an absolute pin reference. 187// The success or otherwise of the process may be tested by the calling code using 188// the return function value. 189// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 190int SIPO8::read_array_pin(uint16_t pin) { 191 if (pin < _num_active_pins) { 192 // pin is in the defined pin range 193 uint8_t pin_status_byte = pin / pins_per_SIPO; 194 uint8_t pin_bit = pin % pins_per_SIPO; 195 return bitRead(pin_status_bytes[pin_status_byte], pin_bit); // high or low status 196 } 197 return pin_read_failure; 198} 199 200// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 201// Function is equivalent to the set_all_array_pins function and is prvided as an 202// alternative choice. 203// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 204void SIPO8::set_banks(bool pin_status) { 205 set_all_array_pins(pin_status); 206} 207 208// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 209// Function will set every pin in each bank, from_bank - to_bank, to the 210// specified pin status. 211// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 212void SIPO8::set_banks(uint8_t from_bank, uint8_t to_bank, bool pin_status) { 213 if (from_bank <= to_bank && to_bank < _next_bank) { 214 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 215 set_bank(bank, pin_status); 216 } 217 } 218} 219 220// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221// Function will set every pin in given bank to the specified pin status. 222// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223void SIPO8::set_bank(uint8_t bank, bool pin_status) { 224 if (bank < _next_bank) { 225 // start with the first pin of the first SIPO in the bank 226 uint16_t first_pin = SIPO_banks[bank].bank_low_pin; // first pin in this bank 227 uint8_t mask = pin_status * 255; // either 0 (all pins set low), or 255 (all pins set high) 228 // determine the first pin status byte for the first pin in the bank 229 uint8_t pin_status_byte = first_pin / pins_per_SIPO; 230 // now deal with each SIPO declared in the bank, setting the 231 // associated pin status bytes accordingly 232 for (uint8_t SIPO = 0; SIPO < SIPO_banks[bank].bank_num_SIPOs; SIPO++) { 233 pin_status_bytes[pin_status_byte + SIPO] = mask; // reset all pin bits 234 } 235 } 236} 237 238// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 239// Function is equivalent to the invert_all_array_pins function and is prvided as an 240// alternative choice. 241// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 242void SIPO8::invert_banks() { 243 invert_all_array_pins(); 244} 245 246// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 247// Function will invert the existing pin status of every pin in the specified banks. 248// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 249void SIPO8::invert_banks(uint8_t from_bank, uint8_t to_bank) { 250 if (from_bank <= to_bank && to_bank < _next_bank) { 251 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 252 invert_bank(bank); 253 } 254 } 255} 256 257// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 258// Function will invert the existing pin status of every pin in the specified bank. 259// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 260void SIPO8::invert_bank(uint8_t bank) { 261 if (bank < _next_bank) { 262 // start with the first pin of the first SIPO in the bank 263 uint16_t first_pin = SIPO_banks[bank].bank_low_pin; // first pin in this bank 264 // determine the first pin status byte for the first pin in the bank 265 uint8_t pin_status_byte = first_pin / pins_per_SIPO; 266 // now deal with each SIPO declared in the bank, setting the 267 // associated pin status bytes accordingly 268 for (uint8_t SIPO = 0; SIPO < SIPO_banks[bank].bank_num_SIPOs; SIPO++) { 269 pin_status_bytes[pin_status_byte + SIPO] = 270 ~pin_status_bytes[pin_status_byte + SIPO]; // invert the status byte bits 271 } 272 } 273} 274 275// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 276// Function for setting specific pin within a given bank. 277// Note that these functions operate relative to the pins defined 278// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 279// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 280int SIPO8::set_bank_pin(uint8_t bank, uint8_t pin, bool pin_status) { 281 if (bank < _next_bank) { 282 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 283 return set_array_pin(pin, pin_status); // returns failure or the absolute pin muber if successful 284 } 285 return pin_set_failure; 286} 287 288// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289// Function for inverting specific existing pin status within a given bank. 290// Note that these functions operate relative to the pins defined 291// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 292// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 293int SIPO8::invert_bank_pin(uint8_t bank, uint8_t pin) { 294 if (bank < _next_bank) { 295 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 296 return invert_array_pin(pin); // returns failure or the new status of the pin if successful 297 } 298 return pin_invert_failure; 299} 300 301// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302// Function will read the given pin's status and return its value to the calling code. 303// Note that these functions operate relative to the pins defined 304// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 305// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 306int SIPO8::read_bank_pin(uint8_t bank, uint8_t pin) { 307 if (bank < _next_bank) { 308 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 309 return read_array_pin(pin); // returns failure or the pin status if successful 310 } 311 return pin_read_failure; 312} 313 314// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315// Function will set the given bank SIPO (8bits) to the secified value 316// Note that this functions operate relative to the SIPOs/pins defined 317// in a bank. 318// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 319int SIPO8::set_bank_SIPO(uint8_t bank, uint8_t SIPO_num, uint8_t SIPO_value) { 320 if (bank < _next_bank) { 321 // bank is valid 322 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 323 if (SIPO_num < SIPOs_this_bank) { 324 // specified SIPO number is valid for this bank 325 // now determine the pin_staus_byte entry for the SIPO 326 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 327 status_byte = status_byte + SIPO_num; // actual status byte to be set 328 pin_status_bytes[status_byte] = SIPO_value;// set required status byte 329 return status_byte; 330 } 331 return SIPO_not_found; 332 } 333 return bank_not_found; 334} 335 336// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 337// Function will invert the current contents of the given bank SIPO (8bits) to the 338// secified value. 339// Note that this functions operate relative to the SIPOs/pins defined 340// in a bank. 341// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 342int SIPO8::invert_bank_SIPO(uint8_t bank, uint8_t SIPO_num) { 343 if (bank < _next_bank) { 344 // bank is valid 345 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 346 if (SIPO_num < SIPOs_this_bank) { 347 // specified SIPO number is valid for this bank 348 // now determine the pin_staus_byte entry for the SIPO 349 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 350 status_byte = status_byte + SIPO_num; // actual status byte to be inverted 351 pin_status_bytes[status_byte] = ~pin_status_bytes[status_byte]; // invert current contents 352 return status_byte; 353 } 354 return SIPO_not_found; 355 } 356 return bank_not_found; 357} 358 359// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 360// Function will read the current contents of the given bank SIPO (8bits) and return 361// the 8bit status value for the SIPO. 362// Note that this functions operate relative to the SIPOs/pins defined 363// in a bank. 364// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 365int SIPO8::read_bank_SIPO(uint8_t bank, uint8_t SIPO_num) { 366 if (bank < _next_bank) { 367 // bank is valid 368 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 369 if (SIPO_num < SIPOs_this_bank) { 370 // specified SIPO number is valid for this bank 371 // now determine the pin_staus_byte entry for the SIPO 372 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 373 status_byte = status_byte + SIPO_num; // actual status byte to be read 374 return pin_status_bytes[status_byte]; 375 } 376 return SIPO_not_found; 377 } 378 return bank_not_found; 379} 380 381// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 382// Given an absolute array pin number, the function determines which 383// bank it resides within and returns the bank number. 384// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 385int SIPO8::get_bank_from_pin(uint16_t pin) { 386 if (pin < _num_active_pins) { 387 for (uint8_t bank = 0; bank < _next_bank; bank++) { 388 if (SIPO_banks[bank].bank_low_pin <= pin && 389 pin <= SIPO_banks[bank].bank_high_pin)return bank; 390 } 391 } 392 return bank_not_found; 393} 394 395// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 396// Determines the number of pins in the given bank 397// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 398int SIPO8::num_pins_in_bank(uint8_t bank) { 399 if (bank < _next_bank) { 400 // valid bank, so return number of pins in this bank 401 return SIPO_banks[bank].bank_num_SIPOs * pins_per_SIPO; 402 } 403 return bank_not_found; 404} 405 406 407// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 408// Selective transfer of array pin satuses based on bank transfers, 409// rather than the entire array of banks. 410// Transfers specified banks' pin statuses to the hardware SIPOs, 411// starting with from_bank and continuing to to_bank. 412// The direction of transfer is determined by the msb_or_lsb parameter 413// which must be either LSBFIRST or MSBFIRST. 414// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 415void SIPO8::xfer_banks(uint8_t from_bank, uint8_t to_bank, bool msb_or_lsb) { 416 if (from_bank <= to_bank && to_bank < _next_bank) { 417 // examine each bank in turn and deal with as many SIPOs as 418 // are configured in each bank 419 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 420 uint16_t low_pin = SIPO_banks[bank].bank_low_pin; // start pin number for this bank 421 uint16_t high_pin = SIPO_banks[bank].bank_high_pin; // end inclusive pin number for this bank 422 uint8_t latch_pin = SIPO_banks[bank].bank_latch_pin; 423 uint8_t clock_pin = SIPO_banks[bank].bank_clock_pin; 424 uint8_t data_pin = SIPO_banks[bank].bank_data_pin; 425 uint8_t num_SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 426 uint8_t SIPO_first_status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO; 427 uint8_t SIPO_last_status_byte = SIPO_banks[bank].bank_high_pin / pins_per_SIPO; 428 uint8_t SIPO_status_byte = 0; 429 digitalWrite(latch_pin, LOW); // tell IC data transfer to start 430 for (uint8_t SIPO = 0; SIPO < num_SIPOs_this_bank; SIPO++) { 431 if (msb_or_lsb == LSBFIRST) { 432 SIPO_status_byte = SIPO_first_status_byte + SIPO; 433 } else { 434 SIPO_status_byte = SIPO_last_status_byte - SIPO; 435 } 436 shift_out_bank(data_pin, clock_pin, pin_status_bytes[SIPO_status_byte], msb_or_lsb); 437 } 438 digitalWrite(latch_pin, HIGH); // tell IC data transfer is finished 439 } 440 } 441} 442 443// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 444// Equivalent to xfer_array, and transfers all array pin statuses to the 445// the hardware SIPOs. Provided as an alternative method. 446// The direction of transfer is determined by the msb_or_lsb parameter 447// which must be either LSBFIRST or MSBFIRST. 448// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 449void SIPO8::xfer_banks(bool msb_or_lsb) { 450 if (_next_bank > 0) { 451 xfer_banks(0, _next_bank - 1, msb_or_lsb); 452 } 453} 454 455// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 456// Specific transfer of the given bank pin statuses to the bank's associated 457// hardware SIPOs. The direction of transfer is determined by the msb_or_lsb 458// parameter which must be either LSBFIRST or MSBFIRST. 459// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 460void SIPO8::xfer_bank(uint8_t bank, bool msb_or_lsb) { 461 if (_next_bank > 0) { 462 xfer_banks(bank, bank, msb_or_lsb); 463 } 464} 465 466// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 467// Transfers all array pin statuses to the hardware SIPOs. 468// The direction of transfer is determined by the msb_or_lsb parameter 469// which must be either LSBFIRST or MSBFIRST. 470// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 471void SIPO8::xfer_array(bool msb_or_lsb) { 472 xfer_banks(msb_or_lsb); 473} 474 475// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 476// Based on the standard Arduino shiftout function. 477// Moves out the given set of pin statuses, status_bits, to the specified SIPO. 478// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 479void SIPO8::shift_out_bank(uint8_t data_pin, uint8_t clock_pin, uint8_t status_bits, bool msb_or_lsb) 480{ // Shuffle each bit of the val parameter (0 or 1) one bit left 481 // until all bits written out. 482 for (uint8_t i = 0; i < pins_per_SIPO; i++) { 483 if (msb_or_lsb == LSBFIRST) { 484 digitalWrite(data_pin, !!(status_bits & (1 << i))); 485 } 486 else 487 { 488 digitalWrite(data_pin, !!(status_bits & (1 << (7 - i)))); 489 } 490 digitalWrite(clock_pin, HIGH); 491 digitalWrite(clock_pin, LOW); 492 } 493} 494 495// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 496// Function is provided to assist end user to provide debug data during development. 497// Prints all active pin status bytes, in bit form, starting with pin 0 and 498// progressing to the last active end pin defined. 499// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 500void SIPO8::print_pin_statuses() { 501 if (_next_bank > 0) { 502 Serial.println(F("\ 503Active pin array, pin statuses:")); 504 // there is at least 1 bank 505 uint8_t SIPO_count = 0; 506 for (uint8_t bank = 0; bank < _next_bank; bank++) { 507 Serial.print(F("Bank ")); 508 if (bank < 10)Serial.print(F(" ")); 509 Serial.print(bank); 510 Serial.print(F(": MS")); 511 uint8_t start_byte = SIPO_count; 512 uint8_t last_byte = start_byte + SIPO_banks[bank].bank_num_SIPOs - 1; 513 SIPO_count = SIPO_count + SIPO_banks[bank].bank_num_SIPOs; 514 for (int16_t next_byte = last_byte; next_byte >= start_byte; next_byte--) { 515 uint8_t SIPO_status = pin_status_bytes[next_byte]; 516 for (int pos = 7; pos >= 0; pos--) { 517 uint8_t pin_status = bitRead(SIPO_status, pos); 518 Serial.print(pin_status); 519 } 520 } 521 Serial.println(F("LS")); 522 } 523 } else { 524 Serial.println(F("\ 525No banks defined")); 526 } 527 Serial.flush(); 528} 529 530// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 531// Function is provided to assist end user to display debug data during development. 532// Prints all setup data as a confirmation that the end user has correctly configured 533// all key data. 534// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 535void SIPO8::print_SIPO_data() { 536 Serial.println(F("\ 537SIPO global values:")); 538 Serial.print(F("pins_per_SIPO = ")); 539 Serial.println(pins_per_SIPO); 540 Serial.print(F("max_SIPOs = ")); 541 Serial.println(_max_SIPOs); 542 Serial.print(F("bank_SIPO_count = ")); 543 Serial.println(_bank_SIPO_count); 544 Serial.print(F("num_active_pins = ")); 545 Serial.println(_num_active_pins); 546 Serial.print(F("num_pin_status_bytes = ")); 547 Serial.println(_num_pin_status_bytes); 548 Serial.print(F("next_free bank = ")); 549 if (_bank_SIPO_count < _max_SIPOs) { 550 Serial.print(_next_bank); 551 Serial.println(); 552 } else { 553 Serial.println(F(" all SIPOs used")); 554 } 555 Serial.print("Number timers = "); 556 Serial.println(_max_timers); 557 Serial.println(F("\ 558Bank data:")); 559 for (uint8_t bank = 0; bank < _next_bank; bank++) { 560 // still SIPOs available to assign to a new bank 561 Serial.print(F("bank = ")); 562 Serial.println(bank); 563 Serial.print(F(" num SIPOs =\ ")); 564 Serial.println(SIPO_banks[bank].bank_num_SIPOs); 565 Serial.print(F(" latch_pin =\ ")); 566 Serial.print(SIPO_banks[bank].bank_latch_pin); 567 Serial.print(F(" clock_pin =\ ")); 568 Serial.print(SIPO_banks[bank].bank_clock_pin); 569 Serial.print(F(" data_pin =\ ")); 570 Serial.println(SIPO_banks[bank].bank_data_pin); 571 Serial.print(F(" low_pin =\ ")); 572 Serial.print(SIPO_banks[bank].bank_low_pin); 573 Serial.print(F(" high_pin =\ ")); 574 Serial.println(SIPO_banks[bank].bank_high_pin); 575 } 576 Serial.flush(); 577} 578 579// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 580// Function sets the given timer as active and records the start time. 581// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 582void SIPO8::SIPO8_start_timer(uint8_t timer) { 583 if (timer < _max_timers) { 584 timers[timer].timer_status = active; 585 timers[timer].start_time = millis(); 586 } 587} 588 589// 590// Function cancels the given timer. 591// 592void SIPO8::SIPO8_stop_timer(uint8_t timer) { 593 if (timer < _max_timers) { 594 timers[timer].timer_status = not_active; 595 } 596} 597 598// 599// Function determines if the time has elapsed for the given timer, if active. 600// 601bool SIPO8::SIPO8_timer_elapsed(uint8_t timer, uint32_t elapsed_time) { 602 if (timer < _max_timers) { 603 if (timers[timer].timer_status == active) { 604 if (millis() - timers[timer].start_time >= elapsed_time) { 605 timers[timer].timer_status = not_active; // mark this timer no longer active 606 return elapsed; 607 } 608 } 609 } 610 return not_elapsed; 611}
Story Board Example 1
c_cpp
Story board example 1 - toggle switches status display
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 5 Example sketch 1 for Arduino Community story board 6 The sketch reads a number of toggle switches which are in one of two 7 states - on(HIGH) or off(LOW). 8 Each switch is mapped to a SIPO bank pin as follows: 9 switches 0-5 -> bank pins 0-5 10 bank pin 6 is not used 11 bank pin 7 is used as a sketch running indicator, 12 or 'heart beat' 13 14 Note that the switches are 'read' periodically sampled by a dummy 15 function using the SIPO8 timers feature. The code is non-blocking. 16 17 This example and code is in the public domain and 18 may be used without restriction and without warranty. 19 20*/ 21 22#include <ez_SIPO8_lib.h> 23 24#define Max_SIPOs 1 25#define Max_timers 1 26#define sample_time 500 // interval period between sampling sensors 27#define num_switches 6 // number of sensors requiring testing/reading in each cycle 28 29// initiate the class for max SIPOs/timers required 30SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 31 32uint8_t bank_id; 33 34// dummy read switch function - returns a random staus for given switch 35// number, based on switch's current status 36bool read_switch_status(uint8_t Switch) { 37 randomSeed(analogRead(A0)*analogRead(A2)); // keep changing seed 38 if (random(0, 4) == 0)return !my_SIPOs.read_bank_pin(bank_id, Switch); 39 return my_SIPOs.read_bank_pin(bank_id, Switch); 40} 41 42void setup() { 43 Serial.begin(9600); 44 // create 1 bank of Max_SIPOs 45 // params are data pin, clock pin anf latch pin, number SIPOs 46 bank_id = my_SIPOs.create_bank(8, 10, 9, Max_SIPOs); 47 if (bank_id == create_bank_failure) { 48 my_SIPOs.print_SIPO_data(); 49 Serial.println(F("failed to create bank")); 50 Serial.flush(); 51 exit(0); 52 } 53my_SIPOs.print_SIPO_data(); // report on global SIPO8 params 54} 55// Scan all defined switches and set their respective bank pin status, LOW/HIGH. 56// Switches/bank pins layout: 57// Switch associated bank pins run from 0 to num_switches-1, inclusive (5) and 58// are used to indicate respective switch status, 59// bank pin 6 is not used and bank pin 7 is used to provide 60// a 'heart beat' to indicate that the sketch is running. 61void loop() { 62 my_SIPOs.set_all_array_pins(LOW); // ensure we start with clear array pool/bank 63 my_SIPOs.xfer_array(MSBFIRST); 64 my_SIPOs.SIPO8_start_timer(timer0); // start the sample timer 65 do { 66 if (my_SIPOs.SIPO8_timer_elapsed(timer0, sample_time) == elapsed) { 67 my_SIPOs.SIPO8_start_timer(timer0); // reset/restart the timer 68 // read each switch and set its virtual SIPO pin in the bank 69 my_SIPOs.invert_bank_pin(bank_id, 7); // flash 'heart beat' 70 for (uint8_t Switch = 0; Switch < num_switches; Switch ++) { 71 my_SIPOs.set_bank_pin(bank_id, Switch, read_switch_status(Switch)); 72 } 73 my_SIPOs.xfer_bank(bank_id, MSBFIRST); // update the physical SIPO pins 74 } 75 } while (true); 76} 77
ez_SIPO8_lib - User Guide - Sketch Example – Driving a 7 Segment LED Matrix Display
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Driving a 7 Segment LED Matrix Display, see User Guide
1// 2// 7 Segment LED Matrix - 3// Sketch uses a single SIPO IC to map the 7 segment matrix and creates 4// a single bank comprising one SIPO IC. 5// 6// This sketch drives a single 7 segment LED matrix, displaying digits 7// from 0 to hex F, in two repeating cycles: 8// 1. cycle 1 - shifting out the most significant bit first (MSBFIRST), with each 9// character appended with the DP character ".", eg "3." 10// 2. cycle 2 - shifting out the least significant bit first (LSBFIRST), without the DP 11// character appended. 12// 13// The sketch offers two methods for updating a 7 Segment LED Matrix, choice 14// is a simple matter a preference/familiarity. 15// 16// This example uses relative bank addressing. 17// 18// Ron D Bentley, Stafford, UK 19// April 2021 20// 21// This example and code is in the public domain and 22// may be used without restriction and without warranty. 23// 24 25#include <ez_SIPO8_lib.h> 26 27#define max_SIPOs 1 // one 1 SIPO for this example 28#define max_timers 0 // no timers required 29 30// initiate the class for max SIPOs/timers required 31SIPO8 my_SIPOs(max_SIPOs, max_timers); 32 33int my_matrix7; // used to keep the SIPO bank id 34 35#define num_digits 16 36uint8_t LSB_matrix_chars[num_digits] = { 37 252, 96, 218, 242, 102, 182, 190, 224, 254, 246, 238, 62, 156, 122, 158, 142 38}; 39#define LSB_DP_char 0b00000001 // "." value for LSBFIRST shiftout 40 41uint8_t MSB_matrix_chars[num_digits] = { 42 63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 119, 124, 57, 94, 121, 113 43}; 44#define MSB_DP_char 0b10000000 // "." value for MSBFIRST shiftout 45 46void setup() { 47 Serial.begin(9600); 48 // create a bank of 1 SIPO using create_bank function: 49 // data pin, clock pin, latch pin, number of SIPO this bank 50 my_matrix7 = my_SIPOs.create_bank(8, 10, 9, 1); // data pin, clock pin, latch pin, number of SIPO this bank 51 if (my_matrix7 == create_bank_failure) { 52 Serial.println(F("\ 53failed to create bank")); 54 Serial.flush(); 55 exit(0); 56 } 57 // print the bank data for confirmation/inspection 58 my_SIPOs.print_SIPO_data(); 59} 60 61void loop() { 62 // keep running through the digits 0 to hex F, as defined by the 63 // bit patterns in the preset array MSB_/LSB_matrix_chars 64 do { 65 // cycle 1 - MSBFIRST, with appended DP character "." 66 my_SIPOs.set_bank_SIPO(my_matrix7, 0, 0b00000000); // reset all LEDs in the matrix to off/LOW 67 my_SIPOs.xfer_bank(my_matrix7, MSBFIRST); 68 delay(50); 69 for (uint8_t digit = 0; digit < num_digits; digit++) { 70 my_SIPOs.set_bank_SIPO(my_matrix7, 0, MSB_matrix_chars[digit] + MSB_DP_char); // append "." 71 my_SIPOs.xfer_bank(my_matrix7, MSBFIRST); 72 delay(500); 73 } 74 // cycle 2 - LSBFIRST, no appended DP character 75 my_SIPOs.set_bank_SIPO(my_matrix7, 0, 0b00000000); // reset all LEDs in the matrix to off/LOW 76 my_SIPOs.xfer_bank(my_matrix7, LSBFIRST); 77 delay(50); 78 for (uint8_t digit = 0; digit < num_digits; digit++) { 79 // if DP char "." required to be appended to a char, then add 'LSB_DP_char' 80 // to the 'LSB_matrix_chars[digit]' parameter 81 my_SIPOs.set_bank_SIPO(my_matrix7, 0, LSB_matrix_chars[digit]); 82 my_SIPOs.xfer_bank(my_matrix7, LSBFIRST); 83 delay(500); 84 } 85 } while (true); 86}
ez_SIPO8_lib - User Guide - Sketch Example – Flashing LEDs, Absolute Pin Addressing
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Flashing LEDs, Absolute Pin Addressing, see User Guide
1// 2// Flash LEDs - 3// This sketch independently flashes eight 4 LEDs each connected to a SIPO output pin, 5// each at a different frequency, 6 using SIPO8 library timers. 7// The demonstration runs for a fixed time before 8 terminating, again this being 9// controlled by a SIPO8 library timer. 10// 11// 12 This example uses absolute array pin addressing. 13// 14// Ron D Bentley, 15 Stafford, UK 16// April 2021 17// 18// This example and code is in the public 19 domain and 20// may be used without restriction and without warranty. 21// 22#include 23 "ez_SPIC8_lib.h" 24 25#define Max_SPICs 1 26#define Max_timers 9 // we will 27 create 9 timers, 0-7 for LEDs and 8 for our timimg 28#define my_timer 8 // we 29 will use SPIC8 timer 8 for timing our demonstration 30 31#define number_banks 32 1 // demonstration using 1 bank 33#define demo_time 20000 // time in milliseconds 34 flash demonstration to run for 35 36int bank0_id; 37 38// setup pin/LED flash 39 data 40uint8_t timer; 41 42uint32_t timer_intervals[Max_timers] = { 43 // millisecond 44 elapse timer values for each timer, 0 - 7 45 300, 400, 500, 600, 700, 800, 900, 46 1000 47}; 48 49uint8_t timer_pins[Max_timers] = { 50 // SPIC output pin absolute 51 addresses for timers 0 - 7 52 0, 1, 2, 3, 4, 5, 6, 7 53}; 54 55SPIC8 my_SPICs(Max_SPICs, 56 Max_timers); // initiate the class for max SPICs/timers 57 58void setup() { 59 60 Serial.begin(9600); 61 // create a single bank, params are: 62 // data pin, 63 clock pin, latch pin, number of SPICs this bank 64 bank0_id = my_SPICs.create_bank(8, 65 10, 9, number_banks); 66 if (bank0_id == create_bank_failure) { 67 Serial.println(F("\ 68failed 69 to create bank")); 70 Serial.flush(); 71 exit(0); 72 } 73 // print 74 the bank data for confirmation/inspection 75 my_SPICs.print_SPIC_data(); 76} 77 78void 79 loop() { 80 // 81 // now lets add in the flashing LED code from Tutorial 3 82 83 // start by setting all SPIC outputs to low (off) 84 my_SPICs.set_all_array_pins(LOW);// 85 set all declared virtual output pins LOW/off 86 my_SPICs.xfer_array(LSBFIRST); 87 // move virtual pin to real SPIC output pins 88 my_SPICs.SPIC8_start_timer(my_timer); 89 // start my_timer 90 // keep processing until our my_timer has elapsed 91 // 92 start all timers 93 for (timer = 0; timer < Max_timers - 1; timer++) { 94 my_SPICs.SPIC8_start_timer(timer); 95 96 } 97 timer = 0; // start checking at first timer 98 do { 99 // check each 100 timer for elapse and, if elapsed, invert the timer's output pin 101 // and reset 102 the timer 103 if (my_SPICs.SPIC8_timer_elapsed(timer, timer_intervals[timer]) 104 == elapsed) { 105 my_SPICs.invert_array_pin(timer_pins[timer]); // invert the 106 pin associated with this timer 107 my_SPICs.xfer_array(MSBFIRST); // 108 update physical SPIC outputs 109 my_SPICs.SPIC8_start_timer(timer); // 110 reset/restart the current timer 111 } 112 timer++; // move on to next timer 113 114 if (timer >= Max_timers - 1) timer = 0; // wrap around to beginning 115 } while 116 (my_SPICs.SPIC8_timer_elapsed(my_timer, demo_time) != elapsed); 117 // 118 // 119 end of LED flash demonstration - now clear down LEDs to off(LOW) 120 my_SPICs.set_all_array_pins(LOW);// 121 set all declared virtual output pins LOW/off 122 my_SPICs.xfer_array(LSBFIRST); 123 // move virtual pin statuses to real SPIC output pins 124 exit(0); 125}
ez_SIPO8_lib - User Guide - Sketch Example – Strobing LEDs, Relative Pin Addressing
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Strobing LEDs, Relative Pin Addressing, see User Guide
1// 2// Strobe - 3// This sketch strobes a number of LEDs driven 4 by a SIPO IC, 8 output pins 5// forwards and backwards at a defined frequency. 6// 7// 8 This example uses relative bank addressing. 9// 10// Ron D Bentley, Stafford, 11 UK 12// April 2021 13// 14// This example and code is in the public domain 15 and 16// may be used without restriction and without warranty. 17// 18 19#include 20 <ez_SIPO8_lib.h> 21 22#define Max_SIPOs 1 // 1 x SIPOs - provides 8 output pins 23#define 24 Max_timers 0 // no timers required, will use delay 25 26#define data_pin 8 27#define 28 clock_pin 10 29#define latch_pin 9 30 31#define strobe_frequency 50 // 32 milli seconds, delay frequency 33 34// initiate the class for max SIPOs/timers 35 required 36SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 37 38int bank_id; // used 39 to keep the SIPO bank id 40 41void setup() { 42 Serial.begin(9600); 43 // 44 create a bank of 'Max_SIPOs' using create_bank function: 45 bank_id = my_SIPOs.create_bank(data_pin, 46 clock_pin, latch_pin, Max_SIPOs); 47 if (bank_id == create_bank_failure) { 48 49 Serial.println(F("\ 50failed to create bank, terminated")); 51 Serial.flush(); 52 53 exit(0); 54 } 55 // start by setting all SIPO outputs to low (off) in the 56 SIPO bank 57 my_SIPOs.set_bank_SIPO(bank_id, 0, 0b00000000); // only 1 SIPO in 58 bank,index 0 59 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 60 // print the bank 61 data for confirmation/inspection 62 my_SIPOs.print_SIPO_data(); 63} 64 65void 66 loop() { 67 //strobe example, strobe bank_id pins forward and back 68 bool msb_or_lsb 69 = MSBFIRST; // pick an initial strobe direction 70 int pins_in_bank = my_SIPOs.num_pins_in_bank(bank_id); 71 // number SIPO output pins in this bank 72 if (pins_in_bank > 0) { 73 do { 74 75 for (uint16_t pin = 0; pin < pins_in_bank; pin++) { 76 my_SIPOs.set_bank_pin(bank_id, 77 pin, HIGH); // set next strobe pin 78 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); 79 // update physical SIPO bank 80 delay(strobe_frequency); 81 my_SIPOs.set_bank_pin(bank_id, 82 pin, LOW); // clear next strobe pin 83 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); 84 // update physical SIPO bank 85 } 86 msb_or_lsb = !msb_or_lsb; // 87 switch strobe direction 88 } while (true); 89 } else { 90 Serial.println(F("\ 91bank 92 not found, terminated")); 93 Serial.flush(); 94 exit(0); 95 } 96}
SIPO8 library header file, ez_SIPO8.h
c_cpp
SIPO8 library header file, ez_SIPO8.h
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 SIPO8 v1-00 5 6 7 Serial/Parallel IC (SIPO) library supporting banking of multiple SIPOs 8 of 9 same/different bit sizes. 10 Supports maximum of up to 255 8bit SIPOs (2040 individual 11 output pins) 12 and up to 255 indivual timers. 13 14 This example and code 15 is in the public domain and 16 may be used without restriction and without warranty. 17 18*/ 19 20#ifndef 21 SIPO8_h 22#define SIPO8_h 23 24#include <Arduino.h> // always include this lib 25 otherwise wont compile! 26 27class SIPO8 28{ 29 public: 30 31 32#define 33 pins_per_SIPO 8 // global 'set in stone' macro for a base SIPO unit 34 35 36 // failure macros... 37#define create_bank_failure -1 38#define pin_read_failure 39 -1 40#define pin_invert_failure -1 41#define pin_set_failure -1 42#define 43 bank_not_found -1 44#define SIPO_not_found -2 45 46 // timer macros... 47#define 48 timer0 0 49#define timer1 1 50#define timer2 2 51#define 52 timer3 3 53#define timer4 4 54#define timer5 5 55#define 56 timer6 6 57#define timer7 7 58#define elapsed true 59#define 60 not_elapsed !elapsed 61#define active true 62#define not_active 63 !active 64 65 uint16_t max_pins = 0; // user accessible 66 params 67 uint16_t num_active_pins = 0; // ... 68 uint8_t num_pin_status_bytes 69 = 0; // ... 70 uint8_t num_banks = 0; // ... 71 uint8_t max_SIPOs 72 = 0; // ... 73 uint8_t bank_SIPO_count = 0; // ... 74 uint8_t 75 max_timers = 0; // ... 76 77 struct SIPO_control { 78 uint8_t 79 bank_data_pin; 80 uint8_t bank_clock_pin; 81 uint8_t bank_latch_pin; 82 83 uint8_t bank_num_SIPOs; 84 uint16_t bank_low_pin; 85 uint16_t 86 bank_high_pin; 87 }*SIPO_banks; 88 89 uint8_t * pin_status_bytes; // records 90 current status of each pin 91 92 // timer control struct(ure) 93 struct 94 timer_control { 95 bool timer_status; // records status of a timer 96 - active or not active 97 uint32_t start_time; // records the millis 98 time when a timer is started 99 } *timers; 100 101 // ******* function declarations.... 102 103 104 SIPO8(uint8_t, uint8_t); // constructor function called when class is initiated 105 106 107 int create_bank(uint8_t, uint8_t, uint8_t, uint8_t); 108 void set_all_array_pins(bool); 109 110 void invert_all_array_pins(); 111 int set_array_pin(uint16_t, bool); 112 113 int invert_array_pin(uint16_t); 114 int read_array_pin(uint16_t); 115 116 117 void set_banks(uint8_t, uint8_t, bool); 118 void set_banks(bool); 119 void 120 set_bank(uint8_t, bool); 121 void invert_banks(); 122 void invert_banks(uint8_t, 123 uint8_t); 124 void invert_bank(uint8_t); 125 126 int set_bank_SIPO(uint8_t, 127 uint8_t, uint8_t); 128 int invert_bank_SIPO(uint8_t, uint8_t); 129 int read_bank_SIPO(uint8_t, 130 uint8_t); 131 132 int set_bank_pin(uint8_t, uint8_t, bool); 133 int invert_bank_pin(uint8_t, 134 uint8_t); 135 int read_bank_pin(uint8_t, uint8_t); 136 137 int get_bank_from_pin(uint16_t); 138 139 int num_pins_in_bank(uint8_t); 140 141 void xfer_banks(uint8_t, uint8_t, 142 bool); 143 void xfer_banks(bool); 144 void xfer_bank(uint8_t, bool); 145 void 146 xfer_array(bool); 147 148 void print_pin_statuses(); 149 void print_SIPO_data(); 150 151 152 void SIPO8_start_timer(uint8_t); 153 void SIPO8_stop_timer(uint8_t); 154 155 bool SIPO8_timer_elapsed(uint8_t, uint32_t); 156 157 // ****** private declarations..... 158 159 private: 160 uint16_t _max_pins = 0; 161 uint16_t _num_active_pins 162 = 0; 163 uint8_t _num_pin_status_bytes = 0; 164 uint8_t _max_SIPOs 165 = 0; 166 uint8_t _bank_SIPO_count = 0; 167 uint8_t _next_bank 168 = 0; 169 uint8_t _max_timers = 0; 170 171 void SIPO_lib_exit(uint8_t); 172 173 void shift_out_bank(uint8_t, uint8_t, uint8_t, bool); 174 175 176 177}; 178 179#endif
ez_SIPO8_lib - Tutorial 3 - SIPO8 Timers (flashing LEDs)
c_cpp
Accompanying sketch for Tutorial 3 - SIPO8 Timers (flashing LEDs)
1// 2// Tutorial 3 - use of ez_SIPO8 library, 3// 1x physical SIPO, 4 and use of SIPO8 timers to control SIPO outputs with time 5// 6// Ron D Bentley, 7 Stafford, UK 8// April 2021 9// 10// This example and code is in the public 11 domain and 12// may be used without restriction and without warranty. 13// 14 15#include 16 <ez_SIPO8_lib.h> 17 18#define Max_SIPOs 1 // one virtual SIPO for this tutorial 19#define 20 Max_timers 8 // 8 timers required to map a complete 8bit SIPO 21 22// initiate 23 the class for Max SIPOs/timers required 24SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 25 26int 27 bank0_id; // used to keep the SIPO bank id 28// 29// setup pin/LED flash data 30uint8_t 31 timer; 32uint32_t timer_intervals[Max_timers] = { 33 300, 400, 500, 600, 700, 34 800, 900, 1000 // millisecond elapse timer values 35}; 36uint8_t timer_pins[Max_timers] 37 = { 38 0, 1, 2, 3, 4, 5, 6, 7 // SIPO output pin absolute addresses 39}; 40 41void 42 setup() { 43 Serial.begin(9600); 44 // create bank, params are: 45 // data 46 pin, clock pin, latch pin, number of SIPOs this bank 47 bank0_id = my_SIPOs.create_bank(8, 48 10, 9, 1); 49 if (bank0_id == create_bank_failure) { 50 Serial.println(F("\ 51failed 52 to create bank")); 53 Serial.flush(); 54 exit(0); 55 } 56 // print 57 the bank data for confirmation/inspection 58 my_SIPOs.print_SIPO_data(); 59} 60 61void 62 loop() { 63 // start by setting all SIPO outputs to low (off) 64 my_SIPOs.set_all_array_pins(LOW);// 65 set all declared virtual output pins LOW/off 66 my_SIPOs.xfer_array(LSBFIRST); 67 // move virtual pin statuses to real SIPO output pins 68 // 69 // start all 70 timers 71 for (timer = 0; timer < Max_timers; timer++) { 72 my_SIPOs.SIPO8_start_timer(timer); 73 74 } 75 timer = 0; // start checking at first timer 76 do { 77 // check each 78 timer for elapse and, if elapsed, invert the timer's output pin 79 // and reset 80 the timer 81 if (my_SIPOs.SIPO8_timer_elapsed(timer, timer_intervals[timer]) 82 == elapsed) { 83 my_SIPOs.invert_array_pin(timer_pins[timer]); // invert the 84 pin associated with this timer 85 my_SIPOs.xfer_array(MSBFIRST); // 86 update physical SIPO outputs 87 my_SIPOs.SIPO8_start_timer(timer); // 88 reset/restart the current timer 89 } 90 timer++; // move on to next timer 91 92 if (timer >= Max_timers) timer = 0; // wrap around to beginning 93 } while 94 (true); 95}
Story Board Example 2
c_cpp
Story board example 2 - strobing LEDs
1/* Ron D Bentley, Stafford, UK 2 April 2021 3 4 Example sketch 5 2 for Arduino Community story board 6 This sketch strobes a number of LEDs driven 7 by a SIPO IC, 8 output pins 8 forwards and backwards at a defined frequency. 9 10 11 This example uses relative bank addressing with pin set and invert functions. 12 13 14 Ron D Bentley, Stafford, UK 15 April 2021 16 17 This example and code 18 is in the public domain and 19 may be used without restriction and without warranty. 20 21*/ 22 23#include 24 <ez_SIPO8_lib.h> 25 26#define Max_SIPOs 1 // 1 x SIPOs - provides 8 output pins 27#define 28 Max_timers 0 // no timers required, will use delay 29 30#define data_pin 8 31#define 32 clock_pin 10 33#define latch_pin 9 34 35#define strobe_frequency 50 // 36 milli seconds, delay frequency 37 38// initiate the class for max SIPOs/timers 39 required 40SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 41 42int bank_id; // used 43 to keep the SIPO bank id 44 45void setup() { 46 Serial.begin(9600); 47 // 48 create a bank of 'Max_SIPOs' using create_bank function: 49 bank_id = my_SIPOs.create_bank(data_pin, 50 clock_pin, latch_pin, Max_SIPOs); 51 if (bank_id == create_bank_failure) { 52 53 Serial.println(F("\ 54failed to create bank, terminated")); 55 Serial.flush(); 56 57 exit(0); 58 } 59 my_SIPOs.print_SIPO_data(); // report on global SIPO8 60 params 61 // start by setting all SIPO outputs to low (off) in the SIPO bank 62 63 my_SIPOs.set_bank_SIPO(bank_id, 0, 0b00000000); // only 1 SIPO in bank,index 0 64 65 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 66} 67 68void loop() { 69 //strobe 70 example, strobe bank_id pins forward and back 71 bool msb_or_lsb = MSBFIRST; // 72 pick an initial strobe direction 73 uint8_t num_pins = Max_SIPOs * pins_per_SIPO; 74 // lots of ways to do this 75 do { 76 for (uint16_t pin = 0; pin < num_pins; 77 pin++) { 78 my_SIPOs.set_bank_pin(bank_id, pin, HIGH); // set strobe pin 79 80 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); // update physical SIPO bank 81 82 delay(strobe_frequency); 83 my_SIPOs.invert_bank_pin(bank_id, pin); 84 // invert strobe pin - alternative to set_bank_pin(low) 85 my_SIPOs.xfer_bank(bank_id, 86 msb_or_lsb); // update physical SIPO bank 87 } 88 msb_or_lsb = !msb_or_lsb; 89 // switch strobe direction 90 } while (true); 91} 92
ez_SIPO8_lib - Tutorial 5 - Bank Interleaving (Strobing LEDs)
c_cpp
Accompanying sketch for Tutorial 5 - Bank Interleaving (Strobing LEDs)
1// 2// Tutorial 5 - use of ez_SPI8 library, 3// Demonstration 4 of SIPO bank interleaving - 8 x physical SIPOs 5// each mapped to an individual 6 bank but with the same 3-wire digital 7// pin microcontroller interface. 8// 9// 10 The sketch sets up each single SIPO bank with a different binary 8bit 11// (8 12 pin) pattern which is then xferred to the physical single SIPO IC. 13// The sketch 14 mimics the strobe sketch by using bank interleaving. 15// To note is the small 16 amount of SIPO8 library code that is used. 17// 18// Ron D Bentley, Stafford, 19 UK 20// April 2021 21// 22// This example and code is in the public domain 23 and 24// may be used without restriction and without warranty. 25// 26 27#include 28 <ez_SIPO8_lib.h> 29 30int bank_id; 31 32#define Num_SIPOs 8 33#define Num_timers 34 0 35 36SIPO8 my_SIPOs(Num_SIPOs, Num_timers); // initiate the class for the 37 tutorial 38 39uint8_t bank_ids[Num_SIPOs]; // one bank_id per SIPO bank 40uint8_t 41 bank; 42 43void setup() { 44 Serial.begin(9600); 45 // create banks of 1 x 46 SIPO, all of same 3-wire interface and initialise 47 // with each strobe pattern 48 - 0b00000001, 0b00000010, 0b00000100, etc. 49 // create_bank params are: data 50 pin, clock pin, latch pin, number of SIPOs this bank 51 for (bank = 0; bank < 52 Num_SIPOs; bank++) { 53 bank_ids[bank] = my_SIPOs.create_bank(8, 10, 9, 1); 54 55 if (bank_ids[bank] == create_bank_failure) { 56 Serial.println(F("failed 57 to create bank")); 58 Serial.flush(); 59 exit(0); 60 } 61 // 62 now set up the strobe patterns in the bank's single SIPO, relative SIPO address 63 is 0 64 // sliding pattern of 1's starting at 0b00000001 65 my_SIPOs.set_bank_SIPO(bank_ids[bank], 66 0, 1 << bank); // set up this bank's strobe pattern 67 } 68 // print the bank 69 data and pin statuses for confirmation/inspection 70 my_SIPOs.print_SIPO_data(); 71 72 my_SIPOs.print_pin_statuses(); 73} 74 75void loop() { 76 // scroll through 77 every SIPO bank (interleave) and xfer the bank's pins 78 // according to the direction 79 for shift out. 80 bool msb_or_lsb = MSBFIRST; // starting direction 81 do { 82 83 for (bank = 0; bank < Num_SIPOs; bank++) { 84 my_SIPOs.xfer_bank(bank, 85 msb_or_lsb); // xfer out this bank's SIPO pins 86 delay(50); 87 } 88 89 msb_or_lsb = !msb_or_lsb; // switch direction 90 } while (true); 91}
ez_SIPO8_lib - Tutorial 1 - Setup & Absolute Pin Addressing
c_cpp
Accompanying sketch for Tutorial 1 - Setup & Absolute Pin Addressing
1// 2// Tutorial 1 - use of ez_SPI8 library 3// Setup and absolute 4 addressing. 5// 6// Ron D Bentley, Stafford, UK 7// April 2021 8// 9// 10 This example and code is in the public domain and 11// may be used without 12 restriction and without warranty. 13// 14 15#include <ez_SIPO8_lib.h> 16 17#define 18 max_SIPOs 1 // one 1 SIPO for this tutorial 19#define max_timers 0 // no timers 20 required 21 22// initiate the class for max SIPOs/timers required 23SIPO8 my_SIPOs(max_SIPOs, 24 max_timers); 25 26int my_LEDs; // used to keep the SIPO bank id 27 28void setup() 29 { 30 Serial.begin(9600); 31 // create a bank of 1 SIPO using create_bank function: 32 33 // data pin, clock pin, latch pin, number of SIPO this bank 34 my_LEDs = my_SIPOs.create_bank(8, 35 10, 9, 1); // data pin, clock pin, latch pin, number of SIPO this bank 36 if (my_LEDs 37 == create_bank_failure) { 38 Serial.println(F("\ 39failed to create bank")); 40 41 Serial.flush(); 42 exit(0); 43 } 44 // print the bank data for confirmation/inspection 45 46 my_SIPOs.print_SIPO_data(); 47} 48 49void loop() { 50 // start by setting 51 all SIPO outputs to low (off) 52 my_SIPOs.set_all_array_pins(LOW); 53 my_SIPOs.xfer_array(LSBFIRST); 54 55 do { 56 // 57 // assemble pattern 0b01010101 into the array 58 my_SIPOs.set_array_pin(0, 59 HIGH); 60 my_SIPOs.set_array_pin(1, LOW); 61 my_SIPOs.set_array_pin(2, HIGH); 62 63 my_SIPOs.set_array_pin(3, LOW); 64 my_SIPOs.set_array_pin(4, HIGH); 65 66 my_SIPOs.set_array_pin(5, LOW); 67 my_SIPOs.set_array_pin(6, HIGH); 68 69 my_SIPOs.set_array_pin(7, LOW); 70 my_SIPOs.xfer_array(MSBFIRST); // now 71 move array to physical SIPO and light up the LEDs 72 delay(500); 73 // assemble 74 inverted pattern 0b10101010 into the array 75 my_SIPOs.set_array_pin(0, LOW); 76 77 my_SIPOs.set_array_pin(1, HIGH); 78 my_SIPOs.set_array_pin(2, LOW); 79 80 my_SIPOs.set_array_pin(3, HIGH); 81 my_SIPOs.set_array_pin(4, LOW); 82 83 my_SIPOs.set_array_pin(5, HIGH); 84 my_SIPOs.set_array_pin(6, LOW); 85 86 my_SIPOs.set_array_pin(7, HIGH); 87 my_SIPOs.xfer_array(MSBFIRST); // now 88 move array to physical SIPO and light up the LEDs 89 delay(500); 90 } while 91 (true); 92}
ez_SIPO8_lib - Tutorial 2 - Relative Pin Addressing
c_cpp
Accompanying sketch for Tutorial 2 - Relative Pin Addressing
1// 2// Tutorial 2 - use of ez_SPI8 library, 3// Relative addressing 4 - 1 x physical SIPO IC 5// The sketch demonstrates two ways in which SIPO output 6 pins 7// may be updated, individually (set_bank_pin) or in a group 8// of 9 8 pins (set_bank_SIPO), representing a single 8it SIPO 10// within a bank. 11// 12// 13 Ron D Bentley, Stafford, UK 14// April 2021 15// 16// This example and 17 code is in the public domain and 18// may be used without restriction and without 19 warranty. 20// 21 22#include <ez_SIPO8_lib.h> 23 24#define Max_SIPOs 1 // 25 two virtual SIPOs for this tutorial 26#define Max_timers 0 // no timers required 27 28// 29 initiate the class for Max SIPOs/timers required 30SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 31 32int 33 bank_id; // used to keep the SIPO bank id 34 35void setup() { 36 Serial.begin(9600); 37 38 bank_id = my_SIPOs.create_bank(8, 10, 9, 1); // absolute pin addresses 0-7, relative 39 addresses 0-7 40 if (bank_id == create_bank_failure) { 41 Serial.println(F("\ 42failed 43 to create bank")); 44 Serial.flush(); 45 exit(0); 46 } 47 // print 48 the bank data for confirmation/inspection 49 my_SIPOs.print_SIPO_data(); 50} 51 52void 53 loop() { 54 // start by setting the only SIPO (0) in the bank to all outputs off/LOW 55 56 my_SIPOs.set_bank_SIPO(bank_id, 0, LOW); 57 my_SIPOs.xfer_bank(bank_id, LSBFIRST); 58 // move virtual pin statuses to real SIPO output pins 59 do { 60 // 61 62 // setup pattern for first cycle: 0b01010101 63 // note that set_bank_pin 64 uses relative addressing 65 my_SIPOs.set_bank_pin(bank_id, 0, HIGH); // least 66 significant bit/pin 67 my_SIPOs.set_bank_pin(bank_id, 1, LOW); 68 my_SIPOs.set_bank_pin(bank_id, 69 2, HIGH); 70 my_SIPOs.set_bank_pin(bank_id, 3, LOW); 71 my_SIPOs.set_bank_pin(bank_id, 72 4, HIGH); 73 my_SIPOs.set_bank_pin(bank_id, 5, LOW); 74 my_SIPOs.set_bank_pin(bank_id, 75 6, HIGH); 76 my_SIPOs.set_bank_pin(bank_id, 7, LOW); // most significant bit/pin 77 78 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 79 delay(500); 80 // 81 // 82 setup reverse pattern using 8bit write function: 0b10101010 83 // note that 84 set_bank_SIPO uses relative addressing for SIPOs in the bank 85 my_SIPOs.set_bank_SIPO(bank_id, 86 0, 0b10101010); 87 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 88 delay(500); 89 90 } while (true); 91}
ez_SIPO8_lib - Tutorial 4 - Cascaded SIPOs, Rotating LED Patterns
c_cpp
Accompanying sketch for Tutorial 4 - Cascaded SIPOs, Rotating LED Patterns
1// 2// Tutorial 4 - use of ez_SPI8 library, 3// 2 x physical SIPOs, 4 cascaded into a single SIPO bank 5// 6// Ron D Bentley, Stafford, UK 7// 8 April 2021 9// 10// This example and code is in the public domain and 11// 12 may be used without restriction and without warranty. 13// 14 15#include <ez_SIPO8_lib.h> 16 17int 18 bank_id; 19 20#define Num_SIPOs 2 21#define Num_timers 0 22 23SIPO8 my_SIPOs(Num_SIPOs, 24 Num_timers); // initiate the class for the tutorial 25 26void setup() { 27 Serial.begin(9600); 28 29 // create a single bank of required number of SIPOs in the bank, 30 // params 31 are: data pin, clock pin, latch pin, number of SIPOs this bank 32 bank_id = my_SIPOs.create_bank(8, 33 10, 9, 2); 34 if (bank_id == create_bank_failure) { 35 my_SIPOs.print_SIPO_data(); 36 37 Serial.println(F("failed to create bank")); 38 Serial.flush(); 39 exit(0); 40 41 } 42 // print the bank data for confirmation/inspection 43 my_SIPOs.print_SIPO_data(); 44} 45 46// 47 patterns to be xferred / shifted out to the SIPO bank 48#define num_patterns 7 49uint8_t 50 patterns[num_patterns] = {// starting patterns 51 0b11111111, 52 0b00001111, 53 54 0b00110011, 55 0b01010101, 56 0b11000011, 57 0b01000010, 58 0b00111100 59}; 60 61void 62 loop() { 63 // scroll through every SIPO bank and assert the given pattern to 64 every 65 // SIPO defined by the bank. 66 do { 67 // setup each pattern in 68 turn 69 for (uint8_t pattern = 0; pattern < num_patterns; pattern++) { 70 // 71 perform 2 passes for each pattern - first, as defined, second inverted 72 for 73 (uint8_t cycle = 0; cycle < 2; cycle++) { 74 // consider each SIPO in this 75 2 SIPO cascaded bank 76 for (uint8_t sipo = 0; sipo < my_SIPOs.SIPO_banks[bank_id].bank_num_SIPOs; 77 sipo++) { 78 my_SIPOs.set_bank_SIPO(bank_id, sipo, patterns[pattern]); 79 // set all pins of this SIPO in this bank_id 80 } 81 my_SIPOs.xfer_bank(bank_id, 82 MSBFIRST); // update physical SIPOs for this bank_id 83 delay(500); 84 85 patterns[pattern] = ~patterns[pattern]; // invert current pattern byte for 86 next pass 87 } 88 } 89 } while (true); 90}
ez_SIPO8_lib - User Guide - Sketch Example – Chasing LEDs, using 8 x SIPO ICs in a Single Cascade
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Chasing LEDs, using 8 x SIPO ICs in a Single Cascade, see User Guide
1// 2// Chasing LEDs - 3// This sketch illuminates a defined sequential 4 array of LEDs connected to 5// SIPO output pins, at a specified frequency (milliseconds). 6// 7 At the end of the LED sequence, the LEDs are reset and the 8// cycle repeated. 9// 10// 11 The sketch can be configured for a SIPO array of any length, but this 12// example 13 is configured to demonstrate the chasing LEDs of a clock dial. 14// In this instance 15 the SIPO array length will be 64 output pins (8 x SIPOs) 16// but only the first 17 60 outputs will be used (0-59 seconds). The frequency 18// will be set to 1 second 19 (1000 millisecs). 20// 21// This example uses absolute addressing of the defined 22 SIPO array. 23// 24// Ron D Bentley, Stafford, UK 25// April 2021 26// 27// 28 This example and code is in the public domain and 29// may be used without 30 restriction and without warranty. 31// 32 33#include <ez_SIPO8_lib.h> 34 35#define 36 Max_SIPOs 8 // 8 x SIPOs - provides 64 output pins 37#define Max_timers 1 // used 38 to count 1 second elapsing 'beats' 39 40#define data_pin 8 41#define clock_pin 42 10 43#define latch_pin 9 44 45#define chase_length 60 // chasing seconds 46 on a clock 47#define frequency 1000 // milli seconds - 1 second frequency 48 49// 50 initiate the class for max SIPOs/timers required 51SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 52 53int 54 my_LEDs; // used to keep the SIPO bank id 55 56void setup() { 57 Serial.begin(9600); 58 59 // create a bank of 'Max_SIPOs' using create_bank function: 60 my_LEDs = my_SIPOs.create_bank(data_pin, 61 clock_pin, latch_pin, Max_SIPOs); 62 if (my_LEDs == create_bank_failure) { 63 64 Serial.println(F("\ 65failed to create bank")); 66 Serial.flush(); 67 68 exit(0); 69 } 70 // start by setting all SIPO outputs to low (off) 71 my_SIPOs.set_all_array_pins(LOW); 72 73 my_SIPOs.xfer_array(MSBFIRST); 74 // print the bank data for confirmation/inspection 75 76 my_SIPOs.print_SIPO_data(); 77} 78 79void loop() { 80 uint8_t next_pin = 81 0; 82 my_SIPOs.SIPO8_start_timer(timer0); // kick off the timer 83 do { 84 85 if (my_SIPOs.SIPO8_timer_elapsed(timer0, frequency) == elapsed) { 86 // 87 1 second time elapsed, so update next pin in the array 88 my_SIPOs.SIPO8_start_timer(timer0); 89 // restart 1 second count for next cycle 90 if (next_pin == chase_length) 91 { // wrap around 92 my_SIPOs.set_all_array_pins(LOW); // clear all pins 93 94 next_pin = 0; 95 } else { 96 my_SIPOs.set_array_pin(next_pin, 97 HIGH); // set absolute next_pin pin status 98 next_pin++; 99 } 100 101 my_SIPOs.xfer_array(MSBFIRST); // update physical SIPOs 102 } 103 } while 104 (true); 105}
SIPO8 library header file, ez_SIPO8.h
c_cpp
SIPO8 library header file, ez_SIPO8.h
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 SIPO8 v1-00 5 6 Serial/Parallel IC (SIPO) library supporting banking of multiple SIPOs 7 of same/different bit sizes. 8 Supports maximum of up to 255 8bit SIPOs (2040 individual output pins) 9 and up to 255 indivual timers. 10 11 This example and code is in the public domain and 12 may be used without restriction and without warranty. 13 14*/ 15 16#ifndef SIPO8_h 17#define SIPO8_h 18 19#include <Arduino.h> // always include this lib otherwise wont compile! 20 21class SIPO8 22{ 23 public: 24 25 26#define pins_per_SIPO 8 // global 'set in stone' macro for a base SIPO unit 27 28 // failure macros... 29#define create_bank_failure -1 30#define pin_read_failure -1 31#define pin_invert_failure -1 32#define pin_set_failure -1 33#define bank_not_found -1 34#define SIPO_not_found -2 35 36 // timer macros... 37#define timer0 0 38#define timer1 1 39#define timer2 2 40#define timer3 3 41#define timer4 4 42#define timer5 5 43#define timer6 6 44#define timer7 7 45#define elapsed true 46#define not_elapsed !elapsed 47#define active true 48#define not_active !active 49 50 uint16_t max_pins = 0; // user accessible params 51 uint16_t num_active_pins = 0; // ... 52 uint8_t num_pin_status_bytes = 0; // ... 53 uint8_t num_banks = 0; // ... 54 uint8_t max_SIPOs = 0; // ... 55 uint8_t bank_SIPO_count = 0; // ... 56 uint8_t max_timers = 0; // ... 57 58 struct SIPO_control { 59 uint8_t bank_data_pin; 60 uint8_t bank_clock_pin; 61 uint8_t bank_latch_pin; 62 uint8_t bank_num_SIPOs; 63 uint16_t bank_low_pin; 64 uint16_t bank_high_pin; 65 }*SIPO_banks; 66 67 uint8_t * pin_status_bytes; // records current status of each pin 68 69 // timer control struct(ure) 70 struct timer_control { 71 bool timer_status; // records status of a timer - active or not active 72 uint32_t start_time; // records the millis time when a timer is started 73 } *timers; 74 75 // ******* function declarations.... 76 77 SIPO8(uint8_t, uint8_t); // constructor function called when class is initiated 78 79 int create_bank(uint8_t, uint8_t, uint8_t, uint8_t); 80 void set_all_array_pins(bool); 81 void invert_all_array_pins(); 82 int set_array_pin(uint16_t, bool); 83 int invert_array_pin(uint16_t); 84 int read_array_pin(uint16_t); 85 86 void set_banks(uint8_t, uint8_t, bool); 87 void set_banks(bool); 88 void set_bank(uint8_t, bool); 89 void invert_banks(); 90 void invert_banks(uint8_t, uint8_t); 91 void invert_bank(uint8_t); 92 93 int set_bank_SIPO(uint8_t, uint8_t, uint8_t); 94 int invert_bank_SIPO(uint8_t, uint8_t); 95 int read_bank_SIPO(uint8_t, uint8_t); 96 97 int set_bank_pin(uint8_t, uint8_t, bool); 98 int invert_bank_pin(uint8_t, uint8_t); 99 int read_bank_pin(uint8_t, uint8_t); 100 101 int get_bank_from_pin(uint16_t); 102 int num_pins_in_bank(uint8_t); 103 104 void xfer_banks(uint8_t, uint8_t, bool); 105 void xfer_banks(bool); 106 void xfer_bank(uint8_t, bool); 107 void xfer_array(bool); 108 109 void print_pin_statuses(); 110 void print_SIPO_data(); 111 112 void SIPO8_start_timer(uint8_t); 113 void SIPO8_stop_timer(uint8_t); 114 bool SIPO8_timer_elapsed(uint8_t, uint32_t); 115 116 // ****** private declarations..... 117 private: 118 uint16_t _max_pins = 0; 119 uint16_t _num_active_pins = 0; 120 uint8_t _num_pin_status_bytes = 0; 121 uint8_t _max_SIPOs = 0; 122 uint8_t _bank_SIPO_count = 0; 123 uint8_t _next_bank = 0; 124 uint8_t _max_timers = 0; 125 126 void SIPO_lib_exit(uint8_t); 127 void shift_out_bank(uint8_t, uint8_t, uint8_t, bool); 128 129 130 131}; 132 133#endif
ez_SIPO8_lib - Tutorial 3 - SIPO8 Timers (flashing LEDs)
c_cpp
Accompanying sketch for Tutorial 3 - SIPO8 Timers (flashing LEDs)
1// 2// Tutorial 3 - use of ez_SIPO8 library, 3// 1x physical SIPO, and use of SIPO8 timers to control SIPO outputs with time 4// 5// Ron D Bentley, Stafford, UK 6// April 2021 7// 8// This example and code is in the public domain and 9// may be used without restriction and without warranty. 10// 11 12#include <ez_SIPO8_lib.h> 13 14#define Max_SIPOs 1 // one virtual SIPO for this tutorial 15#define Max_timers 8 // 8 timers required to map a complete 8bit SIPO 16 17// initiate the class for Max SIPOs/timers required 18SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 19 20int bank0_id; // used to keep the SIPO bank id 21// 22// setup pin/LED flash data 23uint8_t timer; 24uint32_t timer_intervals[Max_timers] = { 25 300, 400, 500, 600, 700, 800, 900, 1000 // millisecond elapse timer values 26}; 27uint8_t timer_pins[Max_timers] = { 28 0, 1, 2, 3, 4, 5, 6, 7 // SIPO output pin absolute addresses 29}; 30 31void setup() { 32 Serial.begin(9600); 33 // create bank, params are: 34 // data pin, clock pin, latch pin, number of SIPOs this bank 35 bank0_id = my_SIPOs.create_bank(8, 10, 9, 1); 36 if (bank0_id == create_bank_failure) { 37 Serial.println(F("\ 38failed to create bank")); 39 Serial.flush(); 40 exit(0); 41 } 42 // print the bank data for confirmation/inspection 43 my_SIPOs.print_SIPO_data(); 44} 45 46void loop() { 47 // start by setting all SIPO outputs to low (off) 48 my_SIPOs.set_all_array_pins(LOW);// set all declared virtual output pins LOW/off 49 my_SIPOs.xfer_array(LSBFIRST); // move virtual pin statuses to real SIPO output pins 50 // 51 // start all timers 52 for (timer = 0; timer < Max_timers; timer++) { 53 my_SIPOs.SIPO8_start_timer(timer); 54 } 55 timer = 0; // start checking at first timer 56 do { 57 // check each timer for elapse and, if elapsed, invert the timer's output pin 58 // and reset the timer 59 if (my_SIPOs.SIPO8_timer_elapsed(timer, timer_intervals[timer]) == elapsed) { 60 my_SIPOs.invert_array_pin(timer_pins[timer]); // invert the pin associated with this timer 61 my_SIPOs.xfer_array(MSBFIRST); // update physical SIPO outputs 62 my_SIPOs.SIPO8_start_timer(timer); // reset/restart the current timer 63 } 64 timer++; // move on to next timer 65 if (timer >= Max_timers) timer = 0; // wrap around to beginning 66 } while (true); 67}
SIPO8 library cpp file, ez_SIPO8.cpp
c_cpp
SIPO8 library cpp file, ez_SIPO8.cpp
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 SIPO8 v1-00 5 6 Serial/Parallel IC (SIPO) library supporting banking of multiple SIPOs 7 of same/different bit sizes. 8 Supports maximum of up to 255 8bit SIPOs (2040 individual output pins) 9 and up to 255 indivual timers. 10 11 This example and code is in the public domain and 12 may be used without restriction and without warranty. 13 14*/ 15 16 17#include <Arduino.h> 18#include <ez_SIPO8_lib.h> 19 20// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21// This function will be called when the class is initiated. 22// The parameter is the maximum number of SIPOs that will be configured 23// in the sketch. 24// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 25SIPO8::SIPO8(uint8_t max_SIPO_ICs, uint8_t Max_timers ) { 26 // Setup the SIPO_banks control data struture sized for the maximum number of 27 // SIPO banks that could be defined 28 SIPO_banks = (SIPO_control *) malloc(sizeof(SIPO_control) * max_SIPO_ICs); 29 if (SIPO_banks == NULL) { 30 SIPO_lib_exit(0); 31 } 32 // Determine how may pin_status_bytes of 'pins_per_SIPO' bit length are 33 // needed to map the number of bank SIPOs defined 34 _max_pins = max_SIPO_ICs * pins_per_SIPO; 35 max_pins = _max_pins; 36 _num_pin_status_bytes = max_SIPO_ICs; 37 num_pin_status_bytes = _num_pin_status_bytes; 38 pin_status_bytes = (uint8_t *) malloc(sizeof(pin_status_bytes) * _num_pin_status_bytes); // 1 byte per 8-bit SIPO 39 if (pin_status_bytes == NULL) { 40 SIPO_lib_exit(1); 41 } 42 // clear down pin_status_bytes to LOW (0) 43 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 44 pin_status_bytes[pin_status_byte] = 0; 45 } 46 // create timer struct(ure) of required size 47 if (Max_timers > 0){ 48 timers = (timer_control *) malloc(sizeof(timer_control) * Max_timers); 49 if (timers == NULL) { 50 SIPO_lib_exit(2); 51 } 52 } 53 _max_timers = Max_timers; 54 max_timers = Max_timers; 55 // initialise other working variables, private and user accessible 56 for (uint8_t timer = 0; timer < max_timers; timer++) { 57 timers[timer].timer_status = not_active; 58 timers[timer].start_time = 0; // elapsed time 59 } 60 _num_active_pins = 0; // no pins yet declared 61 num_active_pins = 0; 62 _max_SIPOs = max_SIPO_ICs; 63 max_SIPOs = _max_SIPOs; 64 _bank_SIPO_count = 0; 65 bank_SIPO_count = 0; 66 _next_bank = 0; 67 num_banks = 0; 68} 69 70// 71// General error reporting routine with termination 72// 73void SIPO8::SIPO_lib_exit(uint8_t reason) { 74 Serial.begin(9600); 75 switch (reason) { 76 case 0: 77 Serial.println(F("Exit:out of memory for setup-SIPO banks")); 78 break; 79 case 1: 80 Serial.println(F("Exit:out of memory for setup-status bytes")); 81 break; 82 case 2: 83 Serial.println(F("Exit:out of memory for setup-timers")); 84 break; 85 default: 86 Serial.println(F("Exit:unspecified")); 87 break; 88 } 89 Serial.flush(); 90 exit(reason); 91} 92 93// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94// The function will try to create a bank of SIPOs if possible. The create process 95// will fail if the more SIPOs for a bank are requested than remain unallocated. 96// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 97int SIPO8::create_bank(uint8_t data_pin, uint8_t clock_pin, uint8_t latch_pin, 98 uint8_t num_SIPOs) { 99 if (_bank_SIPO_count + num_SIPOs <= _max_SIPOs && num_SIPOs > 0) { 100 // still enough free SIPOs available to assign to a new bank 101 pinMode(data_pin, OUTPUT); 102 digitalWrite(data_pin, LOW); 103 pinMode(clock_pin, OUTPUT); 104 digitalWrite(clock_pin, LOW); 105 pinMode(latch_pin, OUTPUT); 106 digitalWrite(latch_pin, LOW); 107 SIPO_banks[_next_bank].bank_data_pin = data_pin; 108 SIPO_banks[_next_bank].bank_clock_pin = clock_pin; 109 SIPO_banks[_next_bank].bank_latch_pin = latch_pin; 110 SIPO_banks[_next_bank].bank_num_SIPOs = num_SIPOs; 111 SIPO_banks[_next_bank].bank_low_pin = _num_active_pins; 112 uint16_t num_pins_this_bank = num_SIPOs * pins_per_SIPO; 113 SIPO_banks[_next_bank].bank_high_pin = _num_active_pins + num_pins_this_bank - 1;// inclusive pin numbers 114 _num_active_pins = _num_active_pins + num_pins_this_bank; 115 num_active_pins = _num_active_pins; 116 _bank_SIPO_count = _bank_SIPO_count + num_SIPOs; 117 bank_SIPO_count = _bank_SIPO_count; 118 _next_bank++; // next bank struct(ure) entry 119 num_banks = _next_bank; // user accessible number of banks defined 120 return _next_bank - 1; // return the bank number of this bank in the SIPOs struct(ure) 121 } 122 return create_bank_failure; // cannot provide number of SIPOs asked for, for this bank request 123} 124 125// 126// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 127// Function will set the entire array of pins to the given status value. Note that 128// this function operates on an entire array basis rather than bank by bank. 129// The parameter pin_status should be HIGH or LOW 130// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 131void SIPO8::set_all_array_pins(bool pin_status) { 132 uint8_t mask = pin_status * 255; // either 0 (all pins set low), or 255 (all pins set high) 133 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 134 pin_status_bytes[pin_status_byte] = mask; 135 } 136} 137 138// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 139// Function will invert the status of each pin the the array. Note that 140// this function operates on an entire array basis rather than bank by bank. 141// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 142void SIPO8::invert_all_array_pins() { 143 for (uint8_t pin_status_byte = 0; pin_status_byte < _num_pin_status_bytes; pin_status_byte++) { 144 pin_status_bytes[pin_status_byte] = ~pin_status_bytes[pin_status_byte]; 145 } 146} 147 148// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 149// Function sets the given pin (absolute pin reference) to the given status value. 150// The success or otherwise of the process may be tested by the calling code using 151// the return function value. 152// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 153int SIPO8::set_array_pin(uint16_t pin, bool pin_status) { 154 if (pin < _num_active_pins) { 155 // pin is in the defined pin range 156 uint8_t pin_status_byte = pin / pins_per_SIPO; 157 uint8_t pin_bit = pin % pins_per_SIPO; 158 bitWrite(pin_status_bytes[pin_status_byte], pin_bit, pin_status); 159 return pin; 160 } 161 return pin_set_failure; 162} 163 164// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 165// Function inverts the existing pin status. Note that pin is given as an absolute 166// pin reference. 167// The success or otherwise of the process may be tested by the calling code using 168// the return function value. 169// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 170int SIPO8::invert_array_pin(uint16_t pin) { 171 if (pin < _num_active_pins) { 172 // pin is in the defined pin range 173 uint8_t pin_status_byte = pin / pins_per_SIPO; 174 uint8_t pin_bit = pin % pins_per_SIPO; 175 bool inverted_status = !bitRead(pin_status_bytes[pin_status_byte], pin_bit); 176 bitWrite(pin_status_bytes[pin_status_byte], 177 pin_bit, 178 inverted_status); 179 return inverted_status; // high or low status 180 } 181 return pin_invert_failure; 182} 183 184// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 185// Funcion will read the status value of the specified pin and return to the calling 186// code. Note that pin is given as an absolute pin reference. 187// The success or otherwise of the process may be tested by the calling code using 188// the return function value. 189// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 190int SIPO8::read_array_pin(uint16_t pin) { 191 if (pin < _num_active_pins) { 192 // pin is in the defined pin range 193 uint8_t pin_status_byte = pin / pins_per_SIPO; 194 uint8_t pin_bit = pin % pins_per_SIPO; 195 return bitRead(pin_status_bytes[pin_status_byte], pin_bit); // high or low status 196 } 197 return pin_read_failure; 198} 199 200// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 201// Function is equivalent to the set_all_array_pins function and is prvided as an 202// alternative choice. 203// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 204void SIPO8::set_banks(bool pin_status) { 205 set_all_array_pins(pin_status); 206} 207 208// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 209// Function will set every pin in each bank, from_bank - to_bank, to the 210// specified pin status. 211// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 212void SIPO8::set_banks(uint8_t from_bank, uint8_t to_bank, bool pin_status) { 213 if (from_bank <= to_bank && to_bank < _next_bank) { 214 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 215 set_bank(bank, pin_status); 216 } 217 } 218} 219 220// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221// Function will set every pin in given bank to the specified pin status. 222// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223void SIPO8::set_bank(uint8_t bank, bool pin_status) { 224 if (bank < _next_bank) { 225 // start with the first pin of the first SIPO in the bank 226 uint16_t first_pin = SIPO_banks[bank].bank_low_pin; // first pin in this bank 227 uint8_t mask = pin_status * 255; // either 0 (all pins set low), or 255 (all pins set high) 228 // determine the first pin status byte for the first pin in the bank 229 uint8_t pin_status_byte = first_pin / pins_per_SIPO; 230 // now deal with each SIPO declared in the bank, setting the 231 // associated pin status bytes accordingly 232 for (uint8_t SIPO = 0; SIPO < SIPO_banks[bank].bank_num_SIPOs; SIPO++) { 233 pin_status_bytes[pin_status_byte + SIPO] = mask; // reset all pin bits 234 } 235 } 236} 237 238// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 239// Function is equivalent to the invert_all_array_pins function and is prvided as an 240// alternative choice. 241// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 242void SIPO8::invert_banks() { 243 invert_all_array_pins(); 244} 245 246// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 247// Function will invert the existing pin status of every pin in the specified banks. 248// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 249void SIPO8::invert_banks(uint8_t from_bank, uint8_t to_bank) { 250 if (from_bank <= to_bank && to_bank < _next_bank) { 251 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 252 invert_bank(bank); 253 } 254 } 255} 256 257// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 258// Function will invert the existing pin status of every pin in the specified bank. 259// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 260void SIPO8::invert_bank(uint8_t bank) { 261 if (bank < _next_bank) { 262 // start with the first pin of the first SIPO in the bank 263 uint16_t first_pin = SIPO_banks[bank].bank_low_pin; // first pin in this bank 264 // determine the first pin status byte for the first pin in the bank 265 uint8_t pin_status_byte = first_pin / pins_per_SIPO; 266 // now deal with each SIPO declared in the bank, setting the 267 // associated pin status bytes accordingly 268 for (uint8_t SIPO = 0; SIPO < SIPO_banks[bank].bank_num_SIPOs; SIPO++) { 269 pin_status_bytes[pin_status_byte + SIPO] = 270 ~pin_status_bytes[pin_status_byte + SIPO]; // invert the status byte bits 271 } 272 } 273} 274 275// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 276// Function for setting specific pin within a given bank. 277// Note that these functions operate relative to the pins defined 278// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 279// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 280int SIPO8::set_bank_pin(uint8_t bank, uint8_t pin, bool pin_status) { 281 if (bank < _next_bank) { 282 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 283 return set_array_pin(pin, pin_status); // returns failure or the absolute pin muber if successful 284 } 285 return pin_set_failure; 286} 287 288// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 289// Function for inverting specific existing pin status within a given bank. 290// Note that these functions operate relative to the pins defined 291// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 292// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 293int SIPO8::invert_bank_pin(uint8_t bank, uint8_t pin) { 294 if (bank < _next_bank) { 295 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 296 return invert_array_pin(pin); // returns failure or the new status of the pin if successful 297 } 298 return pin_invert_failure; 299} 300 301// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 302// Function will read the given pin's status and return its value to the calling code. 303// Note that these functions operate relative to the pins defined 304// in a bank - set_bank_pin, invert_bank_pin, read_bank_pin. 305// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 306int SIPO8::read_bank_pin(uint8_t bank, uint8_t pin) { 307 if (bank < _next_bank) { 308 pin = pin + SIPO_banks[bank].bank_low_pin; // absolute pin number in the array 309 return read_array_pin(pin); // returns failure or the pin status if successful 310 } 311 return pin_read_failure; 312} 313 314// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315// Function will set the given bank SIPO (8bits) to the secified value 316// Note that this functions operate relative to the SIPOs/pins defined 317// in a bank. 318// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 319int SIPO8::set_bank_SIPO(uint8_t bank, uint8_t SIPO_num, uint8_t SIPO_value) { 320 if (bank < _next_bank) { 321 // bank is valid 322 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 323 if (SIPO_num < SIPOs_this_bank) { 324 // specified SIPO number is valid for this bank 325 // now determine the pin_staus_byte entry for the SIPO 326 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 327 status_byte = status_byte + SIPO_num; // actual status byte to be set 328 pin_status_bytes[status_byte] = SIPO_value;// set required status byte 329 return status_byte; 330 } 331 return SIPO_not_found; 332 } 333 return bank_not_found; 334} 335 336// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 337// Function will invert the current contents of the given bank SIPO (8bits) to the 338// secified value. 339// Note that this functions operate relative to the SIPOs/pins defined 340// in a bank. 341// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 342int SIPO8::invert_bank_SIPO(uint8_t bank, uint8_t SIPO_num) { 343 if (bank < _next_bank) { 344 // bank is valid 345 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 346 if (SIPO_num < SIPOs_this_bank) { 347 // specified SIPO number is valid for this bank 348 // now determine the pin_staus_byte entry for the SIPO 349 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 350 status_byte = status_byte + SIPO_num; // actual status byte to be inverted 351 pin_status_bytes[status_byte] = ~pin_status_bytes[status_byte]; // invert current contents 352 return status_byte; 353 } 354 return SIPO_not_found; 355 } 356 return bank_not_found; 357} 358 359// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 360// Function will read the current contents of the given bank SIPO (8bits) and return 361// the 8bit status value for the SIPO. 362// Note that this functions operate relative to the SIPOs/pins defined 363// in a bank. 364// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 365int SIPO8::read_bank_SIPO(uint8_t bank, uint8_t SIPO_num) { 366 if (bank < _next_bank) { 367 // bank is valid 368 uint8_t SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 369 if (SIPO_num < SIPOs_this_bank) { 370 // specified SIPO number is valid for this bank 371 // now determine the pin_staus_byte entry for the SIPO 372 uint8_t status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO;// first status byte for this bank 373 status_byte = status_byte + SIPO_num; // actual status byte to be read 374 return pin_status_bytes[status_byte]; 375 } 376 return SIPO_not_found; 377 } 378 return bank_not_found; 379} 380 381// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 382// Given an absolute array pin number, the function determines which 383// bank it resides within and returns the bank number. 384// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 385int SIPO8::get_bank_from_pin(uint16_t pin) { 386 if (pin < _num_active_pins) { 387 for (uint8_t bank = 0; bank < _next_bank; bank++) { 388 if (SIPO_banks[bank].bank_low_pin <= pin && 389 pin <= SIPO_banks[bank].bank_high_pin)return bank; 390 } 391 } 392 return bank_not_found; 393} 394 395// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 396// Determines the number of pins in the given bank 397// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 398int SIPO8::num_pins_in_bank(uint8_t bank) { 399 if (bank < _next_bank) { 400 // valid bank, so return number of pins in this bank 401 return SIPO_banks[bank].bank_num_SIPOs * pins_per_SIPO; 402 } 403 return bank_not_found; 404} 405 406 407// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 408// Selective transfer of array pin satuses based on bank transfers, 409// rather than the entire array of banks. 410// Transfers specified banks' pin statuses to the hardware SIPOs, 411// starting with from_bank and continuing to to_bank. 412// The direction of transfer is determined by the msb_or_lsb parameter 413// which must be either LSBFIRST or MSBFIRST. 414// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 415void SIPO8::xfer_banks(uint8_t from_bank, uint8_t to_bank, bool msb_or_lsb) { 416 if (from_bank <= to_bank && to_bank < _next_bank) { 417 // examine each bank in turn and deal with as many SIPOs as 418 // are configured in each bank 419 for (uint8_t bank = from_bank; bank <= to_bank; bank++) { 420 uint16_t low_pin = SIPO_banks[bank].bank_low_pin; // start pin number for this bank 421 uint16_t high_pin = SIPO_banks[bank].bank_high_pin; // end inclusive pin number for this bank 422 uint8_t latch_pin = SIPO_banks[bank].bank_latch_pin; 423 uint8_t clock_pin = SIPO_banks[bank].bank_clock_pin; 424 uint8_t data_pin = SIPO_banks[bank].bank_data_pin; 425 uint8_t num_SIPOs_this_bank = SIPO_banks[bank].bank_num_SIPOs; 426 uint8_t SIPO_first_status_byte = SIPO_banks[bank].bank_low_pin / pins_per_SIPO; 427 uint8_t SIPO_last_status_byte = SIPO_banks[bank].bank_high_pin / pins_per_SIPO; 428 uint8_t SIPO_status_byte = 0; 429 digitalWrite(latch_pin, LOW); // tell IC data transfer to start 430 for (uint8_t SIPO = 0; SIPO < num_SIPOs_this_bank; SIPO++) { 431 if (msb_or_lsb == LSBFIRST) { 432 SIPO_status_byte = SIPO_first_status_byte + SIPO; 433 } else { 434 SIPO_status_byte = SIPO_last_status_byte - SIPO; 435 } 436 shift_out_bank(data_pin, clock_pin, pin_status_bytes[SIPO_status_byte], msb_or_lsb); 437 } 438 digitalWrite(latch_pin, HIGH); // tell IC data transfer is finished 439 } 440 } 441} 442 443// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 444// Equivalent to xfer_array, and transfers all array pin statuses to the 445// the hardware SIPOs. Provided as an alternative method. 446// The direction of transfer is determined by the msb_or_lsb parameter 447// which must be either LSBFIRST or MSBFIRST. 448// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 449void SIPO8::xfer_banks(bool msb_or_lsb) { 450 if (_next_bank > 0) { 451 xfer_banks(0, _next_bank - 1, msb_or_lsb); 452 } 453} 454 455// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 456// Specific transfer of the given bank pin statuses to the bank's associated 457// hardware SIPOs. The direction of transfer is determined by the msb_or_lsb 458// parameter which must be either LSBFIRST or MSBFIRST. 459// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 460void SIPO8::xfer_bank(uint8_t bank, bool msb_or_lsb) { 461 if (_next_bank > 0) { 462 xfer_banks(bank, bank, msb_or_lsb); 463 } 464} 465 466// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 467// Transfers all array pin statuses to the hardware SIPOs. 468// The direction of transfer is determined by the msb_or_lsb parameter 469// which must be either LSBFIRST or MSBFIRST. 470// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 471void SIPO8::xfer_array(bool msb_or_lsb) { 472 xfer_banks(msb_or_lsb); 473} 474 475// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 476// Based on the standard Arduino shiftout function. 477// Moves out the given set of pin statuses, status_bits, to the specified SIPO. 478// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 479void SIPO8::shift_out_bank(uint8_t data_pin, uint8_t clock_pin, uint8_t status_bits, bool msb_or_lsb) 480{ // Shuffle each bit of the val parameter (0 or 1) one bit left 481 // until all bits written out. 482 for (uint8_t i = 0; i < pins_per_SIPO; i++) { 483 if (msb_or_lsb == LSBFIRST) { 484 digitalWrite(data_pin, !!(status_bits & (1 << i))); 485 } 486 else 487 { 488 digitalWrite(data_pin, !!(status_bits & (1 << (7 - i)))); 489 } 490 digitalWrite(clock_pin, HIGH); 491 digitalWrite(clock_pin, LOW); 492 } 493} 494 495// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 496// Function is provided to assist end user to provide debug data during development. 497// Prints all active pin status bytes, in bit form, starting with pin 0 and 498// progressing to the last active end pin defined. 499// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 500void SIPO8::print_pin_statuses() { 501 if (_next_bank > 0) { 502 Serial.println(F("\ 503Active pin array, pin statuses:")); 504 // there is at least 1 bank 505 uint8_t SIPO_count = 0; 506 for (uint8_t bank = 0; bank < _next_bank; bank++) { 507 Serial.print(F("Bank ")); 508 if (bank < 10)Serial.print(F(" ")); 509 Serial.print(bank); 510 Serial.print(F(": MS")); 511 uint8_t start_byte = SIPO_count; 512 uint8_t last_byte = start_byte + SIPO_banks[bank].bank_num_SIPOs - 1; 513 SIPO_count = SIPO_count + SIPO_banks[bank].bank_num_SIPOs; 514 for (int16_t next_byte = last_byte; next_byte >= start_byte; next_byte--) { 515 uint8_t SIPO_status = pin_status_bytes[next_byte]; 516 for (int pos = 7; pos >= 0; pos--) { 517 uint8_t pin_status = bitRead(SIPO_status, pos); 518 Serial.print(pin_status); 519 } 520 } 521 Serial.println(F("LS")); 522 } 523 } else { 524 Serial.println(F("\ 525No banks defined")); 526 } 527 Serial.flush(); 528} 529 530// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 531// Function is provided to assist end user to display debug data during development. 532// Prints all setup data as a confirmation that the end user has correctly configured 533// all key data. 534// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 535void SIPO8::print_SIPO_data() { 536 Serial.println(F("\ 537SIPO global values:")); 538 Serial.print(F("pins_per_SIPO = ")); 539 Serial.println(pins_per_SIPO); 540 Serial.print(F("max_SIPOs = ")); 541 Serial.println(_max_SIPOs); 542 Serial.print(F("bank_SIPO_count = ")); 543 Serial.println(_bank_SIPO_count); 544 Serial.print(F("num_active_pins = ")); 545 Serial.println(_num_active_pins); 546 Serial.print(F("num_pin_status_bytes = ")); 547 Serial.println(_num_pin_status_bytes); 548 Serial.print(F("next_free bank = ")); 549 if (_bank_SIPO_count < _max_SIPOs) { 550 Serial.print(_next_bank); 551 Serial.println(); 552 } else { 553 Serial.println(F(" all SIPOs used")); 554 } 555 Serial.print("Number timers = "); 556 Serial.println(_max_timers); 557 Serial.println(F("\ 558Bank data:")); 559 for (uint8_t bank = 0; bank < _next_bank; bank++) { 560 // still SIPOs available to assign to a new bank 561 Serial.print(F("bank = ")); 562 Serial.println(bank); 563 Serial.print(F(" num SIPOs =\ ")); 564 Serial.println(SIPO_banks[bank].bank_num_SIPOs); 565 Serial.print(F(" latch_pin =\ ")); 566 Serial.print(SIPO_banks[bank].bank_latch_pin); 567 Serial.print(F(" clock_pin =\ ")); 568 Serial.print(SIPO_banks[bank].bank_clock_pin); 569 Serial.print(F(" data_pin =\ ")); 570 Serial.println(SIPO_banks[bank].bank_data_pin); 571 Serial.print(F(" low_pin =\ ")); 572 Serial.print(SIPO_banks[bank].bank_low_pin); 573 Serial.print(F(" high_pin =\ ")); 574 Serial.println(SIPO_banks[bank].bank_high_pin); 575 } 576 Serial.flush(); 577} 578 579// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 580// Function sets the given timer as active and records the start time. 581// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 582void SIPO8::SIPO8_start_timer(uint8_t timer) { 583 if (timer < _max_timers) { 584 timers[timer].timer_status = active; 585 timers[timer].start_time = millis(); 586 } 587} 588 589// 590// Function cancels the given timer. 591// 592void SIPO8::SIPO8_stop_timer(uint8_t timer) { 593 if (timer < _max_timers) { 594 timers[timer].timer_status = not_active; 595 } 596} 597 598// 599// Function determines if the time has elapsed for the given timer, if active. 600// 601bool SIPO8::SIPO8_timer_elapsed(uint8_t timer, uint32_t elapsed_time) { 602 if (timer < _max_timers) { 603 if (timers[timer].timer_status == active) { 604 if (millis() - timers[timer].start_time >= elapsed_time) { 605 timers[timer].timer_status = not_active; // mark this timer no longer active 606 return elapsed; 607 } 608 } 609 } 610 return not_elapsed; 611}
ez_SIPO8_lib - User Guide - Sketch Example – Strobing LEDs, Relative Pin Addressing
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Strobing LEDs, Relative Pin Addressing, see User Guide
1// 2// Strobe - 3// This sketch strobes a number of LEDs driven by a SIPO IC, 8 output pins 4// forwards and backwards at a defined frequency. 5// 6// This example uses relative bank addressing. 7// 8// Ron D Bentley, Stafford, UK 9// April 2021 10// 11// This example and code is in the public domain and 12// may be used without restriction and without warranty. 13// 14 15#include <ez_SIPO8_lib.h> 16 17#define Max_SIPOs 1 // 1 x SIPOs - provides 8 output pins 18#define Max_timers 0 // no timers required, will use delay 19 20#define data_pin 8 21#define clock_pin 10 22#define latch_pin 9 23 24#define strobe_frequency 50 // milli seconds, delay frequency 25 26// initiate the class for max SIPOs/timers required 27SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 28 29int bank_id; // used to keep the SIPO bank id 30 31void setup() { 32 Serial.begin(9600); 33 // create a bank of 'Max_SIPOs' using create_bank function: 34 bank_id = my_SIPOs.create_bank(data_pin, clock_pin, latch_pin, Max_SIPOs); 35 if (bank_id == create_bank_failure) { 36 Serial.println(F("\ 37failed to create bank, terminated")); 38 Serial.flush(); 39 exit(0); 40 } 41 // start by setting all SIPO outputs to low (off) in the SIPO bank 42 my_SIPOs.set_bank_SIPO(bank_id, 0, 0b00000000); // only 1 SIPO in bank,index 0 43 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 44 // print the bank data for confirmation/inspection 45 my_SIPOs.print_SIPO_data(); 46} 47 48void loop() { 49 //strobe example, strobe bank_id pins forward and back 50 bool msb_or_lsb = MSBFIRST; // pick an initial strobe direction 51 int pins_in_bank = my_SIPOs.num_pins_in_bank(bank_id); // number SIPO output pins in this bank 52 if (pins_in_bank > 0) { 53 do { 54 for (uint16_t pin = 0; pin < pins_in_bank; pin++) { 55 my_SIPOs.set_bank_pin(bank_id, pin, HIGH); // set next strobe pin 56 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); // update physical SIPO bank 57 delay(strobe_frequency); 58 my_SIPOs.set_bank_pin(bank_id, pin, LOW); // clear next strobe pin 59 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); // update physical SIPO bank 60 } 61 msb_or_lsb = !msb_or_lsb; // switch strobe direction 62 } while (true); 63 } else { 64 Serial.println(F("\ 65bank not found, terminated")); 66 Serial.flush(); 67 exit(0); 68 } 69}
Story Board Example 1
c_cpp
Story board example 1 - toggle switches status display
1/* 2 Ron D Bentley, Stafford, UK 3 April 2021 4 5 Example sketch 1 for Arduino Community story board 6 The sketch reads a number of toggle switches which are in one of two 7 states - on(HIGH) or off(LOW). 8 Each switch is mapped to a SIPO bank pin as follows: 9 switches 0-5 -> bank pins 0-5 10 bank pin 6 is not used 11 bank pin 7 is used as a sketch running indicator, 12 or 'heart beat' 13 14 Note that the switches are 'read' periodically sampled by a dummy 15 function using the SIPO8 timers feature. The code is non-blocking. 16 17 This example and code is in the public domain and 18 may be used without restriction and without warranty. 19 20*/ 21 22#include <ez_SIPO8_lib.h> 23 24#define Max_SIPOs 1 25#define Max_timers 1 26#define sample_time 500 // interval period between sampling sensors 27#define num_switches 6 // number of sensors requiring testing/reading in each cycle 28 29// initiate the class for max SIPOs/timers required 30SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 31 32uint8_t bank_id; 33 34// dummy read switch function - returns a random staus for given switch 35// number, based on switch's current status 36bool read_switch_status(uint8_t Switch) { 37 randomSeed(analogRead(A0)*analogRead(A2)); // keep changing seed 38 if (random(0, 4) == 0)return !my_SIPOs.read_bank_pin(bank_id, Switch); 39 return my_SIPOs.read_bank_pin(bank_id, Switch); 40} 41 42void setup() { 43 Serial.begin(9600); 44 // create 1 bank of Max_SIPOs 45 // params are data pin, clock pin anf latch pin, number SIPOs 46 bank_id = my_SIPOs.create_bank(8, 10, 9, Max_SIPOs); 47 if (bank_id == create_bank_failure) { 48 my_SIPOs.print_SIPO_data(); 49 Serial.println(F("failed to create bank")); 50 Serial.flush(); 51 exit(0); 52 } 53my_SIPOs.print_SIPO_data(); // report on global SIPO8 params 54} 55// Scan all defined switches and set their respective bank pin status, LOW/HIGH. 56// Switches/bank pins layout: 57// Switch associated bank pins run from 0 to num_switches-1, inclusive (5) and 58// are used to indicate respective switch status, 59// bank pin 6 is not used and bank pin 7 is used to provide 60// a 'heart beat' to indicate that the sketch is running. 61void loop() { 62 my_SIPOs.set_all_array_pins(LOW); // ensure we start with clear array pool/bank 63 my_SIPOs.xfer_array(MSBFIRST); 64 my_SIPOs.SIPO8_start_timer(timer0); // start the sample timer 65 do { 66 if (my_SIPOs.SIPO8_timer_elapsed(timer0, sample_time) == elapsed) { 67 my_SIPOs.SIPO8_start_timer(timer0); // reset/restart the timer 68 // read each switch and set its virtual SIPO pin in the bank 69 my_SIPOs.invert_bank_pin(bank_id, 7); // flash 'heart beat' 70 for (uint8_t Switch = 0; Switch < num_switches; Switch ++) { 71 my_SIPOs.set_bank_pin(bank_id, Switch, read_switch_status(Switch)); 72 } 73 my_SIPOs.xfer_bank(bank_id, MSBFIRST); // update the physical SIPO pins 74 } 75 } while (true); 76} 77
Story Board Example 2
c_cpp
Story board example 2 - strobing LEDs
1/* Ron D Bentley, Stafford, UK 2 April 2021 3 4 Example sketch 2 for Arduino Community story board 5 This sketch strobes a number of LEDs driven by a SIPO IC, 8 output pins 6 forwards and backwards at a defined frequency. 7 8 This example uses relative bank addressing with pin set and invert functions. 9 10 Ron D Bentley, Stafford, UK 11 April 2021 12 13 This example and code is in the public domain and 14 may be used without restriction and without warranty. 15 16*/ 17 18#include <ez_SIPO8_lib.h> 19 20#define Max_SIPOs 1 // 1 x SIPOs - provides 8 output pins 21#define Max_timers 0 // no timers required, will use delay 22 23#define data_pin 8 24#define clock_pin 10 25#define latch_pin 9 26 27#define strobe_frequency 50 // milli seconds, delay frequency 28 29// initiate the class for max SIPOs/timers required 30SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 31 32int bank_id; // used to keep the SIPO bank id 33 34void setup() { 35 Serial.begin(9600); 36 // create a bank of 'Max_SIPOs' using create_bank function: 37 bank_id = my_SIPOs.create_bank(data_pin, clock_pin, latch_pin, Max_SIPOs); 38 if (bank_id == create_bank_failure) { 39 Serial.println(F("\ 40failed to create bank, terminated")); 41 Serial.flush(); 42 exit(0); 43 } 44 my_SIPOs.print_SIPO_data(); // report on global SIPO8 params 45 // start by setting all SIPO outputs to low (off) in the SIPO bank 46 my_SIPOs.set_bank_SIPO(bank_id, 0, 0b00000000); // only 1 SIPO in bank,index 0 47 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 48} 49 50void loop() { 51 //strobe example, strobe bank_id pins forward and back 52 bool msb_or_lsb = MSBFIRST; // pick an initial strobe direction 53 uint8_t num_pins = Max_SIPOs * pins_per_SIPO; // lots of ways to do this 54 do { 55 for (uint16_t pin = 0; pin < num_pins; pin++) { 56 my_SIPOs.set_bank_pin(bank_id, pin, HIGH); // set strobe pin 57 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); // update physical SIPO bank 58 delay(strobe_frequency); 59 my_SIPOs.invert_bank_pin(bank_id, pin); // invert strobe pin - alternative to set_bank_pin(low) 60 my_SIPOs.xfer_bank(bank_id, msb_or_lsb); // update physical SIPO bank 61 } 62 msb_or_lsb = !msb_or_lsb; // switch strobe direction 63 } while (true); 64} 65
ez_SIPO8_lib - Tutorial 5 - Bank Interleaving (Strobing LEDs)
c_cpp
Accompanying sketch for Tutorial 5 - Bank Interleaving (Strobing LEDs)
1// 2// Tutorial 5 - use of ez_SPI8 library, 3// Demonstration of SIPO bank interleaving - 8 x physical SIPOs 4// each mapped to an individual bank but with the same 3-wire digital 5// pin microcontroller interface. 6// 7// The sketch sets up each single SIPO bank with a different binary 8bit 8// (8 pin) pattern which is then xferred to the physical single SIPO IC. 9// The sketch mimics the strobe sketch by using bank interleaving. 10// To note is the small amount of SIPO8 library code that is used. 11// 12// Ron D Bentley, Stafford, UK 13// April 2021 14// 15// This example and code is in the public domain and 16// may be used without restriction and without warranty. 17// 18 19#include <ez_SIPO8_lib.h> 20 21int bank_id; 22 23#define Num_SIPOs 8 24#define Num_timers 0 25 26SIPO8 my_SIPOs(Num_SIPOs, Num_timers); // initiate the class for the tutorial 27 28uint8_t bank_ids[Num_SIPOs]; // one bank_id per SIPO bank 29uint8_t bank; 30 31void setup() { 32 Serial.begin(9600); 33 // create banks of 1 x SIPO, all of same 3-wire interface and initialise 34 // with each strobe pattern - 0b00000001, 0b00000010, 0b00000100, etc. 35 // create_bank params are: data pin, clock pin, latch pin, number of SIPOs this bank 36 for (bank = 0; bank < Num_SIPOs; bank++) { 37 bank_ids[bank] = my_SIPOs.create_bank(8, 10, 9, 1); 38 if (bank_ids[bank] == create_bank_failure) { 39 Serial.println(F("failed to create bank")); 40 Serial.flush(); 41 exit(0); 42 } 43 // now set up the strobe patterns in the bank's single SIPO, relative SIPO address is 0 44 // sliding pattern of 1's starting at 0b00000001 45 my_SIPOs.set_bank_SIPO(bank_ids[bank], 0, 1 << bank); // set up this bank's strobe pattern 46 } 47 // print the bank data and pin statuses for confirmation/inspection 48 my_SIPOs.print_SIPO_data(); 49 my_SIPOs.print_pin_statuses(); 50} 51 52void loop() { 53 // scroll through every SIPO bank (interleave) and xfer the bank's pins 54 // according to the direction for shift out. 55 bool msb_or_lsb = MSBFIRST; // starting direction 56 do { 57 for (bank = 0; bank < Num_SIPOs; bank++) { 58 my_SIPOs.xfer_bank(bank, msb_or_lsb); // xfer out this bank's SIPO pins 59 delay(50); 60 } 61 msb_or_lsb = !msb_or_lsb; // switch direction 62 } while (true); 63}
ez_SIPO8_lib - User Guide - Sketch Example – Flashing LEDs, Absolute Pin Addressing
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Flashing LEDs, Absolute Pin Addressing, see User Guide
1// 2// Flash LEDs - 3// This sketch independently flashes eight LEDs each connected to a SIPO output pin, 4// each at a different frequency, using SIPO8 library timers. 5// The demonstration runs for a fixed time before terminating, again this being 6// controlled by a SIPO8 library timer. 7// 8// This example uses absolute array pin addressing. 9// 10// Ron D Bentley, Stafford, UK 11// April 2021 12// 13// This example and code is in the public domain and 14// may be used without restriction and without warranty. 15// 16#include "ez_SPIC8_lib.h" 17 18#define Max_SPICs 1 19#define Max_timers 9 // we will create 9 timers, 0-7 for LEDs and 8 for our timimg 20#define my_timer 8 // we will use SPIC8 timer 8 for timing our demonstration 21 22#define number_banks 1 // demonstration using 1 bank 23#define demo_time 20000 // time in milliseconds flash demonstration to run for 24 25int bank0_id; 26 27// setup pin/LED flash data 28uint8_t timer; 29 30uint32_t timer_intervals[Max_timers] = { 31 // millisecond elapse timer values for each timer, 0 - 7 32 300, 400, 500, 600, 700, 800, 900, 1000 33}; 34 35uint8_t timer_pins[Max_timers] = { 36 // SPIC output pin absolute addresses for timers 0 - 7 37 0, 1, 2, 3, 4, 5, 6, 7 38}; 39 40SPIC8 my_SPICs(Max_SPICs, Max_timers); // initiate the class for max SPICs/timers 41 42void setup() { 43 Serial.begin(9600); 44 // create a single bank, params are: 45 // data pin, clock pin, latch pin, number of SPICs this bank 46 bank0_id = my_SPICs.create_bank(8, 10, 9, number_banks); 47 if (bank0_id == create_bank_failure) { 48 Serial.println(F("\ 49failed to create bank")); 50 Serial.flush(); 51 exit(0); 52 } 53 // print the bank data for confirmation/inspection 54 my_SPICs.print_SPIC_data(); 55} 56 57void loop() { 58 // 59 // now lets add in the flashing LED code from Tutorial 3 60 // start by setting all SPIC outputs to low (off) 61 my_SPICs.set_all_array_pins(LOW);// set all declared virtual output pins LOW/off 62 my_SPICs.xfer_array(LSBFIRST); // move virtual pin to real SPIC output pins 63 my_SPICs.SPIC8_start_timer(my_timer); // start my_timer 64 // keep processing until our my_timer has elapsed 65 // start all timers 66 for (timer = 0; timer < Max_timers - 1; timer++) { 67 my_SPICs.SPIC8_start_timer(timer); 68 } 69 timer = 0; // start checking at first timer 70 do { 71 // check each timer for elapse and, if elapsed, invert the timer's output pin 72 // and reset the timer 73 if (my_SPICs.SPIC8_timer_elapsed(timer, timer_intervals[timer]) == elapsed) { 74 my_SPICs.invert_array_pin(timer_pins[timer]); // invert the pin associated with this timer 75 my_SPICs.xfer_array(MSBFIRST); // update physical SPIC outputs 76 my_SPICs.SPIC8_start_timer(timer); // reset/restart the current timer 77 } 78 timer++; // move on to next timer 79 if (timer >= Max_timers - 1) timer = 0; // wrap around to beginning 80 } while (my_SPICs.SPIC8_timer_elapsed(my_timer, demo_time) != elapsed); 81 // 82 // end of LED flash demonstration - now clear down LEDs to off(LOW) 83 my_SPICs.set_all_array_pins(LOW);// set all declared virtual output pins LOW/off 84 my_SPICs.xfer_array(LSBFIRST); // move virtual pin statuses to real SPIC output pins 85 exit(0); 86}
ez_SIPO8_lib - Tutorial 1 - Setup & Absolute Pin Addressing
c_cpp
Accompanying sketch for Tutorial 1 - Setup & Absolute Pin Addressing
1// 2// Tutorial 1 - use of ez_SPI8 library 3// Setup and absolute addressing. 4// 5// Ron D Bentley, Stafford, UK 6// April 2021 7// 8// This example and code is in the public domain and 9// may be used without restriction and without warranty. 10// 11 12#include <ez_SIPO8_lib.h> 13 14#define max_SIPOs 1 // one 1 SIPO for this tutorial 15#define max_timers 0 // no timers required 16 17// initiate the class for max SIPOs/timers required 18SIPO8 my_SIPOs(max_SIPOs, max_timers); 19 20int my_LEDs; // used to keep the SIPO bank id 21 22void setup() { 23 Serial.begin(9600); 24 // create a bank of 1 SIPO using create_bank function: 25 // data pin, clock pin, latch pin, number of SIPO this bank 26 my_LEDs = my_SIPOs.create_bank(8, 10, 9, 1); // data pin, clock pin, latch pin, number of SIPO this bank 27 if (my_LEDs == create_bank_failure) { 28 Serial.println(F("\ 29failed to create bank")); 30 Serial.flush(); 31 exit(0); 32 } 33 // print the bank data for confirmation/inspection 34 my_SIPOs.print_SIPO_data(); 35} 36 37void loop() { 38 // start by setting all SIPO outputs to low (off) 39 my_SIPOs.set_all_array_pins(LOW); 40 my_SIPOs.xfer_array(LSBFIRST); 41 do { 42 // 43 // assemble pattern 0b01010101 into the array 44 my_SIPOs.set_array_pin(0, HIGH); 45 my_SIPOs.set_array_pin(1, LOW); 46 my_SIPOs.set_array_pin(2, HIGH); 47 my_SIPOs.set_array_pin(3, LOW); 48 my_SIPOs.set_array_pin(4, HIGH); 49 my_SIPOs.set_array_pin(5, LOW); 50 my_SIPOs.set_array_pin(6, HIGH); 51 my_SIPOs.set_array_pin(7, LOW); 52 my_SIPOs.xfer_array(MSBFIRST); // now move array to physical SIPO and light up the LEDs 53 delay(500); 54 // assemble inverted pattern 0b10101010 into the array 55 my_SIPOs.set_array_pin(0, LOW); 56 my_SIPOs.set_array_pin(1, HIGH); 57 my_SIPOs.set_array_pin(2, LOW); 58 my_SIPOs.set_array_pin(3, HIGH); 59 my_SIPOs.set_array_pin(4, LOW); 60 my_SIPOs.set_array_pin(5, HIGH); 61 my_SIPOs.set_array_pin(6, LOW); 62 my_SIPOs.set_array_pin(7, HIGH); 63 my_SIPOs.xfer_array(MSBFIRST); // now move array to physical SIPO and light up the LEDs 64 delay(500); 65 } while (true); 66}
SIPO8 library keyword file, keywords.txt
c_cpp
SIPO8 library keyword file, keywords.txt
1# 2# Ron D Bentley, Stafford, UK 3# April 2021 4# SIPO8 v1-00 5# 6# This example and code is in the public domain and 7# may be used without restriction and without warranty 8# 9 10# class 11SIPO8 KEYWORD1 12 13# macros... 14pins_per_SIPO LITERAL1 15create_bank_failure LITERAL1 16pin_read_failure LITERAL1 17pin_invert_failure LITERAL1 18pin_set_failure LITERAL1 19bank_not_found LITERAL1 20SIPO_not_found LITERAL1 21timer0 LITERAL1 22timer1 LITERAL1 23timer2 LITERAL1 24timer3 LITERAL1 25timer4 LITERAL1 26timer5 LITERAL1 27timer6 LITERAL1 28timer7 LITERAL1 29elapsed LITERAL1 30not_elapsed LITERAL1 31active LITERAL1 32not_active LITERAL1 33 34# user accessible variables... 35max_pins KEYWORD2 36num_active_pins KEYWORD2 37num_pin_status_bytes KEYWORD2 38num_banks KEYWORD2 39max_SIPOs KEYWORD2 40bank_SIPO_count KEYWORD2 41max_timers KEYWORD2 42bank_data_pin KEYWORD2 43bank_clock_pin KEYWORD2 44bank_latch_pin KEYWORD2 45bank_num_SIPOs KEYWORD2 46bank_low_pin KEYWORD2 47bank_high_pin KEYWORD2 48SIPO_banks KEYWORD2 49pin_status_bytes KEYWORD2 50timer_status KEYWORD2 51start_time KEYWORD2 52timers KEYWORD2 53 54# functions... 55create_bank KEYWORD2 56set_all_array_pins KEYWORD2 57invert_all_array_pins KEYWORD2 58set_array_pin KEYWORD2 59invert_array_pin KEYWORD2 60read_array_pin KEYWORD2 61set_banks KEYWORD2 62set_banks KEYWORD2 63set_bank KEYWORD2 64invert_banks KEYWORD2 65invert_banks KEYWORD2 66invert_bank KEYWORD2 67set_bank_SIPO KEYWORD2 68invert_bank_SIPO KEYWORD2 69read_bank_SIPO KEYWORD2 70set_bank_pin KEYWORD2 71invert_bank_pin KEYWORD2 72read_bank_pin KEYWORD2 73get_bank_from_pin KEYWORD2 74num_pins_in_bank KEYWORD2 75xfer_banks KEYWORD2 76xfer_banks KEYWORD2 77xfer_bank KEYWORD2 78xfer_array KEYWORD2 79print_pin_statuses KEYWORD2 80print_SIPO_data KEYWORD2 81SIPO8_start_timer KEYWORD2 82SIPO8_stop_timer KEYWORD2 83SIPO8_timer_elapsed KEYWORD2 84 85# private variables 86_max_pins KEYWORD2 87_num_active_pins KEYWORD2 88 _num_pin_status_bytes KEYWORD2 89_max_SIPOs KEYWORD2 90 _bank_SIPO_count KEYWORD2 91_next_bank KEYWORD2 92_max_timers KEYWORD2 93 94# private functions... 95SIPO_lib_exit KEYWORD2 96shift_out_bank KEYWORD2 97
ez_SIPO8_lib - User Guide - Sketch Example – Chasing LEDs, using 8 x SIPO ICs in a Single Cascade
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Chasing LEDs, using 8 x SIPO ICs in a Single Cascade, see User Guide
1// 2// Chasing LEDs - 3// This sketch illuminates a defined sequential array of LEDs connected to 4// SIPO output pins, at a specified frequency (milliseconds). 5// At the end of the LED sequence, the LEDs are reset and the 6// cycle repeated. 7// 8// The sketch can be configured for a SIPO array of any length, but this 9// example is configured to demonstrate the chasing LEDs of a clock dial. 10// In this instance the SIPO array length will be 64 output pins (8 x SIPOs) 11// but only the first 60 outputs will be used (0-59 seconds). The frequency 12// will be set to 1 second (1000 millisecs). 13// 14// This example uses absolute addressing of the defined SIPO array. 15// 16// Ron D Bentley, Stafford, UK 17// April 2021 18// 19// This example and code is in the public domain and 20// may be used without restriction and without warranty. 21// 22 23#include <ez_SIPO8_lib.h> 24 25#define Max_SIPOs 8 // 8 x SIPOs - provides 64 output pins 26#define Max_timers 1 // used to count 1 second elapsing 'beats' 27 28#define data_pin 8 29#define clock_pin 10 30#define latch_pin 9 31 32#define chase_length 60 // chasing seconds on a clock 33#define frequency 1000 // milli seconds - 1 second frequency 34 35// initiate the class for max SIPOs/timers required 36SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 37 38int my_LEDs; // used to keep the SIPO bank id 39 40void setup() { 41 Serial.begin(9600); 42 // create a bank of 'Max_SIPOs' using create_bank function: 43 my_LEDs = my_SIPOs.create_bank(data_pin, clock_pin, latch_pin, Max_SIPOs); 44 if (my_LEDs == create_bank_failure) { 45 Serial.println(F("\ 46failed to create bank")); 47 Serial.flush(); 48 exit(0); 49 } 50 // start by setting all SIPO outputs to low (off) 51 my_SIPOs.set_all_array_pins(LOW); 52 my_SIPOs.xfer_array(MSBFIRST); 53 // print the bank data for confirmation/inspection 54 my_SIPOs.print_SIPO_data(); 55} 56 57void loop() { 58 uint8_t next_pin = 0; 59 my_SIPOs.SIPO8_start_timer(timer0); // kick off the timer 60 do { 61 if (my_SIPOs.SIPO8_timer_elapsed(timer0, frequency) == elapsed) { 62 // 1 second time elapsed, so update next pin in the array 63 my_SIPOs.SIPO8_start_timer(timer0); // restart 1 second count for next cycle 64 if (next_pin == chase_length) { // wrap around 65 my_SIPOs.set_all_array_pins(LOW); // clear all pins 66 next_pin = 0; 67 } else { 68 my_SIPOs.set_array_pin(next_pin, HIGH); // set absolute next_pin pin status 69 next_pin++; 70 } 71 my_SIPOs.xfer_array(MSBFIRST); // update physical SIPOs 72 } 73 } while (true); 74}
ez_SIPO8_lib - User Guide - Sketch Example – Driving a 7 Segment LED Matrix Display
c_cpp
ez_SIPO8_lib - User Guide - Sketch Example – Driving a 7 Segment LED Matrix Display, see User Guide
1// 2// 7 Segment LED Matrix - 3// Sketch uses a single SIPO IC to map the 7 segment matrix and creates 4// a single bank comprising one SIPO IC. 5// 6// This sketch drives a single 7 segment LED matrix, displaying digits 7// from 0 to hex F, in two repeating cycles: 8// 1. cycle 1 - shifting out the most significant bit first (MSBFIRST), with each 9// character appended with the DP character ".", eg "3." 10// 2. cycle 2 - shifting out the least significant bit first (LSBFIRST), without the DP 11// character appended. 12// 13// The sketch offers two methods for updating a 7 Segment LED Matrix, choice 14// is a simple matter a preference/familiarity. 15// 16// This example uses relative bank addressing. 17// 18// Ron D Bentley, Stafford, UK 19// April 2021 20// 21// This example and code is in the public domain and 22// may be used without restriction and without warranty. 23// 24 25#include <ez_SIPO8_lib.h> 26 27#define max_SIPOs 1 // one 1 SIPO for this example 28#define max_timers 0 // no timers required 29 30// initiate the class for max SIPOs/timers required 31SIPO8 my_SIPOs(max_SIPOs, max_timers); 32 33int my_matrix7; // used to keep the SIPO bank id 34 35#define num_digits 16 36uint8_t LSB_matrix_chars[num_digits] = { 37 252, 96, 218, 242, 102, 182, 190, 224, 254, 246, 238, 62, 156, 122, 158, 142 38}; 39#define LSB_DP_char 0b00000001 // "." value for LSBFIRST shiftout 40 41uint8_t MSB_matrix_chars[num_digits] = { 42 63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 119, 124, 57, 94, 121, 113 43}; 44#define MSB_DP_char 0b10000000 // "." value for MSBFIRST shiftout 45 46void setup() { 47 Serial.begin(9600); 48 // create a bank of 1 SIPO using create_bank function: 49 // data pin, clock pin, latch pin, number of SIPO this bank 50 my_matrix7 = my_SIPOs.create_bank(8, 10, 9, 1); // data pin, clock pin, latch pin, number of SIPO this bank 51 if (my_matrix7 == create_bank_failure) { 52 Serial.println(F("\ 53failed to create bank")); 54 Serial.flush(); 55 exit(0); 56 } 57 // print the bank data for confirmation/inspection 58 my_SIPOs.print_SIPO_data(); 59} 60 61void loop() { 62 // keep running through the digits 0 to hex F, as defined by the 63 // bit patterns in the preset array MSB_/LSB_matrix_chars 64 do { 65 // cycle 1 - MSBFIRST, with appended DP character "." 66 my_SIPOs.set_bank_SIPO(my_matrix7, 0, 0b00000000); // reset all LEDs in the matrix to off/LOW 67 my_SIPOs.xfer_bank(my_matrix7, MSBFIRST); 68 delay(50); 69 for (uint8_t digit = 0; digit < num_digits; digit++) { 70 my_SIPOs.set_bank_SIPO(my_matrix7, 0, MSB_matrix_chars[digit] + MSB_DP_char); // append "." 71 my_SIPOs.xfer_bank(my_matrix7, MSBFIRST); 72 delay(500); 73 } 74 // cycle 2 - LSBFIRST, no appended DP character 75 my_SIPOs.set_bank_SIPO(my_matrix7, 0, 0b00000000); // reset all LEDs in the matrix to off/LOW 76 my_SIPOs.xfer_bank(my_matrix7, LSBFIRST); 77 delay(50); 78 for (uint8_t digit = 0; digit < num_digits; digit++) { 79 // if DP char "." required to be appended to a char, then add 'LSB_DP_char' 80 // to the 'LSB_matrix_chars[digit]' parameter 81 my_SIPOs.set_bank_SIPO(my_matrix7, 0, LSB_matrix_chars[digit]); 82 my_SIPOs.xfer_bank(my_matrix7, LSBFIRST); 83 delay(500); 84 } 85 } while (true); 86}
ez_SIPO8_lib - Tutorial 2 - Relative Pin Addressing
c_cpp
Accompanying sketch for Tutorial 2 - Relative Pin Addressing
1// 2// Tutorial 2 - use of ez_SPI8 library, 3// Relative addressing - 1 x physical SIPO IC 4// The sketch demonstrates two ways in which SIPO output pins 5// may be updated, individually (set_bank_pin) or in a group 6// of 8 pins (set_bank_SIPO), representing a single 8it SIPO 7// within a bank. 8// 9// Ron D Bentley, Stafford, UK 10// April 2021 11// 12// This example and code is in the public domain and 13// may be used without restriction and without warranty. 14// 15 16#include <ez_SIPO8_lib.h> 17 18#define Max_SIPOs 1 // two virtual SIPOs for this tutorial 19#define Max_timers 0 // no timers required 20 21// initiate the class for Max SIPOs/timers required 22SIPO8 my_SIPOs(Max_SIPOs, Max_timers); 23 24int bank_id; // used to keep the SIPO bank id 25 26void setup() { 27 Serial.begin(9600); 28 bank_id = my_SIPOs.create_bank(8, 10, 9, 1); // absolute pin addresses 0-7, relative addresses 0-7 29 if (bank_id == create_bank_failure) { 30 Serial.println(F("\ 31failed to create bank")); 32 Serial.flush(); 33 exit(0); 34 } 35 // print the bank data for confirmation/inspection 36 my_SIPOs.print_SIPO_data(); 37} 38 39void loop() { 40 // start by setting the only SIPO (0) in the bank to all outputs off/LOW 41 my_SIPOs.set_bank_SIPO(bank_id, 0, LOW); 42 my_SIPOs.xfer_bank(bank_id, LSBFIRST); // move virtual pin statuses to real SIPO output pins 43 do { 44 // 45 // setup pattern for first cycle: 0b01010101 46 // note that set_bank_pin uses relative addressing 47 my_SIPOs.set_bank_pin(bank_id, 0, HIGH); // least significant bit/pin 48 my_SIPOs.set_bank_pin(bank_id, 1, LOW); 49 my_SIPOs.set_bank_pin(bank_id, 2, HIGH); 50 my_SIPOs.set_bank_pin(bank_id, 3, LOW); 51 my_SIPOs.set_bank_pin(bank_id, 4, HIGH); 52 my_SIPOs.set_bank_pin(bank_id, 5, LOW); 53 my_SIPOs.set_bank_pin(bank_id, 6, HIGH); 54 my_SIPOs.set_bank_pin(bank_id, 7, LOW); // most significant bit/pin 55 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 56 delay(500); 57 // 58 // setup reverse pattern using 8bit write function: 0b10101010 59 // note that set_bank_SIPO uses relative addressing for SIPOs in the bank 60 my_SIPOs.set_bank_SIPO(bank_id, 0, 0b10101010); 61 my_SIPOs.xfer_bank(bank_id, MSBFIRST); 62 delay(500); 63 } while (true); 64}
ez_SIPO8_lib - Tutorial 4 - Cascaded SIPOs, Rotating LED Patterns
c_cpp
Accompanying sketch for Tutorial 4 - Cascaded SIPOs, Rotating LED Patterns
1// 2// Tutorial 4 - use of ez_SPI8 library, 3// 2 x physical SIPOs, cascaded into a single SIPO bank 4// 5// Ron D Bentley, Stafford, UK 6// April 2021 7// 8// This example and code is in the public domain and 9// may be used without restriction and without warranty. 10// 11 12#include <ez_SIPO8_lib.h> 13 14int bank_id; 15 16#define Num_SIPOs 2 17#define Num_timers 0 18 19SIPO8 my_SIPOs(Num_SIPOs, Num_timers); // initiate the class for the tutorial 20 21void setup() { 22 Serial.begin(9600); 23 // create a single bank of required number of SIPOs in the bank, 24 // params are: data pin, clock pin, latch pin, number of SIPOs this bank 25 bank_id = my_SIPOs.create_bank(8, 10, 9, 2); 26 if (bank_id == create_bank_failure) { 27 my_SIPOs.print_SIPO_data(); 28 Serial.println(F("failed to create bank")); 29 Serial.flush(); 30 exit(0); 31 } 32 // print the bank data for confirmation/inspection 33 my_SIPOs.print_SIPO_data(); 34} 35 36// patterns to be xferred / shifted out to the SIPO bank 37#define num_patterns 7 38uint8_t patterns[num_patterns] = {// starting patterns 39 0b11111111, 40 0b00001111, 41 0b00110011, 42 0b01010101, 43 0b11000011, 44 0b01000010, 45 0b00111100 46}; 47 48void loop() { 49 // scroll through every SIPO bank and assert the given pattern to every 50 // SIPO defined by the bank. 51 do { 52 // setup each pattern in turn 53 for (uint8_t pattern = 0; pattern < num_patterns; pattern++) { 54 // perform 2 passes for each pattern - first, as defined, second inverted 55 for (uint8_t cycle = 0; cycle < 2; cycle++) { 56 // consider each SIPO in this 2 SIPO cascaded bank 57 for (uint8_t sipo = 0; sipo < my_SIPOs.SIPO_banks[bank_id].bank_num_SIPOs; sipo++) { 58 my_SIPOs.set_bank_SIPO(bank_id, sipo, patterns[pattern]); // set all pins of this SIPO in this bank_id 59 } 60 my_SIPOs.xfer_bank(bank_id, MSBFIRST); // update physical SIPOs for this bank_id 61 delay(500); 62 patterns[pattern] = ~patterns[pattern]; // invert current pattern byte for next pass 63 } 64 } 65 } while (true); 66}
Downloadable files
Single SIPO, wiring scheme
See story board/examples and tutorials
Single SIPO, wiring scheme
Single SIPO, wiring scheme
See story board/examples and tutorials
Single SIPO, wiring scheme
Cascaded SIPOs, wiring scheme
See story board/examples and tutorials
Cascaded SIPOs, wiring scheme
Cascaded SIPOs, wiring scheme
See story board/examples and tutorials
Cascaded SIPOs, wiring scheme
Comments
Only logged in users can leave comments
ronbentley1
0 Followers
•0 Projects
Table of contents
Intro
3
0