当前位置:首页 > 编程笔记 > 正文
已解决

PIC16F18323电源控制软件

来自网友在路上 154854提问 提问时间:2023-09-21 12:34:03阅读次数: 54

最佳答案 问答题库548位专家为你答疑解惑

最近使用PIC16F18323设计一个电源的控制软件,主要功能有:检测输入电压,NTC贴片电阻温度监测,电路输出开环检测及输出过压保护锁死等。

PIC16F18323系列单片机有256字节内存,1K字节ROM空间,使用的是高速内部振荡器(锁相环之后时钟频率是32MHz),软件需求如下:

引脚

引脚特性

网络名

功能

功能要求

1

/

VDD

供电脚

2

A/D采样

VIN

输入电压检测

  1. 输入电压检测,上偏电阻102K、下偏电阻5K1;
  2. 输入欠压保护:此脚电压≤1.55V(对应输入32.5V),5、8、9脚同时输出高电平(关闭3路输出),7脚输出低电平(关继电器),6脚输出低电平(输入告警);
  3. 输入欠压恢复:此脚电压≥1.67V(对应输入35V),7脚输出高电平(开继电器),延时100mS后,5、9脚同时输出低电平(开-12V、+12V),再延时100mS,8脚输出低电平(开50V),6脚输出高电平(输入告警解除);
  4. 输入过压保护:此脚电压≥3.71V(对应输入78V),5、8、9脚同时输出高电平(关闭3路输出),7脚输出低电平(关继电器),6脚输出低电平(输入告警);
  5. 输入过压恢复:此脚电压≤3.57V(对应输入75V),7脚输出高电平(开继电器),延时100mS后,5、9脚同时输出低电平(开-12V、+12V),再延时100mS,8脚输出低电平(开50V),6脚输出高电平(输入告警解除)。

3

/

空脚

4

/

MCLR

复位

5

输出

V1_ON

-12V开机信号

开机:输出低电平;

关机:输出高电平,默认值为高电平

6

输出

IN_OK

输入状态信号

输入正常:输出高电平;

输入异常(欠压、过压):输出低电平,默认值为低电平

7

输出

输入继电器控制

继电器开:输出高电平;

继电器关:输出低电平,默认值为低电平

8

输出

50V开机信号

开机:输出低电平;

关机:输出高电平,默认值为高电平

9

输出

V2_ON

+12V开机信号

开机:输出低电平;

关机:输出高电平,默认值为高电平

10

A/D采样

COMP2

+12V开环检测

+12V开环保护:此脚电压≥2.5V时(持续40mS),9脚输出高电平,持续3S,3S之后重新检测10脚电压,如果电压<2.2V,那么9脚输出低电平,反之则输出高电平。开环保护模式:+12V开40mS,关3S,打嗝模式

11

A/D采样

COMP1

-12V开环检测

-12V开环保护:此脚电压≥2.5V时(持续40mS),5脚输出高电平,持续3S,3S之后重新检测11脚电压,如果电压<2.2V,那么5脚输出低电平,反之则输出高电平。开环保护模式:-12V开40mS,关3S,打嗝模式

12

A/D采样

OTP

温度检测

1、NTC型号:APR-CWF104F3950FA55A;

2、过温保护:此电压≥3.5V时(持续20mS,3.5V对应温度96℃),5、8、9脚同时输出高电平(关闭3路输出);

3、过温保护恢复:过温保护之后当电压≤2.8V时,5、9脚同时输出低电平(开-12V、+12V),延时100mS,8脚输出低电平(开50V)。

13

输入

+12V_OVP

+12V输出过压检测

+12V输出过压保护:此脚检测到高电平时(持续5-10mS),9脚持续输出高电平(过压锁死)

14

/

GND

开机时序:

第1步:检测输入正常,延时500mS,7脚输出高电平(开继电器);

第2步:延时100mS,5、9脚同时输出低电平(开-12V、+12V);

第3步:延时100mS,8脚输出低电平(开50V),6脚输出高电平(输入告警解除)

单片机原理图部分:

其实程序逻辑比较简单,就是检测后进行各种控制,我的主要思路是:先进行AD检测,然后设置各个标志位,再根据标志位进行各个输出设备的开关控制。

主程序如下:

头文件main.h

/* * File:   main.h* Author: PD821** Created on September 8, 2023, 5:33 PM*/#ifndef MAIN_H
#define	MAIN_H#ifdef	__cplusplus
extern "C" {
#endif//typedef unsigned char uint8_t;
//typedef unsigned int  uint16_t;
//Configuration bits: selected in the GUI//CONFIG1
#pragma config FEXTOSC = OFF            // FEXTOSC External Oscillator mode Selection bits->Oscillator not enabled
#pragma config RSTOSC = HFINT32         // Power-up default value for COSC bits->HFINTOSC with 2x PLL (32MHz)
#pragma config CLKOUTEN = OFF           // Clock Out Enable bit->CLKOUT function is disabled; I/O or oscillator function on OSC2
#pragma config CSWEN = ON               // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = ON               // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled//CONFIG2
#pragma config MCLRE = ON               // Master Clear Enable bit->MCLR/VPP pin function is MCLR; Weak pull-up enabled
#pragma config PWRTE = OFF              // Power-up Timer Enable bit->PWRT disabled
#pragma config WDTE = OFF               // Watchdog Timer Enable bits->WDT disabled; SWDTEN is ignored
#pragma config LPBOREN = OFF            // Low-power BOR enable bit->ULPBOR disabled
#pragma config BOREN = ON               // Brown-out Reset Enable bits->Brown-out Reset enabled, SBOREN bit ignored
#pragma config BORV = LOW               // Brown-out Reset Voltage selection bit->Brown-out voltage (Vbor) set to 2.45V
#pragma config PPS1WAY = ON             // PPSLOCK bit One-Way Set Enable bit->The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
#pragma config STVREN = ON              // Stack Overflow/Underflow Reset Enable bit->Stack Overflow or Underflow will cause a Reset
#pragma config DEBUG = OFF              // Debugger enable bit->Background debugger disabled//CONFIG3
#pragma config WRT = OFF                // User NVM self-write protection bits->Write protection off
#pragma config LVP = ON                 // Low Voltage Programming Enable bit->Low Voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored.//CONFIG4
#pragma config CP = OFF                 // User NVM Program Memory Code Protection bit->User NVM code protection disabled
#pragma config CPD = OFF                // Data NVM Memory Code Protection bit->Data NVM code protection disabled//CPU clock define
#define     _XTAL_FREQ                  32000000
#define 	ACQ_US_DELAY                1/** bit 7-2 CHS<5:0>: Analog Channel Select bits
111111 = FVR (Fixed Voltage Reference)(2)
111110 = DAC1 output(1)
111101 = Temperature Indicator(3)
111100 =VSS
111011 = Reserved. No channel connected. •
010101 = ANC5(4)
010100 = ANC4(4)
010011 = ANC3(4)
010010 = ANC2(4)
010001 = ANC1(4)
010000 = ANC0(4)
001011 = Reserved. No channel connected. •
000101 = ANA5
000100 = ANA4
000011 = Reserved. No channel connected.
000010 = ANA2
000001 = ANA1
000000 = ANA0*/    
#define		nVIN                    5                   // RA5/ANA5
#define		nTMP1                   1                   // RA1/ANA1
#define		nCOMP1                  2                   // RA2/ANA2
#define		nCOMP2                  16                  // RC0/ANC0
#define     SAMPLE_CNT              32                  // ADC sampling count#define     PV12_OVP                PORTAbits.RA0       //+12V OVP check
#define     NV12_OVP                PORTAbits.RA1       //-12V OVP check#define		RLY_RDY_TIMEOUT		    500                 //If VDC input is normal, we need to delay 500ms before turning on RELAY
#define		V12OUT_RDY_TIMEOUT		100                 //If relay is ready, we delay 100ms before turning on the +12V and -12V output
#define		V50OUT_RDY_TIMEOUT		100                 //If +12 and -12V are both ready, we delay 100ms before turning on the 50V output
#define     IO_FILTER_CNT      		10                  //IO filter count
#define		IO_FILTER_VALID_CNT		10                  //IO valid count of filter
#define     OP_FILTER_CNT      		20                  //OPEN-LOOP filter count
#define		OP_FILTER_VALID_CNT		20                  //OPEN-LOOP valid count of filter
#define     HICCUP_OFF_TIME         3000                //turn OFF about 3 seconds
#define     HICCUP_ON_TIME          50                  //turn ON about 50 milli-seconds
#define     RELAY_ALWAYS_ON         0                   //Is the relay always ON once powered-on? 0: OFF, 1: ON
#define     LOCK_NO_DELAY           1                   //Do we need to lock the output once OVP occurs? 1: turn off the output immediately, 0: delay sometime to turn off the output
#define     LOCK_TIMEOUT            5000                //If the LOCK_NO_DELAY is set to 0, we delay sometime to check the OVP
#define     DELAY_TURN_OFF_TIME     50                  //delay some time to turn OFF the output once the IN_OK is abnormal
#define     WARNING_FLAG_VP12       0x0A13
#define     WARNING_FLAG_VN12       0x1813    //Relay
#define     RELAY_ON()              do { LATCbits.LATC3 = 1; } while(0)
#define     RELAY_OFF()             do { LATCbits.LATC3 = 0; } while(0)//VDC
#define     IN_OK()                 do { LATCbits.LATC4 = 1; } while(0)
#define     IN_NOT_OK()             do { LATCbits.LATC4 = 0; } while(0)//-12V
#define     VN12_ON()               do { LATCbits.LATC5 = 0; } while(0)
#define     VN12_OFF()             	do { LATCbits.LATC5 = 1; } while(0)//+12V
#define     VP12_ON()               do { LATCbits.LATC1 = 0; } while(0)
#define     VP12_OFF()    			do { LATCbits.LATC1 = 1; } while(0)//50V
#define     V50_ON()                do { LATCbits.LATC2 = 0; } while(0)
#define     V50_OFF()    			do { LATCbits.LATC2 = 1; } while(0)struct ALARM
{unsigned	VDC_UVP							: 1;	//VDC under-voltageunsigned	VDC_OVP							: 1;	//VDC over-voltageunsigned	VDC_READY						: 1;	//VDC is readyunsigned	RLY_READY   					: 1;	//the relay is readyunsigned	OTP 					        : 1;	//over temperature protectionunsigned	VN12_OVP      					: 1;    //-12V output is OVPunsigned	VP12_EN							: 1;	//+12V is ready to openunsigned	VP12_ON							: 1;	//+12V output is on or offunsigned	VP12_OVP      					: 1;    //+12V output is OVPunsigned	VP12_OPEN_LOOP  				: 1;    //+12V open-loopunsigned	IN_OK						    : 1;    //IN-OK signalunsigned	OUT_LOCKED					    : 1;    //lock the output permanentlyunsigned	VN12_OPEN_LOOP      			: 1;    //-12V open-loopunsigned	VN12_EN							: 1;	//-12V is ready to openunsigned	VN12_ON							: 1;	//-12V output is on or offunsigned	V50_EN        					: 1;    //50V output is ready to open
};union ALARM_STATUS_UNION 
{struct ALARM	alarm;uint16_t	allbits;
}; typedef union ALARM_STATUS_UNION ALARM_STATUS;#define			ADCFS					1024.0  //the maximum AD value of 10-bit ADC
#define			ADCREF                  5.0     //5V reference voltage
#define			ADC_DIV_REF             (float)(ADCFS/ADCREF)//===========================================================================
//
//					DC under/over voltage macros
//
//===========================================================================
#define         VIN_DIV_RUP				(51.0 + 51.0) //up and down resistors
#define         VIN_DIV_RLOW			5.1
#define         VIN_SENSE_FULLSCALE     ((1.0 + VIN_DIV_RUP/VIN_DIV_RLOW) * ADCREF)	//Maximum input voltage 105V
#define         VIN_DIV_GAIN			((float)(VIN_DIV_RLOW/(VIN_DIV_RLOW + VIN_DIV_RUP)))//gain: 5.1/(5.1+102)
#define         VDC_UV_OFF				32.5     //DC under voltage alarm
#define         VDC_UV_ON				35.0     //DC under voltage recovered
#define         VDC_OV_OFF				78.0     //DC over voltage alarm
#define         VDC_OV_ON				75.0     //DC over voltage recovered
#define         VDC_UV_OFF_AD			(uint16_t)(VDC_UV_OFF * VIN_DIV_GAIN * ADC_DIV_REF)
#define         VDC_UV_ON_AD			(uint16_t)(VDC_UV_ON * VIN_DIV_GAIN * ADC_DIV_REF)
#define         VDC_OV_OFF_AD			(uint16_t)(VDC_OV_OFF * VIN_DIV_GAIN * ADC_DIV_REF)
#define         VDC_OV_ON_AD			(uint16_t)(VDC_OV_ON * VIN_DIV_GAIN * ADC_DIV_REF)//===========================================================================
//
//					OTP macros
//
//===========================================================================
//#define       OTP1_OFF				3.35   //NTC=3.89893K, temperature: 105
//#define       OTP1_RECOVER			2.84   //NTC=6.60883K, temperature: 90
//#define       OTP1_OFF_AD				687    //(0x2AF)//105C, ((uint16_t)(((OTP1_OFF)/(ADCREF)) * (ADCFS)))
//#define       OTP1_RECOVER_AD			581    //(0x246)//90C, ((uint16_t)(((OTP1_RECOVER)/(ADCREF)) * (ADCFS)))
#define         OTP1_OFF				3.5    //temperature: 96
#define         OTP1_RECOVER			2.8    //NTC=6.60883K, temperature: 90
#define			OTP1_OFF_AD				717    //(0x2AF)//105C, ((uint16_t)(((OTP1_OFF)/(ADCREF)) * (ADCFS)))
#define			OTP1_RECOVER_AD			573    //(0x246)//90C, ((uint16_t)(((OTP1_RECOVER)/(ADCREF)) * (ADCFS)))//===========================================================================
//
//					OPEN-LOOP macros
//
//===========================================================================
#define         OP_VP12_OFF				2.5
#define         OP_VP12_RECOVER			2.2
#define			OP_VP12_OFF_AD			(uint16_t)(OP_VP12_OFF * ADC_DIV_REF)
#define			OP_VP12_RECOVER_AD		(uint16_t)(OP_VP12_RECOVER * ADC_DIV_REF)
#define         OP_VN12_OFF				2.5
#define         OP_VN12_RECOVER			2.2
#define			OP_VN12_OFF_AD			(uint16_t)(OP_VN12_OFF * ADC_DIV_REF)
#define			OP_VN12_RECOVER_AD		(uint16_t)(OP_VN12_RECOVER * ADC_DIV_REF)#ifdef	__cplusplus
}
#endif#endif	/* MAIN_H */

C文件main.c

#include "xc.h"
#include "main.h"//#define 	PORTBIT(ADR,BIT_LOC) ((unsigned)(&ADR)*8+(BIT_LOC))
//static bit 	in_SDA 	@PORTBIT(PORTC,1);//SDA data
volatile uint16_t timer1ReloadVal;
uint16_t    rly_rdy_timeout = 0;    //once VDC is normal, we delay some time to turn ON the relay
uint16_t    v12_rdy_timeout = 0;
uint16_t    v50_rdy_timeout = 0;
uint8_t     v12_off_timeout = 0;    //delay some time to turn off the +12V output
uint16_t    cHiccup1OnTime = 0;     //the ON time that the +12V output lasts after delaying 3 seconds
uint16_t    cHiccup1OffTime = 0;    //hiccup OFF time counter
uint8_t     cHiccup1OnFlag = 0;     //flag indicating that hiccup OFF time has reached the designated time and needs to reopen the output for a short time
uint16_t    cHiccup2OnTime = 0;     //the ON time that the -12V output lasts after delaying 3 seconds
uint16_t    cHiccup2OffTime = 0;    //hiccup OFF time counter
uint8_t     cHiccup2OnFlag = 0;     //flag indicating that hiccup OFF time has reached the designated time and needs to reopen the output for a short time
uint8_t     cFlag_1ms = 0;
uint8_t     cFlag_2ms = 0;          //2 milli-seconds timeout for ADC to start the conversion
uint8_t     cSample_cnt = 0;
uint8_t     cSample_flag = 0;       //flag indicating that all the four channels are sampled and the next conversion is ready to start
uint16_t    ovp1_time_cnt = 0;      //once output is OVP, we can decide whether it is necessary to delay some time or immediately to turn OFF the output
uint16_t    ovp2_time_cnt = 0;
volatile	uint8_t	cchannel = 5;   //default channel is VIN
volatile	uint8_t	c2mS_Nct = 0;   //2 milli-seconds counter
volatile    uint8_t io_cnt = 0;
uint8_t     adc_filter_cnt = 0;     //ADC filter counter
uint8_t     op_filter_cnt = 0;      //OPEN-LOOP filter counter//ADC filter and OPEN-LOOP filter
uint8_t vdc_ovp_off = 0,vdc_ovp_recovered = 0;
uint8_t vdc_uvp_off = 0,vdc_uvp_recovered = 0;
uint8_t otp_off = 0,otp_recovered = 0;
uint8_t op_vp12_off = 0,op_vp12_recovered = 0;
uint8_t op_vn12_off = 0,op_vn12_recovered = 0;//Unless stated otherwise, the following variables are similar to those that VDC uses
volatile	uint16_t	iSample_ad = 0;
volatile	uint16_t	iAd_data[4] ={0};uint8_t vp12_ovp_H = 0; //OVP check
uint8_t vp12_ovp_L = 0;ALARM_STATUS AlarmStatus;/******************************************************
name: Init_OSC
brief: configure the system oscillator
input: none
output: none
*****************************************************/
void Init_OSC(void)
{//NOSC HFINTOSC; NDIV 1; OSCCON1 = 0x60;//CSWHOLD may proceed; SOSCPWR Low power; SOSCBE crystal oscillator; OSCCON3 = 0x00;//LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled; OSCEN = 0x00;//HFFRQ 32_MHz; OSCFRQ = 0x07;//HFTUN 0; OSCTUNE = 0x00;
}/******************************************************
name: Init_Timer
brief: configure the timer period, 1 milli-second
input: none
output: none
*****************************************************/
void Init_Timer(void)
{//Set the Timer to the options selected in the GUI//T1GSS T1G_pin; TMR1GE disabled; T1GTM disabled; T1GPOL low; T1GGO_nDONE done; T1GSPM disabled; T1GCON = 0x00;//TMR1H 224; TMR1H = 0xE0;//TMR1L 192; TMR1L = 0xC0;// Clearing IF flag before enabling the interrupt.PIR1bits.TMR1IF = 0;// Load the TMR value to reload variabletimer1ReloadVal=(uint16_t)((TMR1H << 8) | TMR1L);// Enabling TMR1 interrupt.PIE1bits.TMR1IE = 1;// Set Default Interrupt Handler//TMR1_SetInterruptHandler(TMR1_DefaultInterruptHandler);// T1CKPS 1:1; T1SOSC T1CKI_enabled; T1SYNC synchronize; TMR1CS FOSC/4; TMR1ON enabled; //bit7-bit6: TMR1CS<1:0>: Timer1 Clock Source Select bits//00 = Timer1 clock source is instruction clock (FOSC/4)T1CON = 0x01;//0b0000 0001
}/******************************************************
name: Init_ADC
brief: configure the ADC module
input: none
output: none
*****************************************************/
void Init_ADC(void)
{//ADFM right; ADNREF VSS; ADPREF VDD; ADCS FOSC/32 = 1M clock frequency; /** bit 7 ADFM: ADC Result Format Select bit* bit 6-4 ADCS<2:0>: ADC Conversion Clock Select bits111 = ADCRC (dedicated RC oscillator)110 =FOSC/64101 =FOSC/16100 =FOSC/4011 = ADCRC (dedicated RC oscillator)010 =FOSC/32001 =FOSC/8000 =FOSC/2*/ADCON1 = 0xA0; //1010, right justified, FOSC/32//ADACT no_auto_trigger; ADACT = 0x00;//ADRESL 0; ADRESL = 0x00;//ADRESH 0; ADRESH = 0x00;//set the default ADC channelcchannel = nVIN;ADCON0bits.CHS = cchannel;//ADGO stop; ADON enabled; CHS ANA0; //bit 1 GO/DONE: ADC Conversion Status bit//bit 0 ADON: ADC Enable biADCON0 = 0x01;
}/******************************************************
name: Init_GPIO
brief: configure the all pins needed
input: none
output: none
*****************************************************/
void Init_GPIO(void)
{//LATx registers, set default pin value//RC1-V2-ON: 1: OFF//RC2-Alarm: 0: OFF//RC3-Relay: 0: OFF//RC4-IN-OK: 0: OFF//RC5-V1-ON: 1: OFFLATA = 0x00;	// 0000 0000LATC = 0x22;	// 0010 0010//TRISx registers, RA0-RA5 are all input modeTRISA = 0x3F;	// 0011 1111TRISC = 0x01;	// 0000 0001, RC0 is input, RC1-RC5 are output mode//ANSELx registers, the following pins are configured as analog input//RA5: VIN //RA1: OTP//RA2: COMP1//RC0: COMP2ANSELC = 0x01;	// 0000 0001ANSELA = 0x26;	// 0010 0110//WPUx registers, wake pull-up register, this is mainly used for input pins//WPUA = 0x08;	// 0000 1000//WPUC = 0x36;	// 0011 0110//ODx registers, open-drain control//bit 5-4 ODCA<5:4>: PORTA Open-Drain Enable bits//For RA<5:4> pins, respectively//1 = Port pin operates as open-drain drive (sink current only)//0 = Port pin operates as standard push-pull drive (source and sink current)ODCONA = 0x00;ODCONC = 0x00;//SLRCONx registers for RA and RC, slew rate controlSLRCONA = 0x37;//0011 0111/*bit 5-0 SLRC<5:0>: PORTC Slew Rate Enable bitsFor RC<5:0> pins, respectively1 = Port pin slew rate is limited0 = Port pin slews at maximum rate*/SLRCONC = 0x3F;//0011 1111, //INLVLx registers,  input threshold control/** The INLVLA register (Register 12-8) controls the inputvoltage threshold for each of the available PORTA inputpins. A selection between the Schmitt Trigger CMOS orthe TTL Compatible thresholds is available. The inputthreshold is important in determining the value of a readof the PORTA register and also the level at which aninterrupt-on-change occurs, if that feature is enabled.* bit 5-0 INLVLA<5:0>: PORTA Input Level Select bitsFor RA<5:0> pins, respectively1 = ST input used for PORT reads and interrupt-on-change0 = TTL input used for PORT reads and interrupt-on-change*/INLVLA = 0x3F;INLVLC = 0x3F;//bit 4-0 RxyPPS<4:0>: Pin Rxy Output Source Selection bits//10100(0x14) = Rxy source is EUSART TC/CK//RC4PPS = 0x14;   //RC4->EUSART:TX;    //use RC4 as the EUSART TX pin//set the default IO status of all output pinsRELAY_OFF();IN_NOT_OK();VP12_OFF();VN12_OFF();V50_OFF();
}/** interrupt service routine* here we mainly process the timer1's overflow event*/
void __interrupt() ISR(void)							
{//interrupt handlerif(INTCONbits.PEIE == 1){if(PIR1bits.TMR1IF == 1)	// 1000 us{cFlag_1ms = 1;if(++c2mS_Nct>=2){cFlag_2ms = 1;c2mS_Nct = 0;}//Clear the TMR1 interrupt flagPIR1bits.TMR1IF = 0;//TMR1_WriteTimer(timer1ReloadVal);TMR1H = (uint8_t)(timer1ReloadVal >> 8);TMR1L = (uint8_t)timer1ReloadVal;}}      
}/**************************************************************************************************
name:ADC_GetConversion
description:get the AD conversion result
input: channel: the channel to be converted
output: the 16-bit result
***************************************************************************************************/
uint16_t ADC_GetConversion(uint8_t channel)
{// select the A/D channelADCON0bits.CHS = channel;    // Turn on the ADC moduleADCON0bits.ADON = 1;// Acquisition time delay__delay_us(ACQ_US_DELAY);// Start the conversionADCON0bits.ADGO = 1;// Wait for the conversion to finishwhile (ADCON0bits.ADGO);// Conversion finished, return the resultreturn ((uint16_t)((ADRESH << 8) + ADRESL));
}/**************************************************************************************************
name:void	ADC_Sample(void)
description:ADC sample, convert ADC per 2 milli-seconds
input: None
output: iAd_data[0]: VDC voltage;iAd_data[1]: OTP;iAd_data[2]: COMP1;iAd_data[3]: COMP2 
***************************************************************************************************/
void ADC_Sample(void)
{uint16_t	iTemp;if(cSample_flag == 0){if (cSample_cnt == 0){cSample_cnt = 1;return;}switch(cchannel){case nVIN:									//VDC{//GO_nDONE = 1;        					// A2D start conversionADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(++cSample_cnt > SAMPLE_CNT){cSample_cnt = 0;iAd_data[0] = iSample_ad>>5;iSample_ad = 0;cchannel = nTMP1;ADCON0bits.CHS = cchannel;}break;}		case nTMP1:									//temperature{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(++cSample_cnt > SAMPLE_CNT){cSample_cnt = 0;iAd_data[1] = iSample_ad>>5;iSample_ad = 0;cchannel = nCOMP1;ADCON0bits.CHS = cchannel;	}break;}	case nCOMP1:									//COMP1, -12V OPEN-LOOP{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(++cSample_cnt > SAMPLE_CNT){cSample_cnt = 0;iAd_data[2] = iSample_ad>>5;iSample_ad = 0; cchannel = nCOMP2;		ADCON0bits.CHS = cchannel;}break;}case nCOMP2:									//COMP2, +12V OPEN-LOOP{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(++cSample_cnt > SAMPLE_CNT){cSample_cnt = 0;iAd_data[3] = iSample_ad>>5;iSample_ad = 0; cchannel = nVIN;		ADCON0bits.CHS = cchannel;cSample_flag = 1;}break;}default:{cSample_cnt = 0;iSample_ad = 0; cchannel = nVIN;ADCON0bits.CHS = cchannel;break;}	}}
}/******************************************************
name: ADC_Process
brief: just call the ADC_Sample function and clear * cSamle_flag if it is set.* This function is called by main function.
input: none
output: none
*****************************************************/
void ADC_Process(void)
{ADC_Sample();if(cSample_flag == 1){cSample_flag = 0;}
}/*
void ADC_Sample(void)
{uint16_t	iTemp;if(cFlag_2ms == 1){	switch(cchannel){case nVIN:									//VDC{//GO_nDONE = 1;        					// A2D start conversionADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(cSample_cnt>=15){cSample_cnt = 0;iAd_data[0] = iSample_ad>>4;iSample_ad = 0;cchannel = nTMP1;ADCON0bits.CHS = cchannel;}else{	cSample_cnt++;}	break;}		case nTMP1:									//temperature{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(cSample_cnt>=15){cSample_cnt = 0;iAd_data[1] = iSample_ad>>4;iSample_ad = 0;cchannel = nCOMP1;ADCON0bits.CHS = cchannel;	}else{	cSample_cnt++;}	break;}	case nCOMP1:									//COMP1, -12V OPEN-LOOP{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(cSample_cnt>=15){cSample_cnt = 0;iAd_data[2] = iSample_ad>>4;iSample_ad = 0; cchannel = nCOMP2;		ADCON0bits.CHS = cchannel;}else{cSample_cnt++;}	break;}case nCOMP2:									//COMP2, +12V OPEN-LOOP{//GO_nDONE = 1;ADCON0bits.ADGO = 1;__delay_us(ACQ_US_DELAY);while (ADCON0bits.ADGO);iTemp = ADRESH<<8;iTemp = iTemp + ADRESL;iSample_ad = iSample_ad + iTemp;if(cSample_cnt>=15){cSample_cnt = 0;iAd_data[3] = iSample_ad>>4;iSample_ad = 0; cchannel = nVIN;		ADCON0bits.CHS = cchannel;}else{cSample_cnt++;}	break;}default:{cSample_cnt = 0;iSample_ad = 0; cchannel = nVIN;ADCON0bits.CHS = cchannel;break;}	}if(PV12_OVP == 1)//+12V{vp12_ovp_H++;}else{vp12_ovp_L++;}if(io_cnt>=IO_FILTER_CNT)//set or clear OVP flag{if(vp12_ovp_H>=IO_FILTER_VALID_CNT){AlarmStatus.alarm.VP12_OVP = 1;}if(vp12_ovp_L>=IO_FILTER_VALID_CNT){AlarmStatus.alarm.VP12_OVP = 0;//no need to clear this bit}vp12_ovp_H = 0;vp12_ovp_L = 0;vn12_ovp_H = 0;vn12_ovp_L = 0;io_cnt = 0;}else{io_cnt++;}//c2mS_Nct = 0;cFlag_2ms = 0;}
}
*//******************************************************
name: Fault_Check
brief: set or clear all the flags, mainly the ADC resultperiod: 2 milli-second
input: none
output: none
*****************************************************/
static void Fault_Check(void)
{if(cFlag_2ms == 1){if(iAd_data[0]<=VDC_UV_OFF_AD)	//DC under/over voltage filtervdc_uvp_off++;if(iAd_data[0]>=VDC_UV_ON_AD)vdc_uvp_recovered++;if(iAd_data[0]>=VDC_OV_OFF_AD)vdc_ovp_off++;if(iAd_data[0]<=VDC_OV_ON_AD)vdc_ovp_recovered++;	if(iAd_data[1]>=OTP1_OFF_AD)	//OTPotp_off++;if(iAd_data[1]<=OTP1_RECOVER_AD)otp_recovered++;if(adc_filter_cnt >= IO_FILTER_CNT){if(vdc_uvp_off >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.VDC_UVP == 0)    //VDC under voltage{AlarmStatus.alarm.VDC_UVP = 1;}	else if(vdc_uvp_recovered >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.VDC_UVP == 1){AlarmStatus.alarm.VDC_UVP = 0;		}if(vdc_ovp_off >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.VDC_OVP == 0)	//VDC over voltage{AlarmStatus.alarm.VDC_OVP = 1;}	else if(vdc_ovp_recovered >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.VDC_OVP == 1){AlarmStatus.alarm.VDC_OVP = 0;		}if(otp_off >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.OTP == 0)	//OTP{AlarmStatus.alarm.OTP = 1;}	else if(otp_recovered >= IO_FILTER_VALID_CNT && AlarmStatus.alarm.OTP == 1){AlarmStatus.alarm.OTP = 0;		}adc_filter_cnt = 0;vdc_uvp_off = 0;vdc_uvp_recovered = 0;vdc_ovp_off = 0;vdc_ovp_recovered = 0;		otp_off = 0;otp_recovered = 0;}else{adc_filter_cnt++;}//+12V and -12V OPEN-LOOP check//OPEN-LOOP time check should ber longer to avoid the peak current while starting upif(iAd_data[3] >= OP_VP12_OFF_AD)op_vp12_off++;if(iAd_data[3] <= OP_VP12_RECOVER_AD)op_vp12_recovered++;if(iAd_data[2] >= OP_VN12_OFF_AD)op_vn12_off++;if(iAd_data[2] <= OP_VN12_RECOVER_AD)op_vn12_recovered++;if(op_filter_cnt >= OP_FILTER_CNT){if(op_vp12_off >= OP_FILTER_VALID_CNT && AlarmStatus.alarm.VP12_OPEN_LOOP == 0)	//OPEN-LOOP of COMP2{AlarmStatus.alarm.VP12_OPEN_LOOP = 1;}	//else if(op_vp12_recovered >= OP_FILTER_VALID_CNT && AlarmStatus.alarm.VP12_OPEN_LOOP == 1)//{//AlarmStatus.alarm.VP12_OPEN_LOOP = 0;//}if(op_vn12_off >= OP_FILTER_VALID_CNT && AlarmStatus.alarm.VN12_OPEN_LOOP == 0)	//OPEN-LOOP of COMP1{AlarmStatus.alarm.VN12_OPEN_LOOP = 1;}//the warning flat can't be cleared here once it is set//else if(op_vn12_recovered >= OP_FILTER_VALID_CNT && AlarmStatus.alarm.VN12_OPEN_LOOP == 1)//{//AlarmStatus.alarm.VN12_OPEN_LOOP = 0;//}op_filter_cnt = 0;op_vp12_off = 0;op_vp12_recovered = 0;op_vn12_off = 0;op_vn12_recovered = 0;}else{op_filter_cnt++;}cFlag_2ms = 0;}
}/******************************************************
name: Process_VP12
brief: process the +12V output
input: none
output: none
*****************************************************/
static void Process_VP12(void)
{//POWER Dispatch. Under/over voltage protection OR output error OR over temperature, we need to deal with them respectively//if((AlarmStatus.allbits & WARNING_FLAG_VP12)==0)//IN_OK must be set to 1if(AlarmStatus.alarm.IN_OK == 1 && AlarmStatus.alarm.OUT_LOCKED == 0 && AlarmStatus.alarm.VP12_OPEN_LOOP == 0 && AlarmStatus.alarm.OTP == 0){if(AlarmStatus.alarm.VP12_EN == 1)//only when all the conditions are ready can we turn on the +12V output{VP12_ON();AlarmStatus.alarm.VP12_ON = 1; }else{    VP12_OFF();AlarmStatus.alarm.VP12_ON = 0;}cHiccup1OffTime = 0;cHiccup1OnTime = 0;cHiccup1OnFlag = 0;}else if(AlarmStatus.alarm.OUT_LOCKED == 1) //output is locked{VP12_OFF();AlarmStatus.alarm.VP12_EN = 0;AlarmStatus.alarm.VP12_ON = 0;cHiccup1OffTime = 0;cHiccup1OnTime = 0;cHiccup1OnFlag = 0;}else if(AlarmStatus.alarm.VP12_OPEN_LOOP == 1)//OPEN-LOOP hiccup{if(++cHiccup1OffTime>=HICCUP_OFF_TIME)//OFF time{VN12_ON();cHiccup1OffTime = HICCUP_OFF_TIME;cHiccup1OnFlag = 1;}else{VP12_OFF();cHiccup1OnTime = 0;cHiccup1OnFlag = 0;}}else //other exceptions processed in Task_Manager function{//TODO}/*else//other exceptions, such as OVP, UVP or OTP or output is LOCKED{//rly_rdy_timeout=0;if(AlarmStatus.alarm.IN_OK == 0)//we need to delay some to open the output, including -12V, +12V and 50V{v12_rdy_timeout = 0;}v50_rdy_timeout = 0;cHiccup1OffTime = 0;cHiccup1OnTime = 0;cHiccup1OnFlag = 0;#if(RELAY_ALWAYS_ON == 0){AlarmStatus.alarm.RLY_READY = 0;RELAY_OFF();}#endif//VDC_OK=0;if(AlarmStatus.alarm.IN_OK==0)//only after the IN_OK is set to 0 can set we turn OFF the +12V{if(++vp12_off_timeout>=DELAY_TURN_OFF_TIME){vp12_off_timeout=0;VP12_OFF();}}else//OTHER exception rather than IN_OK error, turn OFF the output directly{VP12_OFF();}AlarmStatus.alarm.VP12_EN = 0;AlarmStatus.alarm.VP12_ON = 0;}*/if(cHiccup1OnFlag == 1)//hiccup{		if(++cHiccup1OnTime>=HICCUP_ON_TIME)//the 49V output is on for 50 milli-seconds{			if(iAd_data[3]>=OP_VP12_OFF_AD)//if it is still in OPEN-LOOP state{cHiccup1OffTime = 0;}else{if(iAd_data[3]<OP_VP12_RECOVER_AD)//recovered, return difference is necessary{AlarmStatus.alarm.VP12_OPEN_LOOP = 0;                }cHiccup1OffTime = 0;}cHiccup1OnTime = 0;cHiccup1OnFlag = 0;}}
}/******************************************************
name: Process_VN12
brief: process the -12V output
input: none
output: none
*****************************************************/
static void Process_VN12(void)
{//POWER Dispatch. Under/over voltage protection OR output error OR over temperature, we need to deal with them respectively//if((AlarmStatus.allbits & WARNING_FLAG_VN12) == 0)//IN_OK must be set to 1if(AlarmStatus.alarm.IN_OK == 1 && AlarmStatus.alarm.VN12_OPEN_LOOP == 0 && AlarmStatus.alarm.OTP == 0){if(AlarmStatus.alarm.VN12_EN == 1)//only when all the conditions are ready can we turn on the -12V output{VN12_ON();AlarmStatus.alarm.VN12_ON = 1; }else{    VN12_OFF();AlarmStatus.alarm.VN12_ON = 0;}cHiccup2OffTime = 0;cHiccup2OnTime = 0;cHiccup2OnFlag = 0;}else if(AlarmStatus.alarm.VN12_OPEN_LOOP == 1)//OPEN-LOOP hiccup{if(++cHiccup2OffTime>=HICCUP_OFF_TIME)//OFF time{VN12_ON();cHiccup2OffTime = HICCUP_OFF_TIME;cHiccup2OnFlag = 1;}else{VN12_OFF();cHiccup2OnTime = 0;cHiccup2OnFlag = 0;}}else    //other exceptions processed in Task_Manager function{//TODO}/*else//other exceptions, such as OVP, UVP or OTP{//rly_rdy_timeout=0;v12_rdy_timeout=0;cHiccup2OffTime=0;cHiccup2OnTime=0;cHiccup2OnFlag=0;#if(RELAY_ALWAYS_ON == 0){AlarmStatus.alarm.RLY_READY = 0;RELAY_OFF();}#endif//VDC_OK=0;if(AlarmStatus.alarm.IN_OK == 0)//only after the IN_OK is set to 0 can set we turn OFF the -12V{if(++v12_off_timeout>=DELAY_TURN_OFF_TIME){v12_off_timeout = 0;VN12_OFF();}}else//OTHER exception rather than IN_OK error, turn OFF the output directly{VN12_OFF();}AlarmStatus.alarm.VN12_EN = 0;AlarmStatus.alarm.VN12_ON = 0;}*/if(cHiccup2OnFlag == 1)//hiccup{		if(++cHiccup2OnTime>=HICCUP_ON_TIME)//the -12V output is on for 40 milli-seconds{			if(iAd_data[2]>=OP_VN12_OFF_AD)//if it is still in OPEN-LOOP state{cHiccup2OffTime = 0;}else{if(iAd_data[2]<OP_VN12_RECOVER_AD)//recovered, return difference is necessary{AlarmStatus.alarm.VN12_OPEN_LOOP = 0;                }cHiccup2OffTime = 0;}cHiccup2OnTime = 0;cHiccup2OnFlag = 0;}}
}/**
*@name: Task_Manager
*@description: switch all the states according to the power-supply statuse.g. if the VDC is over-voltage, we need to shut off the main outputAt the same time, we turn ON/OFF the signals according to the status
*@params: none
*@return: none
*/
static void Task_Manager(void)
{//===============================================================================//		  ****** DC power-supply, following the DC powered-on sequences ******//          1. DC_OK                        -->START//          2. delay 50ms                   -->RELAY ON//          6. delay 100ms                  -->49V ON       //===============================================================================    if(AlarmStatus.alarm.VDC_UVP == 0 && AlarmStatus.alarm.VDC_OVP == 0){AlarmStatus.alarm.IN_OK = 1;//It is not until the VDC is normal that we set the IN_OK signal to 1.v12_off_timeout = 0;}else{AlarmStatus.alarm.IN_OK = 0;}    #if (RELAY_ALWAYS_ON == 1){if(rly_rdy_timeout++ >= RLY_RDY_TIMEOUT){rly_rdy_timeout = 0;AlarmStatus.alarm.RLY_READY = 1;}}#else//if(AlarmStatus.alarm.IN_OK == 1 && AlarmStatus.alarm.OTP == 0)//delay some time before we open the relayif(AlarmStatus.alarm.IN_OK == 1){        if(rly_rdy_timeout++ >= RLY_RDY_TIMEOUT) //ONLY when the first time the device is powered-on do we need to delay some time to turn ON the relay.{//rly_rdy_timeout=0;rly_rdy_timeout = RLY_RDY_TIMEOUT;AlarmStatus.alarm.RLY_READY = 1;}}else{//rly_rdy_timeout=0;AlarmStatus.alarm.RLY_READY = 0;}      #endifif(AlarmStatus.alarm.RLY_READY == 1)	//prepare to open +12V AND -12V output{if(v12_rdy_timeout++>=V12OUT_RDY_TIMEOUT)//delay 100ms{//The reason why we don't clear variable v12_rdy_timeout is because we turn ON the -12V and +12V directly without any delay once the OTP is recovered.//v12_rdy_timeout=0;v12_rdy_timeout = V12OUT_RDY_TIMEOUT;AlarmStatus.alarm.VP12_EN = 1;AlarmStatus.alarm.VN12_EN = 1;}}else{v12_rdy_timeout = 0;AlarmStatus.alarm.VP12_EN = 0;AlarmStatus.alarm.VN12_EN = 0;}//if(AlarmStatus.alarm.VP12_EN == 1 && AlarmStatus.alarm.VN12_EN == 1)    //ONLY when the +12V or -12V is powered-on can we turn ON the 50V outputif(AlarmStatus.alarm.VP12_EN == 1 || AlarmStatus.alarm.VN12_EN == 1) {            if(v50_rdy_timeout++>=V50OUT_RDY_TIMEOUT)//delay 100ms{v50_rdy_timeout = 0;AlarmStatus.alarm.V50_EN = 1;}}else//the 50V output is not affected by the 12V and -12V{//v50_rdy_timeout = 0;//AlarmStatus.alarm.V50_EN = 0;}if(PV12_OVP == 1)//+12V OVP check{vp12_ovp_H++;}else{vp12_ovp_L++;}if(io_cnt>=IO_FILTER_CNT)//set or clear OVP flag{if(vp12_ovp_H>=IO_FILTER_VALID_CNT){AlarmStatus.alarm.VP12_OVP = 1;}if(vp12_ovp_L>=IO_FILTER_VALID_CNT){AlarmStatus.alarm.VP12_OVP = 0;//no need to clear this bit}vp12_ovp_H = 0;vp12_ovp_L = 0;io_cnt = 0;}else{io_cnt++;}if(AlarmStatus.alarm.VP12_OVP == 1)//ONLY when the OVP flag is set can we start counting{if(ovp1_time_cnt++>=LOCK_TIMEOUT){ovp1_time_cnt = LOCK_TIMEOUT;}}else{ovp1_time_cnt = 0;}if(AlarmStatus.alarm.IN_OK == 1)//VDC error information{IN_OK();}else{IN_NOT_OK();}if(AlarmStatus.alarm.RLY_READY == 1)//power on the relay{RELAY_ON();}else{    RELAY_OFF();        }if(AlarmStatus.alarm.V50_EN == 1)//turn ON the 50V output{V50_ON();}else{V50_OFF();}if(AlarmStatus.alarm.IN_OK == 0 || AlarmStatus.alarm.OTP == 1)//other exceptions, such as OVP, UVP or OTP{//rly_rdy_timeout=0;//open the delay directly from exception without any delayif(AlarmStatus.alarm.IN_OK == 0)//Each time VDC is abnormal, we need to delay some to open the output, including -12V, +12V and 50V{v12_rdy_timeout = 0;}v50_rdy_timeout = 0;cHiccup1OffTime = 0;cHiccup1OnTime = 0;cHiccup1OnFlag = 0;cHiccup2OffTime = 0;cHiccup2OnTime = 0;cHiccup2OnFlag = 0;AlarmStatus.alarm.VP12_EN = 0;AlarmStatus.alarm.VP12_ON = 0;AlarmStatus.alarm.VN12_EN = 0;AlarmStatus.alarm.VN12_ON = 0;AlarmStatus.alarm.V50_EN = 0;VN12_OFF();VP12_OFF();V50_OFF();#if(RELAY_ALWAYS_ON == 0){if(AlarmStatus.alarm.IN_OK == 0)//don't need to turn OFF the relay once OTP flag is set{AlarmStatus.alarm.RLY_READY = 0;RELAY_OFF();}}        #endif/*//VDC_OK=0;if(AlarmStatus.alarm.IN_OK == 0)//only after the IN_OK is set to 0 can set we turn OFF the +12V{if(++v12_off_timeout>=DELAY_TURN_OFF_TIME){v12_off_timeout=0;VN12_OFF();VP12_OFF();}}else//OTHER exception rather than IN_OK error, turn OFF the output directly{VN12_OFF();VP12_OFF();}*/}
}/**
*@name: OVP_Lock_Check
*@description: output over voltage processHere we need to lock the 12V output or delay some time then lock it.
*@params: none
*@return: none
*/
static void OVP_Lock_Check(void)
{#if(LOCK_NO_DELAY == 1)//lock the output immediately once OVP occurs{//if(AlarmStatus.alarm.VP12_OVP == 1 || AlarmStatus.alarm.VN12_OVP == 1)//Once the OVP flag is set, we'll never clear it.if(AlarmStatus.alarm.VP12_OVP == 1){			AlarmStatus.alarm.OUT_LOCKED = 1;}        else{//AlarmStatus.alarm.OUT_LOCKED=0;}}#else{if(ovp1_time_cnt>=LOCK_TIMEOUT || ovp2_time_cnt>=LOCK_TIMEOUT){        AlarmStatus.alarm.OUT_LOCKED=1;}else{AlarmStatus.alarm.OUT_LOCKED=0;}}#endif
}/**
*@name: Process_1MS
*@description: 1 milli-second task polling
*@params: none
*@return: none
*/
void Process_1MS(void)
{if(cFlag_1ms == 0){return;}		cFlag_1ms = 0;Task_Manager();Process_VP12();Process_VN12();
}/* main task */
int main(void)
{Init_OSC();Init_Timer();Init_GPIO();Init_ADC();INTCONbits.PEIE = 1;INTCONbits.GIE = 1;while(1){        ADC_Process();Fault_Check();Process_1MS();OVP_Lock_Check();}return 0;
}

我想请教下各位:关于AD检测,除了累加求和然后再求平均值外,还有没有其他更好的方法?如果AD值在进行了求平均值后还有没有必要再滤波一定的时间再次确定检测结果?原来程序这样做的目的是避免误操作,举个例子,在电压检测时有可能会有尖峰电压而且持续时间很短,如果不做滤波处理可能就会产生误动作。

麻烦大家对我的程序结构提出一些改善意见,特别是可以优化的地方,谢谢了!

查看全文

99%的人还看了

相似问题

猜你感兴趣

版权申明

本文"PIC16F18323电源控制软件":http://eshow365.cn/6-10687-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!