![]() |
發布時間: 2019-11-4 00:08
正文摘要:stc12c5a60s2 為什么我這個電壓無法讀取 請大師看看呢 我是直接用的單片機5V供電的 #include <STC12C5A60S2.H> #include "intrins.h" //typedef unsigned char BYTE; //typedef unsigned ... |
wulin 發表于 2019-11-7 10:57 師傅,這個程序,如果再增加一路測試電壓的話,程序應該怎么寫呢 |
wulin 發表于 2019-11-7 10:57 非常感謝 我下載了 我需要好好去學習哈 |
不將就123 發表于 2019-11-6 22:07 給你把程序改好了,有詳細注釋。 ![]() ![]() |
感謝論壇的各位朋友 問題現在已經解決了 是開發板上面的 上拉電阻導致的誤差 將I0口拿出來測試 問題得到完美的解決了 temp=(ADC_jiancedaozuidivoltage*AD_jie_guo); temp=(temp*6)/100; //這里為什么要/100 這個是我參考網上大師做的 |
大哥 我重新發了一次 您在給我看看 |
#include <STC12C5A60S2.H> #include "intrins.h" //typedef unsigned char BYTE; //typedef unsigned int WORD; #define uchar unsigned char #define uint unsigned int #define ulong unsigned long /*Define ADC operation const for ADC_CONTR*/ #define ADC_POWER 0x80 //ADC 電源控制位 10000000 0X80 / #define ADC_FLAG 0x10 //ADC 完成標志 00010000 0x10 #define ADC_START 0x08 //ADC 啟動ADC開關 00001000 0x08 / #define ADC_SPEEDLL 0x00 //420 轉換速度 00000000 0x00 / #define ADC_SPEEDL 0x20 //280 轉換速度 00100000 0x20 #define ADC_SPEEDH 0x40 //140 轉換速度 01000000 0x40 #define ADC_SPEEDHH 0x60 //70 轉換速度 01100000 0x60 //float temp; //定義temp為浮點型參數 /*---------------------------------------------------------------------------------------------- meidangzuidivoltage:表示AD最高電壓5V對應10bit_AD轉換的最小電壓是多少 5/1024= 0.00488V 也就是AD在 //10bit下測量的最小電壓, //那么在計算AD電壓值的時候將公式 “GetADCResult(ch)*5/1024”分兩步進行 方便后面對數據分離顯示到 //1602上面 先計算ADC_jiancedaozuidivoltage=5*10000000/1024 先將這個數放大100萬倍 //最后在算AD_jie_guo=(ADC_jiancedaozuidivoltage*GetADCResult(ch); ----------------------------------------------------------------------------------------------*/ ulong ADC_jiancedaozuidivoltage,AD_jie_guo,temp; uint num,i,vlue;//ADC_mV,ADC_RESX,VCC_V=5.2; sbit lcden = P2^7; sbit rs = P2^6; sbit rw = P2^5; sbit LED = P3^0; void Delay(uint n); //延時函數 uint GetADCResult(uchar ch); // ad轉換函數 void InitADC(); //ad初始化函數 //ulong count(uchar ch); //ad計算函數 uchar code table[20]= {" Shu Kong QuDong"}; uchar code table2[20]={" CQDZ Alan V1.01"}; float count(uchar ch); /* 延時函數*/ void delayms(uint xms) { uint i,j; for(i=xms;i>0;i--) for (j=960;j>0;j--); } /******寫命令****/ void lcd_write_com(uchar com) { rw=0; rs=0; //寫命令狀態 P0=com; lcden=1; delayms(5); lcden=0; } /**寫數據 ***/ void write_date_(uchar date) { rw=0; //寫數據 rs=1; //寫數據狀態 P0=date; delayms(5); lcden=1; //使能 delayms(5); lcden=0; } /*初始化顯示屏*/ void lcd_init(void) { lcden=0; lcd_write_com(0x38); //設置8位格式,2行,5*7 lcd_write_com(0x0c); //整體顯示,關光標,不顯示 lcd_write_com(0x06); // 設定輸入方式,增量不移位 lcd_write_com(0x01);//清屏幕 delayms(5); //延? } /*----------------------- 函數名稱 格式定義 函數的介紹 在某個屏幕位置上顯示一個字符,X(0-16),y(1-2) X:表示字的格式 一共16個 Y:表示行 一共2行 -------------------------*/ //格式定義 void lcd_disp_char(uchar y,uchar x, uint dat) { uint address; if(y==1) //y為1 在第一行 address=0x80+0x10+4+x; //整屏左移動以后 從新定義新的起始位置 但是要加上之前移動后的地址 else address=0xc0+0x10+x; //y為2 在第二行 X顯示字的位置 0XC0是 0x80+0x40的結果 lcd_write_com(address); //寫入要寫的位置 write_date_( dat); //寫入你要寫的數據 } /*顯示函數2*********/ void disp() { temp=(ADC_jiancedaozuidivoltage*AD_jie_guo); temp=(temp*6)/100; //擴大電壓 我的量程是0-30V 分壓電阻是 10k 2k 電阻比的5 反推 當測試電壓為5v //的時候 最高電壓為25V 測量后調試 //0x30是顯示數字 0-9 30表示第一個數0 int是將count轉換為整數 lcd_disp_char(1,0, temp%10000000/1000000+0x30 ); //十位 lcd_disp_char(1,1, temp%1000000/100000+0x30); //個位 lcd_disp_char(1,2,'.' ); // 小數點 lcd_disp_char(1,3, temp%100000/10000+0x30 ); //個分位 lcd_disp_char(1,4, temp%10000/1000+0x30 ); //百分位 lcd_disp_char(1,5,'V' ); } //count(0) /*----------------------------------- 功能 開機的時候顯示一下銘牌 for來完成 屏幕左移動 ----------------------------------*/ void init() { // lcd_write_com(0x80+0x10); //定義顯示的位置 起始地址 lcd_write_com(0x80); //定義顯示的位置 起始地址 for(num=0;num<20;num++) { write_date_(table[num]); //初始化屏幕的初始數字“0000” delayms(5); } // lcd_write_com(0x80+0x40+0x10); //定義第二排,顯示的地址 0x80是顯示屏寄存器第一排起始地址 lcd_write_com(0xc0); //定義顯示的位置 起始地址 for(num=0;num<20;num++) //0x40是第二排起始地址 { write_date_(table2[num]); delayms(5); } for(num=0;num<20;num++) //整屏左移動 這里的21就是指可以移動多少格 可以是100可以是1000 相當于是電子屏幕一樣 { lcd_write_com(0x18); //0x18是整屏左移 指令 delayms(50); } } void main() { lcd_init(); init(); InitADC(); //Init ADC sfr ADC_jiancedaozuidivoltage=49700000/1024; //5V參考電壓,計算分度值的時候,數值過小會出現很大偏差 //所以放大1000萬倍 這樣精度會高一些 while (1) { /* if(temp > 3) { LED = 0; // 調試的時候用的 通過判斷temp來判斷是否過壓 如果過壓就啟動保護 } if(temp < 3) { LED = 1; }*/ AD_jie_guo = count(0); //經過上面的計算求出來100次的平均值存放在AD_jie_guo里面 disp(); } } /************************* * 功能 ADC轉換函數 * 帶結果返回 帶結果返回 **************************/ uint GetADCResult(uchar ch) //參數的定義“ch”初始化就是為0 所以這里的“ch”應該是用來設置用哪個端口 { //來設置AD的 這個“ADC_POWER|ADC_SPEEDLL|ch|ADC_START”;或出來的結果是 //10001000 后面三個0對應的是 CHS2 CHS1 CHS0 查表格 剛好是P1.0口 //作為AD模擬輸入的。如果要改變端口就要給ch賦值 假如要P1.2 就需要賦值為ch=0x02; ADC_CONTR = ADC_POWER|ADC_SPEEDLL|ch|ADC_START; //配置相關項目打開 _nop_(); _nop_(); _nop_(); //4個機器時間的延時 以保障轉換完成 _nop_(); while(!(ADC_CONTR&ADC_FLAG)); //判斷是否轉換完成 ADC_CONTR &= ~ADC_FLAG; //關閉ADC vlue = (ADC_RES*4+ADC_RESL); //返回結果10bit 也就是電壓值 Delay(2); //延時一下不然電壓的后2位變化的太快 return vlue; } /****************************** * 功能:計算1結果函數 將10bit的結果計算為對應電壓值MV * 函數類型 float 型 浮點型 * 帶結果返回 帶結果返回 ******************************/ /* ulong count(uchar ch) { ADC_RESX=GetADCResult(ch); ADC_mV=(VCC_V*(long)ADC_RESX*10000/1024+5)/10;//強制轉換長整型運算,得到結果mV(4舍5入) return ADC_mV; }*/ /****************************** * 功能:計算2結果函數 將10bit的結果計算為對應電壓值MV * 函數類型 float 型 浮點型 * 帶結果返回 帶結果返回 ******************************/ float count(uchar ch) { float AD_val; //定義處理后的數值AD_val為浮點數 uchar n; for(n=0;n<100;n++) AD_val+=GetADCResult(ch); //轉換100次求平均值(提高精度) AD_val/=100; //意思是GetADCResult(ch)經過了100次轉換后的值保存到了AD_val里面 然后在 //除以100 就是求平均值 這樣的精度高一點 // AD_val=(AD_val*5)/1024; //AD的參考電壓是單片機上的5v,所以乘5即為實際電壓值,應為分段計算這個就 //暫時不用 如果測量0-5v就可以這樣計算 return AD_val; // temp = (float)GetADCResult(ch)*5/1024; //5表示單片機的供電 這個公式在手冊上可以看到 //temp = (float) temp*5; // return temp; //這里的temp值就是最終的電壓值MV 轉換成V就在乘以1000 } //在顯示屏函Dispy數里面已經做了倍率乘法 /*---------------------------- 功能 ADC初始化函數 ----------------------------*/ void InitADC() //adc初始化函數 { P1M1=0x01; //設置P1.0高阻模式 P1M0=0x00; //設置P1.0高阻模式 P1ASF = 0x01; //開放P1.0通道ADC功能 就是8個I/O口全部開放 ADC_RES = 0; //清除之前的結果 ADC_RESL = 0; ADC_CONTR = ADC_POWER | ADC_SPEEDLL; //打開AD電壓 轉換速度540 Delay(2); //ADC 延時一下 } /*---------------------------- Software delay function ----------------------------*/ void Delay(uint n) { uint x; while (n--) { x = 5000; while (x--); } } |
我發了 但是沒有顯示出來 我重新給您發一下 |
不將就123 發表于 2019-11-5 22:34 代碼在哪? |
wulin 發表于 2019-11-5 12:45
但是現在出現的問題是 測量誤差相當的大 我測量的是30V的電壓 通過 10k 2k 分壓后為5v 然后比例是6 結果當被測電壓為3.0V的時候 單片機測量出來的就是6.78V 麻煩大哥看一下 是哪里出問題了 給我指導一下 非常感謝!!! 代碼有些亂 費心了 |
不將就123 發表于 2019-11-4 20:52 STC12C5A60S2單片機的P1上電默認高電平為準雙向口,用作ADC輸入的端口必須設置為高阻模式,否則端口內部上拉電阻會影響測量精度,其它口保持準雙向口模式可以另作它用。設置P1ASF寄存器的目的是開通MCU內部ADC模擬輸入通道。其它口保持TTL模式可以另作它用。 ADC測量范圍0~VCC,被測電壓高于VCC需要通過分壓電阻降到VCC以內,測量結果按降壓比例放大還原。如果分壓是電阻是 10K和2K,取樣電壓是實際電壓的1/6,等測量結果換算成電壓后*6就是實際電壓值。 |
hhh402 發表于 2019-11-4 10:34 謝謝師傅 |
wulin 發表于 2019-11-4 16:49 可以說一下為什么嗎? 謝謝你 大師 我現在要測量0-30V的電壓 然后電阻分壓是 10k 2k 5/30=0.167比率 然后我 用temp=temp/0.167 以后測量不出來啦 是不是我分離有問題 |
不將就123 發表于 2019-11-4 16:08 只一個P1.0口用作ADC P1ASF = 0x01;//設置P1.0做模擬輸入 P1M1=0x01;//設置P1.0高阻模式 P1M0=0x00;//設置P1.0高阻模式 |
wulin 發表于 2019-11-4 11:34 這是為什么啊 我只用一個p1.0口 |
還要把P1端口設置為高阻模式。 P1M1=0xff; P1M0=0x00; |
wulin 發表于 2019-11-4 06:58 可以了 可以了 我沒有給VCC_V賦值 |
wulin 發表于 2019-11-4 06:58 用了你這段還是不可以啊 |
主函數沒有調用到:uchar GetADCResult(uchar ch), return (ADC_RES*4+ADC_RESL);//會發生數據溢出錯誤 改成:return ((uint)ADC_RES*4+ADC_RESL); |
//函數類型unsigned int uint GetADCResult(uchar ch) { ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ch|ADC_START; _nop_(); _nop_(); _nop_(); _nop_(); while(!(ADC_CONTR&ADC_FLAG)); ADC_CONTR&=~ADC_FLAG; return (ADC_RES*4+ADC_RESL);//返回10位結果 } //函數類型unsigned int uint count(uchar ch) { ADC_RESX=GetADCResult(ch); ADC_mV=(VCC_V*(long)ADC_RESX*10000/1024+5)/10;//強制轉換長整型運算,得到結果mV(4舍5入) return ADC_mV; } |