痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 9366|回復: 39

LCD顯示驅動練習

  [複製鏈接]
發表於 2014-3-20 14:11:19 | 顯示全部樓層 |閱讀模式
本帖最後由 antlu 於 2014-3-20 02:13 PM 編輯

LED  LCM  VFD  顯示都玩過了!! 接下來就是 LCD 的驅動了!!
回收場取得 LCD 拿來練習,目前發現有問題,因為 有些如 小數點 "不點自亮" 還沒找到問題!!
先跟大家分享!!
使用 74HC595 這樣腳數才夠!!

DSC07843.JPG

DSC07842.JPG

DSC07841.JPG

595LCM.png



595LCD.png

評分

3

查看全部評分

發表於 2014-3-20 15:14:31 | 顯示全部樓層
LCD不能用靜態直流驅動,必須交流式驅動要不然LCD會極化。
 樓主| 發表於 2014-3-20 16:04:33 | 顯示全部樓層
本帖最後由 antlu 於 2014-3-20 04:06 PM 編輯
ysc 發表於 2014-3-20 03:14 PM static/image/common/back.gif
LCD不能用靜態直流驅動,必須交流式驅動要不然LCD會極化。


YSC大:

    我用1bit 作為 CLOCK 其他字節會因CLOCK 的 HI/LO 來全面反態,以達到 LCD的交流狀態

   void Display(void)
{

        Send4byte(0xff,0xff,0xff,0xff);//清除lcd的內容       
          if (DriveBIT==0)//為了反向 正向交互所以需要因應而把輸出作為互補
         {
                 Send4byte(TempData[3],TempData[2],TempData[1],TempData[0]);
         }
         else
         {
                 Send4byte(~TempData[3],~TempData[2],~TempData[1],~TempData[0]);
         }
       
       
手頭一捲 74HC595 所以上次請 F大幫忙買了一些"轉板",真的很好用!!
發表於 2014-3-20 16:39:02 | 顯示全部樓層
ysc 發表於 2014-3-20 03:14 PM static/image/common/back.gif
LCD不能用靜態直流驅動,必須交流式驅動要不然LCD會極化。


請教ysc兄,這句話的意思是?
謝謝謝謝!
發表於 2014-3-20 17:02:10 | 顯示全部樓層
fatzeros 發表於 2014-3-20 04:39 PM static/image/common/back.gif
請教ysc兄,這句話的意思是?
謝謝謝謝!

LCD字節與基板之間只要有電位差就會發生對比變化,也就是可以用來顯示圖形或文字,但若一直加著同極性電壓,該字節液晶將會被定型,之後就會顯示不良。

因此,假設基板電位為0,則要顯示的字節必須要在+電位與-電位之間交變,這樣才不會有極化現象發生,一般邏輯電路比較少有負壓,以電位差方式也可以達到相同目的,如同阿乾大一樣,基板以CLOCK驅動,要顯示的字節與CLOCK反相,不顯示的字節與CLOCK同相。

LCD用三用電錶測量要很小心,同極性顯示同一字節很有可能造成損壞。



發表於 2014-3-20 17:32:18 | 顯示全部樓層
ysc 發表於 2014-3-20 05:02 PM static/image/common/back.gif
LCD字節與基板之間只要有電位差就會發生對比變化,也就是可以用來顯示圖形或文字,但若一直加著同極性電 ...

了解了,謝謝ysc兄,
難怪,有時會在有lcd的電路上看到79xx,
原來是這個道理,謝謝謝謝!
 樓主| 發表於 2014-3-20 21:54:21 | 顯示全部樓層
fatzeros 發表於 2014-3-20 05:32 PM static/image/common/back.gif
了解了,謝謝ysc兄,
難怪,有時會在有lcd的電路上看到79xx,
原來是這個道理,謝謝謝謝! ...

F0S大:
    應該可以不需要79XX,我查過網路,他們習慣用 XOR gate ,所以我就用軟體把它改變,因為LCD 的更新蘋率不高,所以速度上面就不要求太大,..使用 74HC595 同一字節當共同腳位給LO時 595就給HI,一段時間共同腳位變HI時候,595就給LO,這樣它會點亮了,後續要看看比較大的LCD會不會成功...
發表於 2014-3-20 22:46:41 | 顯示全部樓層
antlu 發表於 2014-3-20 09:54 PM static/image/common/back.gif
F0S大:
    應該可以不需要79XX,我查過網路,他們習慣用 XOR gate ,所以我就用軟體把它改變,因為LCD 的更 ...

阿乾大功力不淺囉!電子科班出身還不見得懂得如何正確驅動LCD,您更是利用軟體來解決交流驅動問題,厲害喔!

 樓主| 發表於 2014-3-20 23:22:17 | 顯示全部樓層
ysc 發表於 2014-3-20 10:46 PM static/image/common/back.gif
阿乾大功力不淺囉!電子科班出身還不見得懂得如何正確驅動LCD,您更是利用軟體來解決交流驅動問題,厲害 ...

YSC大:
  我是魯班師前"耍刨刀"!! 小問題讓我來回答就可以了!! 複雜的問題(包刮國外文獻)就要靠 YSC大 還有 SCOTTWANG 大解決! 這就是古人說的"有事弟子服其勞,有久肉先生"賺"!!
發表於 2014-3-23 01:57:50 | 顯示全部樓層
我只玩過LCM~原來LCD還有這麼多道理喔~

to antlu.. 你不是還有一個功課,我看到好多人叫你仿一台DCA75 pro 耶~~
看到我都心癢癢~~
 樓主| 發表於 2014-3-23 20:55:03 | 顯示全部樓層
jojoling 發表於 2014-3-23 01:57 AM static/image/common/back.gif
我只玩過LCM~原來LCD還有這麼多道理喔~

to antlu.. 你不是還有一個功課,我看到好多人叫你仿一台DCA75 pro ...

jojoling大:
   你就別笑我了!! 我的程式都是 CO 來 CO去!! 前幾天還為溫度計怎麼沒顯示溫度而"抓臭蟲",後來發現原來主程式忘了設定把I/O設成 類比輸入,設好了總算把溫度給顯示出來了,但是還有問題是 沒事小數點自動跑出來...還有,把電壓轉換成電阻的部分因為遇到浮點運算,問題更頭大,C程式一遇到小數點居然多了7~800 BYTE ...這都還要向你請教呢! 上次 XAIOLABA大給我一些資料才知道,浮點運算的精確度問題.... 我只會作玩具,至於DCA75 我想用買的比較快 ..哈哈哈!!!  
  我終於想到我的 87F51可以用在哪裡了!! 上次用 89C2051作的"馬桶補水不足警報器"功能已經完備了,可以量產了...或是18B20溫度計(因為 LED帽燈還有2000顆)
發表於 2014-3-23 23:59:11 | 顯示全部樓層
本帖最後由 jojoling 於 2014-3-24 12:32 AM 編輯

哈哈 "馬桶補水不足警報器" 這個有趣..
回答你一個問題,就是你的浮點運算,是用軟體模擬出來的,硬體不支援~所以程式會加上那麼多,很正常~
還有浮點數資料型態,本身就有幾種誤差會發生~
計算誤差~
截尾誤差~
程式寫的時後常會把它當整數型態而發生錯誤~ if( value1 == value2) or if(value1 == 3.1400000003) 事實上value1永遠只會趨近於 value2 或 value1只會趨近於3.1400000003~~而造成判斷永遠不成立而抓蟲抓到死~
 樓主| 發表於 2014-3-24 01:12:27 | 顯示全部樓層
jojoling 發表於 2014-3-23 11:59 PM static/image/common/back.gif
哈哈 "馬桶補水不足警報器" 這個有趣..
回答你一個問題,就是你的浮點運算,是用軟體模擬出來的,硬體不支 ...

浮點運算真的搞死人!! 作玩具之中 困擾的幾個動作除了浮點運算外,按鍵掃描短按 長按 跳彈這方面也沒寫好,RS232 送出/讀入資料,都還要多多練習,只有 I/O 還可以!
上次 作24C02的讀寫(時序)也差一點把MCU燒掉(改程式下載次數太多次了...)反正退休有的是"時間"!! 哈哈哈!!
發表於 2014-3-24 02:31:59 | 顯示全部樓層
喔~我懂了,你犯了一個大錯~
沒事不要用浮點數,依照你的程式,跟本不需要浮點數,你的問題是小數點,不該思考用浮點運算解決~
請用整數型態去設計,如需到小數第2位之類的問題,請用 原數值 x 100 來儲存~在顯示才轉換~
按鍵彈跳有用軟的,也有用硬的。用軟的就中斷發生 or detect到~ dealy..再檢查~復位了沒~然後繼續~
以前我超愛那個IC直接處理彈跳的,簡單。
 樓主| 發表於 2014-3-24 08:26:34 | 顯示全部樓層
jojoling 發表於 2014-3-24 02:31 AM static/image/common/back.gif
喔~我懂了,你犯了一個大錯~
沒事不要用浮點數,依照你的程式,跟本不需要浮點數,你的問題是小數點,不該 ...

哈哈!原來還有這樣的技巧,我的經驗算是嫩了下次來試試看能減肥多少!以前用printf也用了很大的容量之後也減肥了。
 樓主| 發表於 2014-3-24 10:03:21 | 顯示全部樓層
LCD顯示的溫度計終於出爐了!!

DSC07845.JPG

這是小改款 其中 ADC轉換由網路上取得的程式小修改,74HC595 串成四個這是 電子負載的程式取得的,LCD 驅動算是自己想出來的,每次顯示更新前都要把輸出清空成為 0XFF; 當CLOCK 轉態時候 所有7段顯示也要全部反向.

還有兩個問題 1.電源電壓變動對溫度改變影響頗大,因為 10K電阻與10K溫度NTC作分壓取出電壓來,電源變動會影響到分壓.
                   2.程式碼 1615byte 太大了,C 語言浮點運算改了又改沒有成功,有待 先進幫忙改一下程式,讓我模仿作為下一玩具的進步空間.

unsigned int transfer(unsigned char an)//溫度電阻=10k/(((N*2)/M)-1)
{
float PP,Kp,qq;
unsigned int Rt;
M=Read(an);// tc read out volt
N=Read(0);//2.5V參考電壓 P1^0
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
Rt=Kp;

/*        這部分也行
float PP,Kp;
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*2.5/N)*1000;//read an temp convert to mV       
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp;
*/       
return Rt;//return thermo-resister value
}



整個程式

/*-----------------------------------------------
20140308想要使用8951 驅動LCD 因為LCD都有單獨的字節而且要顯示的部分還要與 CLK反向才會點亮
CLK頻率為 32 167 200HZ COM加上CLK頻率 若是COM有4個那麼CLK就要加到這四個上面,一但CLK為LO時候原先的字節就要~ 反過來
AD轉換port 一定要設定否則會影響到熱敏電阻值的電壓
電壓變動對溫度顯示影響很大,可能跟取樣電壓分壓有關20140324
------------------------------------------------*/

#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h>
#define DataPort P1// display LED segment P1^1---a P1^2---b ...P1^7---g
#define DataPort2 P2
#define uchar unsigned char
#define uint   unsigned int;
sfr ADC_CONTR   =   0xBC;  //替代15F204EA
sfr ADC_RES     =   0xBD;   
sfr ADC_RESL    =   0xBE;   
sfr P1M0        =   0x92;  
sfr P1M1        =   0x91;   
sfr P1ASF       =   0x9D;  

unsigned int code tempresist[]={28709,27421,26200,25042,23943,22899,21908, 20967, 20072, 19221, 18412, 17642, 16910,16213, 15549,14916,14314,13740,13192,12670,12172, 11696,11243, 10809, 10395,10000,9622,9261, 8916, 8585, 8269, 7967,7677,7400,7135,
6880, 6637, 6403, 6179, 5964, 5758, 5561, 5371, 5189, 5014, 4846, 4685, 4530, 4381, 4238, 4101, 3968, 3841, 3719,
3601, 3487, 3378, 3273, 3172, 3074, 2980, 2890, 2803, 2718, 2637, 2559, 2483, 2411, 2340, 2272, 2207, 2144, 2082, 2023, 1966, 1911, 1858, 1807, 1757, 1709, 1662, 1617, 1573, 1531, 1491, 1451, 1413,
1376, 1340, 1305, 1271, 1239, 1207, 1177, 1147, 1118, 1090, 1063,1037, 1011,987,963,939,917,895,874,853,833,813,794,776,758
};//b值3435 25度 10k
unsigned char code  segment[10]={0x7e,0x0c,0xb6,0x9e,0xcc,0xda,0xfa,0x0e,0xfe,0xde};//
//unsigned char code grid[4]={0x02,0x04,0x08,0x10};// 100.0 位碼0>>100度 左移一位 0x7e,0x0c,0xb6,0x9e,0xcc,0xda,0xfa,0x0e,0xfe,0xde
unsigned int L,M,N,Q,ADC_DATA;//作為adc 計算溫度使用

unsigned char TempData[4];
bit ReadTempFlag;//定义读时间标志
sbit DriveBIT =P3^7;//接到P3^7
sbit SER = P3^4;// 74hc595 送出4組DATA給LCD 7段*4字使用
sbit Latch = P3^3;
sbit Clk = P3^2;
sbit DQ=P3^0;//ds18b20 端口
uchar K;//display count
//unsigned int aa,ba;
//unsigned int TempH,TempL,temp;//16bit temp 是剛剛讀取的溫度數值 TempH 是整數部分 TempL 是小數部分
void Send595(unsigned char Dat) ;//串到並呼叫程式
void Send4byte(unsigned char Dat1,unsigned char Dat2,unsigned char Dat3,unsigned char Dat4);//送出4byte 由小數開始先送出
void Trans4(void);//轉換溫度4位到顯示暫存器TempData[0~3]供顯示之用
void Display(void);//顯示程式 呼叫 送出4byte
void Init_Timer0(void);//定时器初始化
void DelayUs2x(uchar t);
void DelayMs(uchar t);
unsigned char Compare_tempres (unsigned int);
//unsigned int ReadTemperature(void);
//bit Init_DS18B20(void);
//uchar ReadOneChar(void);
//void WriteOneChar(uchar dat);
//void TempPRo (void);
unsigned int TP0,P0n;
unsigned char Rtemp0;
//74hc595 轉換的串—並處理
//*******************************************
void Send595(unsigned char Dat)
{
         unsigned char i;
         for (i=0;i<8;i++)
         {
                 Clk=0;
                 SER=Dat & 0x80;
                 _nop_();        
                 Dat<<=1;
                 Clk=1;
                 _nop_();        
         }
         Latch=0;
         _nop_();        
         _nop_();
         Latch=1;
         _nop_();
         _nop_();
}

void Send4byte(unsigned char Dat1,unsigned char Dat2,unsigned char Dat3,unsigned char Dat4)
{
        //最小位數先送出
         Send595(Dat1);//MIN,0.1c
         Send595(Dat2);//10MIN,1c
               Send595(Dat3);//HR,10c
         Send595(Dat4);//10HR,100c
}

//Send4byte(10hr,hr,10min,min);

void Trans4(void)//轉換溫度4位到顯示暫存器TempData[0~3]供顯示之用
{
        if(Rtemp0/100==0)
         TempData[0]=0;
        else
      TempData[0]=segment[Rtemp0/100]; //十位温度
   if((Rtemp0/100==0)&&((Rtemp0%100)/10==0))//消隐
          TempData[1]=0;//0 表示不顯示
        else
   TempData[1]=segment[(Rtemp0%100)/10]; //十位温度       
//         TempData[1]= TempData[1]|0x01;
   TempData[2]=segment[(Rtemp0%100)%10]; //个位温度,带小数?
         TempData[3]=segment[P0n];
         TempData[3]= TempData[3]|0x01;
}



/* 顯示用函數 用於驅動595做成靜態顯示 LCD
顯示四位數字 1200 0最先送出1最後送出
8bit都要控制否則小數點會有亂顯示,lcd 接腳接地無效一定要驅動
*/
void Display(void)
{

        Send4byte(0xff,0xff,0xff,0xff);//清除lcd的內容       
          if (DriveBIT==0)//為了反向 正向交互所以需要因應而把輸出作為互補
         {
                 Send4byte(TempData[3],TempData[2],TempData[1],TempData[0]);
         }
         else
         {
                 Send4byte(~TempData[3],~TempData[2],~TempData[1],~TempData[0]);
         }
}

/*******************************************************************
adc程式
*******************************************************************/
unsigned int Read (unsigned char CHA){
unsigned char AD_FIN=0; //

    CHA &= 0x07;            
    ADC_CONTR = 0x60;
    _nop_();
    ADC_CONTR |= CHA;      
    _nop_();
    ADC_CONTR |= 0x80;      
    DelayMs(1);           

    ADC_CONTR |= 0x08;  
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    while (AD_FIN ==0){   
    AD_FIN = (ADC_CONTR & 0x10);
    }
    ADC_CONTR &= 0xE7;     
                ADC_DATA=ADC_RES*4+ADC_RESL;               
return (ADC_DATA);         
}

unsigned int transfer(unsigned char an)//溫度電阻=10k/(((N*2)/M)-1)
{
float PP,Kp,qq;
unsigned int Rt;
M=Read(an);// tc read out volt
N=Read(0);//2.5V參考電壓 P1^0
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
Rt=Kp;

/*       
float PP,Kp;
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*2.5/N)*1000;//read an temp convert to mV       
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp;
*/       
return Rt;//return thermo-resister value
}







/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
//TH0=0x00;              //给定初值
//TL0=0x00;
EA=1;            //总中断打开
ET0=1;           //定时器中断打开
TR0=1;           //定时器开关打开
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1
{
static unsigned int num;//cnt;

TH0=(65536-20000)/256;                  //重新赋值 20ms
TL0=(65536-20000)%256;
  num++;
        DriveBIT  = (!DriveBIT);
        Display();//every 10ms display 1 times
if(num==30)        //減少更新次數
   {
    num=0;
    ReadTempFlag=1; //读标志位置1
                 K++;
                 if(K>100)
                 {       
                         K=0;
                         }
               
                 
        }
}


/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(uchar t)
{   
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(uchar t)
{     
while(t--)
{
     //大致延时1mS
     DelayUs2x(245);
         DelayUs2x(245);
}
}

unsigned char Compare_tempres(unsigned int TR)
{
unsigned char cmp_cnt;
cmp_cnt =0;
while (TR<tempresist[cmp_cnt])
{
  cmp_cnt++;
  if (cmp_cnt>100)
  break;
}
return cmp_cnt;
}
   



/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{
P1M0 = 0xff; //ad port 設定
P1M1 = 0x00; //P1.0
P1ASF=0xff;        //all analog in put mode
       
DriveBIT=0;
Init_Timer0();

while (1)         //主循环
  {
       
   if(ReadTempFlag==1)//每隔 10ms*500
    {
                         ReadTempFlag=0;                       
                         DelayMs(250);       
       DelayMs(250);

                        TP0= transfer(1);//read chanel 2 resister value
                        Rtemp0=Compare_tempres(TP0);// 查表取出TP0的溫度值
                        P0n=((tempresist[Rtemp0-1]-TP0)*10)/(tempresist[Rtemp0-1]-tempresist[Rtemp0]);//換算小數點的值線性值
                        Trans4();//轉換成為4位數
    }                               
  }
}


評分

4

查看全部評分

發表於 2014-3-25 19:44:52 | 顯示全部樓層
本帖最後由 jojoling 於 2014-3-25 08:08 PM 編輯

給你一個最簡單的答案~但不是最佳的~

unsigned int transfer(unsigned char an)//溫度電阻=10k/(((N*2)/M)-1)
{
unsigned long PP,Kp,qq;
unsigned int Rt;
M=Read(an);// tc read out volt
N=Read(0);//2.5V參考電壓 P1^0
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
Rt=Kp;

/*        這部分也行
float PP,Kp;
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*25/N)*1000;//read an temp convert to mV        
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp/10;
*/        
return Rt;//return thermo-resister value
}


幾個問題~

1.資料型態是寫程式很重要的基礎,一定要特別了解你對那個cpu / compiler的定義~
不確定你用的是那個compiler..假設你是用Keil C
http://www.keil.com/support/man/docs/c51/c51_le_datatypes.htm

2.資料運算,會有有效資料的rang.需加入考量,如2個16bits 值做運算,你如果不用 32bit來放,一定會溢位~組語會很容易看出~

3.在運算式 or 程式裏,不要為了省略打字,而不把程式分清楚~很容易造成除錯困難~難懂~bug....
在以前,有些bug是來自compiler.現在這些問會比較少~但~還是有可能發生~
example:
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
何不直接把括號加進去~你做的人,看的人都可很快了解~


4.這樣寫的程式,產生誤差太多次~一次除法就產生一次~如果是整數運算的話更大~
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
需先優化~降低計算誤差

5.最好把你要轉換的人看懂的計算式放進去在轉換的那邊~不然很難看的懂~
example:

M=Read(an);// tc read out volt count ,
N=Read(0);//參考電壓count 2.5v

// 轉換公式1~ F(X) = X^3 + 3X + 5.......
PP=(M*2‧5/N)*1000;//read an temp convert to mV
// 轉換公式2~ F(Y) = 3N + c       
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp;

:sam45
發表於 2014-3-25 20:27:54 | 顯示全部樓層
突然覺得阿乾在考我試........

return (5*M)/(2*N); <== 答案

相片 2014-3-25 下午8 21 23.jpg


n_147|
發表於 2014-3-25 22:51:12 | 顯示全部樓層
本帖最後由 jojoling 於 2014-3-25 10:55 PM 編輯

幾點建議~~

-------
/*-----------------------------------------------
20140308想要使用8951 驅動LCD 因為LCD都有單獨的字節而且要顯示的部分還要與 CLK反向才會點亮
CLK頻率為 32 167 200HZ COM加上CLK頻率 若是COM有4個那麼CLK就要加到這四個上面,一但CLK為LO時候原先的字節就要~ 反過來
AD轉換port 一定要設定否則會影響到熱敏電阻值的電壓
電壓變動對溫度顯示影響很大,可能跟取樣電壓分壓有關20140324
------------------------------------------------*/

#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h>
#define DataPort P1// display LED segment P1^1---a P1^2---b ...P1^7---g
#define DataPort2 P2


* 資料型態的定義,用 typedef會比較好,用 #define在很多情況會有很多狀況~
* 重新定義的資料型態,如能放在另一隻 h 檔案,有助於程式易讀性~資料型態的多重使用性~隱藏次要資訊~

#define uchar unsigned char
#define uint   unsigned int;

typedef UINT unsigned int; or typedef uint unsigned int;

* 另一點,就是既然你打算重新定義 unsigned int 的資料型態~你的程式裏,在沒特定必要的,不要2種都用,有助於簡潔~易讀
* 簡潔不是字打的少就是簡潔,需注意~


* 不同硬體的設定描述,另用開一隻  STC_XXX_51.h 來描述,也是可增加程式易讀性~資料型態的多重使用性~隱藏次要資訊~
sfr ADC_CONTR   =   0xBC;  //替代15F204EA
sfr ADC_RES     =   0xBD;   
sfr ADC_RESL    =   0xBE;   
sfr P1M0        =   0x92;  
sfr P1M1        =   0x91;   
sfr P1ASF       =   0x9D;  

#include <STC_xxx_51.h>

unsigned int code tempresist[]={28709,27421,26200,25042,23943,22899,21908, 20967, 20072, 19221, 18412, 17642, 16910,16213, 15549,14916,14314,13740,13192,12670,12172, 11696,11243, 10809, 10395,10000,9622,9261, 8916, 8585, 8269, 7967,7677,7400,7135,
6880, 6637, 6403, 6179, 5964, 5758, 5561, 5371, 5189, 5014, 4846, 4685, 4530, 4381, 4238, 4101, 3968, 3841, 3719,
3601, 3487, 3378, 3273, 3172, 3074, 2980, 2890, 2803, 2718, 2637, 2559, 2483, 2411, 2340, 2272, 2207, 2144, 2082, 2023, 1966, 1911, 1858, 1807, 1757, 1709, 1662, 1617, 1573, 1531, 1491, 1451, 1413,
1376, 1340, 1305, 1271, 1239, 1207, 1177, 1147, 1118, 1090, 1063,1037, 1011,987,963,939,917,895,874,853,833,813,794,776,758
};//b值3435 25度 10k
unsigned char code  segment[10]={0x7e,0x0c,0xb6,0x9e,0xcc,0xda,0xfa,0x0e,0xfe,0xde};//
//unsigned char code grid[4]={0x02,0x04,0x08,0x10};// 100.0 位碼0>>100度 左移一位 0x7e,0x0c,0xb6,0x9e,0xcc,0xda,0xfa,0x0e,0xfe,0xde
unsigned int L,M,N,Q,ADC_DATA;//作為adc 計算溫度使用

unsigned char TempData[4];
bit ReadTempFlag;//定义读时间标志

* 同屬於硬體的設定描述~請移到上述 STC_XXX_51.h 裏去~
sbit DriveBIT =P3^7;//接到P3^7
sbit SER = P3^4;// 74hc595 送出4組DATA給LCD 7段*4字使用
sbit Latch = P3^3;
sbit Clk = P3^2;
sbit DQ=P3^0;//ds18b20 端口



uchar K;//display count
//unsigned int aa,ba;
//unsigned int TempH,TempL,temp;//16bit temp 是剛剛讀取的溫度數值 TempH 是整數部分 TempL 是小數部分
void Send595(unsigned char Dat) ;//串到並呼叫程式
void Send4byte(unsigned char Dat1,unsigned char Dat2,unsigned char Dat3,unsigned char Dat4);//送出4byte 由小數開始先送出
void Trans4(void);//轉換溫度4位到顯示暫存器TempData[0~3]供顯示之用
void Display(void);//顯示程式 呼叫 送出4byte
void Init_Timer0(void);//定时器初始化
void DelayUs2x(uchar t);
void DelayMs(uchar t);
unsigned char Compare_tempres (unsigned int);
//unsigned int ReadTemperature(void);
//bit Init_DS18B20(void);
//uchar ReadOneChar(void);
//void WriteOneChar(uchar dat);
//void TempPRo (void);
unsigned int TP0,P0n;
unsigned char Rtemp0;
//74hc595 轉換的串—並處理
//*******************************************
void Send595(unsigned char Dat)
{
         unsigned char i;
         for (i=0;i<8;i++)
         {
                 Clk=0;
                 SER=Dat & 0x80;
                 _nop_();        
                 Dat<<=1;
                 Clk=1;
                 _nop_();        
         }
         Latch=0;
         _nop_();        
         _nop_();
         Latch=1;
         _nop_();
         _nop_();
}

void Send4byte(unsigned char Dat1,unsigned char Dat2,unsigned char Dat3,unsigned char Dat4)
{
        //最小位數先送出
         Send595(Dat1);//MIN,0.1c
         Send595(Dat2);//10MIN,1c
               Send595(Dat3);//HR,10c
         Send595(Dat4);//10HR,100c
}

//Send4byte(10hr,hr,10min,min);

void Trans4(void)//轉換溫度4位到顯示暫存器TempData[0~3]供顯示之用
{
        if(Rtemp0/100==0)
         TempData[0]=0;
        else
      TempData[0]=segment[Rtemp0/100]; //十位温度
   if((Rtemp0/100==0)&&((Rtemp0%100)/10==0))//消隐
          TempData[1]=0;//0 表示不顯示
        else
   TempData[1]=segment[(Rtemp0%100)/10]; //十位温度        
//         TempData[1]= TempData[1]|0x01;
   TempData[2]=segment[(Rtemp0%100)%10]; //个位温度,带小数?
         TempData[3]=segment[P0n];
         TempData[3]= TempData[3]|0x01;
}



/* 顯示用函數 用於驅動595做成靜態顯示 LCD
顯示四位數字 1200 0最先送出1最後送出
8bit都要控制否則小數點會有亂顯示,lcd 接腳接地無效一定要驅動
*/
void Display(void)
{

        Send4byte(0xff,0xff,0xff,0xff);//清除lcd的內容        
          if (DriveBIT==0)//為了反向 正向交互所以需要因應而把輸出作為互補
         {
                 Send4byte(TempData[3],TempData[2],TempData[1],TempData[0]);
         }
         else
         {
                 Send4byte(~TempData[3],~TempData[2],~TempData[1],~TempData[0]);
         }
}

/*******************************************************************
adc程式
*******************************************************************/
unsigned int Read (unsigned char CHA){
unsigned char AD_FIN=0; //

    CHA &= 0x07;            
    ADC_CONTR = 0x60;
    _nop_();
    ADC_CONTR |= CHA;      
    _nop_();
    ADC_CONTR |= 0x80;      
    DelayMs(1);           

    ADC_CONTR |= 0x08;  
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    while (AD_FIN ==0){   
    AD_FIN = (ADC_CONTR & 0x10);
    }
    ADC_CONTR &= 0xE7;     
                ADC_DATA=ADC_RES*4+ADC_RESL;               
return (ADC_DATA);         
}

unsigned int transfer(unsigned char an)//溫度電阻=10k/(((N*2)/M)-1)
{
float PP,Kp,qq;
unsigned int Rt;
M=Read(an);// tc read out volt
N=Read(0);//2.5V參考電壓 P1^0
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
Rt=Kp;

/*        
float PP,Kp;
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*2.5/N)*1000;//read an temp convert to mV        
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp;
*/        
return Rt;//return thermo-resister value
}







/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
//TH0=0x00;              //给定初值
//TL0=0x00;
EA=1;            //总中断打开
ET0=1;           //定时器中断打开
TR0=1;           //定时器开关打开
}
/*------------------------------------------------
                 定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1
{
static unsigned int num;//cnt;

TH0=(65536-20000)/256;                  //重新赋值 20ms
TL0=(65536-20000)%256;
  num++;
        DriveBIT  = (!DriveBIT);
        Display();//every 10ms display 1 times
if(num==30)        //減少更新次數
   {
    num=0;
    ReadTempFlag=1; //读标志位置1
                 K++;
                 if(K>100)
                 {        
                         K=0;
                         }
               
                 
        }
}


/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(uchar t)
{   
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(uchar t)
{     
while(t--)
{
     //大致延时1mS
     DelayUs2x(245);
         DelayUs2x(245);
}
}

unsigned char Compare_tempres(unsigned int TR)
{
unsigned char cmp_cnt;
cmp_cnt =0;
while (TR<tempresist[cmp_cnt])
{
  cmp_cnt++;
  if (cmp_cnt>100)
  break;
}
return cmp_cnt;
}
   



/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{
P1M0 = 0xff; //ad port 設定
P1M1 = 0x00; //P1.0
P1ASF=0xff;        //all analog in put mode
        
DriveBIT=0;

* 建議在寫韌體的時後,把所有的硬體的初始化,移至特定的程式如 hw_init() 裏~再由裏面依序呼叫執行~
* 同時可把硬體相關的資訊隱藏在特定的副程式集了(如果單位執行時間,stack縱深不是太緊)~有助於主程式是只探討功能,流程,演算法~之類的~

*  example:
*  hw_init() {
*   init_gpio();
*   init_timer1();
*   init_ADC_channel_1();
*   ..........
*  }

Init_Timer0();

while (1)         //主循环
  {
        
   if(ReadTempFlag==1)//每隔 10ms*500
    {
                         ReadTempFlag=0;                        
                         DelayMs(250);        
       DelayMs(250);

                        TP0= transfer(1);//read chanel 2 resister value
                        Rtemp0=Compare_tempres(TP0);// 查表取出TP0的溫度值
                        P0n=((tempresist[Rtemp0-1]-TP0)*10)/(tempresist[Rtemp0-1]-tempresist[Rtemp0]);//換算小數點的值線性值
                        Trans4();//轉換成為4位數
    }                                
  }
}


 樓主| 發表於 2014-3-26 00:35:13 | 顯示全部樓層
本帖最後由 antlu 於 2014-3-26 12:43 AM 編輯
jojoling 發表於 2014-3-25 10:51 PM static/image/common/back.gif
幾點建議~~

-------


jojoling 大:
   拜謝!! Orz.......  感謝,花了這麼多時間看過我的程式!!
   因為沒有正式上過課!! 所以寫程式像是"土八路"(抗戰時期的共匪,不是正規軍) 你的建議我會慢慢了解,消化,進而改變習慣...還有那些計算式對我來說算是很困難的,以前唸書時候數學物理最差(所以唸文組),導公式就一個頭兩個大...不懂的在私下發消息跟你請教好了,再次感謝!!
發表於 2014-3-26 18:24:00 | 顯示全部樓層
阿乾大大~~
我.....錯了,我把你的數學題目解錯了~
答案應該是這個
return (5000*M)/N;
相片 2014-3-26 下午6 12 37.jpg

n_158|
 樓主| 發表於 2014-3-26 19:57:06 | 顯示全部樓層
jojoling 發表於 2014-3-26 06:24 PM static/image/common/back.gif
阿乾大大~~
我.....錯了,我把你的數學題目解錯了~
答案應該是這個

JOJOLING大:
   我昨天把計算式改了一下,發現好像都不太對!! 那個  "減1"不能省,因為計算出來的數值 758~28709 範圍算是很大,不知道是不是我計算式出問題還是... 主要就是分壓算出電阻值 5V加到 10K電阻和 758~28709範圍的溫度變阻上得到的"分壓" 若是溫度電阻(NTC)在25度時候就是 10K 它的輸出就是 2.5V 得到的M值應該是 512而 2.5V參考電壓N值是512(10BIT ADC 的一半),只是程式改成 unsigned long ... 結果卻不行

case1
        unsigned long PP,Kp,qq;//1019byte display 25.8c but no work
unsigned int Rt;
M=Read(an);// tc read out volt
N=Read(0);//2.5V參考電壓 P1^0
qq=2*N/5;//-----------------------順序有差異喔
PP=M/qq*1000;//----------------順序有差異喔
Kp=10000/((5000/PP)-1);        //float caculate
Rt=Kp;
return Rt;//return thermo-resister value        


case2  ok
float PP,Kp;
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*2.5/N)*1000;//read an temp convert to mV       
Kp=10000/(5000/PP-1);        //float caculate
//Rt=Kp;
return Kp;//Rt;//return thermo-resister value
       
case 3
        unsigned long PP,Kp;// float 1333byte display 0.0c  unsigned long 911byte display 101.8
unsigned int Rt;
M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
PP=(M*25/N)*1000;//read an temp convert to mV       
Kp=10000/(5000/PP-1);        //float caculate
Rt=Kp/10;
return Rt;//return thermo-resister value

case 4
        M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count
       
        return (5*M)/(2*N);// 656byte display 101.8c
       
       
        case5
float PP,Kp,qq;//1613byte display 22.6c
unsigned int Rt;
                M=Read(an);// tc read out volt count
N=Read(0);//參考電壓count

Kp=10000/(5/((2.5*M/N)-1));
        Rt=Kp;
        return Rt;//(M)/(N)*2.5;// 1605byte display 57.6c


發表於 2014-3-26 21:01:34 | 顯示全部樓層
阿乾~你的 M,N的值是多少?對映的Rt 應該多少?
列個2組 M,N及相對的 Rt 值出來~
 樓主| 發表於 2014-3-26 22:11:01 | 顯示全部樓層
jojoling 發表於 2014-3-26 09:01 PM static/image/common/back.gif
阿乾~你的 M,N的值是多少?對映的Rt 應該多少?
列個2組 M,N及相對的 Rt 值出來~ ...

JOJOLING大:
   N 因為是參考電壓所以應該在 512 左右, M的值就是分壓值
   2.5V/5V*1024=512
   5V*758/(758+10000)=0.352V   0.352V/5V*1024=72
   5V*28709/(28709+10000)=3.708V  3.708V/5*1024=759
發表於 2014-3-26 22:20:14 | 顯示全部樓層
這時後你應該寫成這樣啦:
跟據電路理論數據~~
當M=100, N=200時,Rt為30.0
當M=200,N=50時,Rt應為50.4
這樣才有辨法分析誤差之由來...
n_167|
 樓主| 發表於 2014-3-26 22:38:51 | 顯示全部樓層
jojoling 發表於 2014-3-26 10:20 PM static/image/common/back.gif
這時後你應該寫成這樣啦:
跟據電路理論數據~~
當M=100, N=200時,Rt為30.0

jojoling大:
   
   了解!!

M        N        10K        溫度阻值        refV        test V
512        512        10000        10000        2.5        2.5
999        512        10000        399600        2.5        4.877929688
1        512        10000        9.775171065        2.5        0.004882813
128        512        10000        1428.571429        2.5        0.625
256        512        10000        3333.333333        2.5        1.25
666        512        10000        18603.35196        2.5        3.251953125
777        512        10000        31457.48988        2.5        3.793945313
發表於 2014-3-26 23:14:14 | 顯示全部樓層
參考電壓2.5V~只是在做修正的~
那 2.5V~對映的電阻值是多少?對映的溫度是多少?
 樓主| 發表於 2014-3-26 23:53:15 | 顯示全部樓層
jojoling 發表於 2014-3-26 11:14 PM static/image/common/back.gif
參考電壓2.5V~只是在做修正的~
那 2.5V~對映的電阻值是多少?對映的溫度是多少?
...

若是分壓為2.5V 就是表示 溫度電阻的阻值10K,依照這溫度電阻的特性 25度時候它的阻值是10K.
這個溫度電阻的阻值隨溫度變化公式是 =10000*EXP(溫度電阻的B值3435*((1/(實際溫度+273.13))-(1/(25度標準溫度+273.13))))  得到0度 28709歐姆  100度 987歐姆
發表於 2014-3-27 00:41:10 | 顯示全部樓層
你的 Rt 與 Kp各自代表什麼?
你給的表裏沒寫

同時那個 Test V又是什麼?
 樓主| 發表於 2014-3-27 01:37:58 | 顯示全部樓層
jojoling 發表於 2014-3-27 12:41 AM static/image/common/back.gif
你的 Rt 與 Kp各自代表什麼?
你給的表裏沒寫

Rt 是指 實際的阻值因為是 整數,Kp是浮點 我當時怕浮點出來 LCM 不接受所以把 浮點 轉換成 整數.
TEST V 是讀出的電壓值,也就是分壓出來的電壓,M就是利用這個電壓經過AD轉換得出的 count 數.
您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2024-11-22 09:58 PM , Processed in 0.285245 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.