Управление сдвиговым регистром

ronny99
Offline
Зарегистрирован: 10.09.2013

Здравствуйте! Помоготе разобраться с регистром 74HC595 пожалуйста...

В общем по SPI подключено 2 регистра, один для LCD, другой для индикации(светодиоды). 

Начал забрираться  как менять значение определенного бита не изменяя существующее значение, нагуглил про оператор сдвига, почитал, вроде всё разжеванно, но всё равно не могу разобраться...

Как считать состояние битов регистра, а затем уже манипулировать "оператором сдвига" для записи нужного значения?

Заранее спасибо!

 

leshak
Offline
Зарегистрирован: 29.09.2011

Как настоящие C-шники:

Arduino - BitwiseAnd

или "Ардуинисто":

Arduino - BitSet

bitWrite

bitRead

bitClear

ronny99
Offline
Зарегистрирован: 10.09.2013

Спасибо! Почитал по ссылкам, но всё равно не въеду :)

#include <SPI.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(10);
int regLED = 9;
void setup(){
  pinMode(regLED, OUTPUT);
  digitalWrite(regLED, LOW);
  SPI.transfer(0);
  digitalWrite(regLED, HIGH);
  lcd.begin(16, 2);
  lcd.print("Hello!");
}
void loop() {
  digitalWrite(regLED, LOW);
  SPI.transfer(1);
  digitalWrite(regLED, HIGH);
  ...
  ...
  if(какое-либо условие){
     int stateRegister = как-то получить текушее состояние регистра;
     // применяем маску
     stateRegister = stateRegister|=(1<<3);
     // устанвливаем значение в регистр
     digitalWrite(regLED, LOW);
     SPI.transfer(stateRegister);
     digitalWrite(regLED, HIGH);
  }

}

Вот что примерно мне нужно...не очень понимаю как например применить bitRead в моем случае...

Извините за тупости :)

leshak
Offline
Зарегистрирован: 29.09.2011

Не очень понятно что-же именно вы хотите. Начните с того что за регистр вы хотите читать (я вообще не понимаю зачем его читать).

Или под "регистром" вы понимаете сам 74HC595?

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Один регистр = 8 бит = 1 байт

Тоесть если 2 регистра - значит нужно отправить 2 байта по SPI - и "дернуть" выводом установки состояния - чтобы эти 2 байта оказались на выходах.

leshak
Offline
Зарегистрирован: 29.09.2011

Все логично. И правильно. Два регистра - два байта нужно для хранения именно его состояния. С "нужно отправить" - все понятно. Не понятно что вы подразумеваете под  " получить текушее состояние регистра", зачем вам bitRead.

Вообщем что и откуда вы хотите прочитать? И зачем?

 

ronny99
Offline
Зарегистрирован: 10.09.2013

Я имею ввиду 74HC595...не правильно я изначально выразился :(

По ходу программы у меня будут включаться-отключаться определенные светодиоды подключенные к 74HC595, я хотел узнать как допустим включить определенный байт не задев существующее состояние...

leshak
Offline
Зарегистрирован: 29.09.2011

"Не задеть" - не выйдет. В любом случае вы будете каждый раз отсылать новое состояние для каждого выхода. Два байта целиком. Отослать единсвенный бит на регистр - не возможно.

Значит вам нужно, всего-то, завести какую-то переменую. Скажем ту же самую stateRegister  (только тип unsigned int был более подходящим). Менять, по потребности в ней биты и каждый раз отсылать ее. Нужно только что-бы переменная не теряла свого значения между проходами loop(). В ней и будет хранится "текущие состояние регистра". Читать ниоткуда не нужно.

Что-бы переменная не "теряла свого значения" - нужно всего-то объявить ее не внутри функции, а вверху скетча (сделать глобальной), либо.... можно и внутри функции, просто дописать, перед ее объявлением ключевое слово static. Тогда ее значение не будет обнулятся между вызовыми функции.

Для того что-бы менять состояние бита в этой переменной, вам не нужны bitRead. Какая разница что в этом бите, если вы хотите установить новое значение?  bitWrite именно это и умеет делать. Поменяет один бит в переменной. Остальные не тронет. Потом эту переменную, с обновленным битом, отсылаете на регистр.

Кстати, вы на этом сайте, нашли туториал по 74HC595? Там есть примерчик который на 99% делает то что вам нужно. Если к нему применить рецепт данный выше ("что-бы переменная не теряла свого значения"), то, если я правильно вас понял, он будет на 100% делать то что вам нужно.

ronny99
Offline
Зарегистрирован: 10.09.2013

Спасибо за подробный ответ!

Если Вы про вот этот http://arduino.ru/Tutorial/registr_74HC595 , то пробегался :)

Спасибо еще раз, теперь все вроде понятно, буду пробовать :)

leshak
Offline
Зарегистрирован: 29.09.2011

Нашли туториал для 74HC595? подсказка: идем в шапку сайта, раздел "Программирование" и ищем раздел "Базовые и полезные знания, необходимые для успешного программирования под платформу Arduino..."

ronny99
Offline
Зарегистрирован: 10.09.2013

И ещё за одно спрошу у гуру :) Если в SPI.transfer() поместить переменную в двоичном виде(int test = B00001111), она переведется в 10 автоматически?

leshak
Offline
Зарегистрирован: 29.09.2011

ronny99 пишет:

Если Вы про вот этот http://arduino.ru/Tutorial/registr_74HC595 , то пробегался :)

Да, про этот.... запустите у себя самый послединий пример. "Код примера 2.2". Что вы видите на светиках 

P.S. Кстати, похоже автор этого примера изначально хотел сделать именно "то что вам нужно", но ошибся... поэтому прийдется чуток поправить его пример :)

ronny99
Offline
Зарегистрирован: 10.09.2013

leshak пишет:

Да, про этот.... запустите у себя самый послединий пример. "Код примера 2.2". Что вы видите на светиках?

Попробую как буду дома :)

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

ronny99 пишет:

И ещё за одно спрошу у гуру :) Если в SPI.transfer() поместить переменную в двоичном виде(int test = B00001111), она переведется в 10 автоматически?

1. Не нужен вам трансфер. Он один байт отсылает. А вам нужно два. Смотрите пример, как там отсылка делается.
2. Переменные в памяти всегда хранятся в "двоичном виде". Системы исчисления (десятичная, двоичная, шестнадцатеричная) это чисто "человеческие заморочки". Как вам понятней и удобней писать. Способ записи и не более того. С точки зрения компилятора B00001111 и 0x0F и 15 не отличаются НИЧЕМ. Прошивка, какой-бы вариант вы не написали, не будет отличатся ни на байт. Контроллер никогда не узнает как оно выглядело в вашем исходнике :)
3. "B00001111), она переведется в 10 автоматически" - конечно нет. Так как B00001111, это 15, а не 10-ть.

Кстати, поэтому и вопросы типа "как перевести переменную в 10/16/2-тичное значение" - не имеет смысла. Переменная не имеет "системы исчисления". Она "просто значение". А вот "как ВЫВЕСТИ ее в том или ином ВИДЕ" - уже осмысленно.

Serial.print(val,DEC);// выводим вал в 10-тичном виде
Serial.print(val,HEX);// выводим вал в 16-тичном виде
Serial.print(val,BIN);// выводим вал в 2-чном виде

Кстати, последний Serial.print будет вам в помощь, когда будете разбиратся какие-же биты, в итоге, вы установили в переменной. Просто Serial.println(stateRegister,BIN) и смотитре в окне сериал монитора :)

ronny99
Offline
Зарегистрирован: 10.09.2013

Спасибо :) Просто у меня на 1 регистре висит дисплей, чтобы работала его библиотека нужно подключать SPI. А на 2 регистре уже индикация. У меня почему-то не работал shiftOut() при подключенной либе SPI... отключал SPI, shiftOut начинал работать, а вот дисплей уже нет :)

leshak
Offline
Зарегистрирован: 29.09.2011

ronny99 пишет:

Спасибо :) Просто у меня на 1 регистре висит дисплей, чтобы работала его библиотека нужно подключать SPI.

Тогда все хуже. Вариант "просто не терять значение переменной" - уже не прокатит. Если кто-то кроме вас, меняет биты регистров (библиотека), то вы не знаете "текущие состояние регистра". Следовательно "не зацепить остальные биты" - вы не можете (и соотвествено библиотека ничего не знает про то какие биты вы выставили. причем, скорее всего она вообще будет думать что там один регистр, а второй - просто посылать нафиг).

Тут уж либо хачить библиотеку нужно будет, либо повестить эти регистры на разные выводы и работать с ними обсолютно независимо (благо shiftOut Это программная реализация, поэтому ее можно на любых пинах запустить).

ronny99
Offline
Зарегистрирован: 10.09.2013

Вот блин...а пинов то свободных уже не осталось :( Но всё равно спасибо за полезную информацию, буду думать как быть!

leshak
Offline
Зарегистрирован: 29.09.2011

ronny99 пишет:

Вот блин...а пинов то свободных уже не осталось :( 

Совсем?  Ни одного? Про аналоговые не забыли?

ronny99
Offline
Зарегистрирован: 10.09.2013

Проверил, остался только D12 и А0 :( На аналоговый можно? :) Что-то я не сообразил :) Придется на плате дорожки резать да проводки кидать, а было всё красиво :)

leshak
Offline
Зарегистрирован: 29.09.2011

Ну прежде чем "резать и и кидать", я бы на макетке вначале проверил.

> На аналоговый можно? :)

Да. A0 может спокойно работать как цифровой пин. Даже делать для этого ничего не нужно. Просто усилием воли говорите себе "это цифровой пин" и все :) digitalRead(A0)/digitalWrite(A0) сразу начинает работать ;)

Щас 100% не скажу (нет времени вникнуть/подумать), но мне есть ощущение, что можно обойтись одним дополнительным пином.  Разделить у них только latch/ss пины. И включать их по очереди.... погуглите в сторону arduino spi slave, и статейка по основам SPI SPI (программный). Память Atmel DataFlash AT45DB081D. / Блог им. Frankie / Сообщество EasyElectronics.ru  может помочь.

ronny99
Offline
Зарегистрирован: 10.09.2013

Ну в общем повесил я второй регистр на D12 и A0, теперь shiftOut с SPI нормально работает :)