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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

電波校時鐘

  [復制鏈接]
跳轉到指定樓層
樓主
ID:238754 發表于 2017-10-12 01:49 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
本內容出自:智慧帽diy(cleverhat)
簡介: 手頭有一個項目,需要一個“精確”的頻率計,作為DIY一族,準備動手制作一個。在制作頻率計之前,需要一個能精確測量晶振頻率的東西。之前嘗試過NTP對時,發現精度太差,不好使。所以準備改用電波對時。百度搜了一下,動手做電波表的朋友還真不少,但講得不夠詳細,解碼部分還是“保密”的。只好嘗試自立更生了。

  BPC電波鐘模塊       電波對時需要一個接收頭,接收授時中心發出的電波信號。我們國家的授時信號頻率為68.5Khz,發射臺在商丘。        接收頭實際上是一個窄帶信號接收器,其帶寬只有幾個赫茲,通常采用晶體濾波器來限制接收帶寬。由于工作頻率比較低,放大部分是比較        容易設計的,有一定無線電基礎的都可以做出來。
      這里我們直接從某寶上買來一個完整的電波鐘模塊。花了15大洋,省了很多事。
           





    BPC模塊上用到的引腳有4條。     
  • VCC :電源,1.5~3.5V
  • GND :地
  • SIG :BPC授時信號輸出
  • EN :模塊使能(低電平使能,高電平關閉模塊)

  BPC解碼和校時       電波鐘模塊輸出的BPC信號如下圖,1分鐘包含3個幀,一個BPC幀的周期為20秒,除了第"0"秒外,其余19秒每秒一個          脈沖。方波秒脈沖有0.1S,0.2S,0.3S,0.4S四種脈沖寬度狀態,分別表示四進制的0, 1, 2, 3,現有的時間編碼都以二進制表示時間信息,          是為了采用微處理器解碼方便。但四進制只是數值的一種表示方式,并不影響微處理器把它作為二進制處理,或者采取簡單的變換就可將1位          四進制數變成2位二進制數。
        





            
  • P0設在每分鐘0,20, 40秒,以缺少秒脈沖使幀與幀隔開,同時作為幀起始預告。
  • P1為幀標志,P1=0表示幀起于第1秒,P1=1表示幀起始于21秒,P1=2表示幀起始于41秒。幀標志是必需的,它用來確定整分的起始。                        例如:當接收完一組包含著“10時38分”的時間編碼時,如果幀標志標明該幀為第二幀,就可以把下一幀的P1位置標定為10時38分41秒,                        再過20秒便是10時39分的起始。
  • P2為預留位。用于需要擴充信息。
  • 時&分表示了時間
  • 其他各位數據在本案中沒有用到,不做詳細說明
              解碼MCU采用了TI公司的MSP430G2211IPW14,MSP系列的MCU以低功耗著稱,非常適合于電池供電的應用。本例中,                MCU大部分時間工作在約20uA的低功耗模式下。        
            BPC解碼軟件使用了MSP430G2211的TimeA,TimeA的計數器由32768Hz的晶振提供時鐘,從0~0xFFFF循環計數。每2秒                循環一周。BPC信號接在MCU的中斷請求上,在上下跳變沿均產生中斷,中斷服務程序中讀取TimerA計數器。根據脈沖寬度解碼BPC編碼的信號。                由于BPC信號的最小脈寬為0.1秒,軟件中還加入了濾波處理,可以濾除脈寬較窄的干擾信號。
  1.   if (MCU_INT_GET(BPC_SIGNAL_PORT, BPC_SIGNAL_PIN)) {
  2.     static uint16 wPrevToggle = 0; //前一次跳變時刻
  3.     static uint16 wLastPulseWidth = 0;  //前一次脈沖寬度
  4.     static uint8  bLastPulsePolarity = 0; //前一次脈沖極性(1:正脈沖,0:負脈沖)
  5.     static uint8  ucBpcBitPos = 0xFF; //BPC解碼位置,0xFF表示解碼狀態機復位
  6.     static uint8  ucBpc[2]; //BPC碼數據,只取包含"時:分:秒"信息的前面2字節。
  7.     uint16 wCurToggle; //本次跳變時刻
  8.     uint16 wCurPulseWidth; //本次脈沖寬度
  9.     uint16 wBpcSecond; //BPC解碼得到的時間秒數
  10.     uint8 bCurPulsePolarity; //本次脈沖極性(1:正脈沖,0:負脈沖)
  11.     uint8 ucTmp;
  12.    
  13.     MCU_INT_XOR_EDGE(BPC_SIGNAL_PORT, BPC_SIGNAL_PIN);
  14.     MCU_INT_CLEAR(BPC_SIGNAL_PORT, BPC_SIGNAL_PIN);
  15.     //正跳變,表示的是負脈沖(結束)
  16.     bCurPulsePolarity = MCU_INT_GET_EDGE(BPC_SIGNAL_PORT, BPC_SIGNAL_PIN) ? 0 : 1;
  17.     wCurToggle = GetCurTimerA();
  18.     wCurPulseWidth =  wCurToggle - wPrevToggle;
  19.     if ((wCurPulseWidth < PULSE_FILTER_OUT) || (bCurPulsePolarity == bLastPulsePolarity)) {
  20.       //本次跳變脈寬過短,將當作干擾毛刺被過濾掉,脈寬同前一次合并
  21.       //本次脈寬極性同前一次相同(跟在干擾毛刺后),脈寬也同前一次合并
  22.       wLastPulseWidth += wCurPulseWidth;
  23.     } else {
  24.       //前一次脈寬數據有效,可以處理了。
  25.       if (!bLastPulsePolarity && (wLastPulseWidth > PULSE_10ms * 100)) {
  26.         //每幀數據頭部有1秒時間的空檔期,表示幀起始
  27.         ucBpcBitPos = 14; //只用到前14bit數據
  28.         ucBpc[0] = ucBpc[1] = 0;
  29.       } else if (ucBpcBitPos != 0xFF) {
  30.         if (!bLastPulsePolarity) {
  31.           //負脈沖
  32.           if (wLastPulseWidth < PULSE_10ms * 55)
  33.             //BPC編碼正脈沖寬度最小600ms,<550ms為非法,解碼狀態機復位
  34.             ucBpcBitPos = 0xFF;
  35.         }
  36.         else {
  37.           //正脈沖
  38.           ucTmp = 0xFF;
  39.           if (wLastPulseWidth < PULSE_10ms * 45) {
  40.             if (wLastPulseWidth > PULSE_10ms * 35) //400ms脈寬
  41.               ucTmp = 3;
  42.             else if (wLastPulseWidth > PULSE_10ms * 25) //300ms脈寬
  43.               ucTmp = 2;
  44.             else if (wLastPulseWidth > PULSE_10ms * 15) //200ms脈寬
  45.               ucTmp = 1;
  46.             else if (wLastPulseWidth > PULSE_10ms * 5)  //100ms脈寬
  47.               ucTmp = 0;
  48.           }
  49.           if (ucTmp == 0xFF) {
  50.             //脈寬非法,解碼狀態機復位
  51.             ucBpcBitPos = 0xFF;
  52.           }
  53.           else {
  54.             //保存合法數據
  55.             ucBpcBitPos -= 2;
  56.             ucBpc[ucBpcBitPos >> 3] |= ucTmp << (ucBpcBitPos & 0x07);
  57.             if (ucBpcBitPos == 0) { //一幀數據接收完成
  58.               ucBpcBitPos = 0xFF; //解碼狀態機復位,等待下次數據
  59.               wBpcSecond = ((ucBpc[1] << 2) | (ucBpc[0] >> 6)) & 0x0F; //小時
  60.               wBpcSecond *= 3600;
  61.               wBpcSecond += ((uint16)(ucBpc[0] & 0x3F)) * 60; //分鐘
  62.               wBpcSecond += ((ucBpc[1] >> 4) & 0x03) * 20 + 21; //秒數
  63.               //如果相臨近的兩次BPC校時都是準確的(沒有誤碼),守時中斷應該在BPC
  64.               //信號的邊界前后,因此,秒數只可能差0或1秒。據此判斷校時成功
  65.               if ((wBpcSecond - s_wRealSecond) < 2)
  66.                 s_wEvent |= BPC_FINISHED;
  67.               s_wRealSecond = wBpcSecond;
  68.               s_wTarSecond = wCurToggle + COUNT_1S;
  69.              } //if (ucBpcBitPos == 0
  70.           }
  71.        }
  72.       }
  73.       wPrevToggle = wCurToggle;
  74.       wLastPulseWidth = wCurPulseWidth;
  75.       bLastPulsePolarity = bCurPulsePolarity;
  76.     }
  77.   }
復制代碼

守時信號輸出             TimerA的通道0工作在比較器模式,用作守時和UART波特率發生器.時間以12小時內的秒數表示,從00:00:00或12:00:00                開始計數,在每秒開始時將時間讀數從UART口發出去。MSP430G2211沒有專用的UART,需要軟件實現。UART數據格式為8位、無校驗、1200波特率.總共                16bit數據,需要用2個字節表示,加上每字節的起始位、停止位,總共20位。
  1. #pragma vector=TIMER0_A0_VECTOR
  2. __interrupt void Uart_ISR(void)
  3. {
  4.   static int8 iBits = 0;
  5.   static uint16 wMask;
  6.   
  7.   TACCTL0 &= ~TAIFG; //清中斷
  8.   //每秒起始位置把16bits實時時間通過UART發送出去
  9.   if ((iBits == 0) || (iBits == 10)) {
  10.     MCU_IO_CLR(UART_TX_PORT, UART_TX_PIN); //起始位
  11.   } else if ((iBits == 9) || (iBits == 19))
  12.     MCU_IO_SET(UART_TX_PORT, UART_TX_PIN); //停止位
  13.   else {
  14.     //發送數據位
  15.     if (s_wRealSecond & wMask)
  16.       MCU_IO_SET(UART_TX_PORT, UART_TX_PIN);
  17.     else
  18.       MCU_IO_CLR(UART_TX_PORT, UART_TX_PIN);
  19.     wMask <<= 1;
  20.   }
  21.   iBits++;
  22.   
  23.   if (iBits == 20) {
  24.     //實時時間發送完畢,準備在下一秒再次發送
  25.     s_wTarSecond += COUNT_1S;
  26.     TACCR0 = s_wTarSecond;
  27.     s_wRealSecond++;
  28.     if (s_wRealSecond >= ((uint16)12*3600))
  29.       s_wRealSecond = 0;    iBits = 0;
  30.     wMask = 1;
  31.     s_wEvent |= SECOND_EVENT;
  32.   } else
  33.     TACCR0 += UART_BIT_WIDTH;
  34.   
  35.   __low_power_mode_off_on_exit();
  36. }
  37.         
復制代碼

守時時鐘校準     本系統需要依靠標稱頻率為32768Hz晶振提供時間基準來守時,晶振負載電容對頻率有微調作用.為了測定晶振實際工作        頻率,可測量一段時間內的積累誤差。例如在10:00:00時進行第一次BPC校時,6個小時后在16:00:00進行第二次BPC校時,用串口工具接收并打印出        第二次BPC校時前后從UART口輸出的守時信號
        
校時之前
        
【2017-10-11 15:58:47:850】CB 0D
        
【2017-10-11 15:58:48:850】CC 0D
        
校時之后
        
【2017-10-11 15:59:47:827】07 0E
        
【2017-10-11 15:59:48:827】08 0E
             從打印出來的數據可以看出,在校時前后兩點(0x0E08-0x0DCC = 60秒),對應PC機系統時間為59:48:827-58:48:850                 = 59.977秒,也就是說6小時內積累的誤差為-0.023秒,可以忽略不計。否則可能需要調整負載電容來對頻率進行微調,或者也可以調整代碼中的                COUNT_1S的宏定義值來重新標定“1秒”。

機芯驅動     本設計初衷是要制作一個能夠準確計時(無累積誤差)的東西.因此完成守時信號輸出就OK了,但既然動了手,就準備弄個        完整的電波鐘玩玩。拆解了一個多時不用的石英鐘,只將機芯步進馬達的線圈引出,其他電路統統拆掉。這里我范了一個錯誤,本以為馬達是1秒        走一步或二步,按此設計了驅動代碼,結果馬達跑得非常別扭,走走退退,不知怎回事,弄了半天才發現問題所在,實際上這個機芯步進馬達是每秒16步        的,差得也太遠了。因此,建議朋友在拆機前先測一下原機的驅動波形。
    這種步進電機的驅動信號為正負交替的脈沖信號。脈沖寬度需要有個合理的范圍,拆機時沒有先用示波器測一下,只好自己        湊了。不過,就算測了也只能供參考,因為原機是1.5V供電的,現在改成3V,脈寬肯定需要調窄,理論上升到2倍電壓后脈寬應是原來的1/4.我的這個馬達        用12ms脈寬驅動,工作得很Happy.朋友自己制作時可以自行調整MOTOR_PULSE_DUTY。
  
    為了實現正負極性的交替,使用了2個IO端口,輸出兩路移相的方波信號.兩路方波信號之間的相差即為脈沖寬度。當鐘面顯示        的時間同實際時間有偏差時,需要改變脈沖周期以調整電機速度,使兩者趨于一致。機芯驅動使用了TimeA的通道1,在其中斷服務中實現
  1. #pragma vector=TIMER0_A1_VECTOR
  2. __interrupt void Motor_drv_ISR(void)
  3. {

  4.   if (TACCTL1 & CCIFG) {
  5.     // 步進電機驅動信號,一個周期分4個Stage,電機走2步。
  6.     // S1,S3提供動力輸出。
  7.     //               ------
  8.     //               | S1  |
  9.     //               |     |
  10.     // --------------|     |--------------|     |
  11.     //      S0                   S2       |     |
  12.     //                                    |     |
  13.     //                                    ------
  14.     //                                      S3
  15.    
  16.     static uint8 ucStage = 0; //步進電機每走一步分2個stage。
  17.     uint16       wS0S2; //S0,S2時間長度
  18.    
  19.     TACCTL1 &= ~CCIFG; //清中斷
  20.     if (ucStage == 2 * STEP_1S - 1) {
  21.       //每秒末進入此處
  22.       ucStage = 0;
  23.       s_wDisplaySecond++;
  24.       if (s_wDisplaySecond >= ((uint16)12 * 3600))
  25.         s_wDisplaySecond = 0;
  26.     }
  27.     else
  28.       ucStage++;  

  29.     //先假定鐘面時間總是偏"快"的,算一下"快"了多少
  30.     if (s_wDisplaySecond > s_wRealSecond)
  31.       wS0S2 = s_wDisplaySecond - s_wRealSecond;
  32.     else //超了一圈(12小時)
  33.       wS0S2 = ((uint16)12 * 3600) - (s_wRealSecond - s_wDisplaySecond);
  34.     //如果算下來"快"了9小時以內,認為其確實"快"了,否則認為實際是"慢"了3小時不到。
  35.     //之所以不以6小時分界,是因為步進馬達可以無限放慢,有限地加快。
  36.     if (wS0S2 < 2) //偏快不多,正常運行
  37.       wS0S2 = MOTOR_PERIOD - MOTOR_PULSE_DUTY; //正常運行
  38.     else if (wS0S2 < ((uint16)9 * 3600)) //偏快,降速運行
  39.       wS0S2 = MOTOR_PERIOD_SLOW - MOTOR_PULSE_DUTY;
  40.     else //偏慢,加速運行
  41.       wS0S2 = MOTOR_PERIOD_FAST - MOTOR_PULSE_DUTY;

  42.     //步進電機驅動信號4個stage一個循環,走2步
  43.     switch(ucStage & 0x03) {
  44.     case 0:
  45.       MCU_IO_CLR(MOTOR_DRVN_PORT, MOTOR_DRVN_PIN);
  46.       TACCR1 += wS0S2;
  47.       break;
  48.     case 1:
  49.       MCU_IO_SET(MOTOR_DRVP_PORT, MOTOR_DRVP_PIN);
  50.       TACCR1 += MOTOR_PULSE_DUTY;
  51.       break;
  52.     case 2:
  53.       MCU_IO_SET(MOTOR_DRVN_PORT, MOTOR_DRVN_PIN);
  54.       TACCR1 += wS0S2;
  55.       break;
  56.     case 3:
  57.       MCU_IO_CLR(MOTOR_DRVP_PORT, MOTOR_DRVP_PIN);
  58.       TACCR1 += MOTOR_PULSE_DUTY;
  59.       break;
  60.     }
  61.   }

  62.   __low_power_mode_off_on_exit();
  63. }
復制代碼


使用方法     由于系統無法讀取鐘面顯示的時間,因此在系統上電啟動時,必須先把鐘面撥到00:00:00的默認位置.上電時,MCU默認為        鐘面顯示時間和系統實際時間為00:00:00.系統在00:00:02啟動BPC對時,對時成功后,“實際時間”就準確了,這時,從UART輸出的守時信號也是準確的了。        但鐘面時間需要一段時間后才能逐步同實際時間一致。以后,系統會在每天的00:00:02和12:00:02各啟動BPC對時一次,如果對時成功或20分鐘內不能對時        則自動關閉BPC模塊以節約電池。對時成功,照明等會點亮2秒。
    在每天的17:00-21:00, 05:00-9:00兩個時段內是BPC發射臺是關閉的,在這兩個時段內開機是無法對時的。
    系統提供了一個按鈕,短按按鈕可以點燈5秒,以便夜間照明。長按2秒以上可以立即打開BPC對時,對時成功或5分鐘內不成功        則自動關閉BPC模塊。這些業務邏輯都在主程序中實現。

  實物圖  
  原理圖      JI為下載接口。MSP430G2211晶振匹配電容內置,可配置,所以不需要外接電容
  





全部資料下載地址:
clock_src.rar (15.25 KB, 下載次數: 290)





評分

參與人數 1黑幣 +5 收起 理由
zgs17951 + 5

查看全部評分

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

使用道具 舉報

沙發
ID:116826 發表于 2017-10-12 09:52 | 只看該作者
一直對電波授時很感興趣,感謝樓主費心分享!
回復

使用道具 舉報

板凳
ID:237243 發表于 2017-10-19 00:18 | 只看該作者
lyxxzrb 發表于 2017-10-12 09:52
一直對電波授時很感興趣,感謝樓主費心分享!

很強啊
回復

使用道具 舉報

地板
ID:207388 發表于 2017-10-20 08:44 | 只看該作者
感謝樓主的分享,這個很好
回復

使用道具 舉報

5#
ID:107522 發表于 2018-2-16 21:37 來自手機 | 只看該作者
bCurPulsePolarity
回復

使用道具 舉報

6#
ID:78901 發表于 2018-3-29 19:24 | 只看該作者
一直對電波授時很感興趣,感謝樓主費心分享!
回復

使用道具 舉報

7#
ID:51443 發表于 2018-4-4 18:20 | 只看該作者
要把普通萬年歷改電波授時會有難度
回復

使用道具 舉報

8#
ID:51443 發表于 2018-4-4 18:44 | 只看該作者
能不能把普通萬年歷改成電波授時?
回復

使用道具 舉報

9#
ID:51443 發表于 2018-4-4 18:45 | 只看該作者
能不能把普通萬年歷改成電波授時?
回復

使用道具 舉報

10#
ID:335118 發表于 2018-5-21 23:09 | 只看該作者
想做一個電波鐘 有資料了
回復

使用道具 舉報

11#
ID:252798 發表于 2018-5-22 08:47 | 只看該作者
值得收藏的寶貴資料
回復

使用道具 舉報

12#
ID:293292 發表于 2018-5-22 10:44 | 只看該作者
很強,收藏一下
回復

使用道具 舉報

13#
ID:78901 發表于 2018-8-6 22:48 | 只看該作者
能不能把普通萬年歷改成電波授時?
回復

使用道具 舉報

14#
ID:16255 發表于 2018-8-7 11:20 | 只看該作者
學習一下

評分

參與人數 1黑幣 +15 收起 理由
凌凈清河 + 15 捕捉!!

查看全部評分

回復

使用道具 舉報

15#
ID:426296 發表于 2018-11-16 12:58 | 只看該作者
感謝樓主的分享,這個很好
回復

使用道具 舉報

16#
ID:167657 發表于 2019-1-29 11:10 | 只看該作者
謝謝,正好需要
回復

使用道具 舉報

17#
ID:430492 發表于 2019-2-13 16:43 | 只看該作者
這么詳細的資料分享,贊一個!!
回復

使用道具 舉報

18#
ID:430492 發表于 2019-2-13 16:44 | 只看該作者

感謝樓主的分享,這個很好!
回復

使用道具 舉報

19#
ID:12816 發表于 2019-6-12 13:09 | 只看該作者
我們用不上電波
回復

使用道具 舉報

20#
ID:562484 發表于 2019-6-14 12:24 | 只看該作者
學習學習,謝謝分享
回復

使用道具 舉報

21#
ID:105826 發表于 2019-9-12 11:42 | 只看該作者
感謝樓主分享,讓大家對電波對時有了更多的認識,樓主動手能力不錯。
回復

使用道具 舉報

22#
ID:493097 發表于 2020-2-18 15:11 | 只看該作者
學習中,謝謝lz分享
回復

使用道具 舉報

23#
ID:701816 發表于 2020-4-5 17:36 | 只看該作者
很好的資料,感謝樓主的分享!!!
回復

使用道具 舉報

24#
ID:889283 發表于 2021-3-7 17:43 | 只看該作者
很好的參考資料
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品在线播放 | 91大神在线看 | 国产精品久久久久国产a级 欧美日韩国产免费 | 超碰最新在线 | 91精品在线观看入口 | 五月综合激情在线 | 日韩一区二区三区在线观看 | 欧美综合一区二区 | 一级毛片,一级毛片 | heyzo在线 | 99精品一区二区 | 国产综合在线视频 | 国产精品久久久久久久久久 | 国产成人精品一区二区三区在线观看 | 一区二区精品 | 亚州春色| 欧美三级视频在线观看 | 91色视频在线观看 | 欧美一级免费 | 亚洲网站在线 | 一a一片一级一片啪啪 | 久久久.com | 亚洲精品乱码久久久久久按摩观 | 在线精品亚洲欧美日韩国产 | 宅男伊人 | 香蕉久久av | 国产高潮av| 欧美综合一区二区三区 | 国产精品视频网站 | 欧美一级一 | 国产在线视频网 | 成人深夜福利 | 国产精彩视频 | 色欧美片视频在线观看 | 在线观看视频你懂得 | 91av入口| 九九九视频精品 | 日韩高清中文字幕 | 色妞av | 久久一及片 | 在线91|