STC15数控直流稳压电源设计

                              

本科学生单片机课程设计报告

        题      目          数控直流稳压电源设计                              

        院  (系)          工程与设计学院                                  

        专业、年级          电子信息工程 2019级                                      

课程设计成绩评定表

项目

评分依据

满分

得分

设计作品

电路板焊接工艺

10

功能完整

20

性能指标

10

程序运行可靠

20

人机交互友好,操作方便

10

设计报告

内容完整

10

写作规范

10

设计报告篇幅符合要求

10

实评总分                   指导教师签名                       

1.设计要求

用单片机、D/A(或数字电位器)、A/D及串联稳压电路设计数控直流稳压电源。性能指标:

用LED数码管或LCD显示设定电压值及实测输出电压值;

电压调节范围:0V—20V,按0.1V步进设置,额定输出电流1A;

稳压精度:负载调整率(0-1A)≤5%,电压调整率(1-10V压降)≤5%

2.硬件电路设计

2.1.设计思路

主控芯片选择STC15W4K48S4,单片机供电系统选择7805作为稳压芯片,通过对24V输入电压进行稳压调整,输出 5V作为电路的供电系统,之后串联稳压部分选择LM358作为电压比较器,并且选择三极管TIP41C作为调整管使用。本设计通过单片机内部AD对实时电压的测量与实际设定值进行比对,PID闭环增益调节PWM输出值,显示模块运用了0.96寸中景园的OLED进行显示。

2.2.单片机供电系统电路

    本设计采用的供电系统电路为L7805构成的5V稳压电路

L7805是常用的三端稳压器件,顾名思义05就是输出电压为5v,7805输出波纹很小,用来给单片机供电。使用方便,在这里用的是TO-220封装。

2.3.串联稳压模块电路

串联稳压电路中,选用了LM358作为比较器,集成运算放大器具有开环增益高和输出阻抗低等特点,用它做稳压电源中的比较放大器是比较理想的。在这里,将单片机的输出作为比较电压,取RP2两端电压作为实际电压值,通过两个电压值经过比较器,再通过三极管TIP41C,这里选取TIP41C作为调整管。

LM358是双运算放大器。内部包括有两个独立的、高增益、内部频率补偿的运算放大器,适合于电源电压范围很宽的单电源使用,也适用于双电源工作模式,在推荐的工作条件下,电源电流与电源电压无关。共模输入范围包括负电源,因而消除了在许多应用场合中采用外部偏置元件的必要性。

电源电压范围宽:单电源(3-30V)单位增益频带宽(约1MHz)

TIP41C作为调整管,有以下特点最大平均电流:6A,最大峰值电流:10A,最大Ice漏电流:700μA(@Vce=60V,Vbe=0),最大Vcbo=100V,最大Vceo=100V,最大Vbe=5V,最高有效结温:最大值150摄氏度,封装形式:直插封装TO-22,主要用途:适用于电子开关线路主要特点:功率大、驱动电流大,所以在这里并不需要选择组合管,只用TIP41C即可满足需要。

2.4.π型LC滤波电路及ADC采样电路

电感滤波电路是用电感器构成的一种滤波电路,其滤波效果相当好,只是要求滤波电感的电感量较大,电路的成本比较高。电路中常使用π型LC滤波电路。L1滤波电感对交流感抗大对直流电阻小,这里电容选取470uf耐压为63V,大于22V电源电压的2½倍

从p1.0口为ADC0输入口进行采样转换,考虑到单片机本身带有内阻,这里对于采样电路进行隔离处理,类似于负载就不会影响到串联稳压电路的增益。

2.5单片机及下载电路

选型STC15W4K48S4,单片机自带八通道十位ADC

MCU封装LQFP44

数据手册给出的下载电路

实际中将P3.1和P3.0引出作为下载口

2.6显示部分电路

采用中景园电子生产的0.96尺寸的OLED,内部自带线与,单片机通过IIC总线控制,时序按照数据手册的时序图编写

3.程序设计

3.1.程序流程图

先进行定时器初始化设置,以及OLED以及的初始化设置,程序设计总思路就是先按键设置好所需要的目标电压值,先按照原先设定的占空比生成PWM波输出,得到此时的输出电压值,同时AD采样得到实时电压值,与设定电压值进行比对,实际输出电压大的话,会减小输出PWM波的占空比,实际输出电压小的话则相反。

3.1.1 pwm波生成部分

先对定时器进行初始化,使用的是定时器0的方式2,通过中断进行pwm波生成,pwm波产生部分程序如下:

void LoadPWM(u16 i)  //计算PWM重装值函数

{

u16 j;

if(i > PWM_HIGH_MAX) i = PWM_HIGH_MAX; //如果写入大于最大占空比数据,则强制为最大占空比。

if(i < PWM_HIGH_MIN) i = PWM_HIGH_MIN; //如果写入小于最小占空比数据,则强制为最小占空比。

j = 65536UL - PWM_DUTY + i; //计算PWM低电平时间

i = 65536UL - i; //计算PWM高电平时间

EA = 0;

PWM_high = i; //装载PWM高电平时间

PWM_low  = j; //装载PWM低电平时间

EA = 1;

}

3.1.2 OLED显示

先对OLED进行初始化设置,设置正常显示,分别显示的是设定电压,以及此时实时电压,和PWM占空比,通过取模软件取四个汉子字库数组用来中文显示调用,部分显示程序如下:

OLED_Init();//初始化OLED

OLED_ColorTurn(0);//0正常显示,1 反色显示

OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示

sprintf(str,"DUTY=%0.2f%c  ",((float)pwm/(float)PWM_DUTY)*100,'%');

OLED_ShowString(0,0,str,16);

sprintf(str,":%0.3f V  ",set_vol);

OLED_ShowString(n*2,4,str,16);

sprintf(str,":%0.3f V  ",vol);

OLED_ShowString(n*2,2,str,16);

void init_system(void)  //OLED屏幕开启初始化

{

do

{

low_voltage();

LoadPWM(pwm);

adc_v=Get_ADC10bitResult_cont(ADC_CH0,5); //ADC0获得采样值

vol=(float)adc_v*5/1023;  //10位ADC,基准5V电压

vol_set();

sprintf(str,"%d",num);

OLED_ShowString(0,4,str,16);

num++;

OLED_ShowString(0,0,"loading.     ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading..    ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading...   ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading....  ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading..... ",16);

delay_ms(200);

}while(vol>init_vol&&num<8);

}

//显示汉字

void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)

{

u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;

for(i=0;i<size1;i++)

{

if(i%sizey==0) OLED_Set_Pos(x,y++);

if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号

// else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号

else return;

}

}

3.1.3 AD采样

采用单片机内部ADC0,在配置完成ADC0的端口后调用ADC值获取函数,通道选用0,采样五次取平均值,得到的值根据十位ADC位数和基准电压进行转换,部分程序如下:

adc_v=Get_ADC10bitResult_cont(ADC_CH0,5); //ADC0获得采样值

vol=(float)adc_v*5/1023;                 //10位ADC,基准5V电压

u16 Get_ADC10bitResult_cont(u8 channel,u16 count)  //均值滤波

{

int temp;

int i=count;

do

{

temp+=Get_ADC10bitResult(channel);

i--;

}while(i>0);

return (temp/count);

}

u16 Get_ADC10bitResult(u8 channel) //channel = 0~7

{

u16 adc;

u8 i;

if(channel > ADC_CH7) return 1024; //错误,返回1024,调用的程序判断

ADC_RES = 0;

ADC_RESL = 0;

ADC_CONTR = (ADC_CONTR & 0xe0) | ADC_START | channel;

NOP(4); //对ADC_CONTR操作后要4T之后才能访问

for(i=0; i<250; i++) //超时

{

if(ADC_CONTR & ADC_FLAG)

{

ADC_CONTR &= ~ADC_FLAG;

if(PCON2 &  (1<<5)) //10位AD结果的高2位放ADC_RES的低2位,低8位在ADC_RESL。

{

adc = (u16)(ADC_RES & 3);

adc = (adc << 8) | ADC_RESL;

}

else //10位AD结果的高8位放ADC_RES,低2位在ADC_RESL的低2位。

{

adc = (u16)ADC_RES;

adc = (adc << 2) | (ADC_RESL & 3);

}

return adc;

}

}

return 1024; //错误,返回1024,调用的程序判断

}

3.1.4按键部分

设定两个按键来对于设定电压进行加减,步进为0.1V,支持连续加减,期间进行延迟软消抖,部分程序如下:

switch(KEY_Scan(1))     //两个按键扫描,分别用来加减设定电压

{

case KEY0_PRES:

set_vol+=0.1;

if(set_vol>20) set_vol=20;

break;

case KEY1_PRES:

set_vol-=0.1;

if(set_vol<0) set_vol=0;

break;

}

u8 KEY_Scan(u8 mode)

{  

static u8 key_up=1;//按键按松开标志

if(mode)key_up=1;  //支持连按   

if(key_up&&(KEY0==0||KEY1==0))

{

// delay_ms(20);//去抖动

key_up=0;

if(KEY0==0)return KEY0_PRES;

else if(KEY1==0)return KEY1_PRES;

}else if(KEY0==1&&KEY1==1)key_up=1;     

  return 0;// 无按键按下

}

3.1.5主控部分

主控部分分为低电压1V一下设定十个点的PWM值实现,高电压部分>1V部分通过实时读取AD采样得到的数据,通过计算AD数据与实际电压之间的差值作为调制系数,用调制系数来对于PWM值进行调整从而改变其高低电平持续的时间,来达到PID改变占空比的算法实现。

void low_voltage(void)

{

PWM_DUTY=27000; // 定义PWM的周期,数值为时钟周期数

                    //1V以下采用PWM频率为1K,pwm数值一定的时候输出电压更低更接近与所需要的1V以下的电压

if(set_vol<0.05) //设定值为0的处理

{

TR0=0;

P35=0;

}

else

{

EA = 1;

TR0=1;

}

if(set_vol>0.05&&set_vol<0.15) pwm=32; //1V内的PWM设定

if(set_vol>0.15&&set_vol<0.25) pwm=69;

if(set_vol>0.25&&set_vol<0.35) pwm=105;

if(set_vol>0.35&&set_vol<0.45) pwm=140;

if(set_vol>0.45&&set_vol<0.55) pwm=176;

if(set_vol>0.55&&set_vol<0.65) pwm=212;

if(set_vol>0.65&&set_vol<0.75) pwm=247;

if(set_vol>0.75&&set_vol<0.85) pwm=282;

if(set_vol>0.85&&set_vol<0.95) pwm=318;

if(set_vol>0.95&&set_vol<1.05) pwm=355;

}

void high_voltage(void)

{

PWM_DUTY=2700;      //1V以上采用PWM频率为10K

EA = 1;

TR0=1;

if(set_vol<=1.15)

{

pwm=114;

}

temp=(set_vol-vol)*p;

if(pwm-temp>32&&pwm+temp<2700) pwm+=temp; //增量式PID

if(vol<set_vol) pwm++;  //比例调节

if(vol>set_vol) pwm--;

if(pwm>PWM_DUTY) pwm=PWM_DUTY;  //设定PWM的上限

if(pwm<50) pwm=50;  //设定PWM的下限

}

  1. PCB板制图

PCB顶层

PCB底层

3D预览视图

5.实验结果图

测量单片机输出PWM波形:

最低到0V的时候:

 

接入25.8欧姆的负载,输出电流为1.01A

 

6.总结

 通过本次课程设计学到了很多东西,最初刚选好课题然后在咨询老师之后,有了初步的设计思路,再到后来的万用板验证,最后PCB画板打板,再一次次焊接测试然后进行电路的改进和原理上的验证,中间经历大概两三个月的时间,有过MCU烧毁时的失落也有一步步尝试改进后来取得进步的欣慰。这次课设作品相比于之前的电赛和平时自己用的最小系统板,第一次尝试MCU裸片的应用的确存在很大的挑战,幸得可以在STC的数据手册上去学习STC15的开发电路,在STC15单片机程序的编写上面也得到很大的帮助。

在刚开始调电路时发现总是达不到0V,后来通过示波器测PWM波形发现其PWM波在占空比过小的情况下会出现明显的抖动和失真现象,这是在之前使用STM32单片机所从未遇到的情况,参考数据手册在得知其PWM的性能与其频率和频率有关后,对于PWM频率选定为1K(用于做1V以下的部分),10k(用于做1V以上的部分)发现效果可以达到题目要求,在屏幕的显示上最初想使用串口屏,因其传输速度较快且占用IO口较少,但后来因为硬件电路修改花时间较长,没能来得及学习串口屏的配置和相关编写软件的使用,改用之前用过的中景园IIC的OLED屏幕,串口屏准备在暑假备赛电赛期间学好用熟。

通过此次课设再一次温习了很多模电的相关知识,为了验证也焊接了许多块万用板和自己画的PCB板,动手焊接能力得到了锻炼,学到了很多东西,期间遇到过一些模电方面的问题——输出端的电流总是上不去,咨询老师后也进行了相关的改进,非常感谢杨老师给予的帮助和指导以及能够有这样一次锻炼的机会。

7.附录:程序

#include    "mycode.h"

#define magn0 4.8   

#define magn1 4.56 //2.5

#define magn2 4.65

#define magn3 4.7

#define p 5

#define n 16

#define init_vol 3.0

sbit ADC1 = P1^4;

u16 pwm; //定义PWM输出高电平的时间的变量。用户操作PWM的变量。

u16     adc_v;

float   vol;        

float   set_vol;  

int temp;   

char str[16];

int num=0;

   

void my_init(void);

void vol_set(void);

void low_voltage(void);

void high_voltage(void);

void init_system(void);

void main(void)

{

my_init();

// UART_config();

GPIO_LEDconfig();

GPIO_ADCconfig();

GPIO_KEYconfig();

ADC_config();

OLED_Init();//初始化OLED

OLED_ColorTurn(0);//0正常显示,1 反色显示

OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示

EA = 0;

set_vol=0.0;

pwm=32;

LoadPWM(pwm);

TR0=0;

P35=0;

low_voltage();

LoadPWM(pwm);

init_system();

OLED_ShowChinese(0,2,7,16);

OLED_ShowChinese(n,2,9,16);

OLED_ShowChinese(0,4,10,16);

OLED_ShowChinese(n,4,11,16);

while (1)

{

adc_v=Get_ADC10bitResult_cont(ADC_CH0,5); //ADC0获得采样值

vol=(float)adc_v*5/1023;                 //10位ADC,基准5V电压

vol_set();

switch(KEY_Scan(1))     //两个按键扫描,分别用来加减设定电压

{

case KEY0_PRES:

set_vol+=0.1;

if(set_vol>20) set_vol=20;

break;

case KEY1_PRES:

set_vol-=0.1;

if(set_vol<0) set_vol=0;

break;

}

if(set_vol<=1.0)

{

low_voltage();

}

else

{

high_voltage();

}

LoadPWM(pwm);

sprintf(str,"DUTY=%0.2f%c  ",((float)pwm/(float)PWM_DUTY)*100,'%');

OLED_ShowString(0,0,str,16);

sprintf(str,":%0.3f V  ",set_vol);

OLED_ShowString(n*2,4,str,16);

sprintf(str,":%0.3f V  ",vol);

OLED_ShowString(n*2,2,str,16);

}

}

void my_init(void)

{

P_PWM = 0;

P3M1 &= ~(1 << 5); //P3.5 设置为推挽输出

P3M0 |=  (1 << 5);

Timer_config();

}

void low_voltage(void)

{

PWM_DUTY=27000; // 定义PWM的周期,数值为时钟周期数

                    //1V以下采用PWM频率为1K,pwm数值一定的时候输出电压更低更接近与所需要的1V以下的电压

if(set_vol<0.05) //设定值为0的处理

{

TR0=0;

P35=0;

}

else

{

EA = 1;

TR0=1;

}

if(set_vol>0.05&&set_vol<0.15) pwm=32; //1V内的PWM设定

if(set_vol>0.15&&set_vol<0.25) pwm=69;

if(set_vol>0.25&&set_vol<0.35) pwm=105;

if(set_vol>0.35&&set_vol<0.45) pwm=140;

if(set_vol>0.45&&set_vol<0.55) pwm=176;

if(set_vol>0.55&&set_vol<0.65) pwm=212;

if(set_vol>0.65&&set_vol<0.75) pwm=247;

if(set_vol>0.75&&set_vol<0.85) pwm=282;

if(set_vol>0.85&&set_vol<0.95) pwm=318;

if(set_vol>0.95&&set_vol<1.05) pwm=355;

}

void high_voltage(void)

{

PWM_DUTY=2700;      //1V以上采用PWM频率为10K

EA = 1;

TR0=1;

if(set_vol<=1.15)

{

pwm=114;

}

temp=(set_vol-vol)*p;

if(pwm-temp>32&&pwm+temp<2700) pwm+=temp; //增量式PID

if(vol<set_vol) pwm++;  //比例调节

if(vol>set_vol) pwm--;

if(pwm>PWM_DUTY) pwm=PWM_DUTY;  //设定PWM的上限

if(pwm<50) pwm=50;  //设定PWM的下限

}

void vol_set(void)

{

if(set_vol<2.5) vol=vol*magn1;

if(set_vol>=2.5&&set_vol<=4.50) vol=vol*magn2;

if(set_vol>=4.5&&set_vol<=14.1)

{

vol=vol*magn2;

vol+=vol*0.01;

}

if(set_vol>14.1)

{

vol=vol*magn3;

vol+=vol*0.005;

}

}

void init_system(void)  //OLED屏幕开启初始化

{

do

{

low_voltage();

LoadPWM(pwm);

adc_v=Get_ADC10bitResult_cont(ADC_CH0,5); //ADC0获得采样值

vol=(float)adc_v*5/1023;  //10位ADC,基准5V电压

vol_set();

sprintf(str,"%d",num);

OLED_ShowString(0,4,str,16);

num++;

OLED_ShowString(0,0,"loading.     ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading..    ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading...   ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading....  ",16);

delay_ms(200);

OLED_ShowString(0,0,"loading..... ",16);

delay_ms(200);

}while(vol>init_vol&&num<8);

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海雾·拂晓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值