📄 main.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 + -