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

📄 capacitor.c

📁 avr 单片机用来测量电容的程序 需要配合实际电路 用的捕获时间方法
💻 C
📖 第 1 页 / 共 3 页
字号:
		}
	    if ((lcd_asc<0x20)||(lcd_asc>=0x80))
	    {
		    lcd_asc=0x20;
	   	}
	    lcd_asc=lcd_asc-0x20;
	    for (lcd_asc_column=0;lcd_asc_column<=0x03;lcd_asc_column++)	  //显示的5列的循环
	    {
	        asc_rdp=&asc[lcd_asc][lcd_asc_column];		  //取出当前字符的每列内容
		 	lcd_buffer1=*asc_rdp;						  //要写入lcd的数据放入lcd_buffer1中
	     	if(lcd_invter&BIT(0))
			{
				lcd_buffer1=~lcd_buffer1;
			}
			lcd_wr1_data(lcd_buffer1);			  			
	   	}
	    asc_rdp=&asc[lcd_asc][lcd_asc_column];		  	  //取出当前字符的每列内容
	    lcd_buffer1=*asc_rdp;						  	  //要写入lcd的数据放入lcd_buffer1中
	    if(lcd_invter&BIT(0))
		{
			lcd_buffer1=~lcd_buffer1;
		}
	    lcd_wr2_data(lcd_buffer1);
	    if(lcd_invter&BIT(0))
		{
			 lcd_wr2_data(0xff);
		}
	    else
	    {
			lcd_wr2_data(0x00);
		}	
	    for (lcd_column_counter=11;lcd_column_counter<=20;lcd_column_counter++)  //显示的0~20列循环计数(cs2为11~20列)
	   	{
	  	    lcd_asc=*lcd_display_rdp;					          //要显示的字符ASC码放在lcd_asc中	

	
		    lcd_display_rdp++;
			if (lcd_asc&BIT(7))
			{
				lcd_invter|=BIT(0);
				lcd_asc&=(~BIT(7));
			}
			else
			{
			    lcd_invter&=(~BIT(0));
			}
		    if ((lcd_asc<0x20)||(lcd_asc>=0x80))
		    {
		        lcd_asc=0x20;
		    }
		    lcd_asc=lcd_asc-0x20;
		    for (lcd_asc_column=0;lcd_asc_column<=0x04;lcd_asc_column++)	  //显示的5列的循环
		    {
		        asc_rdp=&asc[lcd_asc][lcd_asc_column];		  //取出当前字符的每列内容
		        lcd_buffer1=*asc_rdp;						  //要写入lcd的数据放入lcd_buffer1中
	            if(lcd_invter&BIT(0))
				{
					lcd_buffer1=~lcd_buffer1;
				}
				lcd_wr2_data(lcd_buffer1);			  			
		    }
			if(lcd_invter&BIT(0))
			{
				lcd_wr2_data(0xff);
			}
			else
			{
				lcd_wr2_data(0x00);
			}
	    }
	    lcd_wr2_data(0x00);
	    lcd_wr2_data(0x00);
    }
    lcd_wr1_ins(0x3f);	  				  		 //lcd模块1显示
    lcd_wr2_ins(0x3f);	  				  		 //lcd模块2显示
}


//这是按钮按下后调用的函数,主要功能是进行高量程和低量程校准,并把校准值存到EEPROM
void btnpressed(void)
{
 dly(4);
 if(keydown==1)           //PA3口输入低电平,是进行低量程校准的标志
 {
  callow();                   //进行低量程校准
  keydown=0;
  mn();
  lcd_display2();
 }
 if(keydown==2)           //PA1口输入低电平,是进行高量程校准的标志
 {
  calhigh();                  //进行高量程校准
  keydown=0;
//  canoffset();               //进行零偏值校准,但在程序中常常没有意义,暂时将这一句撤销
   mn();
   lcd_display2();
 }
 if(comp1!=0||comp2!=0)
  {
      saveeep();
  }

}


//高量程校准,主要功能是用大电流对标准大电容进行充电,然后通过一个式子算出高量程校准增益comp2,存入EEPROM
void calhigh(void)
{
 jianche=1;                      //jianche置1,是进行高量程校准的标志
//改动 PORTB=PORTB&0b11111110;
 PORTC=PORTC & 0xfd;
 measure();                      //对标准大电容进行测量
// calcomp(10060);                  //计算高量程校准值,参数8200需要根据实际的标准电容进行改变
 calcomp(10000);
//改动 PORTB=PORTB|0b00000001;
 PORTC=PORTC|0x02;
}				


//低量程校准,主要功能是用小电流对标准小电容进行充电,然后通过一个式子算出高量程校准增益comp1,存入EEPROM
void callow(void)
{
 jianche=0;                     //jianche置0,是进行低量程校准的标志
 measure();                     //对标准小电容进行测量
// calcomp(10720);                 //计算低量程校准值,参数8800需要根据实际的标准电容进行改变
 calcomp(10000);
}				  				


//计算增益
void calcomp(long  int i)
{
  if(result==0)                 //4.16改正
  {
      calerr();
      return;
  }
  else
  {
//   if(i==10720)                   //判断是否是低量程校准
 if(jianche==0)
 {
  asm("cli");
  comp1=1000000;         //计算低量程校准增益,里面的1000可以改动,只要与void adjustgain(void)中的相同就可以了
  comp1=comp1/result;
  asm("sei");
 }
// else if(i==10060)              //判断是否为高量程校准
 else if(jianche==1)
 {

  asm("cli");
  comp2=10000000;        //计算高量程校准增益,里面的10000可以改动,只要与void adjustgain(void)中的相同就可以了
  comp2=comp2/result;
  asm("sei");
 }
 else
 {
  calerr();                    //显示失败信号E5
 }

 adjustgain();                 //这两句时自己加的,目的是显示出标准大电容和标准小电容的电容值,没有这两句也可以
 dispval(result);
 jianche=0;

 }
}

//调0偏移,这个函数基本不起作用,因为测量出来的comp3通常都是0
void canoffset(void)
{
 measure();
 if (count2!=0)
 {
  calerr();
 }
 if(count2>=0x70)
 {
  calerr();
 }
 comp3=count1;
 clrdisp();
}


//显示E5,这个是在测量出现错误的时候调用
void calerr(void)
{
 int k=0;
 for(k=0;k<=3;k++)
  {
   pdispbuf[k]=form4[k];   //向pdispbuf数组里存入14,5,15,15四个数字,这四个数字是E5代码在SEG7内的偏移量
  }
  putformd();              //将E5显示出来
  dly(250);                //延时一段时间
}


//延时i*4 ms
void dly(int i)
{
 stm1=i;
 while(stm1)
 {
 }
}


//电容值的测量过程,首先通过PB1输出高电平还是低电平进行判断是大电流充电还是小电流充电,并设置相应的tc1溢出次数上限,然后启动计时器进行计数,如果在响应的溢出次数上限内成功的测量电容大小,就将flags第三位置0,如果超时,就置1
void measure(void)
{
 result=0;                      //4.16修改
 TCNT1H=0;                      //TCNT1是负责计数充电时间的,首先清空
 TCNT1L=0;
 ntc1ovf=0;                     //ntc1ouf是记录tc1溢出次数的变量
//改动 if((PORTB&0b00000001)==0)      //判断PB1是否为0,若为0,表明是高量程测量
 if((PORTC&0x02)==0)
 {
  maxtc1ovf=110;                //maxtc1ovf存储着tc1最多可以溢出几次,也就是说,它决定着测量范围的上限,大电流充电时,最多可                                //以溢出152次
 }
 else
 {
  maxtc1ovf=9;                 //如果是小电流充电,则最多可以溢出20次

 }
 DDRB=DDRB|0x04;          //????这一句话是自己加的,目的是电容在每次测量时都进行一段时间的放电
 for(mm1=300000;mm1>0;mm1--)      //????这一句话是自己加的,目的是电容在每次测量时都进行一段时间的放电
 {
 }                             //????这一句话是自己加的,目的是电容在每次测量时都进行一段时间的放电
 TIFR=0x24;               //tc1输入捕捉标志和tc1溢出中断标志置1
 TIMSK=0x25;              //tc0溢出中断使能,tc1输入捕捉中断使能,tc1溢出中断使能
 flags=flags&0xf8;        //将负数标志,测量完成标志和测量时间超时标志都置0
 TCCR1B=0x41;             //tc1的计数值在ICP1为上升沿的时候出发输入捕捉,同时选择tc1时钟频率是CLK/1,即10M HZ.

 DDRB=DDRB&0xfb;          //将PB2的方向改为输入
 while(((flags&0x02)==0)&&((flags&0x04)==0))   //如果没有测量完成标志和测量时间超时标志的话,就说明没有测量完,等
 {}
 if((flags&0x04)!=0)      //如果测量时间超时标志置1,表明电容过大,超过量程
 {
  TCCR1B=0x40;            //将tc1停止计数
  dly(4);
  count2=0xFF00;                //
  flags=flags|0x08;       //将flags的第3位置1,表明测量时间超时,测量失败
 }
 else if((flags&0x02)!=0) //如果测量完成标志置1,表明测量成功
 {
  TCCR1B=0x40;            //将tc1停止计数
  flags=flags&0xf7;       //将flags的第3位置0,表明测量成功
 }

}



//调0,即将result的值减去comp3的值
void adjustzero(void)
{
//改动 if((PORTB&0x01)==0)     //如果PB1为0,即用大电流对电容充电,则不做任何操作,跳过此程序
 if((PORTC&0x02)==0)
 {
 }
 else
 {
  result=result-comp3;         //将计数值减去0偏值,即进行了调0校准
  if(result<0)
  {
   flags=flags|0x01;     //将flags的第一位置1,即说明测量结果为负数
   result=0xFFFFFFFF-result;
   result=result+1;
  }
 }
}

//调整增益,功能是将测量的计数器计数值result通过comp1或comp2变换成实际的电容值大小
void adjustgain(void)
{
//改动 if((PORTB&0b00000001)!=0)    //如果PB1输出高电平,说明是用小电流对电容进行充电
 if((PORTC&0x02)!=0)
 {
  asm("cli");
  result=result*comp1/100.0;
  asm("sei");
 }
 else
 {
  asm("cli");
  result=result*comp2/1000.0;
  asm("sei");
 }
}

		
				


//将要显示的结果result按从低位到高位存储到strbuf[10]里,并依据高量程测量还是低量程测量,以及result的位数给他找好显示模版,找//显示模板的意思是,看看电容值大小在什么范围内,主要是确定第几位有小数点,以及单位
void dispval(long int i)
{
 int j;
 int k=0;
 int l=0;
 int m=0;
 nbit=0;                  //记录实际电容值result的位数
 for (k=0;k<=9;k++)       //将实际电容值按从低位到高位存储到strbuf[10]中,最低位存在strbuf[0]中,执行后,nbit==10
 {
  j=i%10;
  strbuf[nbit]=j;
  i=i/10;
   nbit++;
 }

 nbit--;                 //nbit减成9

 while (strbuf[nbit]==0) //判断result的位数
 {
  nbit--;
  if(nbit==0)            //4.17修改
      break;             //4.17修改
 }
 nbit++;                 //到此时为止,nbit存储着实际电容值result十进制的位数

 m=nbit;

 if (m<2)               //如果nbit==1,则给他加上一位
 {
  m++;
 }
                               //以下几句是通过判断是高量程测量还是低量程测量,以及result的位数,确定电容值的显示模板
//改动 if((PORTB&0b00000001)==0)     //如果使用高量程测量,就将位数加3,因为高量程测量时的电流正好是低量程测量时电流的1000倍
 if((PORTC&0x02)==0)
 {
  m=m+3;
 }
  j=0;
  k=0;
 if((flags&0x01)==0x01)        //如果负数标志为1,则装入负数偏移
 {
  j=(m-2)*4;
  for(l=0;l<=3;l++)
  {
   pdispbuf[l]=form2[j];
   j++;
  }
 }
 else                          //如果为正数,则转入正数偏移
 {
  j=(m-2)*4;
    for(l=0;l<=3;l++)
  {
   pdispbuf[l]=form1[j];       //向pdispbuf数组里装入显示数据的模板
   j++;
  }
 }
 putformd();                   //套用上面显示的模板,将电容数值表示出来
}


//通过pdispbuf[4]中存储的四个将要显示的数字在seg7当中的偏移,将要显示的代码存储到dispbuf[4]中,他的思路是这样的:如果数码管n//上要显示数字,那么pdispbuf[n]上肯定是0或1,0表示本数码管不显示小数点,1表示本数码管显示小树点,从strbuf数组中高位依次显示//对应数字的显示代码就可以了,如果是显示代码,那么pdispbuf[n]大于1,这时候就直接在seg7中寻找相应的显示代码就行
void putformd(void)
{
 int k=0;
 int d=0;
 for(k=0;k<=3;k++)
 {
  switch(pdispbuf[k])
  {
   case 0:
     dispbuf[d]=strbuf[nbit-1-k]+48;
     d++;
     break;
   case 1:
     dispbuf[d]=strbuf[nbit-1-k]+48;
     d++;
     dispbuf[d]=46;
     d++;
     break;
   case 2:
     dispbuf[d]=50;
     d++;
     break;
	    case 3:
     dispbuf[d]=51;
     d++;
     break;
	    case 4:
     dispbuf[d]=52;
     d++;
     break;
	    case 5:
     dispbuf[d]=53;
     d++;
     break;
	    case 6:
     dispbuf[d]=54;
     d++;
     break;
	    case 7:
     dispbuf[d]=55;
     d++;
     break;
	    case 8:
     dispbuf[d]=56;
     d++;
     break;
	    case 9:
     dispbuf[d]=57;
     d++;
     break;
   case 10:
     dispbuf[d]=45;
     d++;
     break;
   case 11:
     dispbuf[d]=117;
     d++;
     break;
   case 12:
     dispbuf[d]=110;
     d++;
     break;
   case 13:
     dispbuf[d]=112;
     d++;
     break;
   case 14:
     dispbuf[d]=69;

⌨️ 快捷键说明

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