FPGA实现直流电机转速、电压、电流测量系统(基于EP4CE6F17C8 + INA226)
一、项目背景与目标
在电机控制系统中,实时监测电机的运行状态(如转速、电压、电流)对于系统稳定性、效率优化和故障诊断至关重要。本项目基于FPGA平台,利用Verilog HDL语言,设计一套完整的直流电机运行参数采集与显示系统,目标如下:
- Verilog HDL语言设计,Quartus18.1软件开发,FPGA型号EP4CE10,实现对直流电机的转速、工作电压、工作电流的测量;
- FPGA控制电机速度,电机驱动采用20kHz PWM信号,支持按键加减占空比控制速度;
- 测量电机转速、电机工作电压和电流,数码管默认显示转速,通过按键切换显示电压或电流;
- 超过设定速度,蜂鸣器报警;
- 其他功能可定制;
二、系统整体架构
系统由以下几个模块组成:
- PWM生成模块:输出20kHz、占空比可调的PWM信号,用于驱动直流电机;
- 转速测量模块:通过霍尔传感器或编码器输出的脉冲信号,利用FPGA计数器测量转速(单位:RPM);
- INA226通信模块:通过I²C总线读取INA226传感器的电压、电流数据;
- 数码管驱动模块:动态扫描6位共阴数码管,显示当前参数;
- 按键控制模块:检测按键状态,切换显示内容(转速 → 电压 → 电流 → 转速);
- 蜂鸣器模块:检测转速/电压/电流超限时,警告提示用户;
- 顶层模块:整合上述子模块,完成系统协同工作。
三、关键模块设计详解
1. PWM生成模块(20kHz可调)
FPGA系统时钟为50MHz,要生成20kHz PWM,周期为50μs,对应2500个时钟周期(FREQ_DIV_TIME = 50MHz / 20kHz = 2500),同时可手动给定占空比控制PWM脉宽。
module pwm_controller #(parameter SYS_FREQ = 'd50_000_000,parameter PWM_FREQ = 'd20_000
)(input wire clk, // 系统时钟input wire reset_n, // 复位信号input wire [7:0] duty, // 占空比 (0-100)output reg pwm_out // PWM输出信号
);localparam FREQ_DIV_TIME = SYS_FREQ / PWM_FREQ;reg [15:0] counter; // 计数器 用于生成PWM周期reg [7:0] duty_cycle_reg; // 内部寄存器存储占空比always @(posedge clk or negedge reset_n) beginif (!reset_n) begincounter <= 16'd0; // 复位时清零计数器pwm_out <= 1'b0; // 复位时PWM输出为低电平duty_cycle_reg <= 8'd0; // 复位时占空比为0end else beginif (counter >= FREQ_DIV_TIME - 1) begincounter <= 16'd0; // 计数器达到最大值后重置end else begincounter <= counter + 1; // 计数器递增end// 更新占空比寄存器duty_cycle_reg <= duty;// 根据占空比和计数器生成PWM信号if (counter < (FREQ_DIV_TIME * duty_cycle_reg) / 100) beginpwm_out <= 1'b1; // 高电平end else beginpwm_out <= 1'b0; // 低电平endendendendmodule
说明:通过修改
duty
值(如50 = 50%占空比),可调节电机转速。
2. 转速测量模块
假设电机每转输出N个脉冲(如霍尔传感器N=1,编码器N=12等),读取编码器数值并通过“频率法+编码倍频“实现转速测量:
- 在100毫秒定时窗口内计数脉冲数;
- 转速 RPM = (count / N) * 60 * (1000 / 100)。
其中关于AB相输出倍频的代码片段如下:
always @(posedge clk or negedge reset_n) beginif (!reset_n) beginA_prev <= 1'b0;B_prev <= 1'b0;end else beginA_prev <= A_debounced;B_prev <= B_debounced;endend// 边沿检测assign A_rising = ~A_prev & A_debounced; // A相上升沿assign A_falling = A_prev & ~A_debounced; // A相下降沿assign B_rising = ~B_prev & B_debounced; // B相上升沿assign B_falling = B_prev & ~B_debounced; // B相下降沿
代码中给定TIME_WINDOW计数值为100毫秒的时间,计数时间到后,转速输出的计算公式如下:
always @(posedge clk or negedge reset_n) beginif (!reset_n) begintimer_counter <= 0;end else begin/* 定时器与转速计算 */if (timer_counter < TIME_WINDOW) begintimer_counter <= timer_counter + 1;end else beginrpm <= (count * 60000 / time_period) / TOTAL_PULSES_PER_REV; // RPM = 转/mintimer_counter <= 0;endendend
3. INA226 I²C通信模块
INA226是一款高精度电流/电压监测芯片,支持I²C接口。FPGA需实现I²C主控逻辑,读取寄存器:
- Config Register(0x00):配置寄存器
- Bus Voltage Register (0x02):总线电压(mV)
- Current Register (0x04):电流(mA,需根据校准值计算)
- Power Register(0x03): 功率寄存器
- Calib Register(0x05): 校准寄存器(写入值用于配置最大采样电流)
该部分的I2C配置代码通用,关于配置寄存器的配置为:0x4527,转换为2进制为:0100_010_100_100_111,代表设备采用16次的采样平均值,其中电压采样周期为1.1ms,电流采样周期为1.1ms,并使用连续测量的工作模式去采集数据。
校准寄存器的配置计算如下:
其中分母为固定值,分子中SetCurrent为需要设置的采样电流大小,默认单位为安培(A),0.1是INA226的默认采样电阻阻值0.1欧姆。贴出部分代码:
module ina226_measure (input clk, // FPGA时钟输入input rst_n, // 复位信号output reg start, // I2C触发执行信号output reg wr_flag, // I2C读写控制信号output reg [ 7:0] reg_addr, // I2C器件内地址output reg [15:0] wdata, // I2C要写的数据input [15:0] rdata, // I2C读出的数据input done, // I2C一次操作完成// 输出传感器数据output reg [19:0] voltage, // 输出电压值 单位 mVoutput reg [19:0] current, // 输出电流值 单位 mAoutput reg [19:0] power // 输出功率值 单位 mW
);// INA226 寄存器地址和初始值定义(均为8位地址 寄存器数据16位)parameter CONFIG_REG = 8'h00; // 配置寄存器地址parameter VOLTAGE_REG = 8'h02; // 电压寄存器地址parameter CURRENT_REG = 8'h04; // 电流寄存器地址parameter POWER_REG = 8'h03; // 功率寄存器地址parameter CALIB_REG = 8'h05; // 校准寄存器地址parameter CONFIG_VAL = 16'h4527; // 配置寄存器写入值parameter CALIB_VAL = 16'h00A8; // 校准寄存器写入值 最大10A// 计算公式 CAL = 0.00512 / (10/32768) / 0.1Ω
4. 按键与数码管显示模块
按键消抖,使用20ms延时消抖:
// 参数计算localparam CNT_MAX = CLK_FREQ / 1000 * DEBOUNCE_TIME; // 计数器最大值// 内部寄存器定义integer i;reg [KEY_NUM-1:0] key_reg; // 按键输入寄存器reg [31:0] delay_cnt [7:0]; // 每个按键独立的计数器// 按键输入同步与计数器控制逻辑always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n) beginkey_reg <= 1; // 初始化按键寄存器为高电平for (i = 0; i < KEY_NUM; i = i + 1)delay_cnt[i] <= 32'd0; // 初始化计数器end else beginkey_reg <= key_in; // 同步按键输入for (i = 0; i < KEY_NUM; i = i + 1) beginif (key_reg[i] != key_in[i]) // 如果按键状态发生变化delay_cnt[i] <= CNT_MAX; // 重置计数器else if (delay_cnt[i] > 0) // 如果按键状态稳定且计数器未归零delay_cnt[i] <= delay_cnt[i] - 1; // 计数器递减endendend
数码管动态扫描:6位数码管,每位显示0~9,支持显示rpm(0~999999)、电压(0~36V → 显示为36000表示36.0V)、电流(0~10000mA)。
//cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
always @ (posedge dri_clk or negedge rst_n) beginif (rst_n == 1'b0)cnt_sel <= 3'b0;else if(flag) beginif(cnt_sel < 3'd5)cnt_sel <= cnt_sel + 1'b1;elsecnt_sel <= 3'b0;endelsecnt_sel <= cnt_sel;
end
再配合7段译码器输出到数码管。
四、顶层模块整合
module motor_measure_top (input sys_clk, /* 系统时钟输入 */input sys_rst_n, /* 系统复位输入 *//* 蜂鸣器相关 */output beep, /* 蜂鸣器引脚 *//* 编码器相关 */input A, /* 编码器A相 */input B, /* 编码器B相 *//* 电机相关 */output IN1, /* IN1 */output IN2, /* IN2 */output pwm_out, /* PWM占空比输出 *//* 按键相关 */input [4:0] key, /* 5个按键输入 *//* INA226电压电流采样模块 */inout sda, /* INA226 SDA */output scl, /* INA226 SCL *//* 数码管相关 */output [5:0] smg_bit, /* 数码管位选 */output [7:0] smg_seg /* 数码管段选 */
);// 内部信号声明...
// 实例化各子模块...endmodule
五、硬件连接说明
5.1 蜂鸣器及按键
FPGA引脚 | 外设功能 |
---|---|
M7 | 蜂鸣器输出 |
M15 | 按键输入K5 |
M16 | 按键输入K4 |
L10 | 按键输入K3 |
K10 | 按键输入K2 |
M2 | 按键输入K1 |
5.2 6位数码管
FPGA引脚 | 外设功能 |
---|---|
A2 | 数码管位选6 |
A3 | 数码管位选5 |
A4 | 数码管位选4 |
B5 | 数码管位选3 |
A5 | 数码管位选2 |
E6 | 数码管位选1 |
C8 | 数码管段选. |
A10 | 数码管段选G |
B9 | 数码管段选F |
E7 | 数码管段选E |
A7 | 数码管段选D |
D8 | 数码管段选C |
K8 | 数码管段选B |
A9 | 数码管段选A |
5.3 TB6612驱动+带编码器的直流电机
FPGA引脚 | 外设功能 |
---|---|
C9 | TB6612电机驱动的通道A_IN1输入 |
E10 | TB6612电机驱动的通道A_IN2输入 |
E9 | TB6612电机驱动的通道PWM输入 |
P15 | 带编码功能的直流电机编码器A相 |
P16 | 带编码功能的直流电机编码器B相 |
5.4 INA226采样模块
FPGA引脚 | 外设功能 |
---|---|
B8 | INA226 SCL |
F3 | INA226 SDA |
注意:INA226的Vbus接电机电源正极,Shunt电阻串联在GND回路中。
六、测试与效果
- 上电后数码管默认显示电机转速;
- 按下按键,依次切换为电压(如 10.345表示10.345V)、电流(如2.875 表示2.875A);
- 调节PWM占空比,可观察转速与电流同步变化;
- 系统响应快,无明显延迟,满足实时监测需求。
源码不开源,需要的友友可以私聊,如需课程设计定制也可私聊。