Судя по всему прошлый пример, не смотря на простоту идеи получился весьма не удачным. Суть идеи была поделить входную частоту кварца (100МГц), до воспринимаемых человеком 1-2Гц. Вроде как получилось, но осталось больше вопросов, чем ответов, поэтому я решил продолжить изыскания в этой области.
Начнем с вопросов. Оказалось самым сложным сформировать точную задержку. Попытаюсь донести идею. У нас в распоряжении только логика, никаких переменных, циклов и пр. В прошлой статье, я пытался донести, что можно использовать делитель частоты на D триггерах. Но если все время делить частоту пополам, после первого триггера 50Мгц, после второго 25 и т.д. В итоге у нас будет дробная частота, самое близкое к 1Гц это 1,49Гц, на это потребуется 26 D триггеров(делителей). Для компиляции прошлого проекта было «скушано» 62 логических элемента из 240, на мой взгляд это слишком круто, для того чтобы просто помигать диодом.
Но хотелось более точных формирований временных промежутков. В долгих поисках, ничего лучше чем сделать счетчик и считать до определенного значения я не нашел. Работает это так: считаем например от 0 до 100, при достижении 100 сбрасываем счетчик в 0 и инвертируем некий регистр, который будет входной частотой для какого то другого процесса, делитель при этом получится 200, ибо 100 это половина периода.
Реализовать это в виде схемы сложно, зато на Verilog написать легко: входная частота osc, счетчик count, выход clk
module reduced_osc (osc, clk); input osc; // Output of internal osc output clk; // Reduced frequency clock reg [25:0] count; reg clk; initial begin count = 0; clk = 0; end always @ (posedge osc) begin count <= count + 1; if(count == 100)begin clk <= !clk; end end endmodule |
Сразу видно, чем ниже выходная частота, тем больше жрет ресурсов, а если посмотреть RTL схему, то волосы зашевелятся даже там где их нет. Но зато работает точно и исправно. Я запросто намутил себе меандр 1Гц, 10кГц, и 100кГц, поделив соответственно на 50 000 000, 5 000 и 500.
Можно заметить что счетчик count в зависимости от того, на сколько будем делить, можно делать разной разрядности, поэтому, если в схеме не нужна большая скорость, нет смысла ставить большой кварц, это сэкономит ресурсы.
Для отсчета секундных промежутков можно тактироваться от часового кварца на 32768Гц, но на мой взгляд весь кайф в том, чтобы все реализовывать внутри плисины, при этом максимально уменьшая габариты конечного устройства. В общем, сделать можно, но следует несколько раз подумать, ибо формирование длинных промежутков времени не та задача, ради которой стоит юзать ПЛИС, микроконтроллер с этим явно справится лучше.
После того, как стало понятно как отмерить временной промежуток, я решил сделать себе таймер. Но возможности марсохода оказались весьма ущербными, ибо доступных юзеру ножек совсем мало, поэтому я не стал цеплять больше одного индикатора. Мой индикатор с общим анодом, т.е. сегмент включается при наличии нуля на ножке, а не единицы.
Очень важно!!! У платы марсоход 1, некоторые ножки объединены по схеме, по умолчанию не настроенные ножки сидят на земле. Таким образом когда вы включаете ножку и если она объединена с другой, можно устроить коротыш. В общем, не подключенные ножки нужно обязательно настроить как входы (Tri-z). Привязку ножек к сегментам можно посмотреть в Pin planner, резисторы на 100 Ом.
Теперь к прошивке. Если бы мы жили в средние века, инквизиторы наверняка сожгли бы меня на костре, за такой код. В общем понятно, что можно заюзать BCD, как скилл прокачаю, дополню статью. Пока как есть.
module test_timer (osc, clk, e, d, c, b, a, f, g); input osc; // Output of internal osc output clk; // Reduced frequency clock output e;output d;output c;output b; //ножки сегментов output a;output f;output g; reg [26:0] count; reg [3:0] sek; reg clk; reg e;reg d;reg c;reg b;reg a;reg f; reg g; initial begin count = 0; clk=0; e=1;d=1;c=1; b=1;a=1;f=1; g=1; end always @ (posedge clk) begin sek <= sek + 1; if(sek==0)begin e <= 0; d <= 0; c <= 0; b <= 0; a <= 0; f <= 0; g <= 1; end if(sek==1)begin e <= 1; d <= 1; c <= 0; b <= 0; a <= 1; f <= 1; g <= 1; end if(sek==2)begin e <= 0; d <= 0; c <= 1; b <= 0; a <= 0; f <= 1; g <= 0; end if(sek==3)begin e <= 1; d <= 0; c <= 0; b <= 0; a <= 0; f <= 1; g <= 0; end if(sek==4)begin e <= 1; d <= 1; c <= 0; b <= 0; a <= 1; f <= 0; g <= 0; end if(sek==5)begin e <= 1; d <= 0; c <= 0; b <= 1; a <= 0; f <= 0; g <= 0; end if(sek==6)begin e <= 0; d <= 0; c <= 0; b <= 1; a <= 0; f <= 0; g <= 0; end if(sek==7)begin e <= 1; d <= 1; c <= 0; b <= 0; a <= 0; f <= 1; g <= 1; end if(sek==8)begin e <= 0; d <= 0; c <= 0; b <= 0; a <= 0; f <= 0; g <= 0; end if(sek==9)begin e <= 1; d <= 0; c <= 0; b <= 0; a <= 0; f <= 0; g <= 0; sek<=0; end end always @ (posedge osc) begin count <= count + 1; if(count == 50000000) begin clk <= !clk; count <= 0; end end endmodule |
Пояснять тут особо нечего, если секунда 0, то включаем сегменты e, d, c, b, a, f. При этом g выключаем. Когда секунда равна 1, c и b включены, а остальные выключены и т.д. Второй блок это делитель частоты. Собственно все.
Проект кактуса
Про tri-state на ножки и коротыш написано у марсохода в статье по сборке первого проекта.
Да, но не забывайте, когда человек впервые берет в руки совершенно новую для него девайсину, то не знаешь всех тонкостей. Был у меня программатор, у которого не было никакой защиты по питанию, а узнал я об этом, когда случайно перепутал концы, сдох сразу. Поэтому стараюсь избегать всех возможных ситуаций, где можно накосячить, ибо рано или поздно это все равно случится.
Правильно, что написали про особенность, я не спорю. За плевок в сторону довольно неплохого проекта обидно.
Написал помягче дабы не обидеть никого) Мои претензии к первой плате, в моем видении она должна быть другой, вот и все.
Светодиодик мигает еще на плате =)