新人第一次發帖 ,大家不要見笑 程序是在51hei電子論壇下的 再次感謝這位樓主!費時三天。第一次調試1602沒有顯示!檢查半天查看電路沒有錯,按照樓主說的加上拉電阻也沒有字符!原來是調電位器終于顯示了,幸福激動!哪個測大電容的電位器是校準的。沒有合適的電感 電感檔誤差大 隨后在做調整。借用別人的程序(本帖附件中可下載)
原理圖:
實物制作圖:
測試電容105的
沒有按鍵開關只有用這了
電感
5v 電源供電
這是外殼
網購的1602屏
背部飛線嚴重就不拍了
51單片機源程序:
- //*****************************************************************
- // 大道必成 原創作品 //
- //*****************************************************************
- #include "reg52.h"
- #include "intrins.h"
- //-------宏定義---------
- #define u8 unsigned char
- #define u16 unsigned int
- #define u32 unsigned long
- #define Cref 2200 //基準電容值(單位pF)
- #define LCD_DATA P0 //LCD數據口(8位)
- //-------I/O定義--------
- sbit LCD_BUSY = P0^7; //LCD忙信號
- sbit LCD_RS = P1^0; //數據/命令選擇(數據=1,命令=0)
- sbit LCD_RW = P1^1; //讀/寫選擇(寫=0,讀=1)
- sbit LCD_EN = P1^2; //使能信號
- sbit K1_F_LC = P1^3; //F/LC測量選擇按鈕(自鎖),([抬起]=0測LC,[按下]=1測F)
- sbit K2_L_C = P1^4; //L/C測量選擇按鈕(自鎖)([抬起]=0測C,[按下]=1測L)
- sbit K3_Eb_Es = P1^6; //電解量程選擇按鈕(自鎖),([抬起]=0低量程,[按下]=1高量程)
- sbit K4_FLC_EC = P3^6; //FLC或EC(電解電容)測量選擇按鈕(無鎖)(每按一次,翻轉一次)
- sbit K5_Calib = P3^7; //手工校正(清零)按鈕(無鎖)(消除寄生電容值)
- sbit Dischg = P1^5; //測量電解電容時的充放電控制端口(=0放電,=1充電)
- //-------全局變量定義--------
- bit FLC_EC_Flag; //測量標志(=0測FLC,=1測電解電容)
- u8 Measure_Flag; //測量標志(=1測電容,=2測電感,=3測頻率,=4測小電解,=5測大電解)
- u8 Lref; //基準電感值(單位uH)(原作沒有)
- u16 T0_times; //T0中斷計數預設值(每50ms一次),測F=20次(1s),測LC=10次(0.5s)
- u16 Timer0_Num; //T0計數
- u16 Timer1_Num; //T1計數
- u32 Frequency0; //頻率0(未接被測元件時的頻率)
- u32 Frequency1; //頻率1(接入被測元件時的頻率)
- u32 Cx; //被測電容
- u32 Lx; //被測電感
- u32 ECx_H; //被測電解電容(大)
- u32 ECx_L; //被測電解電容(小)
- //------x的n次方------------
- u32 power(u8 x,u8 n)
- {
- u8 i;
- u32 j = 1;
- if(n == 0)
- {
- return 1;
- }
- else
- {
- for(i=0; i<n; i++)
- {
- j *= x;
- }
- return j;
- }
- }
- //----延時n毫秒(12M晶振,12T模式,一個指令周期=1us)---
- //----1ms=(跳轉等3個指令周期+兩個空指令)*200----
- void Delay_ms(u8 n)
- {
- u8 i,j;
- for(i=0; i<n; i++)
- {
- for(j=0; j<200; j++)
- {
- _nop_();
- _nop_();
- }
- }
- }
- //------LCD1602讀忙標志位------
- void Check_busy(void)
- {
- do
- {
- LCD_EN=0;
- LCD_RS=0;
- LCD_RW=1;
- LCD_DATA=0xFF;
- LCD_EN=1;
- }
- while(LCD_BUSY==1);
- LCD_EN=0;
- }
- //------LCD1602寫指令------
- void Write_Command(u8 cmd)
- {
- Check_busy();
- LCD_RS=0;
- LCD_RW=0;
- LCD_DATA=cmd;
- LCD_EN=0;
- LCD_EN=1;
- LCD_EN=0;
- }
- //------LCD1602寫數據------
- void Write_Data(u8 dat)
- {
- Check_busy();
- LCD_RS=1;
- LCD_RW=0;
- LCD_DATA=dat;
- LCD_EN=0; //機器周期小于1us時,須加延時
- LCD_EN=1;
- LCD_EN=0;
- }
- //-----LCD1602寫字符串------
- //---x=列(0~15); y=行(0,1)
- //---從指定的位置開始寫,直到超出屏幕顯示
- void LCD_Write_String(u8 y,u8 x,u8 *Data)
- {
- if(y==0) //第一行
- {
- if(x<16)
- {
- Write_Command(0x80+x); //0x80 + 第一行起始地址
- for(; x<16&&*Data!='\0'; x++) //'\0'字符串結束標志
- {
- Write_Data(*(Data++));
- }
- }
- }
- if(y==1) //第二行
- {
- if(x<16)
- {
- Write_Command(0xc0+x); //0xc0 + 第二行起始地址
- for(; x<16&&*Data!='\0'; x++) //'\0'字符串結束標志
- {
- Write_Data(*(Data++));
- }
- }
- }
- }
- //------LCD1602寫長整型數據------
- //x=列(0~15); y=行(0,1);截取長整型后length個數字顯示在指定位置(全顯示length=10)
- //注意此函數不支持換行,起始列+length>15時后面的顯示不出來,僅能單行顯示
- void LCD_Write_Long(u8 y,u8 x,u8 length,u32 Data)
- {
- u8 i,k;
- if(length>10)
- {
- length = 10;
- }
- if(length<10)
- {
- Data = Data%power(10,length);
- }
- if(y==0) //第一行
- {
- Write_Command(0x80+x); //0x80 + 第一行起始地址
- for(i=0; i<length; i++)
- {
- k = (u8)(Data/power(10,length-1-i));
- Data = Data%power(10,length-1-i);
- Write_Data(k+0x30);
- }
- }
- if(y==1) //第二行
- {
- Write_Command(0xc0+x); //0xc0 + 第二行起始地址
- for(i=0; i<length; i++)
- {
- k = (u8)(Data/power(10,length-1-i));
- Data = Data%power(10,length-1-i);
- Write_Data(k+0x30);
- }
- }
- }
- //------LCD1602寫長整型數據,可以指定小數點后位數-------
- //x=列(0~15); y=行(0,1);截取長整型后length個數字顯示在指定位置(全顯示length=10)
- //注意此函數不支持換行,起始列+length>15時后面的顯示不出來,僅能單行顯示
- //pot:小數點后顯示幾個數字 例:1234567 pot=2時顯示為12345.67
- void LCD_Write_LongPoint(u8 y,u8 x,u8 length,u8 pot,u32 Data)
- {
- u8 i,j,k;
- if(length>10)
- {
- length = 10;
- }
- if(length<10)
- {
- Data = Data%power(10,length);
- }
- if(y==0) //第一行
- {
- j=0;
- Write_Command(0x80+x); //0x80 + 第一行起始地址
- for(i=0; i<=length; i++)
- {
- if(i==(length-pot))
- {
- Write_Data(0x2e); //小數點
- Write_Command(0x80+x+i+1);
- }
- else
- {
- k = (u8)(Data/power(10,length-1-j));
- Data = Data%power(10,length-1-j);
- Write_Data(k+0x30);
- j++;
- }
- }
- }
- if(y==1) //第二行
- {
- j=0;
- Write_Command(0xc0+x); //0xc0 + 第二行起始地址
- for(i=0; i<=length; i++)
- {
- if(i==(length-pot))
- {
- Write_Data(0x2e); //小數點
- Write_Command(0xc0+x+i+1);
- }
- else
- {
- k = (u8)(Data/power(10,length-1-j));
- Data = Data%power(10,length-1-j);
- Write_Data(k+0x30);
- j++;
- }
- }
- }
- }
- //------LCD1602清屏---------
- void LCD_Clear(void)
- {
- Write_Command(0x01);
- }
- //------LCD1602初始化-----
- void LCD1602_Init(void)
- {
- Delay_ms(15);
- Write_Command(0x38); //16x2顯示,8位數據
- Write_Command(0x0c); //開顯示
- Write_Command(0x06); //AC自動加1,字符依次向后寫
- LCD_Clear();
- }
- //------判斷測量類型-------
- void Get_Measure_Flag(void)
- {
- if(FLC_EC_Flag==0) //測FLC按鍵選擇標志位
- {
- if(K1_F_LC==1)
- {
- Measure_Flag = 3; //測頻率
- T0_times = 20; //T0定時1s
- }
- else
- {
- if(K2_L_C==0)
- {
- Measure_Flag = 1; //測電容
- }
- else
- {
- Measure_Flag = 2;
- }
- T0_times = 10; //T0定時0.5s
- }
- }
- else
- {
- TR0 = 0; //關閉測頻率(含LC)功能
- ET0 = 0;
- if(K3_Eb_Es==0)
- {
- Measure_Flag = 4; //測小電解
- }
- else
- {
- Measure_Flag = 5; //測大電解
- }
- }
- }
- //------測試(F/L/C)初始化(T0,T1初始化)------
- void MeasureFLC_init(void)
- {
- Timer0_Num = 0;
- Timer1_Num = 0;
- TMOD = 0x51; //T0作定時器,T1作計數器
- TH0 = 0x3c; //T0初值高8位(定時50ms)
- TL0 = 0xb0; //T0初值低8位
- TH1 = 0x3c; //T1初值高8位(計數50000次)
- TL1 = 0xb0; //T1初值低8位
- TR0 = 1; //T0開
- TR1 = 1; //T1開
- ET0 = 1; //T0中斷開
- ET1 = 1; //T1中斷開
- EA = 1; //總中斷開
- }
- //--------計算L/C值--------
- void LC_Calculate(void)
- {
- float mes;
- mes = (float)Frequency0/(float)Frequency1; //頻率比
- mes *= mes; //平方值
- if(mes < 1) //取絕對值
- {
- mes = 1 - mes;
- }
- else
- {
- mes -= 1;
- }
- Cx = 100 * mes * Cref; //計算被測電容值(精確到0.1pF)
- if((Cx%10) >= 5) //四舍五入
- {
- Cx = Cx/10 + 1;
- }
- else
- {
- Cx = Cx/10;
- }
- Lx = mes * Lref * 1000; //計算被測電感值(精確到0.01uH)
- if((Lx%10) >= 5) //四舍五入
- {
- Lx = Lx/10 + 1;
- }
- else
- {
- Lx = Lx/10;
- }
- if(Frequency1<50) //防止不接入電感時顯示溢出值
- {
- Lx = 0;
- }
- }
- //----自動校正(清除寄生電容值)-------
- void Auto_Calib(void)
- {
- u8 i;
- if((K1_F_LC != 0) || (K2_L_C != 0)) //判斷K1,K2的初始位置
- {
- LCD_Clear();
- LCD_Write_String(0,0,"Auto Calib fail!");
- if((K1_F_LC == 1) && (K2_L_C == 1))
- {
- LCD_Write_String(1,0,"Need up K1 & K2 ");
- }
- else
- {
- if(K1_F_LC == 1)
- {
- LCD_Write_String(1,0," Need up K1 ");
- }
- else
- {
- LCD_Write_String(1,0," Need up K2 ");
- }
- }
- while((K1_F_LC == 1) || (K2_L_C == 1)); //等待K1,K2的準確初始位置
- for(i=0; i<20; i++)
- {
- Delay_ms(75); //延時1.5秒,消抖.
- }
- }
- LC_Calculate();
- Delay_ms(150);
- Lref = (Cx/Cref + 1) * 100; //計算基準電感值(單位uH)
- Frequency0 = Frequency1;
- }
- //-------按鍵讀取--------
- void Get_Key(void)
- {
- if(K4_FLC_EC == 0) //如果=0(按鈕按下)
- {
- Delay_ms(50);
- if(K4_FLC_EC == 0)
- {
- FLC_EC_Flag = ~FLC_EC_Flag; //測量標志取反
- if(FLC_EC_Flag == 0) //如果=0,是測FLC
- {
- EX0 = 0; //關閉測電解電容的功能(外部中斷0關)
- MeasureFLC_init(); //測試(F/L/C)初始化(T0,T1初始化)
- }
- else //否則,是測量電解電容.
- {
- TR0 = 0; //T0關
- ET0 = 0; //T0中斷關
- }
- }
- }
- if(K5_Calib == 0) //如果=0(按鈕按下)(手工校正)
- {
- Delay_ms(50); //延時50sm,消抖
- if(K5_Calib == 0)
- {
- if((K1_F_LC == 0) && (K2_L_C == 0)) //如果K1,K2處于測量電容位置
- {
- Frequency0 = Frequency1;
- }
- }
- }
- }
- //-------測試電解電容初始化(T0,T1及外部中斷初始化)-------
- void MeasureElec_init(void)
- {
- u8 i;
- ECx_H = 0;
- ECx_L = 0;
- TR1 = 0;
- ET1 = 0;
- EX0 = 0; //關外部中斷
- Dischg = 0; //放電
- Delay_ms(180);
- Delay_ms(200);
- Dischg = 1; //充電
- Timer1_Num = 0;
- TMOD = 0x11; //T0,T1都作定時器
- TH1 = 0x3c; //T1初值高8位(定時50ms)
- TL1 = 0xb0; //T1初值低8位
- TR1 = 1; //T1開
- ET1 = 1; //T1中斷開
- IT0 = 1; //下降沿觸發
- EX0 = 1; //外部中斷開
- EA = 1; //總中斷開
- for(i=0; i<65; i++) //延時1.3s,等待測量
- {
- Delay_ms(20);
- if(K4_FLC_EC == 0) //如果測量期間K4鍵按下
- {
- Delay_ms(20);
- if(K4_FLC_EC == 0)
- {
- break; //中止
- }
- }
- }
- EX0 = 0; //外部中斷關
- Dischg = 0; //放電
- }
- //--------定時器0中斷處理---------
- void Timer0_interrupt(void) interrupt 1
- {
- TH0 = 0x3c; //重裝載T0初值高8位(定時50ms)
- TL0 = 0xb0; //重裝載T0初值低8位
- Timer0_Num++; //T0計次累加
- if(Timer0_Num >= T0_times) //如果T0計次數=T0預設值(測F=20(1s),測LC=10(0.5s))
- {
- TR0 = 0; //T0關
- TF0 = 0; //T0溢出標志清零
- TR1 = 0; //T1關
- TF1 = 0; //T1溢出標志清零
- Frequency1 = 50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0);
- //計算頻率值(Frequency1)
- Timer0_Num = 0; //T0計次清零
- Timer1_Num = 0; //T1計次清零
- TH0 = 0x3c; //重裝載T0初值高8位(定時50ms)
- TL0 = 0xb0; //重裝載T0初值低8位
- TH1 = 0x3c; //重裝載T1初值高8位(計數50000次)
- TL1 = 0xb0; //重裝載T1初值低8位
- TR0 = 1; //T0開
- TR1 = 1; //T1開
- }
- }
- //------定時器1中斷處理-------
- void Timer1_interrupt(void) interrupt 3
- {
- TH1 = 0x3c; //重裝載T1初值高8位(定時50ms,或計數50000次)
- TL1 = 0xb0; //重裝載T1初值低8位
- Timer1_Num++; //T1計次累加
- }
- //-------外部INT0中斷處理--------
- void INT0_Interrupt(void) interrupt 0
- {
- if(Measure_Flag==4)
- {
- ECx_L = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*100/2000;
- //計算低容量電解電容值(精確到0.01uF)
- if((ECx_L-2)>=0)
- {
- ECx_L -= 2; //修正誤差
- }
- }
- if(Measure_Flag==5)
- {
- ECx_H = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*10/100;
- //計算高容量電解電容值(精確到0.1uF)
- if((ECx_H-4)>=0)
- {
- ECx_H -= 4; //修正誤差
- }
- }
- }
- //-----------
- void Main(void)
- {
- u8 i;
- u8 clear; //清屏標志位,如果功能轉換則需要清屏
- Measure_Flag = 0;
- FLC_EC_Flag = 0; //開機默認測FLC
- T0_times = 10;
- Timer0_Num = 0;
- Timer1_Num = 0;
- Frequency0 = 169500;
- //基準頻率的一半(基準頻率是:當L=100uH,C=2200pF時的頻率,=339000Hz)
- Frequency1 = 0;
- LCD1602_Init();
- MeasureFLC_init();
- LCD_Write_String(0,0," L.C.F Meter ");
- LCD_Write_String(1,0," 2015-08-01 ");
- for(i=0; i<20; i++)
- {
- Delay_ms(150); //開機畫面顯示3秒
- }
- Auto_Calib();
- while(1)
- {
- Get_Key(); //按鍵掃描
- Delay_ms(70); //該延時使按鍵切換穩定
- clear = Measure_Flag; //讀測量類型標志及清屏
- Get_Measure_Flag(); //獲取測量類型標志
- if(clear != Measure_Flag)
- {
- LCD_Clear();
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
51黑論壇_自動校正.zip
(32.65 KB, 下載次數: 490)
2017-10-3 11:06 上傳
點擊文件名下載附件
程序 電路
|