📄 capacitor.c
字号:
d++;
break;
case 15:
dispbuf[d]=32;
d++;
break;
}
}
}
//将存储显示代码的数组dispbuf[4]清空,即不显示任何数字
void clrdisp (void)
{
dispbuf[0]=48;
dispbuf[1]=48;
dispbuf[2]=48;
dispbuf[3]=48;
dispbuf[4]=48;
}
//从EEPROM中读取comp1和comp2
void loadeep(void)
{
int i;
comp1l=readeep(1);
comp1h=readeep(2);
comp2l=readeep(3);
comp2h=readeep(4);
i=readeep(5);
if(i!=0) //本句是检查comp1,comp2是否存取错误,一般没有用
{
}
comp1=(comp1h<<8)+comp1l;
comp2=(comp2h<<8)+comp2l;
}
//往EEPROM中写入comp1和comp2
void saveeep(void)
{
// int i=1;
comp1l=((long int)comp1)%256;
comp1h=((long int)comp1)/256;
comp2l=((long int)comp2)%256;
comp2h=((long int)comp2)/256;
writeeep(1,comp1l);
writeeep(2,comp1h);
writeeep(3,comp2l);
writeeep(4,comp2h);
writeeep(5,0);
}
//写入一个数字
void writeeep(int adress,int data)
{
while(EECR & BIT(1)) //如果写操作没有完成,就等待
{}
EEAR=adress;
EEDR=data;
asm("cli");
EECR |= BIT(2); //这两个控制字是使能写操作
EECR |= BIT(1);
asm("sei");
}
//读出一个数值
int readeep(int adress)
{
while(EECR & BIT(1)) //如果写操作没有完成,就等待
{}
EEAR=adress;
EECR|=BIT(1); //使能读操作
return EEDR;
}
//检测按钮是否按下,为了防止噪声脉冲的影响,需要在连续的两次调用此函数时都判断按钮被按下时才将按钮按下标志置1,这通过//keyscan数组实现,开始两位为0,0,第一次检测到按钮被按下后变成0,1,第二次检测到按钮被按下时变成1,1,这时才将按钮按下标志//置1,如果检测到按钮被松开,就在经过两次调用此函数后,又变成0,0;
void scankey(void)
{
ADCSRA |= 0x40;
temp = AD_Receive();
// if(temp>200)
if(11<temp && temp<33)
{
if((keyscan[0][0]==0)&&(keyscan[0][1]==0))
{
keyscan[0][1]=1;
}
else if((keyscan[0][0]==0)&&(keyscan[0][1]==1))
{
keyscan[0][0]=1;
keydown=1;
}
else if((keyscan[0][0]==1)&&(keyscan[0][1]==1))
{
keydown=1;
}
}
//else if(temp<10)
else if(temp<11)
{
if((keyscan[0][0]==0)&&(keyscan[0][1]==0))
{
}
else if((keyscan[0][0]==1)&&(keyscan[0][1]==0))
{
keyscan[0][0]=0;
}
else if((keyscan[0][0]==1)&&(keyscan[0][1]==1))
{
keyscan[0][1]=0;
}
else if((keyscan[0][0]==0)&&(keyscan[0][1]==1))
{
keyscan[0][1]=0;
}
if((keyscan[1][0]==0)&&(keyscan[1][1]==0))
{
}
else if((keyscan[1][0]==1)&&(keyscan[1][1]==0))
{
keyscan[1][0]=0;
}
else if((keyscan[1][0]==1)&&(keyscan[1][1]==1))
{
keyscan[1][1]=0;
}
else
{
keyscan[1][1]=0;
}
}
else if(temp>33&&temp<55)
{
if((keyscan[1][0]==0)&&(keyscan[1][1]==0))
{
keyscan[1][1]=1;
}
else if((keyscan[1][0]==0)&&(keyscan[1][1]==1))
{
keyscan[1][0]=1;
keydown=2;
}
else if((keyscan[1][0]==1)&&(keyscan[1][1]==1))
{
keydown=2;
}
}
if(stm1!=0) //如果stm1不为0,就减1
{
stm1--;
}
if(stm2!=0) //如果stm2不为0,就减1
{
stm2--;
}
}
void port_init(void)
{
/* PORTA = 0x00;
DDRA = 0xFC;
PORTB = 0x71;
DDRB = 0x87;
PORTC = 0x00; //m103 output only
DDRC = 0x83;
PORTD = 0x00;
DDRD = 0x9C;*/
PORTA = 0x00;
DDRA = 0x00;
PORTB = 0x00;
DDRB = 0x07;
PORTC = 0x02; //m103 output only
DDRC = 0xc2;
PORTD = 0x00;
DDRD = 0x80;
}
//TIMER0 initialize - prescale:256
// WGM: Normal
// desired value: 39KHz
// actual value: 39.063KHz (0.2%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x00; //set count
OCR0 = 0x01; //set compare
TCCR0 = 0x04; //start timer
}
//tc0溢出中断主要是为了不断的刷新显示4个数码管,检查按钮是否按下
//#pragma interrupt_handler timer0_ovf_isr:12
#pragma vector=TIMER0_OVF_vect
__interrupt void timer0_ovf_isr(void)
{
TCNT0 = 256-39; //reload counter value则TC0只需要加39次就进行一次溢出中断
if(dispptr<=3) //由于是4个数码管显示,所以如果没有显示完一遍,就继续显示
{
code=dispbuf[dispptr]; //code中存储着将要显示的代码,dispptr中存放着将在第几个数码管上显示
dispptr++; //dispptr+1,是为下一个数码管显示做准备
asm("sei");
}
else
{
scankey(); //每4次tc0溢出中断才调用一次检测按钮是否按下的函数
dispptr=0; //将dispptr清零,为四个数码管的下一轮显示做准备
code=dispbuf[0]; //code中存储着将要显示的代码,dispptr中存放着将在第几个数码管上显示
asm("sei");
}
}
//TIMER1 initialize - prescale:1
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 10MHz
// actual value: 10.000MHz (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x00; //setup
TCNT1L = 0x00;
OCR1AH = 0x00;
OCR1AL = 0x01;
OCR1BH = 0x00;
OCR1BL = 0x01;
ICR1H = 0x00;
ICR1L = 0x01;
TCCR1A = 0x00;
TCCR1B = 0x00; //start Timer
}
//tc1捕捉中断是在电容电压和比较电压相同的时候调用,每次对电容测量时要调用此中断两次,0.17Vcc,0.5Vcc时各一次
//#pragma interrupt_handler timer1_capt_isr:7
#pragma vector=TIMER1_CAPT_vect
__interrupt void timer1_capt_isr(void)
{
//timer 1 input capture event, read (int)value in ICR1 using;
// value=ICR1L; //Read low byte first (important)
// value|=(int)ICR1H << 8; //Read high byte and shift into top byte
int i;
if((DDRB&0x02)!=0) //如果DDRB的第0位为输出,表明比较电压为0.17Vcc,计数开始了
{
a=ICR1L;
b=ICR1H;
count1a=b*256+a;
count2a=ntc1ovf;
DDRB=DDRB&0xfd; //将DDRB的第0位设置成输入,比较电压就变成了0.5Vcc
resulta=count2a*65536+count1a;
for(i=20;i>0;i--)
{
}
TIFR=0x20; //输入捕捉中断标志位置1
asm("sei");
}
else if((DDRB&0x02)==0) //如果DDRB的第0位为输入,表明比较电压为0.5Vcc,计数结束
{
a=ICR1L;
b=ICR1H;
count1b=b*256+a;
count2b=ntc1ovf;
resultb=count2b*65536+count1b;
count1=count1b-count1a;
count2=count2b-count2a;
result=resultb-resulta; //0.5Vcc时刻的计数值减去0.17Vcc时刻的计数值,就是充电时的计数值,用此数据衡量电容的大小
DDRB=DDRB|0x06; //恢复初始设置
TIMSK=0x01;
flags=flags|0x02; //将第一位置1,表明测量成功
asm("sei");
}
}
//这个函数主要记录充电过程中tc1溢出多少次,溢出次数×65536+tc1当前的计数值就是充电时间
//#pragma interrupt_handler timer1_ovf_isr:10
#pragma vector=TIMER1_OVF_vect
__interrupt void timer1_ovf_isr(void)
{
//TIMER1 has overflowed
TCNT1H = 0x00; //reload counter high value
TCNT1L = 0x00; //reload counter low value
ntc1ovf++; //这个变量记录着tc1溢出的次数
if (ntc1ovf>=maxtc1ovf) //如果溢出次数大于设定的溢出次数的上限,说明测量时间超时,测量失败了
{
DDRB=DDRB|0x06; //恢复初始设置
flags=flags|0x04; //将测量时间超时标志置1,测量失败
TIMSK=0x01; //tc0溢出中断使能
}
asm("sei");
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
asm("cli"); //disable all interrupts
port_init();
timer0_init();
timer1_init();
adc_init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x01; //timer interrupt sources
asm("sei"); //re-enable interrupts
//all peripherals are now initialized
}
//
void main(void)
{
int k=0;
init_devices(); //调用函数,对端口,计时器等进行初始设置
//insert your functional code here...
ACSR=ACSR|0x04; //模拟比较器输入捕捉使能
flags=0;
asm("sei");
dispbuf[0]=56; //开机的时候显示8.8.8.8.
dispbuf[1]=56;
dispbuf[2]=56;
dispbuf[3]=56;
dispbuf[4]=56;
mn();
lcd_display2();
dly(125);
loadeep(); //从EEPROM中读取低量程校准值,高量程校准值
if((comp1==0)&&(comp2==0)) //如果读出的都是0xFFFF,表明还没有进行校准过
{
for (k=0;k<=3;k++) //显示E4
{
pdispbuf[k]=form3[k];
}
putformd();
mn();
lcd_display2();
dly(250);
}
while(1)
{
while (((comp1==0)&(keydown!=0))||((comp2==0)&(keydown!=0))) // 应该是while (((comp1&comp2)==0xFFFF)|(comp3==0)),但由于comp3即零偏值通常都是0, //暂且改一下,即如果没有进行校准过,就进行校准程序
{
btnpressed(); //在这个函数中进行各种校准
flags=flags&0x7f; //将按钮按下标志置0
}
stm2=25; //给stm2赋值是为了设置一个时限,用来检查在这个时限里,小电流是否能把电容充满
measure();
if((flags&0x04)!=0) //如果测量结束后,stm2已经变成了0,表明在这个时限里,小电流没有完成充电任务
{
//改动 PORTB=PORTB&0b11111110; //将PB1输出低电平,即采用大电流对电容进行充电
PORTC=PORTC&0xfd;
measure(); //再进行充电测量
}
// adjustzero();
adjustgain(); //对计数值进行处理,转换成与实际电容值对应的数字
dispval(result); //将电容值显示出来
//改动 PORTB=PORTB|0b00000001; //将PB1输出低电平,为下一次测量电容值做准备
PORTC=PORTC|0x02;
mn();
lcd_display2();
dly(250);
}
}
void mn(void)
{
lcd_display_wrp=&lcd_display2_buffer[3][7];
*lcd_display_wrp=dispbuf[0];
lcd_display_wrp++;
*lcd_display_wrp=dispbuf[1];
lcd_display_wrp++;
*lcd_display_wrp=dispbuf[2];
lcd_display_wrp++;
*lcd_display_wrp=dispbuf[3];
lcd_display_wrp++;
if(dispbuf[0]!=46&&dispbuf[1]!=46&&dispbuf[2]!=46&&dispbuf[3]!=46)
*lcd_display_wrp=32;
else
{
*lcd_display_wrp=dispbuf[4];
lcd_display_wrp++;
}
lcd_display_wrp=&lcd_display2_buffer[0][0];
lcd_display_rdp=&lcd_display2_buffer[0][0];
}
int AD_Receive( void )
{
while ( (ADCSRA & BIT(6)) );
return ADCH;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -