单相逆变电源软件设计

文章目录

  • 单相逆变电源软件设计
  • 一、题目要求
    • 1.题目
    • 2.系统总体框图
  • 二、控制核心及环境配置
    • 1.CCS环境配置
    • 2.Quartus环境配置
  • 三、软件核心功能
    • 1.产生SPWM波
    • 2.PID算法调控输出电压
    • 3.顶层设计
  • 四、其他
    • 1.FPGA生成固化文件
    • 2.其他代码
  • 总结

一、题目要求

1.题目


要求设计并制作输入为15V直流电压,输出为10V正弦交流电压的单相逆变电源。

2.系统总体框图

软件思路:
FPGA:利用Matlab生成正弦及三角波查找表,在Quartus中使用rom查表产生正弦波与三角波,比较二者的大小,正弦波大于三角波为“1”,正弦波小于三角波为“0”(双极性调制),产生两路互补的SPWM波,经由逆变电路及滤波电路最终可以得到正弦交变电压,通过改变正弦波的幅值可以改变最终输出电压的大小。
单片机:接收频率设定并传给FPGA,显示当前状态,进行AD采样数字信号到具体值的转换,PID算法稳压。
AD采样:采用ADS8688进行采样,通过积分法Urms2=1T∫0T∣U∣2dtU_{rms}^2=\frac{1}{T}{\int_{0}^{T}}\left| U \right| ^ 2dtUrms2​=T1​∫0T​∣U∣2dt得到交流有效值。

二、控制核心及环境配置

tiva系列单片机:TM4C123GH6PM
Cyclone IVE 系列FPGA:EP4CE6E22C8
IDE:Code Composer Studio 以及 Quartus 17.0

1.CCS环境配置

Code Composer Studio配置:

2.Quartus环境配置

Quartus 17.0配置:

三、软件核心功能

1.产生SPWM波

方案一:单极性调制

方案二:双极性调制

这里我使用的是方案二,双极性调制产生正弦波。
首先利用Matlab产生正弦查找表以及三角波查找表。

产生正弦查找表的代码如下:

ADDR_WIDTH=12;
DATA_WIDTH=16;
depth=2^ADDR_WIDTH;
x=ceil(((2^DATA_WIDTH/2-1)*sin(0:pi*2/depth:2*pi)+2^DATA_WIDTH/2));
fid=fopen('sinrom1.mif','w');
fprintf(fid,'width=%d;\n',DATA_WIDTH);
fprintf(fid,'depth=%d;\n',depth);
fprintf(fid,'address_radix=uns;\n');
fprintf(fid,'data_radix=uns;\n');
fprintf(fid,'Content Begin\n');
for(k=1:depth)fprintf(fid,'%d:%d;\n',k-1,x(k));
end
fprintf(fid,'end;');

产生三角波查找表的代码如下:

ADDR_WIDTH=12;
DATA_WIDTH=16;
depth=2^ADDR_WIDTH;
x=ceil(2*(2^DATA_WIDTH/2-1)*sawtooth(0:pi*2/depth:2*pi)+2^DATA_WIDTH - 1);
y=ceil(-2*(2^DATA_WIDTH/2-1)*sawtooth(0:pi*2/depth:2*pi)+2^DATA_WIDTH - 1);
fid=fopen('trirom1.mif','w');
fprintf(fid,'width=%d;\n',DATA_WIDTH);
fprintf(fid,'depth=%d;\n',depth);
fprintf(fid,'address_radix=uns;\n');
fprintf(fid,'data_radix=uns;\n');
fprintf(fid,'Content Begin\n');
for(k=1:depth/2)fprintf(fid,'%d:%d;\n',k-1,x(k));
end
for(j=depth/2+1:depth)fprintf(fid,'%d:%d;\n',j-1,y(j));
end
fprintf(fid,'end;');

然后在Quartus中利用IP核生成rom查找表实例。

一路Next直到下图所示页面,如图所示选中Matlab生成的.mif文件作为查找表。

最后勾选生成实例文件即可。

生成正弦波和三角波后,比较生成互补的SPWM波,注意要设置死区!

生成SPWM波代码如下:

always @(posedge clk, negedge rst_n)
beginif(!rst_n)beginspwm1_tmp <= 0;spwm2_tmp <= 0;cnt1 <= 0;cnt2 <= 0;endelsebegin//spwm1if(sin_sig >= tri_sig)     //延后一段时间再拉高beginif(cnt1 >= dead)            //cnt1 == deadbeginspwm1_tmp <= 1;cnt1 <= 0;endelse if(spwm1_tmp != 1)   //spwm1还没被拉高,则计数cnt1 <= cnt1 + 1;else;  endelsebegin spwm1_tmp <= 0; end//spwm2 if(sin_sig >= tri_sig)begin spwm2_tmp <= 0; endelse                             //延后一段时间再拉高beginif(cnt2 >= dead)            //cnt == deadbeginspwm2_tmp <= 1;cnt2 <= 0;endelse if(spwm2_tmp != 1)    //spwm2还没被拉高,则计数cnt2 <= cnt2 + 1;else;  endend
end

2.PID算法调控输出电压

调控输出电压可以通过改变正弦波的调制度来实现。这里我使用ADS8688芯片进行交流采样,计算获取交流电压的有效值(代码放在其他代码的压缩包中)。

PID调控代码如下:

void PID(void)
{double deltK;deltV[2] = Vset - Vrms;deltK = Kp * (deltV[2] - deltV[1]) + Ki * deltV[2] + Kd * (deltV[2] - 2 * deltV[1] - deltV[0]);deltV[0] = deltV[1];deltV[1] = deltV[2];K = K + (int)deltK;if(K > KMAX)K = KMAX;else;if(K < KMIN)K = KMIN;else;}

让输出电压稳定的关键一在PID参数选取的适当,二在AD采样准确稳定。

3.顶层设计

Verilog顶层文件:

module DC_AC
(
input wire clk,             // 50MHz
input wire rst_n,
input wire [7:0]ADDR,
input wire RD,WR,
input wire SDO,                         // ADS8688 串行数字输出
//input wire [15:0] K,
//input wire [23:0] fs,output wire spwm1_sig,
output wire spwm2_sig,
output wire irq,
output wire RST,                                // ADS8688 复位信号
output wire CS,                         // ADS8688 片选信号(低电平有效)
output wire SCLK,                           // ADS8688 串行时钟
output wire SDI,                            // ADS8688 串行数字输入
output wire alarm,inout wire [15:0]DATA,
inout wire [3:0]KEY_H,KEY_V
);wire cs0,cs1,cs2,cs3,cs4,cs5,cs6;
wire software_rst_n;
wire [7:0] rddat0;  //mcu读键盘值   CS0
wire [15:0] wrdat0;
wire [15:0] wrdat1; //K CS5
wire [15:0] wrdat2;
wire [15:0] wrdat3; //fs    CS7
wire datacs0,datacs1;
wire [3:0]addr_ad;wire [23:0] fc = 24'd17_000;    //载波频率17k
wire [23:0] fs;     //调制频率
wire [15:0] K;      //调制度
wire [15:0] sin_sig;
wire [15:0] tri_sig;
wire clk_50Hz;wire [15:0] outRMS0;  //CS1
wire [15:0] outRMS1;    //CS2assign fs = wrdat3;
assign K = wrdat1;assign alarm = (K>500)?0:1;Sin Sin_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.fre(fs) ,   // input [23:0] fre_sig.sin_sig(sin_sig)    // output [15:0] sin_sig_sig
);Tripul Tripul_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.fre(fc) ,   // input [23:0] fre_sig.tri_sig(tri_sig)    // output [15:0] tri_sig_sig
);SPWM SPWM_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.sin_input(sin_sig) ,    // input [15:0] sin_input_sig.tri_sig(tri_sig) ,    // input [15:0] tri_sig_sig.K(K)    ,.spwm1_sig(spwm1_sig) ,    // output  spwm1_sig_sig.spwm2_sig(spwm2_sig)   // output  spwm2_sig_sig
);clkdiv clkdiv_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.div(32'd1_000_000) ,   // input [31:0] div_sig.clkout(clk_50Hz)    // output  clkout_sig
);BUS BUS_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.ADDR(ADDR) ,    // input [7:0] ADDR_sig.RD(RD) ,    // input  RD_sig.WR(WR) ,   // input  WR_sig.DATA(DATA) ,   // inout [7:0] DATA_sig.software_rst_n(software_rst_n) ,    // output  software_rst_n_sig.cs0(cs0) ,    // output  cs0_sig.cs1(cs1) ,   // output  cs1_sig.cs2(cs2) ,   // output  cs2_sig.cs3(cs3) ,   // output  cs3_sig.cs4(cs4) ,   // output  cs4_sig.cs5(cs4) ,   // output  cs5_sig.cs6(cs4) ,   // output  cs6_sig.rddat0(rddat0) , // input [7:0] rddat0_sig.rddat1(outRMS0) , // input [7:0] rddat1_sig.rddat2(outRMS1) , // input [7:0] rddat2_sig
//  .rddat3(rddat3) ,   // input [7:0] rddat3_sig.wrdat0(wrdat0) ,  // output [7:0] wrdat0_sig.wrdat1(wrdat1) , // output [7:0] wrdat1_sig.wrdat2(wrdat2) , // output [7:0] wrdat2_sig.wrdat3(wrdat3) , // output [7:0] wrdat3_sig.addr_ad(addr_ad) ,   //output reg [3:0]addr_ad.datacs0(datacs0)  ,   //output reg datacs0.datacs1(datacs1)       //output reg datacs1
);KEY KEY_inst
(.clk(clk) ,    // input  clk_sig.rst_n(rst_n) ,    // input  rst_n_sig.rddat(rddat0) , // output [7:0] rddat_sig.irq(irq) ,    // output  irq_sig.cs(cs0) ,    // input  cs_sig.KEY_H(KEY_H) , // inout [3:0] KEY_H_sig.KEY_V(KEY_V)   // inout [3:0] KEY_V_sig
);ads8688 ads8688_inst
(.clk_50M(clk) ,    // input  clk_50M_sig.rst_n(rst_n) ,    // input  rst_n_sig.addr(addr_ad) , // input [3:0] addr_sig.RD(RD) ,    // input  RD_sig.datacs0(datacs0) , // input  datacs0_sig.datacs1(datacs1) ,    // input  datacs1_sig.clk_50Hz(clk_50Hz) ,  // input  clk_50Hz_sig.RST(RST) ,   // output  RST_sig.CS(CS) , // output  CS_sig.SCLK(SCLK) ,  // output  SCLK_sig.SDI(SDI) ,  // output  SDI_sig.SDO(SDO) ,   // input  SDO_sig.outRMS0(outRMS0) ,    // output [15:0] outRMS0_sig.outRMS1(outRMS1)   // output [15:0] outRMS1_sig
//  .Vc(Vc)
);
endmodule

CCS中的main函数:

#include "common.h"
#include "bus_fpga.h"
#include "LCD12864_rom_enable.h"
#include "blue.h"
#include <math.h>/*** main.c* 1.7增加了附加功能:1、按键设置 2、过流保护灯亮 3、蜂鸣器*/const int FMIN = 1;
const int FMAX = 999;
const double FULL = 10.24;
const double Vset = 10;
const int KMAX = 990;
const int KMIN = 900;char keydat;
int a;
int fs = 50;
int K = 900;    //K的精度为1/1000
double Vrms = 0;
double Irms = 0;
double deltV[3] = {0};
float Kp = 45;  //65 30 60; 38 35
float Ki = 10;  //27 16 24; 17
float Kd = -12; //-10; -25 -20 -25
double V_list[5] = {0};
double I_list[5] = {0};
double V_sum;
double I_sum;
unsigned int j;
int overFlag = 0;
int fs_tmp[3] = {-1,-1,-1};void mcuInit(void);
void getKey(void);
void getAD(int cnt);
void overCurrent(void);
void keyResponse(void); //无用
void changeFreq(void);
void PID(void);
void showPID(void); //无用
void ctrlPID(void); //无用
double change_voltage(unsigned int AD_value,double FS);
void showStatus(void);
void WRFPGA(void);
int datalen(int data);
void __key_delay(void);int main(void)
{mcuInit();initialize_uart();while(1){V_sum = 0;I_sum = 0;for(j=0;j<5;j++){   //采样5次取平均值__key_delay();getKey();changeFreq();
//      getStringFVT();
//      updateKey(&a);getAD(j);PID();showStatus();WRFPGA();V_sum = V_sum + V_list[j];I_sum = I_sum + I_list[j];}Vrms = V_sum / 5 * 7.80435435;   // * 7.810155Irms = I_sum / 5 * 0.47501069;PID();overCurrent();}}

四、其他

1.FPGA生成固化文件

FPGA本身并没有存储程序的功能,需要依靠外部flash芯片来实现程序的固化。以下两种方法分别介绍了用AS口和JTAG口固化程序。
方法一:生成.pof文件
step1:从Assignments进入Device。

step2:选择Device and Options。

step3:按照下图更改选项,注意这里的Device要看你FPGA上的flash芯片型号。

step4:全编译一下即可得到.pof文件。第一次烧录需要 Add Device 和 Add File。

方法二:生成.jic文件
step1:在File里面找到Convert Programming Files。

step2:选择生成.jic文件,同时选择flash芯片型号。

step3:往下翻找到Flash Loader添加设备,添加对应FPGA型号。


step4:选择SOF Data,添加.sof文件。


step5:点击Generate再重新全编译一遍即可生成.jic文件,用JTAG口,在烧录时Add File中选中相应的.jic文件即可。

烧录后,FPGA重新上电即成功固化程序。

2.其他代码

见单相逆变电源程序压缩包。

总结

在用Tiva和FPGA进行开发的时候,要注意二者之间的通信问题,比如有时候通信通道会传一些不定值,可能换个通道就好了。在CCS中烧录程序时如果配置出错可能会导致程序无法烧录,务必要正确配置后再进行烧录,可以先了解一些配置的基础知识。

单相逆变电源软件设计相关推荐

  1. matlab单相电源在哪里,浅谈基于MATLAB的单相独立光伏逆变电源电路仿真设计

    156电子技术 独立型光伏发电系统系统结构如图 1 所示,主要有太阳电池组件(方阵).控制器.储能蓄电池(组).直流 / 交流逆变器等部分组成.光伏阵列发出的直流电通过器将其逆变为交流电供给负载,蓄电 ...

  2. 从零开始做单相逆变电源(硬件)

    文章目录 前言 一.主要模块需求 1.全桥模块 2.采样电路 光耦 前言 题目:单相正弦逆变电源 具体软件部分请参照从零开始做单相逆变电源(软件)] 一.主要模块需求 本系统以TM4C123GH6PM ...

  3. 三相逆变器双pi控制器参数如何调节_单相逆变电源的电压双闭环矢量控制新方法,解决传统方案的不足...

    东北大学信息科学与工程学院.潞安集团司马煤业有限公司的研究人员宋崇辉.徐涛.王振环.刁乃哲.陈宏志,在2019年第16期<电工技术学报>上撰文(论文标题为"单相逆变电源电压双闭环 ...

  4. 多核片上系统(SoC)架构的嵌入式DSP软件设计

    多核片上系统(SoC)架构的嵌入式DSP软件设计 Multicore a System-on-a-Chip (SoC) Architecture SoCs的软件开发涉及到基于最强大的计算模型在各种处理 ...

  5. 软件设计之 数据库设计

    [按语:在软件设计或是动态网站开发中,数据库设计时很重要,我觉得可以说是开发工作的核心部分,所以学好数据库设计,是很重要的,也是大有前途的...]  ◆.概念 首先要搞清楚容易混淆的两个概念:&quo ...

  6. 概要设计实例_多核片上系统(SoC)架构的嵌入式DSP软件设计

    多核片上系统(SoC)架构的嵌入式DSP软件设计 Multicore a System-on-a-Chip (SoC) Architecture SoCs的软件开发涉及到基于最强大的计算模型在各种处理 ...

  7. 由学习《软件设计重构》所想到的代码review(二)

    前言 对于一个程序员来讲如何来最直接的来衡量他的技术能力和产出呢?我想最直观的作法是看他的代码编写能力,就拿我经常接触的一些程序员来看,他们买了很多技术重构类书籍,但是看完后代码编写能力并没有显著提高 ...

  8. 面向过程的软件设计方法

    面向过程的软件设计方法 前面主要是对系统的分析,从而明确我们系统的逻辑模型.也就是说,通过前面几章我们清楚了"系统需要做什么?".而软件设计阶段主要任务则是要实现系统逻辑模型向物流 ...

  9. 自己拿项目,软件设计开发,释放你的力量

    自己拿项目,软件设计开发,释放你的力量,链接地址 http://un.zhubajie.com/r/?u=4674706&l=http://u.zhubajie.com/user/buyer ...

最新文章

  1. layer的一种用法,自己画出弹出框样式
  2. [Android]反编译apk + eclipse中调试smali
  3. 在线聊天javascript代码
  4. Ollydbg使用教程学习总结(四)
  5. “辩者21事”之解读——分析性理性要与辩证理性相结合
  6. 基于Java+jsp+servlet的养老院管理系统设计和实现
  7. 菜鸟喜欢的C# 入门认识和添加,修改,删除 文件夹 文件 大全(转)
  8. 还不会用typedef?C语言typedef的详细用法总结,一篇解决你的困惑。(学习笔记2--typedef设置别名)
  9. python猫狗大战pytorch_深度学习实战---猫狗大战(pytorch实现)
  10. 安卓运行时监听配置更改:sim卡、本地语言、键盘显示或隐藏、字体大小、UI模式、屏幕方向、屏幕布局(另一个屏幕)、可用屏幕大小(横纵向)、无屏幕大小(外接屏幕)。
  11. 数据结构——一些小点
  12. 三菱PLC自带FIFO操作指令编程应用
  13. 电阻电感电容基本单位、读数、封装类型、种类
  14. ireport mysql_iReport连接Mysql创建图表报表
  15. mysql建立spj_数据库概论——SQL练习一(SPJ零件问题)
  16. 什么是Cloud Computing?
  17. 数据可视化中的格式塔心理学
  18. 解决iphone的短信中心号码设置错误的方案
  19. 微巴士阳光出行---竞品分析
  20. 油气计量比较好的软件_您准备好使用计量互联网了吗?

热门文章

  1. 本科生学计算机科学行吗,【学习方法】一位大三本科生的计算机科学与技术学习反思录...
  2. Kong 网关 | Route
  3. wechat talk
  4. 为什么实际下载速度比宽带带宽小很多
  5. 中关村知识产权领军和重点示范企业申报,200万资金补助
  6. kubernetes-nvidia-plugin设计解读
  7. 详解Java中的Object.getClass()方法
  8. onload、onunload、onbeforeunload的区别
  9. AV-TEST杀毒软件能力测试(2018年1月-12月)杀毒软件排名
  10. ieframe.dll修复方法