0

我编写了一些组件来前后移动步进电机。我已经在 modelsim 中对其进行了模拟,它可以按预期工作,但它在硬件中的工作方式完全不同。

基本上我有一个电机驱动组件,它接受步数、保持时间和速度的命令,然后执行运动。然后我有 control_arbiter,它只是一个中间桥,连接想要访问电机的组件和电机驱动组件。最后我有一个“搜索模式”组件,它基本上发出命令来来回移动电机。

我的问题是,当它在硬件中运行时,我似乎无法改变方向,无论它是否在模拟中工作。

对此的任何帮助将不胜感激

电机驱动器:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;


entity motor_ctrl is

port(   clk: in std_logic;

        -- Hardware ports
        SCLK, CW, EN: out std_logic;    -- stepper driver control pins

        -- Soft ports
        Speed, steps: in integer;   
        dir: in std_logic;          -- 1 = CW; 0 = CCW;
        hold_time: in integer;      -- if > 0, steppers will be held on for this many clock periods after moving
        ready: out std_logic;       -- indicates if ready for a movement
        activate: in std_logic;     -- setting activate starts instructed motion. 
        pos_out: out integer            -- starts at 2000, 180deg = 200 steps, 10 full rotations trackable
        );

end motor_ctrl;


architecture behavioural of motor_ctrl is

type action is (IDLE, HOLD, MOVE);
signal motor_action: action := IDLE;

signal clk_new: std_logic;
signal position: integer := 2000;

signal step_count: integer := 0;
signal drive: boolean := false;

begin

-- Clock divider
clk_manipulator: entity work.clk_divide port map(clk, speed, clk_new);

-- Drive motors
with drive select
    SCLK <= clk_new when true,
                    '0' when false;

pos_out <= position;

process(clk_new)
    -- Counter variables
    variable hold_count: integer := 0;      
begin

    if rising_edge(clk_new) then
        case motor_action is

            when IDLE =>
                -- reset counter vars, disable the driver and assert 'ready' signal
                hold_count := 0;
                step_count <= 0;
                drive <= false;
                EN <= '0';
                ready <= '1';

                -- When activated, start moving and de-assert ready signal
                if(activate = '1') then
                    motor_action <= MOVE;
                end if;

            when HOLD =>
                -- Stop the step clock signal
                ready <= '0';
                drive <= false; 
                -- Hold for given number of clock periods before returning to idle state
                if(hold_count = hold_time) then
                    motor_action <= IDLE;
                end if;
                -- increment counter
                hold_count := hold_count + 1;

            when MOVE =>                    
                -- Enable driver, apply clock output and set direction
                ready <= '0';
                EN <= '1';
                drive <= true;
                CW <= dir;      

                -- track the position of the motor
                --if(dir = '1') then    
                --  position <= steps + step_count;
                --else
                --  position <= steps - step_count;
                --end if;

                -- Increment count until complete, then hold/idle
                if(step_count < steps-1) then
                    step_count <= step_count + 1;
                else
                    motor_action <= HOLD;
                end if;

        end case;
    end if;

end process;


end behavioural;

控制仲裁器:

entity Control_arbiter is

port (clk: in std_logic;
        EN, RST, CTRL, HALF, SCLK, CW: out std_logic_vector(2 downto 0)
        -- needs signals for levelling and lock
        );

end Control_arbiter;


architecture fsm of Control_arbiter is

type option is (INIT, SEARCH);
signal arbitration: option := INIT;

-- Motor controller arbiter signals
-- ELEVATION
signal El_spd, El_stps, El_hold, El_pos: integer;
signal El_dir, El_rdy, El_run: std_logic;


-- Search signals
signal search_spd, search_stps, search_hold: integer; 
signal search_dir, search_Az_run, search_El_run: std_logic := '0';
-- status
signal lock: std_logic := '0';

begin

-- Motor controller components
El_motor: entity work.motor_ctrl port map(clk, SCLK(0), CW(0), EN(0),
                                                        El_spd, El_stps, El_dir, El_hold, El_rdy, El_run);                                                      


-- Search component
search_cpmnt: entity work.search_pattern port map(  clk, '1', search_dir, search_stps, search_spd, search_hold, 
                                                                    El_rdy, search_El_run);


process(clk, arbitration)

begin

    if rising_edge(clk) then

        case arbitration is

            when INIT =>
                -- Initialise driver signals
                EN(2 downto 1) <= "11";
                CW(2 downto 1) <= "11";
                SCLK(2 downto 1) <= "11";
                RST  <= "111";
                CTRL <= "111";
                HALF <= "111";
                -- Move to first stage
                arbitration <= SEARCH;

            when SEARCH =>
                -- Map search signals to motor controllers
                El_dir  <= search_dir;
                El_stps <= search_stps;
                El_spd  <= search_spd;
                El_hold <= search_hold;
                El_run  <= search_El_run;
                -- Pass control to search
                -- Once pointed, begin search maneuvers
                 -- map search signals to motor controllers
                 -- set a flag to begin search
                 -- if new pointing instruction received, break and move to that position (keep track of change)
                 -- On sensing 'lock', halt search
                 -- return to holding that position


        end case;

    end if;

end process;


end fsm;

搜索模式:

entity search_pattern is

generic (step_inc: unsigned(7 downto 0) := "00010000"
            );
port (clk: in std_logic;
        enable: in std_logic;
        dir: out std_logic;
        steps, speed, hold_time: out integer;
        El_rdy: in std_logic;
        El_run: out std_logic
        );

end search_pattern;


architecture behavioural of search_pattern is

type action is (WAIT_FOR_COMPLETE, LATCH_WAIT, MOVE_EL_CW, MOVE_EL_CCW);
signal search_state: action := WAIT_FOR_COMPLETE;
signal last_state: action := MOVE_EL_CCW;

begin

hold_time <= 1; 
speed <= 1;
steps <= 2;

process(clk)

begin

    if rising_edge(clk) then

        -- enable if statement

            case search_state is

                when LATCH_WAIT =>
                    -- Make sure a GPMC has registered the command before waiting for it to complete
                    if(El_rdy = '0') then       -- xx_rdy will go low if a stepper starts moving
                        search_state <= WAIT_FOR_COMPLETE;      -- Go to waiting state and get ready to issue next cmd
                    end if;

                when WAIT_FOR_COMPLETE =>

                    -- Wait for the movement to complete before making next
                    if(El_rdy = '1') then       
                        -- Choose next command based on the last
                        if last_state = MOVE_EL_CCW then
                            search_state <= MOVE_EL_CW;
                        elsif last_state = MOVE_EL_CW  then
                            search_state <= MOVE_EL_CCW;
                        end if;
                    end if;             

                when MOVE_EL_CW =>
                    dir <= '1';
                    El_run <= '1';
                    last_state <= MOVE_EL_CW;
                    search_state <= LATCH_WAIT;

                when MOVE_EL_CCW =>
                    dir <= '0';
                    El_run <= '1';
                    last_state <= MOVE_EL_CCW;
                    search_state <= LATCH_WAIT;

                when others =>
                    null;
            end case;

        -- else step reset on not enable

    end if;

end process;

end behavioural;        

辛:http: //i.imgur.com/JAuevvP.png

4

1 回答 1

1

快速浏览您的代码,您应该更改一些内容以进行综合:

1)时钟分频器:使您的motor_driver进程对clk而不是clk_new敏感。要对时钟进行分频,每 n 个时钟产生一个 1 个时钟周期的使能信号。该过程的开始可能如下所示:

    process(clk)
        ... 
    begin

    if rising_edge(clk) then
        if enable='1' then
            case motor_action is
             ...

2) 表单的初始化

    signal position: integer := 2000;

仅适用于模拟,但不适用于合成。对于综合中的初始化,在过程中使用复位信号。

3) 向所有状态机添加“当其他人”子句,其中状态设置为定义的值(例如 search_state<=INIT)。

于 2013-03-21T21:57:12.567 回答