久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3957|回復: 7
打印 上一主題 下一主題
收起左側

stc12c5a60s2 0-30電壓測量 有注釋

  [復制鏈接]
跳轉到指定樓層
樓主
ID:254747 發表于 2019-11-7 19:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
#include <STC12C5A60S2.H>
#include "intrins.h"

#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


/*----------------------------------------------------------------------------------------------
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,temp,AD_jie_guo;          //長整形數據  16bit

float OVP;                 //定義一個浮點數  以保留小數點 提高進度

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初始化函數
void OCP_1();                                         //過壓 欠壓  提醒函數聲明
float count(uchar ch);       //AD值100次平均值函數
//ulong  count(uchar ch);  //ad計算函數測量0-5V時候用的
uchar code table[20]= {"     Shu Kong QuDong"};        //  開機畫面的布置
uchar code table2[20]={"     CQDZ Alan V1.01"};


/*-----------------
  延時函數
  -----------------*/
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()
{

     AD_jie_guo = count(0);   //經過上面的計算求出來100次的平均值存放在AD_jie_guo里面


/*-------------------------------------------------------------------------------
        //擴大電壓   我的量程是0-30V  分壓電阻是 10k 2k 電阻比的6  反推 當測試電壓為5v
   //的時候 最高電壓為30V 測量后調試OK 因電阻誤差 調整了數據為6.02  
  //同時這里也可以用(temp/0.167)/100  這個是電壓比也就是30V分壓為5V  
  //然后5/30=0.167的結果也是一樣的
---------------------------------------------------------------------------------*/
         temp=((ADC_jiancedaozuidivoltage*AD_jie_guo)*6.02)/100;
//         temp=(temp*6.02)/100;    //備用算法 這樣太占用位置 我把這步合并到上面了         
                 
                                                          
        //0x30是顯示數字 0-9 30表示第一個數0  
        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/10000+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=(49600000)/1024;  //5V參考電壓,計算分度值的時候,數值過小會出現很大偏差
                                                          //所以放大1000萬倍 這樣精度會高一些

    while (1)
    {
       disp();
           OCP_1();
    }
}

/*************************
*  功能        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  也就是電壓值         ,左移幾次就乘以2的幾次方
                                     //右移幾次就除以2的幾次方  這里的ADC_RES*4相當于ADC_RES<<2 左移了2
        Delay(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 型  浮點型  保留小數點 提高精度
*  帶結果返回  帶結果返回
*  同時對GetADCResult(ch)采樣100次求平均值 提高進度
******************************/

float count(uchar ch)
{
    float AD_val;     //定義處理后的數值AD_val為浮點數  初始狀態AD_val為0 經過100次變化后
        uchar n;                  //AD_val值為100次的GetADCResult(ch)這個變化值 然后在除以100就是平均值

        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就可以這樣計算
        OVP = ( AD_val*4.96 ) / 1024;  //為過壓 欠壓 提醒做 前期的計算 方便后面使用
        return AD_val;

}                                                                         
/*-------------------------------------------------------------------------------
函數功能   過壓ovp 欠壓 檢測    cpu供電VCC測量的是4.96V 本程序用的也是4.96V
下面計算也用4.96V。
計算方案:
   通過計算AD基礎值變化也就是"0-5V"的變化情況,然后人為的乘以擴量程倍率“6.02”
得到的就是要過壓去,欠壓保護的值。
例如:現在要電壓達到10v的時候啟動欠壓提醒
計算過程:方法一
本次計算實際是通過vlue = (ADC_RES*4+ADC_RESL);在0-1024之間變化的值來確認模擬
電壓輸入是多少的 如 1024/4.96V(VCC)*(VIN)模擬量,那么對應10v的模擬量電壓應該為
10/6.02=1.7V,那么它vlue = (ADC_RES*4+ADC_RESL)就要變化到多少才是對應的1.7V呢,
通過公式1024/4.96V(vcc)*1.7V(vin)=350;
通過計算它的值在1.7V的時候vlue = (ADC_RES*4+ADC_RESL)=350. 那么我們通過判斷
這個vlue = (ADC_RES*4+ADC_RESL)的數據也可以判斷對應保護電壓,但是計算很麻煩
所以我們把這個麻煩的過程直接讓程序計算好,然后直接用對應系數1.7V即可。
方法二
這個就是我在float count(uchar ch)函數里面計算好了的(OVP)如下
OVP =( AD_val*4.96 ) / 1024;
OVP必須是float類型的數據保留小數點 不然誤差大,只要保留了小數點誤差非常小
通過上面計算好的這個過程然后我們要計算欠壓就非常好算了,例如我要12V欠壓
直接用12V/6.02這個系數 得到的就是你要的AD模擬量大小  12/6.02約等于2.0V
只要判斷OVP到了2.0就說明12V到了 做什么處理就看使用者了 可以報警 可以切斷電源

本程序我是10V欠壓 計算 10/6.02約等于1.7V  我判斷是OVP>1.7 也就是對應的欠壓過壓點
到了 我是點亮LED,低于1.7也就是10V 就關閉LED;   
----------------------------------------------------------------------------------*/
void OCP_1()
{



       if(OVP > 1.7)   //高于10V  10/6.02=1.7
                   {
                  LED = 0;
                                                 //  調試的時候用的   通過判斷temp來判斷是否過壓 如果過壓就啟動保護  
                 }
           if(OVP < 1.7) //低于10v    10/6.02=1.7
                   {
                  LED = 1;
                 
                 }   
}





/*----------------------------
功能   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 延時一下
}


/*----------------------------
延時函數
----------------------------*/
void Delay(uint n)
{
   uint x;

    while (n--)
    {
        x = 5000;
        while (x--);
    }
}




分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏16 分享淘帖 頂 踩
回復

使用道具 舉報

來自 2#
ID:254747 發表于 2019-11-8 12:51 | 只看該作者
一定要記住  當I/O口設置為高阻模式的時候 千萬不要有上拉電阻否則會造成高阻模式處于上拉狀態 造成誤差

高阻模式的電平是什么
     答  高阻模式的電平為任意電平 可以是高  也可以是低  可以是無窮大   高阻的中心定義就是和電路看上去是斷開的 但實際又沒有斷開   只是阻抗高而已   
高阻模式主要用在哪里 為什么要高阻模式   
     答  高阻模式主要用在總線上面 例如I2C總線   因為總線每次通訊的時候只能和一個IC通訊, 這是為什么呢   因為每一個IC通訊的時候 電平不一樣 如果都通訊就會造成通訊混亂
     從這個描述上看   高阻模式就是一個抗干擾能力強的開關  但是他比開關更先進  高阻抗 高抗干擾能力 低功耗  而且是一個被動的開關,
    經過上面的描述我們可以知道  只要總線上一個IC損壞就會導致整個總線損壞  為什么?因為總線沒有被釋放,出現了通訊混亂
  高阻模式的電平由誰控制
   答   由負載控制   負載是低  高阻模式就是低   負載是高  高阻模式就是高   

  所以在AD轉換的時候  用高阻模式提高精度  是唯一途徑

評分

參與人數 1黑幣 +90 收起 理由
admin + 90 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

板凳
ID:355469 發表于 2019-11-8 07:31 | 只看該作者
好,需要,謝謝。
回復

使用道具 舉報

地板
ID:113020 發表于 2019-11-8 10:08 | 只看該作者
很好!收藏了
回復

使用道具 舉報

5#
ID:138282 發表于 2019-11-8 21:52 | 只看該作者
好帖謝謝分享!
回復

使用道具 舉報

6#
ID:600631 發表于 2020-1-28 01:33 來自觸屏版 | 只看該作者
師傅,這個程序如果顯示電流和功率的話,應該怎么寫程序呢
回復

使用道具 舉報

7#
ID:105786 發表于 2020-3-4 20:54 | 只看該作者
自制STC 12C5A60S2電壓電流表正在學習中
回復

使用道具 舉報

8#
ID:163501 發表于 2020-3-5 21:56 | 只看該作者
這個壇的好就是活躍人多,有東西學
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 久久久久久久久久一区 | 男人的天堂在线视频 | 免费亚洲视频 | 日韩精品成人一区二区三区视频 | 男女羞羞网站 | 国产美女在线观看 | www精品 | 人成在线视频 | 成人在线不卡 | 久久久久久91| av看片网站 | 欧美日韩在线视频一区二区 | 国产九九av | 国产成人高清在线观看 | 一区二区三区四区av | 中文字幕日韩欧美一区二区三区 | 国产精品久久久久久吹潮 | 五月槐花香 | 日韩精品二区 | 亚洲不卡在线观看 | 成年男女免费视频网站 | 一区二区三区免费在线观看 | 日本成人在线网址 | 中文字幕不卡在线88 | 国产精品乱码一区二区三区 | 久久久久久久久久久一区二区 | 精品国产欧美一区二区三区不卡 | 在线播放91 | 久久久久久久久久久久一区二区 | 青青草视频网 | 国产一区二区三区久久久久久久久 | 91免费电影| 成人免费黄视频 | 国产午夜在线 | 天天拍天天草 | 国产高清精品一区二区三区 | 亚洲国产欧美日韩 | 日韩精品在线一区 | av天天看 | 国产探花在线观看视频 | 99精品欧美一区二区三区 |