基于STM32的桌面数控电源项目连载

基于STM32的桌面数控电源项目连载

一个数控桌面电源项目


文章目录

    • 基于STM32的桌面数控电源项目连载
  • 前言
  • 一、尺寸与外观
  • 二、元器件选型
    • 1.升压芯片
    • 2.辅助电源
    • 3.参考电源
    • 4.电流检测
    • 4.温度检测
    • 5.MCU
    • 6.OLED
  • 三、原理图
    • 1.电源部分
    • 2.中控部分
    • 3.显示部分
  • 四、PCB部分
    • 1.电源部分
    • 2.控制部分
    • 3.显示部分
  • 五、说说原理
    • 1.电压控制部分
    • 2.传感器(电压、电流、温度)
    • 3.PID算法
  • 六、建模
  • 七、制造过程
    • 1.电源板
    • 2.主控板
    • 3.显示面板
  • 八、测试
    • 1.开机动画
    • 2.过温保护
    • 3.过流保护
    • 4.精度测试
    • 5.使用测试
  • 九、资料
    • 1.PCB
    • 2.源码
    • 3.外壳
  • 总结

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200823153042355.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1lWT05ORU9I,size_16,color_FFFFFF,t_70#pic_center)

前言

作为一个大学僧,成品可调电源笨重且占据桌面空间;而市售USB升压模块2、3W的功率是在不堪大用。于是,博主将从零开始,研发一款实用的桌面可调电源。

基于STM32的桌面数控电源项目连载_第1张图片


一、尺寸与外观

尺寸上,该桌面电源参考华为22.5WSCP充电器,与华为系列快充较好兼容。
基于STM32的桌面数控电源项目连载_第2张图片

二、元器件选型

1.升压芯片

为最大限度兼容PD/SCP/FCP/QC等协议,该电路模块需要有宽电压输入范围。主升压芯片选用XL6019。该芯片为TO263-5封装,最大电流5A,输出电压-0.3~60V,能够满足日常实用需求。
基于STM32的桌面数控电源项目连载_第3张图片

2.辅助电源

辅助电源供给STM32和OLED面板,要求并不高,选熟悉的3.3V线性稳压芯片即可。这里选用的是HT7333。
在这里插入图片描述

3.参考电源

参考电源输入STM32的Vbat引脚,作为基准电压使用,一定程度上决定了电源的精度。若要求不高,可直接并入辅助电源。这里使用一颗TL431,分压电阻为1.33K和4.22k。(TL431分压电阻的计算小工具放在下面链接中)
基于STM32的桌面数控电源项目连载_第4张图片

4.电流检测

由于本人不想搭模电电路,所以选用了德州仪器的电流检测芯片INA180A3IDBVR,该型号芯片可以将检流电阻上的微小电压放大100倍,使用十分方便。
基于STM32的桌面数控电源项目连载_第5张图片

4.温度检测

选用温度传感器TC1047AVNBTR,该型号芯片输出与温度呈线性关系的电压值,使用起来较为方便。

基于STM32的桌面数控电源项目连载_第6张图片

5.MCU

通过分析,MCU至少具备3路ADC(电流、电压、温度),一路DAC(控制电压),一路SPI(OLED),一路UART(扩展蓝牙)。事实上,许多单片机不具备DAC,而因为懒不想增加DAC芯片,所以选型比较受限制。最终选择STM32F103RCT6。(千万不要买RBT6,RBT6没有DAC!!!

6.OLED

没啥好说的,烂大街的0.91寸SPI OLED(中景园15脚),放个图,溜了。

基于STM32的桌面数控电源项目连载_第7张图片

三、原理图

1.电源部分

基于STM32的桌面数控电源项目连载_第8张图片

2.中控部分

基于STM32的桌面数控电源项目连载_第9张图片

3.显示部分

基于STM32的桌面数控电源项目连载_第10张图片

四、PCB部分

PCB分为三层,采用排针及FCP排线连接,方便不同模块升级及替换。

1.电源部分

基于STM32的桌面数控电源项目连载_第11张图片

2.控制部分

基于STM32的桌面数控电源项目连载_第12张图片

3.显示部分

基于STM32的桌面数控电源项目连载_第13张图片

五、说说原理

1.电压控制部分

事实上,任何一款市售的电源模块通过简单的改造均可实现数控。
基于STM32的桌面数控电源项目连载_第14张图片
5脚为电源的反馈引脚,查阅芯片手册,Vfb=1.25V,即该引脚上的电压高于1.25V,MOS管关闭,否则MOS导通,从而实现电压的控制。
分析电路可得公式:(Vo-Vfb)/R2 + ( Vdac-VF)/R6 = Vfb/R9(VF为二极管得压降)
即可得到输出电压。
在本方案中R2=4.7K,R9=91K,R6=5.6K,可实现4.5~25V的调压范围。

2.传感器(电压、电流、温度)

无非就是寻常的多通道ADC检测+多次采样平均+DMA传输。多通道ADC与DMA配置如下。

 
void  Adc_Init(void)
{ 	 
	    GPIO_InitTypeDef  GPIO_InitStructure;
	    ADC_InitTypeDef  ADC_InitStructure; 
	    
	 
	
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE );   
		  						//RCC_APB2Periph_GPIOx,x=GPIOx
	    RCC_ADCCLKConfig(RCC_PCLK2_Div8);            
	    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2;	 //PA0/1/2/3 
	    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                
   		GPIO_Init(GPIOA, &GPIO_InitStructure);
   	  	ADC_DeInit(ADC1);  //½«ÍâÉè ADC1 µÄÈ«²¿¼Ä´æÆ÷ÖØÉèΪȱʡֵ
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC¹¤×÷ģʽ:ADC1ºÍADC2¹¤×÷ÔÚ¶ÀÁ¢Ä£Ê½
        ADC_InitStructure.ADC_ScanConvMode =ENABLE;        //¶àÐŵÀɨÃèģʽ
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  //Ä£Êýת»»¹¤×÷ÔÚÁ¬Ðøת»»Ä£Ê½
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //Íⲿ´¥·¢×ª»»¹Ø±Õ
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADCÊý¾ÝÓÒ¶ÔÆë
        ADC_InitStructure.ADC_NbrOfChannel = 3;        //´Ë´¦¿ª6¸öÐŵÀ£¨¿É¿ªµÄΪ1~16£©
        ADC_Init(ADC1, &ADC_InitStructure);        //¸ù¾ÝADC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèADCxµÄ¼Ä´æÆ÷
        
		//ADC³£¹æÐŵÀÅäÖÃ
        //ADC1,ADCͨµÀx,¹æÔò²ÉÑù˳ÐòֵΪy,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_13Cycles5 );                
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_13Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_13Cycles5 );                

         // ¿ªÆôADCµÄDMAÖ§³Ö£¨ÒªÊµÏÖDMA¹¦ÄÜ£¬»¹Ðè¶ÀÁ¢ÅäÖÃDMAͨµÀµÈ²ÎÊý£©
         ADC_DMACmd(ADC1, ENABLE);       //ʹÄÜADC1µÄDMA´«Êä         
         ADC_Cmd(ADC1, ENABLE);           //ʹÄÜÖ¸¶¨µÄADC1
         ADC_ResetCalibration(ADC1);        //¸´Î»Ö¸¶¨µÄADC1µÄУ׼¼Ä´æÆ÷
         while(ADC_GetResetCalibrationStatus(ADC1));        //»ñÈ¡ADC1¸´Î»Ð£×¼¼Ä´æÆ÷µÄ״̬,ÉèÖÃ״̬ÔòµÈ´ý
         ADC_StartCalibration(ADC1);                //¿ªÊ¼Ö¸¶¨ADC1µÄУ׼״̬
         while(ADC_GetCalibrationStatus(ADC1));                //»ñÈ¡Ö¸¶¨ADC1µÄУ׼³ÌÐò,ÉèÖÃ״̬ÔòµÈ´ý
}				  

void DMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{	DMA_InitTypeDef DMA_InitStructure;    
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
 	DMA_DeInit(DMA_CHx);   //½«DMAµÄͨµÀ1¼Ä´æÆ÷ÖØÉèΪȱʡֵ
    DMA_InitStructure.DMA_PeripheralBaseAddr =  cpar;  //DMAÍâÉèADC»ùµØÖ·
    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMAÄÚ´æ»ùµØÖ·
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //ÄÚ´æ×÷ΪÊý¾Ý´«ÊäµÄÄ¿µÄµØ
    DMA_InitStructure.DMA_BufferSize = cndtr;  //DMAͨµÀµÄDMA»º´æµÄÊý¾Ýµ¥Ôª´óС
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //ÍâÉèµØÖ·¼Ä´æÆ÷²»±ä
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //ÄÚ´æµØÖ·¼Ä´æÆ÷µÝÔö
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //Êý¾Ý¿í¶ÈΪ16λ
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //Êý¾Ý¿í¶ÈΪ16λ
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //Ñ­»·¹¤×÷ģʽ
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMAͨµÀ xÓµÓиßÓÅÏȼ¶ 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMAͨµÀxûÓÐÉèÖÃΪÄÚ´æµ½ÄÚ´æ´«Êä
    DMA_Init(DMA_CHx, &DMA_InitStructure);  //¸ù¾ÝDMA_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯DMAµÄͨµÀ
}


3.PID算法

算法没啥稀奇,普通PID,输入电压,调整DAC。直接放代码。

#ifndef _pid_
#define _pid_
#include "stm32f10x_conf.h"
#define     MODEL_P         1
#define     MODEL_PI         2
#define     MODEL_PID     3

typedef struct
{
    u8 choose_model;    
    
  float curr;              
    float set;               //Óû§É趨ֵ
    

    float En;                    //µ±Ç°Ê±¿Ì
    float En_1;                //ǰһʱ¿Ì
    float En_2;                //Ç°¶þʱ¿Ì
        
    float Kp;               //P
    float T;                //²ÉÑùÖÜÆÚ
    u16   Tdata;            //ÅжÏÊÇ·ñµ½²ÉÑùÖÜÆÚ
    float Ti;               //i
    float Td;               //d
    
    float Dout;                //PIDÔöÁ¿
    float OUT0;                //άÎÈÊä³ö
    
    u16 currdac;      //µ±Ç°dacÖµ
    u16 daccycle;       //pwm??

}PID;


extern u8 STATUS;
extern PID pid;
void PIDParament_Init(void);  
void pid_calc(void);                  

#endif
#include "pid.h"
#include "dac.h"
#include "dac.h"
#include "led.h"

PID pid;

void PIDParament_Init()  //
{
    pid.choose_model = MODEL_PID;
    pid.T=50;                //¶¨Ê±Æ÷1ms ×îС²ÉÑùÖÜÆÚ330ms
    pid.set =5.0;            //Óû§É趨ֵ
    pid.Kp=0.4;                //±ÈÀýϵÊý
    pid.Ti=80;                //΢·ÖϵÊý³£Êý
    pid.Td=2;                //»ý·Öʱ¼ä³£Êý
    pid.OUT0=0;                //ά³ÖϵÊý
    pid.daccycle = 50;       //PWM 
	  pid.currdac=2000;
}

    
void pid_calc()  
{
  float dk1,dk2;
  float t1,t2,t3;
	u16 temp;
//    
//    if(pid.Tdata < (pid.T))  //×îС¼ÆËãÖÜÆÚδµ½
//     {
//            return ;
//     }
//    pid.Tdata = 0;
    
    pid.En=pid.set-pid.curr;  //±¾´ÎÎó²î
    dk1=pid.En-pid.En_1;   //±¾´ÎÎó²îÓëÉÏ´ÎÎó²îÖ®²î
    dk2=pid.En-2*pid.En_1+pid.En_2;
    
    t1=pid.Kp*dk1;                            //±ÈÀý
    
    t2=(pid.Kp*pid.T)/pid.Ti;      //»ý·Ö
    t2=t2*pid.En;
    
    t3=(pid.Kp*pid.Td)/pid.T;        //΢·Ö
    t3=t3*dk2;
    
    switch(pid.choose_model)
     {
         case MODEL_P:     pid.Dout= t1;                   
             break;
         
         case MODEL_PI:  pid.Dout= t1+t2;               
             break;
                 
         case MODEL_PID: pid.Dout= t1+t2+t3;        //¼ÆËãPIDÔöÁ¿
             break;
     } 
          
    pid.currdac-=77.69*pid.Dout;  //Êä³ödacÖµ
    
    if(pid.currdac>4090)            //УÑ鷶Χ
    {
      pid.currdac=4090;
    }
    if(pid.currdac<2000)
    {
     pid.currdac=2000;
    }
    
    pid.En_2=pid.En_1;
    pid.En_1=pid.En;
		temp=pid.currdac;
		
		temp=(int)pid.currdac;
		temp=(short)temp;
		DAC_SetChannel1Data(DAC_Align_12b_R,temp );
    
    
    
    

}

六、建模

开篇说了,要和手头华为快充配套,那自然是大小,材质一样咯。

话说立创EDA不能导出STEP是真蛋疼,三维模型折腾了好久,话说有兴趣可以开一贴,如何从立创EDA导出三维模型(很烦很烦)。

建模和渲染都是基于Solidworks.
壳体
基于STM32的桌面数控电源项目连载_第15张图片
效果图
基于STM32的桌面数控电源项目连载_第16张图片

七、制造过程

1.电源板



调压测试,最高25V.

2.主控板

平平无奇的STM32开发板

囊中羞涩的我并没有买蓝牙模块,蓝牙原计划选的是易佰特E14 BT05。

3.显示面板



显示面板焊接不要太久,我有个贼漂亮的橙色OLED被我焊的光衰了,基本看不出了字,谁有橙色0.91 SPI OLED的购买方式麻烦私我一下,谢谢啦。

八、测试

1.开机动画

基于STM32的桌面数控电源项目连载_第17张图片

2.过温保护


警报灯亮起,屏幕显示温度计图标。

3.过流保护

警报灯亮起,屏幕显示电流,输出切断。
看官老爷对不住,实在没抓拍到。

4.精度测试


输出10.10V,实测10.08~10.11浮动,可以接受,加个大电容会好一些。

5.使用测试

该表通过中键切换模式,有电流/电压、温度/功率、循环三档。
左右键选择电压,步进0.5v.

九、资料

1.PCB

https://download.csdn.net/download/YVONNEOH/12740947

2.源码

https://download.csdn.net/download/YVONNEOH/12740952

3.外壳

https://download.csdn.net/download/YVONNEOH/12740960

总结

外壳还没加工好,待更,勿催。。。
最后,在评论区评论+暗号awsl,抽一个人送一套PCB邮费自理,截止日期2020.9.10.

你可能感兴趣的:(基于STM32的桌面数控电源项目连载)