基于zybo z720开发板的pca9685的机械臂控制

文章目录

  • 设计基础
  • 模块说明
    • 模块框图
    • 参数解释
    • 模块详解
  • 代码实现
    • Control_setPWM
    • 顶层执行模块



设计基础

pca9685的舵机控制
Verilog实现IIC主机对从机的写操作(zybo z7板运行代码)


模块说明

模块框图

基于zybo z720开发板的pca9685的机械臂控制_第1张图片

参数解释

输入信号:
word[15:0]——输入理想的舵机角度
write[2:0]——输入指定转动的舵机序号
start——传输信号开始
initialize——重置所有舵机角度
输出信号:
SDA——IIC数据线
SCL——IIC时钟线

模块详解

IIC_SEND模块的主要功能为将接受到的并行8位数据信号,寄存器地址信号转为串行方式输出,同时在一次传输结束之后发送O_done_flag信号,告知控制模块一次发送完成。
Control_setPWM模块的主要功能为接受前一转换器模块发送来的控制信号,进而将16位数据信号转换为高8位和低8位分别发送,同时接受相应的write信号并将其转化为实际的从机的寄存器地址。因为每次改变舵机角度时需要发送4次IIC信号给pca9685驱动板,所以当Control_setPWM收到start信号时,进入一个4状态的有限状态机,在4状态循环内进入下一状态的标志为IIC_SEND完成一次发送的O_done_flag信号,同时在4状态完成时发送done信号代表一次控制命令执行完成。


代码实现

在Verilog实现IIC主机对从机的写操作(zybo z7板运行代码)
这篇博文中已经上传了verilog实现IIC信号传输的代码,所以这里只需要Control_setPWM模块的代码和顶层模块代码就可以实现了

Control_setPWM

//实现setPWM功能
module Control_setPWM(
    input O_done_flag,//检测一次IIC传输是否完成
    input [2:0]write,//输入地址写入信号(0--3号舵机)
    input [15:0]word,//输入16进制下降沿的时间
    input start,//开始信号,改变数据后是否开始传输
    input rst,
    input clk,
    
    input initialize,//初始化信号
    
    output  reg [7:0]word_add,//输出寄存器地址
    output  reg [7:0]data,//输出数据
    output  reg en,//输出使能信号
    output  reg done//一次命令传输完成
    
//    output reg [4:0]state//检验输出
    );
    //variation declaration
    reg en_reg,en_next;
    reg [4:0]state_reg,state_next;//有限状态机,一共5个状态,1个空闲位,一次发送4个数据
    reg [7:0]data_reg,data_next;
    reg [7:0]word_add_reg,word_add_next;
    reg [15:0]word_reg;//存储输入的下降沿时间
    reg done_reg,done_next;
    reg [16:0]i_reg,i_next;//循环计数值
    parameter ON_L=8'H06;//16进制
    parameter ON_H=8'H07;
    parameter OFF_L=8'H08;
    parameter OFF_H=8'H09;
    parameter PCA9685_MODE1=8'H00;//寄存器1地址
    parameter PCA9685_PRESCALE=8'HFE;//周期寄存器地址
    always@(posedge clk,posedge rst)
    if(rst) begin//没有输出数据
    state_reg<=0;
    data_reg<=0;
    word_add_reg<=0;
    en_reg<=0;
    done_reg<=0;
    i_reg=17'b11000011010100000;
//    i_reg<=5;
    end
    else begin
    state_reg<=state_next;
    data_reg<=data_next;
    word_add_reg<=word_add_next;
    en_reg<=en_next;
    done_reg<=done_next;
    i_reg<=i_next;
    end
    
    always@*
    begin
    state_next<=state_reg;
    data_next<=data_reg;
    word_add_next<=word_add_reg;
    en_next<=en_reg;
    done_next<=done_reg;
    case(state_reg)
    0://idle状态,复位所有寄存器,并让使能信号拉低
    if(initialize)//当有初始化信号时,优先进入初始化
    begin
    state_next<=26;//进入初始化状态
//    data_next<=8'b00110001;
    data_next<=8'b00000000;//1st发送全0信号
    word_add_next<=PCA9685_MODE1;//装载MODE1
    en_next<=1;
    done_next<=0;
    end
    else//再考虑传输信号
    if(start)//传输信号开始
    begin
    state_next<=1;
    word_add_next<=ON_L+4*write;
    data_next<=8'H00;//起始信号一直为0
    en_next<=1;//使能
    done_next<=0;
    end
    else begin
    state_next<=0;//停留在idle状态
    word_add_next<=0;
    data_next<=0;
    en_next<=0;//使能信号为低电平
    done_next<=0;//返回为低电平
    end
    1://ON_L状态
    if(O_done_flag)//接受传输是否完成信号,完成进入下一个状态
    begin
    state_next<=2;
    word_add_next<=ON_H+4*write;
        data_next<=0;
        en_next<=1;
        done_next<=0;
    end
    else begin
    state_next<=1;//保持
    end
    2://ON_H状态
    if(O_done_flag)
    begin
    state_next<=3;//发送完毕后进入下一个状态 
    word_add_next<=OFF_L+4*write;
            data_next<=word[7:0];//先输入前7位
            en_next<=1;
            done_next<=0;
    end
    else begin
    state_next<=2;
    end
    3://OFF_L状态
    if(O_done_flag)
    begin
        state_next<=4;//发送完毕后进入下一个状态 
        word_add_next<=OFF_H+4*write;//写入下降位高位地址
        data_next<=word[15:8];//先输入高8位
        en_next<=1;//使能传输 
        done_next<=0;//传输完成
        end
        else begin
        state_next<=3;
        end
    4://OFF_H状态
    if(O_done_flag)begin
        state_next<=0;//停留在idle状态
        word_add_next<=0;
        data_next<=0;
        en_next<=0;//使能信号为低电平
        done_next<=1;//结束信号才表示传输完成
        end
        else begin
        state_next<=4;
        end
    5://初始化第一个状态,进入睡眠,默认使用内部时钟
    if(O_done_flag)
    begin
    data_next<=8'b01111111;//127
    word_add_next<=PCA9685_PRESCALE;
    en_next<=1;
    state_next<=6;
    done_next<=0;
    end
    else
    state_next<=5;
    6://设置内部周期寄存器
    if(O_done_flag)
    begin
    data_next<=8'b00000000;//退出睡眠
     word_add_next<=PCA9685_MODE1;
        en_next<=1;
        state_next<=7;
        done_next<=0;
        i_next<=17'b11000011010100000;
//        i_next<=5;//提前给计数位赋值
    end
    else
    state_next<=6;
    7://延迟状态
    if(O_done_flag)
    begin
    state_next<=8;//进入延迟阶段
    done_next<=0;
    word_add_next<=0;
    data_next<=0;
    en_next<=0;//不传输信号
    i_next<=i_reg-1;//计数位自减
    end
    else
    state_next<=7;
    8://延迟1ms
    if(i_reg==0)
    begin
    state_next<=9;
    data_next<=8'b10100001;//发送重置信号
        word_add_next<=PCA9685_MODE1;
        en_next<=1;
        done_next<=0;
        end
    else
    begin
    state_next<=8;//保留在延迟阶段
    done_next<=0;
    word_add_next<=0;
    data_next<=0;
    en_next<=0;//不传输信号
    i_next<=i_reg-1;//计数位自减
    end
    9://复位信号
    if(O_done_flag)//回归0状态
    begin
       state_next<=10;
       data_next<=8'b00000000;
       en_next<=1;
       done_next<=1;//复位完成,进入重载信号,标志位放1
       word_add_next<=ON_L;//写入0号舵机寄存器低位
       end
       else
       state_next<=9;
    10://0号舵机
    if(O_done_flag)  
    begin
    state_next<=11;
    data_next<=0;
    en_next<=1;
    done_next<=0;
    word_add_next<=ON_H;//写入0号舵机寄存器高位
    end
    else
    state_next<=10;//保留在10
    11:
    if(O_done_flag) begin
    state_next<=12;
    data_next<=8'b00110011;
    en_next<=1;
    done_next<=0;
    word_add_next<=OFF_L;//写入0号舵机寄存器低位
    end
    else
    state_next<=11;
    12:
    if(O_done_flag) begin
       state_next<=13;
       data_next<=8'b00000001;
       en_next<=1;
       done_next<=0;
       word_add_next<=OFF_H;//写入寄存器高位
       end
       else
       state_next<=12;
    13:
     if(O_done_flag) begin
    state_next<=14;
    data_next<=8'b00000000;
    en_next<=1;
    done_next<=0;
    word_add_next<=ON_L+4;//写入1号舵机寄存器低位
       end
       else
       state_next<=13;
    14:
    if(O_done_flag) begin
        state_next<=15;
        data_next<=8'b00000000;
        en_next<=1;
        done_next<=0;
        word_add_next<=ON_H+4;//写入1号舵机寄存器高位
           end
           else
           state_next<=14;
     15:
     if(O_done_flag) begin
         state_next<=16;
         data_next<=8'b00110011;
         en_next<=1;
         done_next<=0;
         word_add_next<=OFF_L+4;//写入1号舵机寄存器低位
            end
            else
            state_next<=15;
            16:
            if(O_done_flag) begin
                     state_next<=17;
                     data_next<=8'b00000001;
                     en_next<=1;
                     done_next<=0;
                     word_add_next<=OFF_H+4;//写入1号舵机寄存器低位
                        end
                        else
                        state_next<=16;
    17:
    if(O_done_flag) begin
             state_next<=18;
             data_next<=8'b00000000;
             en_next<=1;
             done_next<=0;
             word_add_next<=ON_L+8;//写入1号舵机寄存器低位
                end
                else
                state_next<=17;
    18:
    if(O_done_flag) begin
             state_next<=19;
             data_next<=8'b00000000;
             en_next<=1;
             done_next<=0;
             word_add_next<=ON_H+8;//写入1号舵机寄存器高位
                end
                else
                state_next<=18;
    19:
    if(O_done_flag) begin
                 state_next<=20;
                 data_next<=8'b00110011;
                 en_next<=1;
                 done_next<=0;
                 word_add_next<=OFF_L+8;//写入1号舵机寄存器低位
                    end
                    else
                    state_next<=19;
     20:
     if(O_done_flag) begin
                  state_next<=21;
                  data_next<=8'b00000001;
                  en_next<=1;
                  done_next<=0;
                  word_add_next<=OFF_H+8;
                     end
                     else
                     state_next<=20;
    21:
    if(O_done_flag) begin
                 state_next<=22;
                 data_next<=8'b00000000;
                 en_next<=1;
                 done_next<=0;
                 word_add_next<=ON_L+12;
                    end
                    else
                    state_next<=21;
    22:
    if(O_done_flag) begin
                     state_next<=23;
                     data_next<=8'b00000000;
                     en_next<=1;
                     done_next<=0;
                     word_add_next<=ON_H+12;
                        end
                        else
                        state_next<=22;
    23:
    if(O_done_flag) begin
                         state_next<=24;
                         data_next<=8'b00110011;
                         en_next<=1;
                         done_next<=0;
                         word_add_next<=OFF_L+12;
                            end
                            else
                            state_next<=23;
    24:
    if(O_done_flag) begin
                         state_next<=25;
                         data_next<=8'b00000001;
                         en_next<=1;
                         done_next<=0;//写完OFF高位代表4个舵机全部初始化完成,返回done信号
                         word_add_next<=OFF_H+12;
                            end
                            else
                            state_next<=24;
    25:
    if(O_done_flag) begin
                         state_next<=0;//返回idle状态
                         data_next<=8'b00000000;//数据位置零
                         en_next<=0;//发送位置0
                         done_next<=1;//完成标志位置0
                         word_add_next<=0;//寄存器都置零
                        end
                        else
                       state_next<=25;
    26:
     if(O_done_flag) begin
                         state_next<=5;//进入睡眠状态
                         data_next<=8'b00010000;//数据位置零,1的位置出错!!!!
                         en_next<=1;//发送位置1
                         done_next<=0;//完成标志位置0
                         word_add_next<=PCA9685_MODE1;//寄存器都置零
                        end
                        else
                       state_next<=26;
    default:
    begin
    state_next<=0;//默认进入空闲位
    word_add_next<=0;
    en_next<=0;
    data_next<=0;
    done_next<=0;
    end
    endcase
    end
    
    //output logic
    always@(posedge clk) begin
    data<=data_reg;
    word_add<=word_add_reg;
    en<=en_reg;
    done<=done_reg;
//    state<=state_reg;
    end
    
endmodule//实现setPWM功能

顶层执行模块

module IIC_RECEIVE_COMMAND(
    input clk,
    input rst,
    input start,
    input initialize,
    input [2:0]write,
    input [15:0]word,
    output O_scl,
    output IO_sda,
    output done
//    output [4:0]state
    );
    
    wire [7:0]word_add;//地址线
    wire [7:0]data;//数据线
    wire O_done_flag;//完成标志位
    wire en;//使能线
    
//    reg [2:0]write=3'b001;//2号舵机
//    reg [15:0]word=16'H00ef;//角度为60度,占空比6%
    
    Control_setPWM c1(
    .O_done_flag(O_done_flag),
    .write(write),
    .word(word),
    .rst(rst),
    .clk(clk),
    .start(start),
    .initialize(initialize),
    .done(done),
    .en(en),//使能信号
    .data(data),
    .word_add(word_add)
//    .state(state)
    );
    
    IIC_SEND t1(
    .I_clk(clk),
    .I_rst_n(rst),
    .I_iic_send_en(en),
    .I_word_addr(word_add),
    .I_write_data(data),
    .O_done_flag(O_done_flag),
    .O_scl(O_scl),
    .IO_sda(IO_sda)
    );
endmodule

你可能感兴趣的:(VIVADO)