找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6571|回復(fù): 12
收起左側(cè)

基于12單片機(jī)通過雙串口查詢電表電量的問題,麻煩大家?guī)臀铱匆幌,感激不盡(DLT64...

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



/*要實(shí)現(xiàn)功能:通過單片機(jī)兩個(gè)串口,串口二連接在電腦端,
              串口一連接電表,完成查詢正向有功功率任務(wù)。
  目前進(jìn)度:  兩串口均測試可與電腦單獨(dú)通訊沒有問題,
              把串口一接入電表無法接收到返回信息
*/
#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ā)送中斷請求標(biāo)志位
#define S2RI 0x01      // 串口2接收中斷請求標(biāo)志位
sbit REDE=P1^4;

void delay(uint x)          //  延時(shí)子函數(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();        //初始化串口二           //兩串口        波特率均設(shè)為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;          //標(biāo)志變?yōu)?,等待串口一接收數(shù)據(jù)后標(biāo)志再次變?yōu)?.
                              //重復(fù)查詢功能暫時(shí)不用,先用電腦手動再次發(fā)送
                  }
                   delay(1000);                                                                                
        }
          
}
void UartInit_1(void) //1200bps@12MHz
{
        TMOD=0x20;          //設(shè)置定時(shí)器1位工作方式2
        TH1=0xE8;          //方式2為8位自動重裝,
                       //初值查表可得1200波特率
        TL1=0xD0;
        TR1=1;         //打開定時(shí)器1
        SM0=0;         //設(shè)置串口工作方式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; //設(shè)定獨(dú)立波特率發(fā)生器重裝值
IE2 |= 0x01;            //充許串口2中斷
//AUXR &= 0xfb; //獨(dú)立波特率發(fā)生器時(shí)鐘為Fosc/12,即12T
//AUXR = 0x10; //啟動獨(dú)立波特率發(fā)生器

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

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;          //先不讓標(biāo)志位=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;
}

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

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

把串口一換到電表上

把串口一換到電表上

串口一二接到電腦時(shí)的測試

串口一二接到電腦時(shí)的測試

電表138000122774

電表138000122774

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

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

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

1. uart2可以用計(jì)時(shí)器做波特率發(fā)生器也可以用獨(dú)立波特率發(fā)生器 如果用兩個(gè)串口 盡量各自用一個(gè)波特率發(fā)生器 我是因?yàn)閮蓚(gè)串口速率不一樣 其它模塊是57600 屏是115200

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

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

使用道具 舉報(bào)

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

使用道具 舉報(bào)

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

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

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

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

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

使用道具 舉報(bào)

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

使用道具 舉報(bào)

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

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

使用道具 舉報(bào)

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

void Init_UART1();         ...

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

使用道具 舉報(bào)

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

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

使用道具 舉報(bào)

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

串口一接收不到反饋信息,我現(xiàn)在也不確定是電表沒接收到數(shù)據(jù),還是我的接收數(shù)據(jù)程序有問題。我可以確定的是我再電腦端的串口助手能收到我發(fā)送的查詢數(shù)據(jù)。而且這串查詢數(shù)據(jù)我用抄表軟件發(fā)送時(shí)沒問題的,唯獨(dú)放到我程序里沒有回應(yīng)。您看一下我的發(fā)送和接收有問題嗎?
//發(fā)送函數(shù),在主函數(shù)中,截取相關(guān)部分
         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ù),截取相關(guān)部分,已將串口1并連電腦和電表。
/*串口一發(fā)送程序*/
void s1_send_char(uchar dat)//?發(fā)送端(發(fā)送的是字符)
{
        SBUF=dat;       
        while(!TI);         
        TI=0;          //清零標(biāo)志
}
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;
                }
        }
}                        
回復(fù)

使用道具 舉報(bào)

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

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

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

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

使用道具 舉報(bào)

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

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

使用道具 舉報(bào)

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

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

使用道具 舉報(bào)

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

使用道具 舉報(bào)

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

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

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

快速回復(fù) 返回頂部 返回列表