Arduino:Примеры/ShftIn22

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Проверка разных комбинаций на двух комплектах переключателей[1]

Это скетч для платы Arduino и двух сдвиговых регистров CD4021B. Он считывает данные с переключателей, подключенных к сдвиговым регистрам, сравнивает их с заданными настройками и сообщает, соответствуют ли считанные данные заданным настройкам. «Настройками» служат разные ноты и накладываемые на них звуковые эффекты. Кроме того, скетч определяет, какие переключатели находятся в положении «вкл».

Код

//**************************************************************//
//  Название    : Проверка разных комбинаций                    //
//              : на двух комплектах переключателей             //                                
//  Автор       : Кэрлин Мо                                     //
//  Дата        : 25 января 2007 года                           //
//  Версия      : 1.0                                           //
//  Примечания  : Скетч для использования с двумя сдвиговыми    //
//              : регистрами CD4021B                            //
//**************************************************************//

// задаем номера для интерфейсных контактов: 
int latchPin = 8;
int dataPin = 9;
int clockPin = 7;

// задаем переменные, которые будут хранить данные для 
// каждого сдвигового регистра; в целях отладки лучше начать 
// со значений без «0»:   
byte switchVar1 = 72;  //01001000
byte switchVar2 = 159; //10011111

// задаем массив со значениями для каждого контакта 
// на первом сдвиговом регистре: 
char note2sing[] = {
  'C', 'd', 'e', 'f', 'g', 'a', 'b', 'c'}; 

// задаем массив со значениями для 1-7 (не 0) контактов 
// на втором сдвиговом регистре; без 0, потому что этот контакт
// будет использоваться для флагового значения:
byte settingVal[] = {
  0, 0, 0, 0, 0, 0, 0};   

// флаговая переменная для определения того, находится ли скетч 
// в режиме обновления настроек: 
byte settingSwitch = 0;  

void setup() {
  // запускаем последовательную коммуникацию:
  Serial.begin(9600);

  // задаем режимы для контактов:
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, INPUT);

}

void loop() {

  // подаем импульс на контакт-защелку;
  // чтобы собрать параллельные данные, задаем ему значение «1»:
  digitalWrite(latchPin,1);
  // ждем:
  delayMicroseconds(20);
  // задаем ему «0», чтобы передать последовательные данные: 
  digitalWrite(latchPin,0);

  // пока сдвиговые регистры переключены в последовательный режим, 
  // собираем все их данные в байт; сначала это делает регистр, 
  // подключенный к чипу:
  switchVar1 = shiftIn(dataPin, clockPin);
  switchVar2 = shiftIn(dataPin, clockPin);

  // показываем результат; если первый контакт получит значение HIGH, 
  // то «0», стоящий в старшей части байта (7, 6, 5 и т.д.), 
  // будет удален:  
  Serial.println(switchVar1, BIN);
  Serial.println(switchVar2, BIN);


  // этот цикл loop() бит за битом прочесывает байт, 
  // содержащий данные сдвигового регистра; найдя значение HIGH (1),
  // он печатает соответствующее место в массиве: 
  for (int n=0; n<=7; n++)
  {
    // таким образом, когда «n» равно «3», код сравнивает биты 
    // в switchVar1 и двоичное число «00001000», возвращая «true» 
    // лишь в том случае, если в этом бите (т.е. контакте) 
    // есть значение «1», присланное от сдвигового регистра: 
    if (switchVar1 & (1 << n) ){
      // печатаем значение из этого места в массиве: 
      Serial.println(note2sing[n]);
    }
  }

// далее изучаем весь байт и создаем комбинации настроек;

// эти настройки (читай, разные ситуации) создаются при помощи
// оператора switch, которому «скармливается» переменная switchVar1; 
// далее switchVar1 сравнивается с несколькими заданными 
// числовыми значениями: 

  switch (switchVar1) {
  case B00101010:
    Serial.println("D minor");  //  "Ре минор"
    break;
  case B00010101:
    Serial.println("C major");  //  "До мажор"
    break;
  case B01010100:
    Serial.println("E minor");  //  "Ми минор"
    break;
  case B00101001:
    Serial.println("F major")  //  "Фа мажор";
    break;    
  case B01010010:
    Serial.println("G major");  //  "Соль мажор"
    break;        
  case B00100101:
    Serial.println("A minor");  //  "Ля минор"
    break;     
  case B01001010:
    Serial.println("B diminished");  //  "Си (полтона)"
    break;     
  default: 
    // если ничего не подходит, пишем следующее:
    Serial.println("Play It, Joe");  //  "Сыграй-ка сам, Василий!"
  }


//--- ВТОРОЙ СДВИГОВЫЙ РЕГИСТР
// он ведет себя чуть сложнее


// если переключатель, подключенный к контакту 7, 
// находится в состоянии HIGH:
  if (switchVar2 & (1 << 7) ){
    // печатаем сообщение о том, что идет обновление настроек:
    Serial.println("Check, Check");  //  «Идет обновление настроек»
    // задаем флаговой переменной значение «1», чтобы сообщить скетчу, 
    // что идет обновление настроек:
    settingSwitch = 1;

    // пока переключатель на контакте 7 имеет значение HIGH,
    // берем оставшиеся 7 битов и загружаем их в массив; 
    // так будет удобнее до них «дотянуться» в дальнейшем, 
    // когда они понадобятся:
    for (int v=6; v>=0; v--)
    {
      if (switchVar2 & (1 << v) ){
        settingVal[v] = 1;
      } 
      else {
        settingVal[v] = 0;
      }
    }
  }
  // если переключатель находится в состоянии LOW...
  else {
    // ...и если в последний раз при проверке оператором if() 
    // этот переключатель находился в состоянии HIGH (т.е. если 
    // переменная settingSwitch по-прежнему имеет значение «1»): 
    //set to "1"):
    if (settingSwitch) {
      // ...то задаем переменной settingSwitch значение «0»:
      settingSwitch=0;

      // печатаем текущие настройки:
      Serial.println("___SETTINGS___");  //  "___НАСТРОЙКИ___"

      for (int s=0; s<=6; s++)
      {

      // печатаем названия настроек;
      // поскольку на февраль 2007 года в язык Arduino 
      // еще не были встроены строковые массивы,
      // это делается с помощью оператора «case»:
        switch (s) {
        case 0:
          Serial.print("Mute");  //  "Выключение звука"
          break;
        case 1:
          Serial.print("Octave Shift");  //  "Смещение октавы"
          break;
        case 2:
          Serial.print("Delay");  //  "Задержка"
          break;
        case 3:
          Serial.print("Reverb");  //  "Реверберация"
          break;    
        case 4:
          Serial.print("Vibrato");  //  "Вибрация"
          break;        
        case 5:
          Serial.print("Funkify");  //  "Фанкизация"
          break;     
        case 6:
          Serial.print("Dampen");  //  "Приглушение"
          break;     
        default: 
          // если соответствий нет, пишем сообщение по умолчанию:
          Serial.println("Not Defined");  //  "Не определено"
        }

        // печатаем статус:
        if (settingVal[s]) {
          Serial.print(" On");    //  " вкл."
          } 
        else {
          Serial.print(" Off") ;   //  " выкл."    
         }

         // пустое место:
         Serial.println();

      }
    }
  }


// пустое место:
Serial.println("-------------------");
// вставляем задержку, чтобы все как следует допечаталось: 
delay(500);

}

//------------------------------------------------конец главного цикла

////////// ----------------------------------- функция shiftIn()
///// в качестве аргументов ей требуются лишь контакт для данных 
///// и контакт-защелка; возвращает байт, у которого каждый бит 
///// соответствует какому-либо контакту сдвигового регистра: 
///// 7-ой бит – это 7-ой контакт, 0-ой бит – это 0-ой контакт

byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);
// 8 раз подаем на тактовый контакт значение HIGH (0,..,7),
// т.е. при каждом прохождении цикла for();

// в начале каждого цикла мы задаем тактовому контакту значение LOW;
// это нужно для последующего перехода из LOW в HIGH, чтобы сдвиговый 
// регистр поменял состояние на основе значения в следующем бите 
// последовательного потока данных;

// регистр передает информацию о контактах в порядке с 7-го по 0-ой,
// поэтому наша функция ведет отсчет в обратном порядке:

  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      // несмотря ни на что, задаем биту значение «0»: 
      myDataIn = myDataIn | (1 << i);
    }
    else {
      pinState = 0;
    }

    // печатаем отладочную информацию (если отладка не нужна,
    // оставьте эти строчки закоментированными):
    //Serial.print(pinState);
    //Serial.print("     ");
    //Serial.println (dataIn, BIN);

    digitalWrite(myClockPin, 1);

  }
  // печатаем пустое место, разделяющее отладочные данные: 
  //Serial.println();
  //Serial.println(myDataIn, BIN);
  return myDataIn;
}

См.также

Внешние ссылки