单片机手机电板充电器程序(PWM自动调压)

来源:互联网 发布:squid 端口 编辑:程序博客网 时间:2024/04/24 02:59
 
 /*******************
 C语言运算符优先级 
 
   1级优先级 左结合    
  () 圆括号   [] 下标运算符   -> 指向结构体成员运算符   . 结构体成员运算符      
   
   2级优先级 右结合     
  ! 逻辑非运算符   ~ 按位取反运算符  ++ 自增运算符  -- 自减运算符  - 负号运算符 (类型) 类型转换运算符 * 指针运算符 & 地址与运算符 sizeof 长度运算符
           
   3级优先级 左结合     
  * 乘法运算符   / 除法运算符   % 取余运算符
   
   4级优先级 左结合    
  + 加法运算符   - 减法运算符 
   5级优先级 左结合     
  << 左移运算符   >> 右移运算符 
   6级优先级 左结合    
  <、<=、>、>= 关系运算符 
   7级优先级 左结合    (注意"等于"运算符== ) 
  == 等于运算符   != 不等于运算符 
         
   8级优先级 左结合     
  & 按位与运算符 
   9级优先级 左结合   
  ^ 按位异或运算符 
   10级优先级 左结合  
  | 按位或运算符 
   11级优先级 左结合    
  && 逻辑与运算符 
   
   12级优先级 左结合  
  || 逻辑或运算符    
   
   13级优先级 右结合    
  ? : 条件运算符 
   14级优先级 右结合 (赋值运算符) 
  =+ =- =*   =/ =% =   >= < <=   &= ^= |= 全为赋值运算符 
   15级优先级 左结合  
  , 逗号运算符 
 *******************************/
#include <stc12c2052ad.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define AD_SPEED   0x60 //0110,0000   1      1     270个时钟周期转换一次, 
//少占鱼制作  河北正定欢迎您   长沙航空职业技术学院  2010 年QQ:411656434 
//
sbit M=P1^5; //过压指示灯 
sbit N=P1^6; //欠压指示灯 
sbit LED=P1^7; //充满 指示灯 
sbit  REF=P1^0;
sbit PWM=P3^7;
bit START =0;
uchar timeL=0x90;
uchar timeH=0x90;
/****************************************************************/
void pwm();
void delayms(uint);          
void ADC();
void InitADC();
//void baohu();
float voltage=0.0; 
const float Uref=2.500 ;
/***8**************************************************************/
 void main()
{  
  
 PWM=1;
   delayms(700);
 START=0;
 PWM=0;
 LED=0;
 REF=0;
 delayms(9000);
 delayms(1000);
 M=0;
 N=0;
 LED=0;
  delayms(7000);
 M=1;
 N=1;
   LED=1;
    delayms(7000);
 PWM=1;
    delayms(1000);//延时 
  pwm();
    InitADC();
    delayms(6000);
    START=0;
   while(1)
   {
     ADC();
  if(START)
  {
  pwm();
  delayms(2000);
     }
   }
    
}
//
//
 void pwm()

   CR=0; 
   START=0;
    //PCA模块工作于PWM模式 C程序   
   CMOD = 0x02; //用定时器0溢出做PCA脉冲     
   CL = 0x00; //PCA定时器低8位 地址:E9H    
   CH = 0x00; //PCA高8位 地址 F9H   
   CCON=0x00;
   CCAP0L = timeL; //PWM模式时他俩用来控制占空比   
   CCAP0H = timeH; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   CCAPM0 = 0x42; //0100,0010 Setup PCA module 0 in PWM mode
               // ECOM0=1使能比较 PWM0=1 使能CEX0脚用作脉宽调节输出
/*********************
PCA 模块工作模式设置 (CCAPMn 寄存器 n= 0-3四种)
 7     6        5        4       3       2     1      0
 -   ECOMn   CAPPn     CAPNn   MATn     TOGn   PWMn   ECCFn
选项: 0x00 无此操作
       0x20 16位捕捉模式,由 CEXn上升沿触发
       0x10 16位捕捉模式,由CEXn下降沿触发
       0x30 16位捕捉模式,由CEXn的跳变触发
       0x48 16位软件定时器
       0x4c 16位高速输出
       0x42  8位PWM输出
 每个PCA模块另外还对应两个寄存器:CCAPnH和CCAPnL 。  捕获或者比较时,它们用来
保存16位计数值,当工作于PWM模式时,用来控制占空比    
*******************************/      
   CR=1; //Start PCA Timer.
}

//AD转换初始化 ----打开ADC电源 
void InitADC()
{
P1=0xff;
ADC_CONTR|=0x80;
delayms(3);
//这两个寄存器用来设置 P1口四种状态,每一位对应一个P1引脚 ,按状态组合操作 
/*****************
 P1M0 和P1M1 寄存器位  7      6     5    4     3      2     1     0 
                     P1.7  P1.6  P1.5  P1.4  P1.3  P1.2  P1.1  P1.0 
 同理P3M0  P3M0 也是。因为STC12C2052AD只有两个P口,所以只有这俩组  STC12C5410AD还多P2M0 P1M0 有三组    
  P1M0   P1M1                 高 
    0   0     普通I0口 (准双向)        P1寄存器位  7      6     5    4     3      2     1     0 
 0      1     强推挽输出 (20MA电流 )尽量少用      P1.7  P1.6  P1.5  P1.4  P1.3  P1.2  P1.1  P1.0 
 1  0     仅做输入  A/D转换时可用此模式     
 1      1    开漏 ,A/D转换时可用此模式 
  
  例如: 
  要设置P1.2为 AD 输入口 
  则 P1M0=0X02 ;
     P1M1=0X02;   开漏即可 
  当不用AD时,最好 关闭ADC电源 ,恢复为IO口状态 
********************************/
P1M0=0x06;//这两个寄存器用来设置 P1口四种状态,每一位对应一个P1引脚 ,按状态组合操作 
P1M1=0x06;//设置P1.1 P1.2开漏状态 
 }
 
// AD转换程序 
void  ADC() 

    float V0,V1;
    ADC_DATA   = 0; //清除结果 
    ADC_CONTR = 0x60;      //转换速度设置  0x60  最快速度 
    ADC_CONTR = 0xE0;               //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位 
   ADC_CONTR =0xe1;
  //  ADC_CONTR |= 0x01;           //选择 A/D 当前通道   P1.1 
    delayms(1);                       //使输入电压达到稳定 
   ADC_CONTR = 0xe9;
   // ADC_CONTR |= 0x08;              //0000,1000 令 ADCS = 1, 启动A/D转换,  
    while(!(ADC_CONTR & 0x10)); //!的优先级比&高太多了  
   //养成经常加括号的习惯 ,没坏处 。也不浪费速度 
 /***************
 这里while 不能改成while(ADC_CONTR & 0x10==0) ;就错误了,因为优先级 ==比&高 ,所以要加括号 
  while( (ADC_CONTR & 0x10)  ==0)    或者非一下  while(!(ADC_CONTR & 0x10)); //!的优先级比&高太多了  
    ******************************/
 ADC_CONTR =0xe1;
    //ADC_CONTR &= 0xE7;     //1111,0111 清 ADC_FLAG 位, 关闭A/D转换,  
    V0=  ADC_DATA; //返回 A/D 10 位转换结果 
    ADC_DATA   = 0; //清除结果 
    ADC_CONTR = 0x60;      //转换速度设置  0x60  最快速度 
    ADC_CONTR = 0xE0;               //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位 
   ADC_CONTR =0xe2;
   //  ADC_CONTR |= 0x01;           //选择 A/D 当前通道   P1.2 
    delayms(1);                       //使输入电压达到稳定 
    ADC_CONTR = 0xea;
   // ADC_CONTR |= 0x08;              //0000,1000 令 ADCS = 1, 启动A/D转换,  
    while(!(ADC_CONTR & 0x10)); //!的优先级比&高太多了  
   //养成经常加括号的习惯 ,没坏处 。也不浪费速度 
 ADC_CONTR =0xe2;
    //ADC_CONTR &= 0xE7;     //1111,0111 清 ADC_FLAG 位, 关闭A/D转换,  
 V1=  ADC_DATA; //返回 A/D 10 位转换结果 
 voltage=V1/V0*Uref*3.000;
   
   if( voltage>4.180)
    {
     M=0;//过压灯 
     N=1;
     LED=1;
 timeL=timeL+0x08;
 timeH=timeH+0x08;
 START=1;
 LED=0;
    }
   if(voltage<3.601)
    { 
    N=0;//欠压灯 
 M=1;
 LED=1;
 timeL=timeL-0x01;
 timeH=timeH-0x01;
 START=1;
    }
 if(voltage>=3.601&&voltage<=4.155)
 {
  M=1;
  N=1;
  LED=1;
 }  
 
    if(voltage>=4.110&&voltage<=4.155)
   {
    timeL = 0xa2; //PWM模式时他俩用来控制占空比
    timeH = 0xa2; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出) 
    START=1;
 LED=0;
    }
     if(voltage>=4.155&&voltage<=4.180)
   {
    timeL = 0xb2; //PWM模式时他俩用来控制占空比
    timeH = 0xb2; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出) 
    START=1;
 LED=0;
    }
  /**************************
     if( voltage<3.772&&(timeL!=0xf0))
    {
   timeL = 0xf0; //PWM模式时他俩用来控制占空比
   timeH = 0xf0; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
    }
   if( voltage<4.052&&voltage>3.772&&(timeL!=0xf2))
    {
   timeL = 0xf2; //PWM模式时他俩用来控制占空比
   timeH = 0xf2; //0xc0 64/256=25% 占空比(溢出) 高电平时间     
   START=1;
     M=1;
  N=1;
  LED=1;
    }
  
   if( voltage>4.052&&voltage<4.167&&(timeL!=0xfd))
    {
   timeL = 0xfd; //PWM模式时他俩用来控制占空比
   timeH = 0xfd; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
     M=1;
  N=1;
  LED=1;
    }
    if( voltage>4.167&&voltage<4.208&&(timeL!=0x60))
   {
   timeL = 0x80; //PWM模式时他俩用来控制占空比
   timeH = 0x80; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
     M=1;
  N=1;
  LED=1;
    }
   if(voltage>4.2050&&voltage<4.235)
   {
    timeL = 0x96; //PWM模式时他俩用来控制占空比
    timeH = 0x96; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出) 
    START=1;
 LED=0;
    }
   ****************************************************/
 


 /**********
// 保护函数 
   void baohu()
   {
   
      if( voltage>4.231)
    {
     M=0;//过压灯 
     N=1;
     LED=1;
    }
   if(voltage<3.501)
    { 
    N=0;//欠压灯 
 M=1;
 LED=1;
    }
     if( voltage<3.772&&(timeL!=0xcf))
    {
   timeL = 0xcf; //PWM模式时他俩用来控制占空比
   timeH = 0xcf; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
    }
   if( voltage<4.052&&voltage>3.772&&(timeL!=0x60))
    {
   timeL = 0x60; //PWM模式时他俩用来控制占空比
   timeH = 0x60; //0xc0 64/256=25% 占空比(溢出) 高电平时间     
   START=1;
    }
  
   if( voltage>4.052&&voltage<4.167&&(timeL!=0xb0))
    {
   timeL = 0xb0; //PWM模式时他俩用来控制占空比
   timeH = 0xb0; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
    }
   if( voltage>4.167&&voltage<4.218&&(timeL!=0xe0))
   {
   timeL = 0xe0; //PWM模式时他俩用来控制占空比
   timeH = 0xe0; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出)     
   START=1;
    }
   if(voltage>4.220&&(timeL!=0xf2))
   {
    timeL = 0xf2; //PWM模式时他俩用来控制占空比
    timeH = 0xf2; //0xff-0xc0=0x3f  64/256=25% 占空比(溢出) 
    START=1;
 LED=0;
    }
 

 }
***************************/
//延时函数 
void delayms(uint k)
{
uint data i,j;
for(i=0;i<k;i++)
  {
    for(j=0;j<600;j++)
     {;}
   }
}