⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 采用MEGA16作为主芯片
💻 C
字号:
//ICC-AVR application builder : 2006-3-21 0:22:17
// Target : M16
// Crystal: 8.0000Mhz

#include <iom16v.h>
#include <macros.h>

#define Uchar unsigned char
#define Uint unsigned int
#define Ulong unsigned long

#define nop() asm("nop")
#define _nop_() asm("nop")


#define PA PORTA
#define PB PORTB
#define PC PORTC
#define PD PORTD
 
#define RSH PD|=0x01
#define RSL PD&=~0x01

#define RWH PD|=0x02
#define RWL PD&=~0x02

#define ENH PD|=0x04
#define ENL PD&=~0x04

#define DataPort PC
#define DataPortDRN DDRC
#define DataPortIN PINC
#define Busy    0x80

#define LED1H PB|=0x01
#define LED1L PB&=~0x01

#define LED2H PB|=0x02
#define LED2L PB&=~0x02

#define BUZZL PB|=0x04
#define BUZZH PB&=~0x04

#define SW1 (!(PIND&0x40))
#define SW2 (!(PIND&0x80))
#define STOP_PWM TCCR1A = 0x00;TCCR1B = 0x00;PD&=~0x20

#define START_PWM timer1_init();


void port_init(void)//端口初始化
{
 PORTA = 0x00;
 DDRA  = 0x00;
 PORTB = 0x00;
 DDRB  = 0x07;
 PORTC = 0x00; //m103 output only
 DDRC  = 0xFF;
 PORTD = 0xc0;
 DDRD  = 0x3F;
 
 BUZZL;
}


void adc_init(void)//ADC初始化
{
 ADCSR = 0x00; //disable adc
 ADMUX = 0x00; //select adc input 0
 ACSR  = 0x80;
 ADCSR = 0x87;
}

void timer1_init(void)//定时器PWM模式初始化
{
 TCCR1B = 0x00; //stop
 TCNT1H = 0x00 /*INVALID SETTING*/; //setup
 TCNT1L = 0x00 /*INVALID SETTING*/;
 OCR1A = 2 /*INVALID SETTING*/;

 OCR1BH = 0x00 /*INVALID SETTING*/;
 OCR1BL = 0x00 /*INVALID SETTING*/;
 ICR1  = 800 /*INVALID SETTING*/;
 
 TCCR1A = 0x82;
 TCCR1B = 0x19; //start Timer
}
//call this routine to initialize all peripherals
void init_devices(void)//芯片初始化
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 adc_init();
 timer1_init();
 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x00; //timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}


Uint ReadADC (Uchar channel)//读ADC
{
Uint int1,int2;
ADMUX&=~0x1F;
ADMUX|=channel;
ADCSRA|=0x40;
while(~ADCSRA&0x10);
int2=ADCL;
int1=ADCH;
int1<<=8;
return (int1+int2);//*(channel+1)
}




void Delay (Uint time)//延迟
{
while(time)
{
time--;
}
}

void Wcommand ( Uchar CMD,Uchar firststart )//写指令
{
if (firststart) Waitok();
RSL;ENL;RWL;nop();
DataPort=CMD;nop();nop();
ENH;nop();nop();nop();nop();
ENL;
}

void Wdata( char dataW )//写数据
{      
Waitok ();
RSH;RWL;ENL;nop();
DataPort=dataW;nop();nop();
ENH;nop();nop();nop();nop();
ENL;
}


void Waitok ( void ) //等待液晶忙碌
{Uchar dat=0;
DataPort=0x00;
DataPortDRN=0;
RSL; RWH; ENH; _nop_();
while( DataPortIN & Busy );
ENL;
DataPortDRN=0xff;
}

void Reset( void )//液晶初始化
{
  
   Wcommand( 0x38,0);
    Delay(6000);
   Wcommand( 0x38,0);
    Delay(6000);
   Wcommand( 0x38,0);
    Delay(6000);
	Wcommand( 0x38,1); 
	Wcommand( 0x38,1);                   
    Wcommand( 0x08,1);
    Wcommand( 0x01,1);                
    Wcommand( 0x06,1);
    Wcommand( 0x0c,1);  
	 
}


void Disp_XY( char posx,char posy) //设定液晶坐标
{
Uchar temp;

    temp = posx & 0xf;
    posy &= 0x1;
    if ( posy )temp |= 0x40;
    temp |= 0x80;
    Wcommand(temp,1);
}

void DispOneChar(Uchar x,Uchar y,Uchar dat)//显示一个字符
{
    Disp_XY( x, y );                
    Wdata( dat);            
}

void DispNChar(Uchar x,Uchar y,const Uchar *ptr)//显示字符串
{
     Uchar i;
     Wcommand(0x06,1);
     DispOneChar(x,y,ptr[0]);
     for(i=1;ptr[i]!=0;i++)
     {  
      Wdata(ptr[i]);    
     };
}

void DispNum(Uchar x,Uchar y,Uchar num)//显示一个数字
{
    Uchar number[]={0,0,0};
     Uchar a, i;
     a=num/100; num=num-a*100;
     number[0]=a+48;
     a=num/10; num=num-a*10;
     number[1]=a+48;     
     number[2]=num+48;  
     Wcommand(0x06,1);
     DispOneChar(x,y,number[0]);
     for(i=1;i<=2;i++)
     {  
      Wdata(number[i]);    
     };
}




void DispVotage(Uchar x,Uchar y,Ulong num)//显示电压,12345为12.35V
{
Uchar number[6]={0},offset=0;
Ulong a;
Uchar test;
test=num%10;
if(test>=5)num+=10;
     a=num/10000; num=num-10000*a;
     number[0]=a+48;
	  DispOneChar(x+0,y,number[0]);  
	 //else  {offset=9;DispOneChar(x+47-offset,y,' ');};
     a=num/1000; num=num-1000*a;
     number[1]=a+48;
	 a=num/100; num=num-100*a;
     number[2]=a+48;
	 a=num/10; num=num-10*a;
     number[3]=a+48; 
Wdata(number[1]);
Wdata('.'); 
Wdata(number[2]);
Wdata(number[3]);
Wdata('V');
}

void DispCurrent(Uchar x,Uchar y,Uint num)//显示电流,100显示0.1A
{
    Uchar number[]={0,'.',0,0,0};

     Uchar a, i;

     a=num/100; num=num-a*100;
     number[0]=a+48;
     a=num/10; num=num-a*10;
     number[2]=a+48;     
     number[3]=num+48;  
     Wcommand(0x06,1);
     DispOneChar(x,y,number[0]);
     for(i=1;i<=3;i++)
     {  
      Wdata(number[i]);    
     };
	 
Wdata('A');
}



const Uchar cur_str[][7]={"0.1A ","0.2A ","0.3A","0.4A"};



main()
{
Uchar start=0;
Uchar a;
Uchar k1=0,k2=0;//按键自锁
Uchar mode=0;//电流选择
Uchar error=0;//过热标志
Uchar stage=0;//充电阶段
Uint buzcon=0;//蜂鸣器定时
Uchar buzzmod=0;
Uchar cur_sel=0;
Uint cur_set=0;//电流大小标定
Uint cur=0;//当前电流
Uint vot=0;//当前电压
Uint P=0;//PWM参数
Uchar ref=0;//屏幕刷新调节
Uint tem=0;//温度
init_devices();

Reset();

while(1)
{

if(start)//开始充电循环
{


DispVotage(0,0,vot);//电压显示
if(error){DispNChar(8,0,"Warning");LED1H;}//过热显示
else
{
if(stage)
DispNChar(8,0,"Running");
else
DispNChar(8,0,"Charging");
}


//DispNChar(0,1,&cur_str[mode][0]);

ref++;
if(ref>80)
{
ref=0;
DispCurrent(0,1,cur/5);//刷新电流显示
}


LED2H;

switch(mode)//选择充电电流参数,改变参数可以调节充电电流
{
case 0:cur_set=50;
break;
case 1:cur_set=100;
break;
case 2:cur_set=150;
break;
case 3:cur_set=200;


}

vot=(ReadADC(0)+ReadADC(0)+ReadADC(0)+ReadADC(0)+ReadADC(0)+ReadADC(0))/1.2276;//采样电压,VOT为整形变量,为实际电压的一千倍
if(vot>4500)if(P>2)P-=2;//过电压减小PWM
cur=ReadADC(1);//电流采样
tem=ReadADC(2);//温度采样

switch(stage)//充电阶段
{
case 0:break;//不充电
case 1://恒流模式
if(cur<cur_set){if(P<700)P++;}
else {if(P>1)P--;}
if(vot>=4200)stage=2;//切换状态到恒压

break;
case 2://恒压模式
if(vot<4200){if(P<700)P++;}//恒压PWM调节
else {if(P>1)P--;}
if(cur<30)//等待电流下降到指定数值后停止充电,当前为30*2=60毫安
{
stage=0;
buzzmod=2;
}

}

if(tem<115){error=1;buzzmod=2;stage=3;P=0;}//过热保护,我现在设定的是115,用火机一烤就可以报警,温度越高数值越小,


switch(stage)//各个阶段状态显示
{
case 0:DispNChar(8,1,"VOER  ");STOP_PWM;//停止PWM,充电结束
break;
case 1:DispNChar(8,1,"stage1");//横流阶段
break;
case 2:DispNChar(8,1,"stage2");//恒压阶段
break;
case 3:DispNChar(8,1,"STOP  ");STOP_PWM;//意外结束充电
}





}

else//充电等待界面
{
DispNChar(0,0,"Ready to start");//欢迎界面
DispNChar(0,1,"Currrent");
DispNChar(9,1,&cur_str[mode][0]);//显示设定电流菜单
LED2L;
P=0;//初始化PWM
stage=0;//初始化阶段0

if(SW2)//电流选择按钮程序
{
if(!k2)
{
buzzmod=1;
k2=1;
mode++;
if(mode>=4)mode=0;
}
}
else
{
k2=0;
}

error=0;

LED1L;
STOP_PWM;
}
OCR1A=P;


////////////////////////
if(SW1)//开始充电按钮程序
{
if(!k1)
{
buzzmod=1;
k1=1;
stage=start=!start;
if(start)START_PWM;
DispNChar(0,0,"                ");//刷新屏幕垃圾
DispNChar(0,1,"                ");
}
}
else
{
k1=0;
}
//////////////////////////




/////////////////////////喇叭控制代码,0关闭 ,1响一下, 3长响
buzcon++;
switch(buzzmod)
{
case 0:buzcon=0;
BUZZL;
break;
case 1:
if(buzcon>100)buzzmod=0;
BUZZH;

break;
case 2:
BUZZH;
break;

}




}


}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -