本次设计中数控稳压电源的设计要求如下:
(1)数控稳压电源系统输入电压为15V,输出0-12V,最大输出电流为2A;
(2)输出电压纹波不大于200mV;
(3)可对输出电压进行预置;可对输出电压进行加减,其步进电压为0.1V;
(4)实现人机交互,通过按键可对设定电压与输出电压进行调节。
(5)PID算法与BUCK电路
本设计以直流电压源为核心,STC15W4K32S4单片机为主控制器,单片机系统是数控电源的核心,同步整流BUCK电路、IR2104驱动模块、LCD1602显示模块、信号调理电路等组成的数控稳压电源。它通过软件的运行来控制整个仪器的工作,从而完成设定的功能。通过数字键盘来设置直流电源的输出电压,输出电压范围为0-12V,最大电流为2A,并可由液晶屏LCD1602显示实际输出电压值。本设计由单片机程控输出数字信号,经过D/A转换器(DAC0832)输出模拟量,最后输出各种设备所需要的电压。实际测试结果表明,数控稳压电源具有智能化高、操作方便、转换效率高等特点。
本次功率级电路为一个高效率宽输出范围的同步整流Buck型电路,其主要性能参数为输入电压为15V,输出电压范围为0V~12V,最大输出电流,开关频率为,输出电压纹波小于200mV。对BUCK电路原理进行分析,可以对功率开关管、输出电容、储能电感进行参数计算。
BUCK电路的工作原理:当开关管Q1驱动为高电平时,开关管导通,储能电感L1被充磁,流经电感的电流增加,然后可以给电容C1充电,最后给负载R1提供能量。
|
(3-1) |
当开关管Q1驱动为低电平时,其开关管关断,电感L1可以通过续流二极管放电,电感电流减少,输出电压只能依靠滤波电容C1放电和减小的电感电流维持。
|
(3-2) |
通过式(3-1)与(3-2)可得:
|
(3-3) |
其中,D为占空比,T为周期,为电流变化量,为输入电压,为输出电压。
由于电感电流时脉动的,在其直流分量中含有谐波,为了维持输出电压的稳定,一般在输出端并联一些电容,这样一来就可以在输出端形成LC滤波电路,实现输出电压的稳定,本次设计的功率级电路原理图如下图所示。
图32BUCK电路原理图
数控闭环稳压电源,这个方案是以单片机为主控制电路,用户可以通过按键来设定一个输出电压值,将这个设定输出电压值传入单片机,单片机通过运算可以一方面把设定的输出电压值送给液晶显示电路进行显示,另一方面可以通过内部定时器产生一个脉宽可调的周期信号,然后通过驱动电路进行驱动放大从而驱动开关管的导通和关断,然后通过BUCK电路进行降压,输出一个电压值。该方案可以通过取样电阻上的电压进行采样,然后经A/D模数转换传给单片机,最后单片机对设定的输出电压值和采样得到的实际电压值进行比较,从而得到差值,再通过预设的PID算法对周期信号的脉冲宽度进行调节,即可改变输出电压值,得到一个稳定的输出电压,最后单片机将实际输出电压值送至液晶显示模块进行显示。
测试与分析
5.1实物测试
实物
图51实物图
本次测试采用空载测试,其测试方法采用两个万用表进行测试,一个万用表并联供电电源输出口,一个万用表并联输出电压口进行测试,其输出电压测试图如下
图52输出电压为零测试图
图53输出电压为4V测试图
图54输出电压为3V测试图
图55输出电压为12V测试图
图56输出电压为5V测试图
表51空载输出电压测试表
序号 |
预设电压值(V) |
实际电压值(V) |
1 |
1 |
1.02 |
2 |
2 |
2.10 |
3 |
3 |
2.96 |
4 |
4 |
4.10 |
5 |
5 |
4.94 |
6 |
6 |
6.21 |
7 |
7 |
7.13 |
8 |
8 |
7.96 |
9 |
9 |
9.12 |
10 |
10 |
9.95 |
11 |
11 |
11.10 |
12 |
12 |
11.93 |
本次测试采用带载测试,其测试方法采用输出接100欧姆电阻测试,其输出电压测试图如下
图57输出电压为7.9V测试图
图58输出电压为6.9V测试图
图59输出电压为2.9V测试图
图510输出电压为1.9V测试图
图511输出电压为4.8V测试图
图512输出电压为0.9V测试图
表51带载载输出电压测试表(100R)
序号 |
预设电压值(V) |
实际电压值(V) |
实际电流值(A) |
1 |
0.9 |
1.08 |
0.011 |
2 |
1.9 |
2.10 |
0.021 |
3 |
2.9 |
3.06 |
0.031 |
4 |
4.8 |
5.00 |
0.050 |
5 |
6.9 |
7.06 |
0.071 |
6 |
7.9 |
8.07 |
0.081 |
5.2实验结果分析
用单片机控制的电源时,输出直流0-12V,液晶屏显示清晰正确,误差较小,完美的实现了数控直流稳压源这一课题。在数控稳压电源系统中功率级电路的输入电压为+15V,输出接入100欧姆负载时,该数控稳压电源的样机效率≥60%,其原因可能为输入电压太小,其负载根本没法正常工作,造成负载电阻较大,影响其效率。本设计的在带载功能上还不够强大,没有显示预置电压,由于制作过程中遇到的一些问题。所以原先设计要求里过流保护和过压保护电路没有实现,本设计还可以进一步得到提高。
系统误差产生的原因,主要有以下几个方面:
(1)在计算时,保留尽量多的小数位,但仍存在误差
(2)万用表自身存在误差,测量精度不是很高,使得实际检测电压值与真实值有偏 差
(3)取样电阻自身存在误差:采样电阻随温度的上升阻值增大,使其实际电压变大
(4)ADC存在转换误差
(5)供电电源存在较大的纹波电压,影响 Buck 变换器的输出电压
立创EDA原理图
主程序代码如下
#include <stc15.h>
#include "LCD1602.h"
#include "ADC0832.h"
#include "intrins.h"
sbit button1=P1^0;
sbit button2=P1^1;
sbit button3=P0^3;
sbit button4=P0^4;
sbit button5=P0^5;
sbit button6=P0^6;
sbit but=P1^2;
sbit IR21_SD=P1^5;
float voltage_get=0; //获取电压值
//float voltage_set=0; //设定电压值 这个地方就是你要设定的电压 修改这个值就可以获得想要的电压值 现在是36V
float voltage_kp=0.01; //PID KP比例系数
float voltage_ki=0.5; //PID KI积分系数
float voltage_output=500; //PID输出
float voltage_error=0; //实际值与给定的误差
float voltage_error_last=0; //记录上次的误差
int PWM_control=0;
/
extern unsigned char char_reverse(unsigned char number);
void pwm();
//char start_end=0,run_onetime=0;
//unsigned int pwmset=50;
float voltage_set=8.0;
int cnt=0,cnt1=0;
char button5_last=0,button6_last=0;
//int vout=0,vset=0;
//float pwm_float=0,interge=0;
/* STC15Fxx 系列 输出任意周期和任意占空比的PWM实例*/
#define CYCLE 0x04b0L //定义PWM周期1200,50us,20kHz(最大值为32767)
void pwm(int DUTY)//pwm模块配置占空比函数
{
P0M0 = 0x00; //因PWM模块相关IO口初始状态为高阻,需要将IO口设置为准双向或推挽输出才能正常输出波形;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P7M0 = 0x00;
P7M1 = 0x00;
P_SW2 |= 0x80; //使能访问XSFR,否则无法访问以下特殊寄存器
PWMCFG = 0x00; //配置PWM的输出初始电平为低电平,也就是第一次翻转前输出的电平
PWMCKS = 0x00; //选择PWM的时钟为Fosc/(0+1),其中FOSC为外部或内部系统时钟经分频后给单片机的工作时钟
PWMC = CYCLE; //设置PWM周期(最大值为32767),该寄存器为15位,实际使用时最好定义周期形参为unsigned int
PWM2T1 = 0x0001; //设置PWM2第1次反转的PWM计数,也就是电平第一次发生翻转的计数值 //此例中定义PWM2T1为0,初始电平也为0,所以在一开始,也就是计数为0时,直接翻转为高,这样方便计算占空比
PWM2T2 = DUTY+1; //设置PWM2第2次反转的PWM计数,其实这两个寄存器不分先后,没有第1第2之分,只是设置两个点,到点电平翻转
//占空比为(PWM2T2-PWM2T1)/PWMC
PWM2CR = 0x00; //选择PWM2输出到P3.7,不使能PWM2中断,也可以通过该寄存器切换要输出PWM的IO口
PWMCR = 0x01; //使能PWM信号输出
PWMCR |= 0x80; //使能PWM模块,此处有坑,容后详述!!
P_SW2 &= ~0x80;
}
//sbit key0=P7^0;
//sbit key1=P7^1;
//unsigned int i=0;
//long j=0;
//char etmp=0;
void xinashi()
{
LCD1602_write_com(0x80+0x00);LCD1602_write_word("Voltage set:");
LCD1602_write_com(0x80+0x40);LCD1602_write_word("Output Vo:");
}
void delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<1230;j++);
}
//unsigned char adc_dat=0;
unsigned char str[5]="000 ";
void Uart1Init(void) //9600bps@24.000MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //设定定时器1为16位自动重装方式
TL1 = 0x8F; //设定定时初值
TH1 = 0xFD; //设定定时初值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void SendData(unsigned char dat)
{
SBUF = dat; //Send data to UART buffer
while(!TI);
TI=0;
}
/*----------------------------
串口发送字符串
----------------------------*/
void SendString(char *s)
{
while (*s) //Check the end of the string
{
SendData(*s++); //Send current char and increment string ptr
}
}
//unsigned long cnt=0,ocp=0;
void main()
{
P0M0 = 0xFF; //因PWM模块相关IO口初始状态为高阻,需要将IO口设置为准双向或推挽输出才能正常输出波形;
P0M1 = 0x00;
P1M0 = 0xFF;
P1M1 = 0x00;
P2M0 = 0xff;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
Uart1Init();
//配置定时器0
EA = 1; //使能总中断
TMOD = 0x01; //设置T0为模式1
TH0 = 0xfc; //为T0赋初值0x3cb0,定时25ms
TL0 = 0x67;
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
delay_ms(1000);
// jidianqi=0;
// P37=0;
// pwm_float=pwmset;
Init_LCD1602();//1602液晶初始化
xinashi();
IR21_SD=1;
while(1)
{
//SendData(char_reverse(0xa0));
// if(start_end==1)
// {
// vout=ADC0832();//采样输出电压
// voltage_set=56;
if(!button1) voltage_set=0;
else if(!button2) voltage_set=3;
else if(!button3) voltage_set=5;
else if(!button4) voltage_set=12;
// else if(!button5) voltage_set=12;
if(button5_last!=button5)
{
button5_last=button5;
if(button5==0)
{
delay_ms(10);
if(button5==0)
voltage_set=voltage_set+0.1;
}
}
if(button6_last!=button6)
{
button6_last=button6;
if(button6==0)
{
delay_ms(10);
if(button6==0)
voltage_set=voltage_set-0.1;
}
}
// i=adc_dat;
// vout=(int)(adc_dat*1.96608);//计算输出电压
interge+=(vout-setVo);
// if(vout-setVo>0&&pwmset>5) pwm_float=(pwm_float-0.5*(vout-setVo));//利用PID控制里算法面的比例控制来计算占空比
// if(setVo-vout>0&&pwmset<1100) pwm_float=(pwm_float+0.5*(setVo-vout));//利用PID控制算法里面的比例控制来计算占空比
// pwmset=(int)pwm_float;
// pwm(pwmset);//设定占空比输出
// }
//
// if(ADC0832_2()>30) //检测过流的ADC0832检测到电压大于0.588V,也就是电流大于0.588/0.1=5.88A
// {
// jidianqi=1;//拉闸
// ocp=1;
// }
pwm(PWM_control);
str[0]=(int)(voltage_get*10)/100+'0';//1602显示当前电压输出
str[1]=(int)(voltage_get*10)/10%10+'0';
str[2]='.';
str[3]=(int)(voltage_get*10)%10+'0';
LCD1602_write_com(0x80+0x4a);
LCD1602_write_word(str);
str[0]=(int)(voltage_set*10)/100+'0';//1602显示设定电压
str[1]=(int)(voltage_set*10)/10%10+'0';
str[2]='.';
str[3]=(int)(voltage_set*10)%10+'0';
LCD1602_write_com(0x80+0x0c);
LCD1602_write_word(str);
}
}
//char key0_state=0;
//char key1_state=0;
定时器0中断服务函数
用于占空比的改变
void tim0() interrupt 1
{
TH0 = 0xfc; //为T0赋初值,定时25ms
TL0 = 0x67;
// cnt++;
// cnt1++;
voltage_get=(ADC0832()/255.0*5*5);
// voltage_get=17;
voltage_error=voltage_set-voltage_get;
voltage_output+=voltage_kp*(voltage_error-voltage_error_last)
+voltage_ki*voltage_error;
voltage_error_last=voltage_error;
if (voltage_output>1195) voltage_output=1195;
else if(voltage_output<5) voltage_output=5;
PWM_control=(int)voltage_output;
// if(start_end==1)//if电路正在运行
// {
// if(((vout-setVo)>20)||((vout)<setVo-20))//if设定电压与实际电压相差2V
// {
// if(j++>2000) jidianqi=1;//并且这个时间持续2秒钟就拉闸
// }
// else
// {
// j=0;
//
// }
// }
// cnt++;
// if(key0!=key0_state&&key0==0&&setVo<=420) setVo+=10;//按键按下设定电压+1V
// if(key1!=key1_state&&key1==0&&setVo>=120) {if(start_end==1) setVo-=10; start_end=1;}//按键按下电路开始工作以及设定电压-1V
// key0_state=key0;
// key1_state=key1;
}
ADC0832电压采集函数
#include "ADC0832.h"
#include<stc15.h>
sbit ADC_CLK=P3^4;
sbit ADC_DI=P3^5;// DI DO也可用同一引脚,因为IO口双向且DI DO在不同时间使用,互不干扰
sbit ADC_DO=P3^6;
sbit ADC_CS=P3^3;
/*******************************************************************/
void Delay(unsigned char x)
{
unsigned char i;
for(i=0;i<x;i++);
}
unsigned char ADC0832(void) //把模拟电压值转换成8位二进制数并返回
{
unsigned char i,data_c;
data_c=0;
ADC_CS=0;
ADC_DO=0;//片选,DO为高阻态
for(i=0;i<10;i++)
{;}
ADC_CLK=0;
Delay(2);
ADC_DI=1;
ADC_CLK=1;
Delay(2); //第一个脉冲,起始位
ADC_CLK=0;
Delay(2);
ADC_DI=1;
ADC_CLK=1;
Delay(2); //第二个脉冲,DI=1表示双通道单极性输入
ADC_CLK=0;
Delay(2);
ADC_DI=1;
ADC_CLK=1;
Delay(2); //第三个脉冲,DI=1表示选择通道1(CH2)
ADC_CLK=0;//
ADC_DI=0;
ADC_DO=1;//DI转为高阻态,DO脱离高阻态为输出数据作准备
//ADC_CLK=1;
//Delay(2);
//ADC_CLK=0;
//Delay(2);//经实验,这里加一个脉冲AD便能正确读出数据,
//不加的话读出的数据少一位(最低位d0读不出)
for (i=0; i<8; i++)
{
ADC_CLK=1;
Delay(2);
ADC_CLK=0;
Delay(2);
data_c=(data_c<<1)|ADC_DO;//在每个脉冲的下降沿DO输出一位数据,最终ch为8位二进制数
}
ADC_CS=1;//取消片选 一个转换周期结束
return(data_c);//返回
}
//函数名:ADC0832_ReadAD
//形参变量:无
//返回值return:AD_value:转化之后的数字量
//sbit ADC0832_CS=P3^3;//片选信号段
//sbit ADC0832_CLK=P3^4;//时钟信号端
//sbit ADC0832_DIN=P3^5;//串行数据输入端
//sbit ADC0832_DOUT=P3^6;//串行数据输出端
//void ADC0832_init(void)
//{
// ADC0832_CS=1;//芯片不工作
// ADC0832_CLK=0;
// ADC0832_DIN=0;
//}
//unsigned char ADC0832_ReadAD(void)
//{
// unsigned char i,AD_value1=0x00,AD_value2=0x00;
// ADC0832_CS=0;//芯片工作(初始cs信号为高电平)
//
// ADC0832_DIN=1;//起始信号S
// ADC0832_CLK=1;//上升沿将起始信号Start写入
// ADC0832_CLK=0;
//
----------------通道地址设置----0通道(单端模式)---------------//
//
// ADC0832_DIN=1;//mode状态位置1
// ADC0832_CLK=1;//将mode状态位写入
// ADC0832_CLK=0;
//
// ADC0832_DIN=0;//通道选择0通道
// ADC0832_CLK=1;//将通道选择位写入
// ADC0832_CLK=0;//第4个脉冲下降沿后,ADC0832_DIN端口失效,无作用
//
// ADC0832_DIN=1;//ADC0832_DIN转为改高阻状态(数据线拉高,等待下次接收数据)
//
---------------------读取相对应的通道0的AD数据--------------------------//
// ADC0832_DOUT=1;//数据线拉高,等待接收数据
//
// for(i=0;i<8;i++)//MSB
// {
// ADC0832_CLK=1;
// ADC0832_CLK=0;
// if(ADC0832_DOUT){AD_value1=AD_value1 |(0x80>>i);}//优先读取最高位 MSB
// }
//
// for(i=0;i<8;i++)//LSB
// {
// if(ADC0832_DOUT){AD_value2=AD_value2 |(0x01<<i);}//优先读取最低位 LSB
// ADC0832_CLK=1;
// ADC0832_CLK=0;
// }
// ADC0832_DOUT=1;//数据线拉高,等待接收数据
// ADC0832_CS=1;//芯片停止工作
// return (AD_value1==AD_value2)? AD_value1:0;//判断前后两次读取数据是否相同(前后两个字节数据校验)
//}
LCD1602显示函数文章来源:https://www.toymoban.com/news/detail-728860.html
#include "LCD1602.h"
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void LCD1602_delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<1230;j++);
}
unsigned char char_reverse(unsigned char number)
{
unsigned char i;
unsigned char num_reversed = 0;
for(i = 0; i < 8; i++)
{
num_reversed += (number & 0x01) << (7 - i);
number >>= 1;
}
return num_reversed ;
}
//****************************************************
//写指令
//****************************************************
void LCD1602_write_com(unsigned char com)
{
LCD1602_RS = 0;
LCD1602_delay_ms(1);
LCD1602_EN = 1;
LCD1602_PORT = char_reverse(com);
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
//****************************************************
//写数据
//****************************************************
void LCD1602_write_data(unsigned char dat)
{
LCD1602_RS = 1;
LCD1602_delay_ms(1);
LCD1602_PORT = char_reverse(dat);
LCD1602_EN = 1;
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
//****************************************************
//连续写字符
//****************************************************
void LCD1602_write_word(unsigned char *s)
{
while(*s>0)
{
LCD1602_write_data(*s);
s++;
}
}
void Init_LCD1602()
{
LCD1602_EN = 0;
LCD1602_RW = 0; //设置为写状态
LCD1602_write_com(0x38); //显示模式设定
LCD1602_write_com(0x0c); //开关显示、光标有无设置、光标闪烁设置
LCD1602_write_com(0x06); //写一个字符后指针加一
LCD1602_write_com(0x01); //清屏指令
}
变量声明文章来源地址https://www.toymoban.com/news/detail-728860.html
#ifndef __LCD1602_H__
#define __LCD1602_H__
//#include <reg52.h>
#include <stc15.h>
//LCD1602 IO设置
#define LCD1602_PORT P2
sbit LCD1602_RS = P0^0;
sbit LCD1602_RW = P0^1;
sbit LCD1602_EN = P0^2;
//函数或者变量声明
extern void LCD1602_delay_ms(unsigned int n);
extern void LCD1602_write_com(unsigned char com);
extern void LCD1602_write_data(unsigned char dat);
extern void LCD1602_write_word(unsigned char *s);
extern void Init_LCD1602();
extern unsigned char char_reverse(unsigned char number);
#endif
#ifndef __ADC0832_H__
#define __ADC0832_H__
extern unsigned char ADC0832(); //把模拟电压值转换成8位二进制数并返回unsigned char ADC0832(); //把模拟电压值转换成8位二进
#endif
//函数或者变量声明
extern void Delay_ms(unsigned int n);
extern void Get_Maopi();
extern void Get_Weight();
extern void Scan_Key();
到了这里,关于基于单片机的多路输出数控直流稳压电源设计与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!