Попросили тут помощи по теме, решил оформить постом.
Итак, я как-то писал о входных сдвиговых регистрах серии 74HC165 (далее — просто «регистры»), но как-то не учёл сложности включения их каскадом («гирляндой», daisy chain). Объясню, в чём суть. Допустим нам нужно обработать 24 кнопки, а у регистра всего 8 входов. Первое решение, которое приходит в голову — обработать данные с 3х регистров независимо. Но это решение плохо тем, что на каждый регистр нужно выделять свою линию SS для работы по SPI — по одной линии на каждый вывод SH/~LD, а использовать одну общую не получится, так как по шине SPI полезут биты сразу с трёх регистров, и программа прочитает мусор.
Для решения этой проблемы придумали каскадное подключение. Идея такова: раз при каждом дёргании CLK биты, захваченные со входов регистра, проталкиваются к выходу (QH и ~QH), то почему бы не заставить регистр проталкивать после своих битов ещё и биты, захваченные с внешнего источника — ещё одного сдвигового регистра:
При этом используется всего одна линия SS на все регистры, благодаря чему подключение к Arduino требует всего 3 провода — SS, SCK и MISO.
Проиллюстрирую такое подключение на примере 3х регистров (таких же, как и в предыдущей статье по ним). Смотрим на расположение выводов:
Соединяем регистры, как в предыдущей статье, добавив для каскада следущее:
Вывод SER третьего регистра соединяем с GND, чтобы с SER читались нули, а вывод QH подключем к SER второго.
Вывод QH второго регистра соединяем с SER первого.
Вывод QH первого регистра соединяем с MISO на Arduino (пин 12).
SCK (пин 13) и SS (пин 10) — общие для всех регистров. Ну и для проверки на вшивость соединим через резисторы 10 кОм (у меня под рукой были только 510 Ом, если что) выводы 1C, 2B и 3A с землёй, а выводы 1E, 2F и 3G — с питанием (+5 В) и напишем скетч, в котором будем проверять состояние только этих выводов, ибо с остальных будет читаться мусор — они же не подключены. Для проверки на изменение состояний входов можно потыкать их проводком, соединённым с землёй или питанием через резистор.
Как это выглядит у меня:
Теперь модифицируем чуток скетч, считывающий состояние входов регистра, чтобы он работал через библиотеку SPI_Bus (проще кодить) и опрашивал только указанные выше входы:
#include <LineDriver.h>
#include <SPI.h>
#include <SPI_Bus.h>
SPI_Bus reg(_24bit, 10, MSBFIRST);
void setup()
{
Serial.begin(9600);
reg.setSelectionPolicy(SPI_Bus::SELECT_BEFORE);
}
void loop()
{
static uint32_t last_input_states = 0;
/* Читаем наши 24 бита разом. В C++ нет типов данных для 24-битных чисел,
* поэтому используем read32bits(), который считает столько бит,
* сколько мы указали при создании объекта reg (24 бита), но вернёт их
* одним 32-битным значением.
*/
uint32_t states = reg.read32bits();
if (states != last_input_states)
{
uint32_t changed = states ^ last_input_states;
last_input_states = states;
for (int i = 0; i < reg.bandwidth() * 8; ++i)
{
/* А вот тут проверяем только нужные нам входы */
if ((i == 0 || // 3A
i == 6 || // 3G
i == 9 || // 2B
i == 13 || // 2F
i == 18 || // 1C
i == 20) && // 1E
(changed & 1))
{
Serial.print("#");
Serial.print(i);
Serial.print(" -> ");
Serial.println(states & 1);
}
changed >>= 1;
states >>= 1;
}
}
}
Добрый день. Для чайников же пишите, так? Епт, куда и в каком виде положить SPI_Bus и LineDriver?
На одном регистре все завел без проблем. Считать же больше восьми бит при каскадном подключении регистров не могу из-за того, что новые библиотеки не видятся, соответственно не воспринимается reg.setSelectionPolicy(SPI_Bus::SELECT_BEFORE);.
Доброго времени суток. Короче, ёпт, библиотеки кидай в папку libraries, где у тебя проекты Arduino лежат. Ну, или там, где Arduino IDE установлена. Вот так вот.
Спасибо за скорый ответ, та и за полезный пост вообще.
Проблема в следующем: обычно, програмил в с++ и если надо было докинуть новую библиотеку (это файл с *.h), то его просто добавлял в лайбрариез и компилятор начинал её видеть и ей пользоваться. Заглянул в лайбрариез у ардуино. Там куча папок с названиями и уже внутри папок среди прочего может лежать та или иная библиотека. Ну, думаю, кину SPI_Bus.h и LineDriver.h в корень лайбрариез. Не помогло. Компилятор ругается. Кинул эти библиотеки вместе с папками, так как там всё в папках — не помогло. Вот за мысль подкинуть библиотечку к самому скетчу спасибо. Скорее всего так и надо было сразу сделать. Давно ничего не писал вот и туплю.
Собственно, после первых эмоций и неудачливых попыток с библиотеками, просто отказался от spi вообще и тупо программно сам начал параллельно считывать данные, стробировать (сдвигать побитово на выход регистра) и последовательно считывать данные ардуиной в булиновский массив нужного размера. Оказалось программно покороче и экономнее в плане использования памяти. Вопрос: такой алгоритм на много медленнее приведенного вами? Почему?
Приветствую! Ознакомился с вашей работой «Каскад входных сдвиговых регистров», спасибо за сей труд! Если же требуется обработать гораздо большее количество входов, около 300, и такое же количество выходов, получится ли это реализовать на каскаде сдвиговых регистров? Придется организовать считывание в массив? И вывод данных из массива в каскад регистров?
С уважением, Александр.
Вы правильно всё поняли. Но у каскадов сдвиговых регистров есть один недостаток: задержка считывания прямо пропорциональна длине каскада. На каждый считываемый бит нужно 1 раз «дёрнуть» CLK, а для 300 входов — 300 раз, соответственно. Частота «дёргания» ограничена быстродействием МК, и при большом количестве входов задержка может оказаться неприемлемой — возможно, придётся отказаться от функций Arduino и работать с периферией МК напрямую, что немного сложнее (но эффективнее).
Впрочем, если вы не планируете как-либо обрабатывать считываемые данные, и просто нужно, скажем, на каждую кнопку зажигать светодиод, то вы можете просто соединить выход последнего входного регистра в цепочке со входом первого выходного, и тогда можно обойтись без массива, а задача МК сведётся к дёрганию ножками:
Быстродействие наверное теоретически ограничено частотой процессора, ведь еще есть минимальная длительность сигналов CLK и сам бит информации, верно?
Задача следующая: Есть порядка 300 кнопок, необходимо в случае нажатия какой либо из них отправить в СОМ порт номер кнопки и зажечь светодиод в этой кнопке, для надежности наверное лучше еще принимать ответ от компьютера- подтверждение правильного приема: в виде того же номера и только после этого включать светодиод. Нажатия будут не чаще чем раз в секунду. Использовать планируется nano 16 МГц.
Еще как вариант есть идея разделить количество кнопок между несколькими платами, скажем по 100 на плату, а 4 платой принимать данные с 3-х и отправлять уже в СОМ. Но это в случает слишком большой задержки при использовании 1 платы.
Быстродействие наверное теоретически ограничено частотой процессора, ведь еще есть минимальная длительность сигналов CLK и сам бит информации, верно?
Верно, но максимальная частота работы использованных в статье регистров — 50 МГц, так что вы ограничены только частотой МК.
необходимо в случае нажатия какой либо из них отправить в СОМ порт номер кнопки и зажечь светодиод в этой кнопке, для надежности наверное лучше еще принимать ответ от компьютера
Ну да, нужен массив. Вы пульт охраны делаете? :) Если да, то проверять ответ обязательно, как и сообщать о его отсутствии.
Комментарии (15)
RSS свернуть / развернутьв моём случае это было очень критично и пришлось отказаться от такого каскада…
lehha
burjui
brujodentista
burjui
Gore123
burjui
На одном регистре все завел без проблем. Считать же больше восьми бит при каскадном подключении регистров не могу из-за того, что новые библиотеки не видятся, соответственно не воспринимается reg.setSelectionPolicy(SPI_Bus::SELECT_BEFORE);.
zed
burjui
Проблема в следующем: обычно, програмил в с++ и если надо было докинуть новую библиотеку (это файл с *.h), то его просто добавлял в лайбрариез и компилятор начинал её видеть и ей пользоваться. Заглянул в лайбрариез у ардуино. Там куча папок с названиями и уже внутри папок среди прочего может лежать та или иная библиотека. Ну, думаю, кину SPI_Bus.h и LineDriver.h в корень лайбрариез. Не помогло. Компилятор ругается. Кинул эти библиотеки вместе с папками, так как там всё в папках — не помогло. Вот за мысль подкинуть библиотечку к самому скетчу спасибо. Скорее всего так и надо было сразу сделать. Давно ничего не писал вот и туплю.
Собственно, после первых эмоций и неудачливых попыток с библиотеками, просто отказался от spi вообще и тупо программно сам начал параллельно считывать данные, стробировать (сдвигать побитово на выход регистра) и последовательно считывать данные ардуиной в булиновский массив нужного размера. Оказалось программно покороче и экономнее в плане использования памяти. Вопрос: такой алгоритм на много медленнее приведенного вами? Почему?
zed
C:\Users\User\Documents\Arduino\libraries\LineDriver\LineDriver.cpp:22:22: fatal error: WProgram.h: No such file or directory
#include «WProgram.h»
^
compilation terminated.
Ошибка компиляции.
kit4606
С уважением, Александр.
Sanische
Впрочем, если вы не планируете как-либо обрабатывать считываемые данные, и просто нужно, скажем, на каждую кнопку зажигать светодиод, то вы можете просто соединить выход последнего входного регистра в цепочке со входом первого выходного, и тогда можно обойтись без массива, а задача МК сведётся к дёрганию ножками:
burjui
Задача следующая: Есть порядка 300 кнопок, необходимо в случае нажатия какой либо из них отправить в СОМ порт номер кнопки и зажечь светодиод в этой кнопке, для надежности наверное лучше еще принимать ответ от компьютера- подтверждение правильного приема: в виде того же номера и только после этого включать светодиод. Нажатия будут не чаще чем раз в секунду. Использовать планируется nano 16 МГц.
Еще как вариант есть идея разделить количество кнопок между несколькими платами, скажем по 100 на плату, а 4 платой принимать данные с 3-х и отправлять уже в СОМ. Но это в случает слишком большой задержки при использовании 1 платы.
Sanische
Ну да, нужен массив. Вы пульт охраны делаете? :) Если да, то проверять ответ обязательно, как и сообщать о его отсутствии.
Тогда вообще можно не париться.
burjui
myfriend
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.