51微控制器解析衛星定位資料來源碼+DHT11,1602顯示

weixin_33720956發表於2018-08-10
12993316-76000d7a5e8d6620.jpg

什麼都不多說,直接看程式碼:

#include <REG52.H>
#include <stdio.h>
#include <intrins.h>
////////////========================================================================================

/*
1602A(16*2)模擬口線接線方式
連線線圖:   
       ---------------------------------------------------
       |LCM-----51   |  LCM-----51   |  LCM------51      |
       --------------------------------------------------|
       |DB0-----P0.0 |  DB4-----P0.4 |  RW-------P1.5    |
       |DB1-----P0.1 |  DB5-----P0.5 |  RS-------P1.4    |
       |DB2-----P0.2 |  DB6-----P0.6 |  E--------P1.6    |
       |DB3-----P0.3 |  DB7-----P0.7 |  V0接10K電阻到GND |
       ---------------------------------------------------
溫溼度DHT11接線:模組data接   P3^2
******************/
sbit Data= P3^2;   //定義資料線      溫溼度感測器DHT11資料接入
unsigned char rec_dat[9];   //用於顯示的接收資料陣列  

unsigned char  flag_rec=0;     
unsigned char  num_rec=0;
   
unsigned char code kaijihuamian[]="BeiDou_DHT11";    //開機顯示
unsigned char code kaijihuamian2[]="AnShan_17-12-01";
unsigned char code receiving[]="Receiving!";
unsigned char code nodata[]="No BD data!";
unsigned char code LCD_161[]="BD_HeGuang Studios";
unsigned char code LCD_162[]="TEL:15117255049";

char code TIME_AREA= 8;     //時區
unsigned char flag_data;    //資料標誌位

//BD資料儲存陣列
unsigned char JD[10];       //經度
unsigned char JD_a;     //經度方向
unsigned char WD[9];        //緯度
unsigned char WD_a;     //緯度方向
unsigned char date[6];      //日期
unsigned char time[6];      //時間
unsigned char time1[6];     //時間
unsigned char speed[5]={'0','0','0','0','0'};       //速度
unsigned char high[6];      //高度
unsigned char angle[5];     //方位角
unsigned char use_sat[2];   //使用的衛星數
unsigned char total_sat[2]; //天空中總衛星數
unsigned char lock;         //定位狀態

//串列埠中斷需要的變數
unsigned char seg_count;    //逗號計數器
unsigned char dot_count;    //小數點計數器
unsigned char byte_count;   //位數計數器
unsigned char cmd_number;   //命令型別
unsigned char mode;         //0:結束模式,1:命令模式,2:資料模式
unsigned char buf_full;     //1:整句接收完成,相應資料有效。0:快取資料無效。
unsigned char cmd[5];       //命令型別儲存陣列

sbit rs = P1^4;
sbit rw = P1^5;
sbit ep = P1^6;

//-----------------------------------------------------------------------------------------------
//延時子程式
void delayms(unsigned char ms)
{
    unsigned char i;
    while(ms--)
    {
    for(i = 0; i < 120; i++);
    }
}


bit lcd_bz(void)
{                           // 測試LCD忙碌狀態
    bit result;
    rs = 0;
    rw = 1;
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    result = (bit)(P0 & 0x80);
    ep = 0;
    return result;  
}

void lcd_wcmd(unsigned char cmd)
{                           // 寫入指令資料到LCD
    while(lcd_bz());
    rs = 0;
    rw = 0;
    ep = 0;
    _nop_();
    _nop_();    
    P0 = cmd;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 0;     
}

void lcd_pos(unsigned char pos)
{                           //設定顯示位置
    lcd_wcmd(pos | 0x80);
}

void lcd_pos_2(unsigned char pos)
{                           //設定顯示位置
    lcd_wcmd(pos | 0xC0);
}

void lcd_wdat(unsigned char dat)    
{                           //寫入字元顯示資料到LCD
    while(lcd_bz());
    rs = 1;
    rw = 0;
    ep = 0;
    P0 = dat;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 1;
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    ep = 0; 
}
void lcd_string(unsigned char *ptr,unsigned char pos)
{

    unsigned char i;
    lcd_pos(pos);
    while(*(ptr+i) != '\0')
    {                       // 顯示字元"welcome!"
        lcd_wdat(*(ptr+i));
        i++;
    }       

}

lcd_init()
{                           //LCD初始化設定
    lcd_wcmd(0x38);         //
    delayms(1);
    lcd_wcmd(0x0c);         //
    delayms(1);
    lcd_wcmd(0x06);         //
    delayms(1);
    lcd_wcmd(0x01);         //清除LCD的顯示內容
    delayms(1);
}
//-----------------------------------------------------------------------------------------------
//延時子程式
void delaym(unsigned int ms)
{
    unsigned int i,j;
    for(i = 0;i < ms ;i++)
    {
        for(j = 0;j < 125 ;j++)
            ;
    }
}

void DHT11_delay_us(unsigned char n)
{
    while(--n);
}

void DHT11_delay_ms(unsigned int z)
{
   unsigned int i,j;
   for(i=z;i>0;i--)
      for(j=110;j>0;j--);
}

void DHT11_start()
{
   Data=1;
   DHT11_delay_us(2);
   Data=0;
   DHT11_delay_ms(20);   //延時18ms以上
   Data=1;
   DHT11_delay_us(30);
}
//-----------------------   溫溼度讀取   -----------------------------------

unsigned char DHT11_rec_byte()      //接收一個位元組
{
   unsigned char i,dat=0;
  for(i=0;i<8;i++)    //從高到低依次接收8位資料
   {          
      while(!Data);   ////等待50us低電平過去
      DHT11_delay_us(8);     //延時60us,如果還為高則資料為1,否則為0 
      dat<<=1;           //移位使正確接收8位資料,資料為0時直接移位
      if(Data==1)    //資料為1時,使dat加1來接收資料1
         dat+=1;
      while(Data);  //等待資料線拉低    
    }  
    return dat;
}

void DHT11_receive()      //接收40位的資料
{
    unsigned char R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; 
    DHT11_start();
    if(Data==0)
    {
        while(Data==0);   //等待拉高     
        DHT11_delay_us(40);  //拉高後延時80us
        R_H=DHT11_rec_byte();    //接收溼度高八位  
        R_L=DHT11_rec_byte();    //接收溼度低八位  
        T_H=DHT11_rec_byte();    //接收溫度高八位  
        T_L=DHT11_rec_byte();    //接收溫度低八位
        revise=DHT11_rec_byte(); //接收校正位

        DHT11_delay_us(25);    //結束

        if((R_H+R_L+T_H+T_L)==revise)      //校正
        {
            RH=R_H;
            RL=R_L;
            TH=T_H;
            TL=T_L;
        } 
        /*資料處理,方便顯示*/
        rec_dat[0]='0'+(RH/10);
        rec_dat[1]='0'+(RH%10);
        rec_dat[2]='R';
        rec_dat[3]='H';
        rec_dat[4]=' ';
        rec_dat[5]=' ';
        rec_dat[6]='0'+(TH/10);
        rec_dat[7]='0'+(TH%10);
        rec_dat[8]='C';
    }
}

//-------------------------   <初始化設定 結束>   -------------------------------------
void DHT11_main(unsigned int zxi){      
    lcd_init();            //初始化1602
    lcd_wcmd(0x01);     //清除LCD的顯示內容
    delaym(1);
    //============溫溼度讀取============================================================
    DHT11_delay_ms(1500);    //DHT11上電後要等待1S以越過不穩定狀態在此期間不能傳送任何指令
  DHT11_receive();  
    lcd_pos(3);         // 設定顯示位置
    for(zxi = 0;zxi<6;zxi++)
    {
        lcd_wdat(kaijihuamian[zxi+6]);  // 顯示字元dht11
    }
    zxi = 0;
    delayms(100);
    lcd_pos_2(2);              
    while(rec_dat[zxi] != '\0'){
        lcd_wdat(rec_dat[zxi]); //顯示
        zxi++;
    }
    delaym(1000);               
}
//==================================================================================
//傳送位元組
void sendbyte(unsigned char ptr)
{
    SBUF=ptr;
    while(TI==0);
    TI=0;
}
//---------------------------------------------------------------------------
//傳送資料流
void sendstring(unsigned char *ptr,unsigned char len)
{

    int i=0;
    while(i<len)
    {   
        SBUF=*(ptr+i);               //SUBF接受/傳送緩衝器
        while(TI==0);
        TI=0;
        i++;    
    }
    num_rec=0;  

}
void init_all(void) //9600  11.05926
{

    SCON = 0x50;      //REN=1允許序列接受狀態,串列埠工作模式1                  
    TMOD|= 0x20;      //定時器工作方式2                    
    PCON|= 0x80;                                                          
    TH1 = 0xFa;     //baud*2  /* reload value 9600、資料位8、停止位1。效驗位無 (11.0592)             
  TL1 = 0xF3;         
    TR1  = 1;                                                             
    ES   = 1;        //開串列埠中斷                  
    EA   = 1;        // 開總中斷
    lcd_init() ;

} 
//將UTC時間轉成BJ時間
void trans_time(void)
{
    unsigned char temp,hour_shi,hour_ge;
    temp=(time[0]-'0')*10+(time[1]-'0');
    if(temp<=16)
    {
        temp=temp+8;
        hour_shi=temp/10;
        hour_ge=temp%10;
        time[0]=hour_shi+'0';
        time[1]=hour_ge+'0';    
    }
    else
    {
        temp=temp+8-24;
        time[0]='0';
        time[1]=temp%10+'0';    
    }
} 
//判斷是否有BD資料 有1,無0
bit BD_data(void)
{
    if(buf_full&0x01!=0)
        return 1;
    else 
        return 0;   
}
//----------------------------------------------------------------------------
void main () 
{   
    unsigned int X;
    unsigned char i;
    init_all(); 
    lcd_wcmd(0x01);         //清除LCD的顯示內容
    delayms(10);
    i = 0;
    X = 0;
    lcd_pos(1);         // 設定顯示位置
    while(kaijihuamian[i] != '\0')
    {
        lcd_wdat(kaijihuamian[i]);  // 顯示字元時間
        i++;
    }
    delayms(10);
    i=0  ;
    lcd_pos_2(0);           // 設定顯示位置
    while(kaijihuamian2[i] != '\0')
    {
        lcd_wdat(kaijihuamian2[i]); // 顯示字元時間
        i++;
    }
    i = 0;
    delayms(5000);
    lcd_wcmd(0x01);         //清除LCD的顯示內容
    delayms(10);
    while(1)
    {
        if(flag_data==0)// 如果沒有資料
        {
            lcd_wcmd(0x01);         //清除LCD的顯示內容
            delayms(10);
            i=0  ;
            lcd_pos(2);         // 設定顯示位置
            while(nodata[i] != '\0')
            {
                lcd_wdat(nodata[i]);    // 顯示字元
                i++;
            }
            delayms(1000);
            lcd_wcmd(0x01);         //清除LCD的顯示內容
            delayms(10);    
            //第三頁開始==================================================================
            DHT11_main(i);// 顯示字元DHT11 溫度 溼度 資訊
            delaym(3000);
            i = 0;
            lcd_wcmd(0x01);         
            delaym(1);
            //第四頁開始==================================================================
            lcd_pos(0);         // 設定顯示位置
            while(LCD_161[i] != '\0'){
                lcd_wdat(LCD_161[i]);   // 顯示字元禾灮資訊
                i++;
            }
            delayms(1);
            i=0  ;
            lcd_pos_2(0);           // 設定顯示位置
            while(LCD_162[i] != '\0'){
                lcd_wdat(LCD_162[i]);   // 顯示字元禾灮資訊
                i++;
            }   
            //結束==================================================================
            delayms(5000);
            lcd_wcmd(0x01);         //清除LCD的顯示內容
            delayms(1);
        }
        if(flag_rec==1)             //data 解碼完畢
        {
            flag_rec=0;  //清資料有效標誌位         
            if (lock==1) //如果已經定位
            {

                for(X;X <10;X++){           
                    trans_time();//UTC--BJ TIME轉換為北京時間                      
                    lcd_pos_2(0);           // 設定顯示位置     
                    lcd_wdat(' ');         //顯示 北京時間        
                    lcd_wdat(time[5]);  
                }
                    delayms(1);          //第一頁顯示完畢======經緯度+北京時間====定位+授時
                    lcd_wcmd(0x01);         //清除LCD的顯示內容
                    delayms(1);
                    X = 0;
                for(X;X <10;X++){
                    //第二頁開始=================================================================================
                    lcd_pos(0);         // 設定顯示位置
                    lcd_wdat('H');              // 顯示海拔 衛星個數
                    delayms(100);
                    lcd_pos(1);            
                    while(high[i] != '\0'){
                        lcd_wdat(high[i]);  //顯示海拔
                        i++;
                    }
                    delayms(100);
                    while(use_sat[i] != '\0'){
                        lcd_wdat(use_sat[i]);   // // 顯示 衛星個數
                        i++;
                    }
                    delayms(100);
                    i=0  ;  
                    
                    //delayms(5000);         //第二頁顯示完畢======顯示海拔+衛星個數===速度+方位
                    //lcd_wcmd(0x01);           //清除LCD的內容
                            
                    while(angle[i] != '\0'){
                        lcd_wdat(angle[i]); // // 顯示 方位角    
                        i++;
                    }
                    i=0  ;  
                }
                delayms(10);         //第二頁顯示完畢======顯示海拔+衛星個數===速度+方位
                lcd_wcmd(0x01);         //清除LCD的顯示內容
                delayms(1);
                X = 0;

                //第三頁開始==================================================================
                DHT11_main(i);// 顯示字元DHT11 溫度 溼度 資訊
                delaym(3000);
                i = 0;
                lcd_wcmd(0x01);         
                delaym(1);
                //第四頁開始==================================================================
                lcd_pos(0);         // 設定顯示位置
                while(LCD_161[i] != '\0'){
                    lcd_wdat(LCD_161[i]);   // 顯示字元禾灮資訊
                    i++;
                }
                delayms(1);
                i=0  ;
                lcd_pos_2(0);           // 設定顯示位置
                while(LCD_162[i] != '\0'){
                    lcd_wdat(LCD_162[i]);   // 顯示字元禾灮資訊
                    i++;
                }   
                //結束==================================================================
                delayms(5000);

                delayms(1);         //顯示完畢======顯示禾灮資訊
                lcd_wcmd(0x01);         //清除LCD的顯示內容
                delayms(1); 
            }
            else if(lock==0)
            {      //未定位    //display relative message              
                lcd_wcmd(0x01);         //清除LCD的顯示內容
                delayms(10);
                i=0  ;
                lcd_pos(3);         // 設定顯示位置
                while(receiving[i] != '\0')
                {
                    lcd_wdat(receiving[i]); // 顯示字元時間
                    i++;
                }
                delaym(1000);
                lcd_wcmd(0x01);         //清除LCD的顯示內容
                delaym(10);                 
                X = 0;
                //第三頁開始==================================================================
                DHT11_main(i);// 顯示字元DHT11 溫度 溼度 資訊
                delaym(3000);
                i = 0;
                lcd_wcmd(0x01);         
                delaym(1);
                //第四頁開始==================================================================
                lcd_pos(0);         // 設定顯示位置
                while(LCD_161[i] != '\0'){
                    lcd_wdat(LCD_161[i]);   // 顯示字元禾灮資訊
                    i++;
                }
                delayms(1);
                i=0  ;
                lcd_pos_2(0);           // 設定顯示位置
                while(LCD_162[i] != '\0'){
                    lcd_wdat(LCD_162[i]);   // 顯示字元禾灮資訊
                    i++;
                }   
                //結束==================================================================
                delayms(5000);
                delayms(1);                         
            }                   
        }           
    }
}

//--------------------------------------------------------------------
//串列埠中斷程式
void ser_int (void) interrupt 4 using 1
{
    
    unsigned char tmp;
    if(RI)
    {
        RI=0;
        tmp=SBUF;
        switch(tmp)
        {
            case '$':
                cmd_number=0;       //命令型別清空
                mode=1;             //接收命令模式
                byte_count=0;       //接收位數清空
                flag_data=1;
                flag_rec=1;     //資料標誌位置一
                break;
            case ',':
                seg_count++;        //逗號計數加1
                byte_count=0;
                break;
            case '*':
                switch(cmd_number)
                {
                    case 1:
                        buf_full|=0x01;
                        break;
                    case 2:
                        buf_full|=0x02;
                        break;
                    case 3:
                        buf_full|=0x04;
                        break;
                }
                mode=0;
                break;
            default:
                if(mode==1) //命令種類判斷
                {
                    cmd[byte_count]=tmp;            //接收字元放入型別快取
                    if(byte_count>=4)
                    {               //如果型別資料接收完畢,判斷型別
                        if(cmd[0]=='G')
                        {
                            if(cmd[1]=='N')
                            {
                                if(cmd[2]=='G')
                                {
                                    if(cmd[3]=='G')
                                    {
                                        if(cmd[4]=='A')
                                        {
                                            cmd_number=1;      //data type
                                            mode=2;
                                            seg_count=0;
                                            byte_count=0;
                                        }
                                    }
                                    else if(cmd[3]=='S')
                                    {
                                        if(cmd[4]=='V')
                                        {
                                            cmd_number=2;
                                            mode=2;
                                            seg_count=0;
                                            byte_count=0;
                                        }
                                    }
                                }
                                
                    switch (cmd_number)
                    {
                        case 1:             //型別1資料接收。GNGGA————北斗與GPS組合資料   
                            switch(seg_count)
                            {
                                case 2:     //緯度處理
                                    if(byte_count<9)
                                    {
                                        WD[byte_count]=tmp;
                                    }
                                    break;
                                case 3:     //緯度方向處理
                                    if(byte_count<1)
                                    {
                                        WD_a=tmp;
                                    }
                                    break;
                                case 4:     //經度處理
                                    if(byte_count<10)
                                    {
                                        JD[byte_count]=tmp;
                                    }
                                    break;
                                case 5:     //經度方向處理
                                    if(byte_count<1)
                                    {
                                        JD_a=tmp;
                                    }
                                    break;
                                case 6:     //定位判斷
                                    if(byte_count<1)
                                    {
                                        lock=tmp;
                                    }
                                    break;
                                case 7:     //定位使用的衛星數
                                    if(byte_count<2)
                                    {
                                        use_sat[byte_count]=tmp;
                                    }
                                    break;
                                case 9:     //高度處理
                                    if(byte_count<6)
                                    {
                                        high[byte_count]=tmp;
                                    }
                                    break;
                            }
                            break;                          
                }
                byte_count++;       //接收數位加1
                break;
        }
    }       
}

相關測試結果:

12993316-bd0e83c7e6af645d
12993316-6b5d965e3d26ec59

12993316-ae9c417c2cc223b2

測試視訊地址:點選進入


    感謝一直關注著禾灮成長進步的朋友們。你們的信任、支援和鼓勵,鞭策著我們一路走到了今天。
    
    感謝所有的合作伙伴,我們相互促進,共同見證了彼此的成長。

    感謝所有曾經在禾灮彼此倚靠、相互鼓勵、攜手同心、砥礪同行的兄弟姐妹。這裡承載了我們的青春與熱血。

                禾灮,感謝有你。

    未來,我們將一如既往,砥礪前行。

                                        禾灮·小楊
                                       2018.08.10

相關文章