Мы продолжаем изучение ПЛИС и языка VHDL. В данной статье, ориентированной на новичков, мы изучим явление «дребезг контактов» и рассмотрим способ избавления от него.
Итак, цель работы: Изучить явление «дребезг контактов», создать проект в Xilinx ISE Project Navigator: При нажатии на кнопку значение регистра увеличивается на 1.
«Дре́безг — явление, возникающее в электрических и электронных переключателях, при котором они вместо некоторого стабильного сигнала выдают на выходе случайные высокочастотные колебания» (с) Википедия.
Говоря проще, при нажатии и отпускании кнопки она переходит в нужное состояние не сразу. Какое-то время контакты кнопки «дребезжат» между собой, что будет воспринято микроконтроллером как многократные импульсы. Количество этих импульсов может превышать тысячи. Наглядно дребезг можно увидеть на осциллограмме, на которой показан момент отпускания кнопки:
В моей предыдущей статье было подробно описано создание нового проекта для Spartan-3E Starter Kit в Xilinx ISE Project Navigator v12.3. Создадим проект еще раз, назовем его, например, drebezg_habr и внесем в него некоторые изменения:
1. Нам потребуется одна кнопка и восемь светодиодов. Добавим входной сигнал btn и 8 выходных сигналов led в порты:
2. В файле pin.ucf напишем имена ножек, соответствующие кнопке и каждому светодиоду:
Ножка K17 соответствует нижней кнопке из имеющихся:
Слово PULLUP подключает кнопку по следующей схеме (прямо внутри ПЛИС):
Переходим в файл drebezg_habr.vhd. Создадим 8-битный регистр-счетчик, который мы будем пытаться прибавлять на единицу при однократном нажатии кнопки: между architecture и begin пишем
И сразу же, после слова begin, направляем этот счетчик на наши светодиоды:
Теперь наша задача прибавить единицу к счетчику count_led при нажатии кнопки. Сразу же напрашивается решение сделать переменную, которая бы хранила предыдущее состояние кнопки и сравнивалась с ее текущим состоянием. Давайте так и сделаем:
Транслируем, зашиваем, тестируем. Уверен, что результат вас совершенно не устроит, ибо диоды будут просто совершенно неупорядоченно мигать. Это связано с тем, что событий if old_btn = '0' and btn = '1' then во время нажатия и отпускания кнопки очень много как раз из-за дребезга контактов. Чтобы избавиться от этого явления нам необходимо дождаться четко установившегося значения логической единицы. Для этого мы заведем счетчик, который увеличивается на 1, пока кнопка имеет значение логической единицы. Счетчик обнуляется, если кнопка приняла значение логического нуля. Таким образом, сколько бы не было импульсов во время нажатия кнопки из-за дребезга, настанет момент, когда значение btn четко установится в логическую единицу, счетчик достигнет определенного значения, и мы сможем судить о том, что действительно было совершено нажатие кнопки. Теперь нам не потребуется переменная old_btn.
Значение btn_wait было выбрано 0.25 секунды для того, чтобы значение count_led не прибавлялось слишком часто, пока кнопка находится в зажатом состоянии.
Еще один вариант антидребезга (даже более надежный) — прибавление count на 1 когда btn является логической единицей, и вычитание из count 1 когда btn является нулем. При этом если значение count опускается до 0 значит кнопка не нажата, либо был дребезг. Ну а если count досчитал до заветного btn_wait значит произошло нажатие =)
В качестве домашнего задания могу посоветовать дописать проект: сделайте прибавление count_led после того, как кнопка была нажата и отпущена.
Итак, мы ознакомились на практике с явлением «дребезг контактов» и научились избавляться от него. Это явление можно наблюдать не только в кнопках, тумблерах и прочих подобных вещах, но даже иногда и в различных протоколах, например RS-232.
Исходники проекта здесь. Желаю всем успехов в освоении ПЛИС!
Итак, цель работы: Изучить явление «дребезг контактов», создать проект в Xilinx ISE Project Navigator: При нажатии на кнопку значение регистра увеличивается на 1.
Часть 1. Что такое «дребезг контактов»?
«Дре́безг — явление, возникающее в электрических и электронных переключателях, при котором они вместо некоторого стабильного сигнала выдают на выходе случайные высокочастотные колебания» (с) Википедия.
Говоря проще, при нажатии и отпускании кнопки она переходит в нужное состояние не сразу. Какое-то время контакты кнопки «дребезжат» между собой, что будет воспринято микроконтроллером как многократные импульсы. Количество этих импульсов может превышать тысячи. Наглядно дребезг можно увидеть на осциллограмме, на которой показан момент отпускания кнопки:
Часть 2. Создание проекта.
В моей предыдущей статье было подробно описано создание нового проекта для Spartan-3E Starter Kit в Xilinx ISE Project Navigator v12.3. Создадим проект еще раз, назовем его, например, drebezg_habr и внесем в него некоторые изменения:
1. Нам потребуется одна кнопка и восемь светодиодов. Добавим входной сигнал btn и 8 выходных сигналов led в порты:
entity drebezg_habr is
Port ( clk : in STD_LOGIC;
btn : in STD_LOGIC;
led : out STD_LOGIC_VECTOR(7 downto 0));
end drebezg_habr;
2. В файле pin.ucf напишем имена ножек, соответствующие кнопке и каждому светодиоду:
NET "clk" LOC = "C9";
NET "led<0>" LOC = "F12";
NET "led<1>" LOC = "E12";
NET "led<2>" LOC = "E11";
NET "led<3>" LOC = "F11";
NET "led<4>" LOC = "C11";
NET "led<5>" LOC = "D11";
NET "led<6>" LOC = "E9";
NET "led<7>" LOC = "F9";
NET "btn" LOC = "K17";
NET "btn" PULLUP;
Ножка K17 соответствует нижней кнопке из имеющихся:
Слово PULLUP подключает кнопку по следующей схеме (прямо внутри ПЛИС):
Часть 3. Программирование.
Переходим в файл drebezg_habr.vhd. Создадим 8-битный регистр-счетчик, который мы будем пытаться прибавлять на единицу при однократном нажатии кнопки: между architecture и begin пишем
signal count_led: std_logic_vector(7 downto 0);
И сразу же, после слова begin, направляем этот счетчик на наши светодиоды:
led <= count_led;
Теперь наша задача прибавить единицу к счетчику count_led при нажатии кнопки. Сразу же напрашивается решение сделать переменную, которая бы хранила предыдущее состояние кнопки и сравнивалась с ее текущим состоянием. Давайте так и сделаем:
architecture Behavioral of drebezg_habr is
signal count_led: std_logic_vector(7 downto 0);
signal old_btn: std_logic;
begin
process(clk)
begin
if rising_edge(clk) then
old_btn <= btn;
if old_btn = '0' and btn = '1' then
count_led <= count_led + 1;
end if;
end if;
end process;
led <= count_led;
end Behavioral;
Транслируем, зашиваем, тестируем. Уверен, что результат вас совершенно не устроит, ибо диоды будут просто совершенно неупорядоченно мигать. Это связано с тем, что событий if old_btn = '0' and btn = '1' then во время нажатия и отпускания кнопки очень много как раз из-за дребезга контактов. Чтобы избавиться от этого явления нам необходимо дождаться четко установившегося значения логической единицы. Для этого мы заведем счетчик, который увеличивается на 1, пока кнопка имеет значение логической единицы. Счетчик обнуляется, если кнопка приняла значение логического нуля. Таким образом, сколько бы не было импульсов во время нажатия кнопки из-за дребезга, настанет момент, когда значение btn четко установится в логическую единицу, счетчик достигнет определенного значения, и мы сможем судить о том, что действительно было совершено нажатие кнопки. Теперь нам не потребуется переменная old_btn.
architecture Behavioral of drebezg_habr is
signal count_led: std_logic_vector(7 downto 0);
constant clk_freq : integer := 50_000_000; -- частота кварца
constant btn_wait : integer := clk_freq/4; -- будем ждать 0.25 секунды установления единицы
signal count : integer range 0 to btn_wait := 0;
begin
process(clk)
begin
if rising_edge(clk) then
if btn = '1' then
count <= count + 1;
if count = btn_wait then
count_led <= count_led + 1;
count <= 0;
end if;
else
count <= 0;
end if;
end if;
end process;
led <= count_led;
end Behavioral;
Значение btn_wait было выбрано 0.25 секунды для того, чтобы значение count_led не прибавлялось слишком часто, пока кнопка находится в зажатом состоянии.
Еще один вариант антидребезга (даже более надежный) — прибавление count на 1 когда btn является логической единицей, и вычитание из count 1 когда btn является нулем. При этом если значение count опускается до 0 значит кнопка не нажата, либо был дребезг. Ну а если count досчитал до заветного btn_wait значит произошло нажатие =)
В качестве домашнего задания могу посоветовать дописать проект: сделайте прибавление count_led после того, как кнопка была нажата и отпущена.
Итак, мы ознакомились на практике с явлением «дребезг контактов» и научились избавляться от него. Это явление можно наблюдать не только в кнопках, тумблерах и прочих подобных вещах, но даже иногда и в различных протоколах, например RS-232.
Исходники проекта здесь. Желаю всем успехов в освоении ПЛИС!