شمارنده یکی از پایهایترین و همچنین پرکاربردترین کامپوننتها در کار با FPGAها و طراحی دیجیتال میباشد. شما همچنین برای اینکه یک تایمر داشته باشید، در ابتد باید یک کانتر یا همان شمارنده بسازید و سپس با توجه به سرعت کلاک و نحوهی تغییرات شمارنده زمان مورد نظر خود را با استفاده کانتر موردنظر خود را بدست آورید.
شمارندهها انواع متفاوتی دارند، اما عملکرد کلی آنها به یک صورت است و شما با تغییرات کوچکی در هر یک از آنها میتوانید آن را به نوع دیگری تبدیل کنید.
ما در ادامه قصد داریم که با استفاده از زبان VHDL یک شمارنده BCD را توصیف کنیم. شمایی که در حال خواندن این مقاله هستید به احتمال زیاد با BCD و همینطور شمارنده BCD به خوبی آشنا هستید. اما به صورت مختصر در ادامه به شرح این موضوع خواهیم پرداخت.
BCD یا همان Binary Coded Decimal، نوعی کد برای تبدیل اعداد دهدهی به دودویی میباشد. اعداد در دنیای دیجیتال به صورت دودویی یا همان باینری میباشند. اما اعدادی که ما روزانه با آنها سر و کار داریم و در دنیای واقعی به صورت دهدهی یا دسیمال میباشند. پس لازم است که ما این تبدیل اعداد را انجام بدهیم.
برای اعداد در مبنای 10، ما ده عدد متفاوت داریم یعنی از 0 تا 9. حال اگر بخواهیم این اعداد را در مبنای 2 نشان بدهیم نیاز به چند بیت داریم؟
برای این کار نیاز به چهار بیت داریم. با چهار بیت میتوان شانزده حالت مختلف را نشان داد. ما از ده حالت آن استفاده میکنیم و بقیهی حالات آن عملا بدون استفاده باقی میمانند.
پس متوجه شدیم که در BCD هر عدد دسیمال با چهار بیت به صورت باینری نمایش داده میشود.
برای توضیحات بیشتر میتوانید به این لینک در ویکیپدیا یا این لینک از فرادرس مراجعه کنید.
به طور کلی شمارنده توصیف شدهی ما همانند تصویر زیر است:
با توجه به تصویر بالا شمارنده BCD از عدد 0 تا 9 میشمارد، و هنگامی که به عدد 9 رسید دوباره به مقدار 0 برمیگردد. تعریف BCD هم چیزی غیر از این نیست.
کدی که ما برای شمارنده BCD در زیر توصیف کردیم، دارای یک ریست آسنکرون است، یعنی هر زمان که ریست شد بدون توجه به کلاک مقدار شمارنده 0 میشود.
سپس اگر ریست فعال نبود و همچنین ماژول فعال بود، با هر لبه بالارونده کلاک یک واحد به شمارنده اضافه میشود. با یک شرط چک میشود که اگر بیشتر از 9 شد دوباره به مقدار 0 ریست شود.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity bcd_counter1 is port ( i_clk : in std_logic; i_rstb : in std_logic; i_sync_reset : in std_logic; i_count_ena : in std_logic; o_bcd : out std_logic_vector(3 downto 0)); end bcd_counter1; architecture rtl of bcd_counter1 is signal r_count : unsigned(3 downto 0); begin o_bcd <= std_logic_vector(r_count); p_count : process(i_clk,i_rstb) begin if(i_rstb='0') then r_count <= (others=> '0'); elsif(rising_edge(i_clk)) then if(i_sync_reset='1') then r_count <= (others=> '0'); elsif(i_count_ena='1') then if(r_count = 9) then r_count <= (others=> '0'); else r_count <= r_count + 1; end if; end if; end if; end process p_count; end rtl;
شما در پروژههایتان میتوانید با الگوبرداری از کد بالا هر شمارنده دیگر و حتی تایمر را پیادهسازی کنید.
ما کد دیگری را نیز برای اینکه شمارنده BCD را بر روی سون سگمنت نشان دهیم نوشتیم.
کد زیر همان عملکرد کد بالا است با این تفاوت که در هر State معادل سون سگمنت آن نیز نوشته شده است و در نهایت آن را به صورت عملی بر روی برد نمایش خواهیم داد.
توجه کنید که چون سون سگمتهایی که بر روی برد ALINX قرار دارند، آند مشترک هستند، هر سگمت با 0 منطقی روشن میشود. شما متناسب با بردتان میتوانید این مقادیر را تغییر دهید.
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity Counter_BCD is Port ( Clock : in STD_LOGIC; Scan_Sig : out unsigned (5 downto 0); Seven_Seg : out unsigned (7 downto 0) ); end Counter_BCD; architecture Behavioral of Counter_BCD is signal Seven_Segment_Int : unsigned (7 downto 0) := (others=>'0'); signal BCD_Int : unsigned (3 downto 0) := (others=>'0'); signal One_Sec_Counter : unsigned (25 downto 0) := (others=>'0'); begin Seven_Seg <= Seven_Segment_Int; Scan_Sig <= "111110"; process(Clock) begin if rising_edge(Clock) then One_Sec_Counter <= One_Sec_Counter + 1; if (One_Sec_Counter = to_unsigned(50000000,26)) then BCD_Int <= BCD_Int + 1; One_Sec_Counter <= (others=>'0'); end if; if (BCD_Int = to_unsigned(10,4)) then BCD_Int <= (others=>'0'); end if; case BCD_Int is when "0000" => Seven_Segment_Int <= "11000000"; when "0001" => Seven_Segment_Int <= "11111001"; when "0010" => Seven_Segment_Int <= "10100100"; when "0011" => Seven_Segment_Int <= "10110000"; when "0100" => Seven_Segment_Int <= "10011001"; when "0101" => Seven_Segment_Int <= "10010010"; when "0110" => Seven_Segment_Int <= "10000010"; when "0111" => Seven_Segment_Int <= "11111000"; when "1000" => Seven_Segment_Int <= "10000000"; when "1001" => Seven_Segment_Int <= "10010000"; when others => Seven_Segment_Int <= (others=>'0'); end case; end if; end process; end Behavioral;
ویدئوی زیر تست این کد را بر روی FPGA نشان میدهد
منبع : سیسوگ