找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6891|回復: 12
收起左側

基于12單片機通過雙串口查詢電表電量的問題,麻煩大家?guī)臀铱匆幌拢屑げ槐M(DLT64...

[復制鏈接]
ID:209219 發(fā)表于 2017-6-9 13:26 | 顯示全部樓層 |閱讀模式
20黑幣
   STC12系列單片機擁有雙串口,所以我用串口一與電表通信,串口二與電腦通信,以單片機為樞紐,把串口一收到到數(shù)據(jù)再從串口二發(fā)送給電腦,同樣電腦端發(fā)送查詢數(shù)據(jù),hex模式,通過串口二傳遞給串口一再發(fā)送出去,具體請看我程序。問題就出在這,電腦發(fā)送的數(shù)據(jù)發(fā)送出去了,卻沒有收到電表回復的數(shù)據(jù)。
  我單獨測試過串口一二與電腦通信沒有問題,并將兩串口同時接到電腦,在電腦端打開兩個串口助手,也能完成通信。當我把串口一摘下經(jīng)過TTL轉(zhuǎn)232模塊、232轉(zhuǎn)485模塊再接到電表測試時,收不到電表傳回的信息。
  一開始我是直接用的TTL轉(zhuǎn)485與電表通信的,也是沒有成功,在論壇看到有位前輩用TTL轉(zhuǎn)232再232轉(zhuǎn)485與電表通信成功了,他是用的51 ,單串口1602顯示的,然后按照他硬件電路試了一下還是沒有成功。我想問題應該是出在我程序上了,麻煩各位前輩幫我看一看有什么問題,通信規(guī)約我已經(jīng)仔細看過了,程序要求不需要太復雜,只要求發(fā)送同一條指令(我已存到數(shù)組中),能接收到電表返回的數(shù)據(jù)信息就行,具體數(shù)據(jù)我再進行處理就好,麻煩大家?guī)臀彝瓿蛇@一步,在下感激不盡,有地方我說的不明白的請再詢問我,我真的被這個程序塊搞壞了。。。
  下面是我程序,麻煩大家?guī)臀曳治鲆幌隆?br />



/*要實現(xiàn)功能:通過單片機兩個串口,串口二連接在電腦端,
              串口一連接電表,完成查詢正向有功功率任務。
  目前進度:  兩串口均測試可與電腦單獨通訊沒有問題,
              把串口一接入電表無法接收到返回信息
*/
#include <stc12c5a60s2.h>
#include "intrins.h"
#include "uart.h"
uchar flag=0,dat,a=0,b=0;

uchar code uart[]={0xFE,0xFE,0xFE,0x68,0x74,0x27,0x12,0x00,
                             0x80,0x13,0x68,0x01,0x02,0x43,0xC3,0x19,0x16};
                                   //讀正向有功總電能命令幀,電表
uchar data uart_1[36];
uchar data uart_2[36];
#define S2TI 0x02      // 串口2發(fā)送中斷請求標志位
#define S2RI 0x01      // 串口2接收中斷請求標志位
sbit REDE=P1^4;

void delay(uint x)          //  延時子函數(shù)
{
        uint i,j;

        for(i=x;i>0;i--)
          for(j=110;j>0;j--);
}

void main()
{
    uchar m;
        UartInit_1();        //初始化串口一          //  為遵循DLT645-1997與電表通信規(guī)約
        UartInit_2();        //初始化串口二           //兩串口        波特率均設為1200bps
        while(1)
        {               
                  if(flag=0)
                  {
                   for(m=0;m<17;m++)                //上電先通過串口一發(fā)送讀正向有功總電能命令幀
                   {                                                //根據(jù)DLT645-1997規(guī)約編輯的命令幀,串口波特率1200bps
                      s1_send_char(uart[m]);                  
                   }
                   flag=1;          //標志變?yōu)?,等待串口一接收數(shù)據(jù)后標志再次變?yōu)?.
                              //重復查詢功能暫時不用,先用電腦手動再次發(fā)送
                  }
                   delay(1000);                                                                                
        }
          
}
void UartInit_1(void) //1200bps@12MHz
{
        TMOD=0x20;          //設置定時器1位工作方式2
        TH1=0xE8;          //方式2為8位自動重裝,
                       //初值查表可得1200波特率
        TL1=0xD0;
        TR1=1;         //打開定時器1
        SM0=0;         //設置串口工作方式1,10位固定
        SM1=1;
        REN=1;         //允許串口接收數(shù)據(jù)
        EA=1;         //打開總中斷
        ES=1;         //打開串口中斷
}

void UartInit_2(void) //1200bps@12MHz        0xE8
{
AUXR = 0x10; //波特率不倍速
S2CON = 0x50; //8位數(shù)據(jù),可變波特率
BRT = 0xE8; //設定獨立波特率發(fā)生器重裝值
IE2 |= 0x01;            //充許串口2中斷
//AUXR &= 0xfb; //獨立波特率發(fā)生器時鐘為Fosc/12,即12T
//AUXR = 0x10; //啟動獨立波特率發(fā)生器

}
/*串口一發(fā)送程序*/
void s1_send_char(uchar dat)//發(fā)送端(發(fā)送的是字符)
{
        SBUF=dat;       
        while(!TI);         
        TI=0;          //清零標志
}

void s1_send_string(uchar *pt)         //發(fā)送字符串
{
        while(*pt != '\0')
        {
                s1_send_char(*pt++);
        }
}
/*串口二發(fā)送程序*/
void s2_send_char(uchar dat2)   // 發(fā)送端(發(fā)送的是字符)
{
        S2BUF = dat2;  
        while(!(S2CON&S2TI));
        S2CON &= ~S2TI;
}

void s2_send_string(uchar *pt2)           //發(fā)送字符串
{
        while(*pt2!='\0')
        {
                s2_send_char(*pt2++);
        }
}
                                                                                                                                 
void UART1() interrupt 4  //串口1中斷函數(shù)          
{                                                  //串口一收到電表數(shù)據(jù),存入uart2,再通過串口二發(fā)送到電腦                                                                                                          
    if(RI==1) //接收數(shù)據(jù)
        {       
                uart_2[a]=SBUF;                 
                s2_send_char(uart_2[a]);  //串口二發(fā)送到電腦
                a++;
                RI=0;
                if(a>=17)         //接收17位       
                {
                        a=0;
                //        flag=0;          //先不讓標志位=0;想要再發(fā)送查詢正向有功功率可以在電腦端串口二發(fā)送
                }
        }                                                                                                       
//        if(RI==1)                                                                                                                       
//        {
//          if(a==0&&0x68==SBUF)
//          {         
//                  uart_2[0]=SBUF;
//                  s2_send_char(uart_2[a]);                     
//          }       
//          
//          if(a>0&&uart_2[0]==0x68)
//          {
//             uart_2[a]=SBUF;
//                   s2_send_char(uart_2[a]);
//                                                                                         
//          }
//          a++;            
//          RI=0;                                                                                     
//         }
//         
//         if(a>=36)
//         {
//                 a=0;
//         }                                                                                                                  
//         flag=1;                                                                                 
}
void UART2() interrupt 8  //串口2中斷函數(shù)                                          
{                                                 //如果串口二接收到電腦端發(fā)送的查詢命令幀數(shù)據(jù),
                         //先存入數(shù)組uart1,再通過串口一發(fā)送給電表                                                                                                                                             
        if(S2CON&S2RI)                                                                                         
        {                                                                                                                      
           uart_1[b]=S2BUF;
           S2CON&=~S2RI;
        }
        s1_send_char(uart_1[b]);        //讓串口一發(fā)送查詢命令幀數(shù)據(jù)
        b++;
         if(b>=17)            
         {
                 b=0;
         }
//         flag=1;
}

雙串口均接到電腦測試沒問題

雙串口均接到電腦測試沒問題

把串口一換到電表上

把串口一換到電表上

串口一二接到電腦時的測試

串口一二接到電腦時的測試

電表138000122774

電表138000122774
回復

使用道具 舉報

ID:47286 發(fā)表于 2017-6-9 14:13 | 顯示全部樓層
上班呢 程序沒看 你說的應用我用過 沒有任何問題 你堅信一定會成功吧

我用12c5a做顯示屏 屏幕是串口屏 用uart2和屏通訊 uart1+485和其它模塊通訊 和你的應用差不多

1. uart2可以用計時器做波特率發(fā)生器也可以用獨立波特率發(fā)生器 如果用兩個串口 盡量各自用一個波特率發(fā)生器 我是因為兩個串口速率不一樣 其它模塊是57600 屏是115200

2. 485完全無需轉(zhuǎn)其它方式 直接ttl到485就沒問題 這個我用過很多很多很多 但485片子不同廠家有時候會出各種莫名其妙的不通訊問題 要注意485的電源濾波電容大小 按你買品牌的手冊要求高 我遇到過要求1.5uf的我用0.1uf就不行

3. uart1和2的轉(zhuǎn)發(fā) 你直接在內(nèi)存開個緩沖區(qū) 如果第一位不是0或者ff或者你定義的什么東西 就直接發(fā) 實驗的時候 你可以不斷的用串口1往上位機發(fā)緩沖區(qū)內(nèi)容 觀察串口2是否正常工作了 這樣有利于找到問題 我就是寫了個雙向直接轉(zhuǎn)發(fā)的程序 連串口屏自動聯(lián)機都可以
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-9 14:14 | 顯示全部樓層
請大家?guī)蛶头治龇治?/td>
回復

使用道具 舉報

ID:47286 發(fā)表于 2017-6-9 14:22 | 顯示全部樓層
另 附上我用的串口1和2初始化 基本上是用STC-ISP生成的 你對比一下看看 也許有幫助

void Init_UART1();                                                                //串口初始化 1T/定時器1作波特率發(fā)生器

void Init_UART1()        //串口初始化 1T/定時器1作波特率發(fā)生器
{
        PCON |= 0x80;                        //使能波特率倍速位SMOD
        SCON = 0x50;                        //8位數(shù)據(jù),可變波特率
        AUXR |= 0x40;                        //定時器1時鐘為Fosc,即1T
        AUXR &= 0xFE;                        //串口1選擇定時器1為波特率發(fā)生器
        TMOD &= 0x0F;                        //清除定時器1模式位
//        TMOD |= 0x21;                        //設定定時器1為8位自動重裝方式
        TMOD |= 0x20;                        //設定定時器1為8位自動重裝方式
        TL1=TH1=BAUD1;                        //設定定時初值
        ET1 = 0;                                //禁止定時器1中斷
        TR1 = 1;                                //啟動定時器1
        ES=1;                                        //開串口中斷
}

void Init_UART2();                //串口2初始化 1T/獨立波特率發(fā)生器(串口2只能使用獨立波特率發(fā)生器)

void Init_Uart2()                //串口2初始化 115200bps@11.0592MHz@獨立波特率發(fā)生器
{
       
        AUXR |= 0x08;                //使能波特率倍速位S2SMOD 0000 1000
        S2CON = 0x50;                //8位數(shù)據(jù),可變波特率 0101 0000
        AUXR |= 0x04;                //獨立波特率發(fā)生器時鐘為Fosc,即1T 0000 0100
        BRT = BAUD2;                //設定獨立波特率發(fā)生器重裝值
        AUXR |= 0x10;                //啟動獨立波特率發(fā)生器 0001 0000
        IE2=0X01;                        //允許串口2中斷
}
回復

使用道具 舉報

ID:59827 發(fā)表于 2017-6-9 14:37 來自觸屏版 | 顯示全部樓層
首先問一下樓主,你串口一能夠正常和電表通訊嗎?
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-9 17:02 | 顯示全部樓層
lshhjx 發(fā)表于 2017-6-9 14:37
首先問一下樓主,你串口一能夠正常和電表通訊嗎?

串口一能正常通訊我確定,但是和電表通訊沒有成功,我每次發(fā)送數(shù)據(jù),模塊的發(fā)送指示燈都會亮,但是接收指示燈一直沒有亮,應該是通訊沒有成功。
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-9 17:22 | 顯示全部樓層
dzbj 發(fā)表于 2017-6-9 14:22
另 附上我用的串口1和2初始化 基本上是用STC-ISP生成的 你對比一下看看 也許有幫助

void Init_UART1();         ...

我串口一波特率發(fā)生器用的T1,串口二用的獨立的波特率發(fā)生器。因為DLT645-1997通信規(guī)約要求,與電表通信波特率為1200bps,為方便,我兩個都設了1200bps。發(fā)送數(shù)據(jù),模塊RXD指示燈會亮,但是TXD指示燈一直都不會亮,應該是通訊沒有成功。我沒有設奇偶校驗,單純的發(fā)送查詢命令幀后等待串口一接收中斷,好像一直沒有觸發(fā)。您有時間再幫我在看看吧,我也嘗試其他方法。方便加QQ交流嗎875576671
回復

使用道具 舉報

ID:47286 發(fā)表于 2017-6-9 21:13 | 顯示全部樓層
寧采塵 發(fā)表于 2017-6-9 17:22
我串口一波特率發(fā)生器用的T1,串口二用的獨立的波特率發(fā)生器。因為DLT645-1997通信規(guī)約要求,與電表通信 ...

我大概看了一下你說的DLT645-1997 這是個通訊協(xié)議 從你說的情況感覺不是單片機串口的問題 是和DLT645-1997通訊沒成功 你可以這樣 先不用串口2 直接把上位機并聯(lián)到串口1上 相當于三機互連 然后看單片機發(fā)送給電表和電表反饋的數(shù)據(jù)是什么 根據(jù)反饋修改程序 直到調(diào)通它們后 再考慮串口2轉(zhuǎn)發(fā)的問題
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-10 11:24 | 顯示全部樓層
dzbj 發(fā)表于 2017-6-9 21:13
我大概看了一下你說的DLT645-1997 這是個通訊協(xié)議 從你說的情況感覺不是單片機串口的問題 是和DLT645-199 ...

串口一接收不到反饋信息,我現(xiàn)在也不確定是電表沒接收到數(shù)據(jù),還是我的接收數(shù)據(jù)程序有問題。我可以確定的是我再電腦端的串口助手能收到我發(fā)送的查詢數(shù)據(jù)。而且這串查詢數(shù)據(jù)我用抄表軟件發(fā)送時沒問題的,唯獨放到我程序里沒有回應。您看一下我的發(fā)送和接收有問題嗎?
//發(fā)送函數(shù),在主函數(shù)中,截取相關部分
         while(1)
        {
                  if(k==0)        //按鍵按下一次發(fā)送一次查詢命令
                  {
                          delay(20);
                          if(k==0)
                          {
                                  flag=0;
                          }
                  }
                  if(flag==0)
                  {
                   for(m=0;m<15;m++)
                   {
                   s1_send_char(uart[m]);                 
                   }
                   flag=1;
                  }
       //           uchar code uart[]={0xFE,0x68,0x74,0x27,0x12,0x00,
       //          0x80,0x13,0x68,0x01,0x02,0x43,0xC3,0x19,0x16};
                                   //讀正向有功總電能命令幀
     }

//接收函數(shù),截取相關部分,已將串口1并連電腦和電表。
/*串口一發(fā)送程序*/
void s1_send_char(uchar dat)//?發(fā)送端(發(fā)送的是字符)
{
        SBUF=dat;       
        while(!TI);         
        TI=0;          //清零標志
}
void UART1() interrupt 4  //串口1中斷函數(shù)          
{                                                                                                                                                          
    if(RI==1)
        {       
                uart_2[a]=SBUF;
                s1_send_char(uart_2[a]);
                a++;
                RI=0;
                if(a>14)
                {
                        a=0;
                //        flag=1;
                }
        }
}                        
回復

使用道具 舉報

ID:47286 發(fā)表于 2017-6-10 19:50 | 顯示全部樓層
寧采塵 發(fā)表于 2017-6-10 11:24
串口一接收不到反饋信息,我現(xiàn)在也不確定是電表沒接收到數(shù)據(jù),還是我的接收數(shù)據(jù)程序有問題。我可以確定的 ...

大致掃了一下你的程序 我覺得沒什么問題 有個建議是  s1_send_char(uart_2[a]); 這種函數(shù)盡量不放在中斷里 你這里這么用沒問題 但是沖斷的優(yōu)先級都高于正常程序 以后寫別的有可能有影響 養(yǎng)成個好習慣

你這段程序的意思是把串口2收到的東西用串口1轉(zhuǎn)發(fā)出來是么 如果是 先不進行這個 還是我之前說的 你直接把上位機并在單片機和模塊之間的通訊上 看它們之間聊的怎么樣

昨天看你說那個協(xié)議的時候 也是匆匆一掃 它好象有什么對位或者應答之類的要求 你這程序里有么
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-12 09:31 | 顯示全部樓層
dzbj 發(fā)表于 2017-6-10 19:50
大致掃了一下你的程序 我覺得沒什么問題 有個建議是  s1_send_char(uart_2[a]); 這種函數(shù)盡量不放在中斷 ...

通信規(guī)約上沒應答之類,此類通訊應該是半雙工通信,數(shù)據(jù)的發(fā)送和接收都有起始符,結束符,和校驗碼,我在發(fā)送和接收中加了判斷起止結束位和校驗碼,奇偶校驗位(以前沒加,因為校驗碼都計算好了沒有問題,所以本不想判斷了),對比和參考了一下前人寫的液晶顯示的51與電表通信。最后通信成功,將返回數(shù)據(jù)處理后與電表電量一致。但問題真正原因還是沒找到,不加判斷起始結束就沒法接收嗎(例如,判斷起始位68H,如果不判斷是不是68H,來的數(shù)據(jù)我都接收也應該可以啊,又不是應答之類的),我覺得問題不是出在這里。
回復

使用道具 舉報

ID:209219 發(fā)表于 2017-6-12 09:34 | 顯示全部樓層
dzbj 發(fā)表于 2017-6-10 19:50
大致掃了一下你的程序 我覺得沒什么問題 有個建議是  s1_send_char(uart_2[a]); 這種函數(shù)盡量不放在中斷 ...

總之還是要謝謝您能在工作之余還能幫我分析問題,真的非常感謝,一個人的思路畢竟是有局限的,謝謝前輩的幫助,有機會再一起討論
回復

使用道具 舉報

ID:290231 發(fā)表于 2018-5-1 14:21 來自觸屏版 | 顯示全部樓層
老哥,你解決了嗎,我也碰到同樣的問題,能講下嗎
回復

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表