<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統 > 設計應用 > 數字萬年歷設計

          數字萬年歷設計

          作者:時間:2023-12-15來源:電子森林收藏
          • 普通列表項目任務:基于核心板 和 底板 完成數字設計并觀察調試結果
          • 普通列表項目要求:驅動底板上的實時時鐘芯片DS1340Z獲取時間信息(年、月、日、周、時、分、秒),顯示在8位數碼管上,分兩頁顯示,第一頁顯示年月日周信息,第二頁顯示時分秒信息,通過旋轉編碼器調節數字和控制顯示,具體控制如下:
            • 有8個狀態(常態、調年、調月、調日、調周、調時、調分、調秒)
            • 按動旋轉編碼器在8個狀態中依次循環切換
            • 常態下,轉動編碼器切換顯示頁,逆時針轉顯示第一頁,順時針轉顯示第二頁
            • 調節狀態下,旋轉調節時間,逆時針轉減,順時針轉加
            • 調節狀態下,顯示被調節選項所在頁,同時被調節選項閃爍顯示
          • 普通列表項目解析:通過編程驅動實時時鐘芯片DS1340Z,實現時間寫入和讀出的功能,驅動旋轉編碼器獲取操作信息,設計一個控制模塊根據編碼器操作信息控制數字萬年歷的邏輯(包括時間調節,顯示控制),最后驅動數碼管顯示數字萬年歷信息。

          前面的章節中我們學習了掃描式數碼管模塊和旋轉編碼器模塊的工作原理及驅動方法,也對I2C總線協議及相關知識,本實驗主要對I2C總線驅動方法加以練習,同時完成數字萬年歷時間調節和顯示控制的邏輯,最終完成數字萬年歷總體設計。

          本文引用地址:http://www.ex-cimer.com/article/202312/453964.htm
          • 復習I2C總線工作原理及通信協議
          • 練習I2C接口驅動設計方法,完成實時時鐘芯片DS1340Z驅動設計
          • 根據要求完成數字萬年歷調時和顯示控制的邏輯
          • 完成數字萬年歷設計實現

          根據前面的實驗解析我們可以得知,該設計可以拆分成幾個功能模塊實現,

          • Encoder:驅動旋轉編碼器旋轉功能實現,獲取轉動信息
          • Debounce:驅動旋轉編碼器按鍵功能實現,實現按鍵消抖
          • modectrl:根據編碼器操作信息控制萬年歷時間調節和顯示控制邏輯 * DS1340Zdriver:驅動實時時鐘芯片DS1340Z完成時間寫入和讀出功能
          • Segment_scan:通過驅動掃描式數碼管將萬年歷信息顯示出來。

          Top-Down層次設計

           

          模塊結構設計

          實驗原理

          DS1340Z模塊介紹

          從DS1340Z芯片手冊可以得到如下信息,DS1340Z芯片典型電路連接如下:

          典型電路連接

          DS1340Z芯片管腳功能描述如下(SO-8封裝):

          管腳功能描述

          DS1340Z芯片內部結構圖如下:

          芯片內部結構圖

          DS1340Z模塊連接

          底板上的實時時鐘芯片DS1340Z模塊電路圖如下(上拉電阻未顯示):

          DS1340Z模塊電路

          我們的實時時鐘芯片為DS1340Z-33,模塊電路中有電池座,電池電壓范圍為1.3V~5.5V,當安裝電池后底板掉電不影響實時時鐘芯片的運行,重新上電后讀取實時時鐘數據。

          DS1340Z電壓范圍

          實時時鐘芯片DS1340Z需要外置32.768KHz的晶體,芯片內部集成起振電阻電容等電路,晶體直接連接即可。

          DS1340Z晶振連接

          DS1340Z驅動設計

          前面實驗中我們已經講述學習過I2C總線驅動的設計,本實驗可以上原來的基礎上調整,首先來了解DS1340Z時序中的參數要點。

          DS1340Z時序圖

          DS1340Z時序參數

          通過DS1340Z時序參數了解,DS1340Z支持I2C通信400KHz快速模式同時兼容100KHz的標準模式,還有兩種模式下時序中的各種時間參數,所以通信速度不需要調整。

          • 普通列表項目分頻得到400KHz的時鐘,程序實現同智能接近系統設計實驗。

          I2C時序基本單元(啟動、停止、發送、接收、發應答、讀應答)協議里統一的,所以所以基本單元狀態的設計也是不需要調整的。

          • 啟動時序狀態設計程序實現同智能接近系統設計實驗。
          • 發送單元和讀應答單元合并,時序狀態設計程序實現同智能接近系統設計實驗。
          • 接收單元和寫應答單元合并,時序狀態設計程序實現同智能接近系統設計實驗。
          • 停止時序狀態設計程序實現同智能接近系統設計實驗。

          DS1340Z芯片有很多寄存器,用于存儲實時時鐘的時間信息,例如地址為00H的寄存器中,bit7為晶體使能控制位,低有效,默認使能,bit6~bit0為秒鐘數據,且是BCD碼的格式(bit6~bit4代表秒鐘的十位,bit3~bit0代表秒鐘的個位),當需要調整秒鐘時間時,對00H寄存器寫操作,當讀取秒鐘時間時, 對00H寄存器讀操作。其他寄存器也是一樣,詳細請參考每個寄存器的功能說明。

          DS1340Z寄存器布局

          本實驗涉及DS1340Z的寫寄存器和讀寄存器操作,查看手冊給出的操作時序流程。

          芯片支持連續寫寄存器操作(寄存器地址自加1),時序流程如下:

          DS1340Z連續寫操作

          根據連續寫寄存器時序流程,其設計程序實現如下:

          MAIN:begin
                  if(cnt_main >= 6'd11) //對MAIN中的子狀態執行控制cnt_main
                      cnt_main <= 6'd0;   //
                  else cnt_main <= cnt_main + 1'b1;   
                  case(cnt_main)
                      6'd0:   begin state <= START; end   //I2C通信時序中的START
                      6'd1:   begin data_wr <= 8'hd0; state <= WRITE; end     //寫地址為8'hd0
                      6'd2:   begin data_wr <= 8'h00; state <= WRITE; end     //8'h00,起始寄存器
                      6'd3:   begin data_wr <= adj_sec; state <= WRITE; end   //00寄存器地址,寫秒
                      6'd4:   begin data_wr <= adj_min; state <= WRITE; end   //01寄存器地址,寫分
                      6'd5:   begin data_wr <= adj_hour; state <= WRITE; end  //02寄存器地址,寫時
                      6'd6:   begin data_wr <= adj_week; state <= WRITE; end  //03寄存器地址,寫周
                      6'd7:   begin data_wr <= adj_day; state <= WRITE; end   //04寄存器地址,寫日
                      6'd8:   begin data_wr <= adj_mon; state <= WRITE; end   //05寄存器地址,寫月
                      6'd9:   begin data_wr <= adj_year; state <= WRITE; end  //06寄存器地址,寫年
                      6'd10:  begin data_wr <= 8'h40; state <= WRITE; end   //07寄存器地址,8'h40
                      6'd11:  begin state <= STOP; end    //I2C通信時序中的STOP
                      default: state <= IDLE; //如果程序失控,進入IDLE自復位狀態
                  endcase
              end

          芯片支持連續讀寄存器操作(寄存器地址自加1),時序流程如下:

          DS1340Z連續讀操作

          根據連續寫寄存器時序流程,其設計程序實現如下:

          MAIN:begin
                  if(cnt_main >= 6'd32) //對MAIN中的子狀態執行控制cnt_main
                      cnt_main <= 6'd12;         //否則只執行時間讀取操作
                  else cnt_main <= cnt_main + 1'b1;   
                  case(cnt_main)
                      6'd12:  begin state <= START; end   //I2C通信時序中的START
                      6'd13:  begin data_wr <= 8'hd0; state <= WRITE; end //寫地址為8'hd0
                      6'd14:  begin data_wr <= 8'h00; state <= WRITE; end //8'h00,寄存器初始地址
                      6'd15:  begin state <= START; end   //I2C通信時序中的START
                      6'd16:  begin data_wr <= 8'hd1; state <= WRITE; end //讀地址為8'hd1
                      6'd17:  begin ack <= ACK; state <= READ; end    //讀秒
                      6'd18:  begin rtc_sec <= rtc_data_r; end
                      6'd19:  begin ack <= ACK; state <= READ; end    //讀分
                      6'd20:  begin rtc_min <= rtc_data_r; end
                      6'd21:  begin ack <= ACK; state <= READ; end    //讀時
                      6'd22:  begin rtc_hour <= rtc_data_r; end
                      6'd23:  begin ack <= ACK; state <= READ; end    //讀周
                      6'd24:  begin rtc_week <= rtc_data_r; end
                      6'd25:  begin ack <= ACK; state <= READ; end    //讀日
                      6'd26:  begin rtc_day <= rtc_data_r; end
                      6'd27:  begin ack <= ACK; state <= READ; end    //讀月
                      6'd28:  begin rtc_mon <= rtc_data_r; end
                      6'd29:  begin ack <= ACK; state <= READ; end    //讀年
                      6'd30:  begin rtc_year <= rtc_data_r; end
                      6'd31:  begin ack <= NACK; state <= READ; end   //控制
                      6'd32:  begin state <= STOP; end    //I2C通信時序中的STOP,讀取完成標志
                      default: state <= IDLE; //如果程序失控,進入IDLE自復位狀態
                  endcase
              end

          上面兩段程序就是對于DS1340Z芯片的兩種操作,調時間和讀時間,對于萬年歷來說因為有電池供電,實時時鐘一直都處于工作狀態,當給上電時只需要讀時間即可,只有遇到時間不對的時候才需要調時間,所以DS1340Z驅動模塊平時都在循環讀取時間,所以如果將調時間和讀時間的時序操作融合到同一個狀態下時,對于cntmain要加以控制,cntmain初值為12,且運行軌跡在12~32之間,控制程序調整如下:

          if(cnt_main >= 6'd32) //對MAIN中的子狀態執行控制cnt_main
              if(set_flag)cnt_main <= 6'd0;   //當set_flag被置位時才會執行時間寫入操作
              else cnt_main <= 6'd12;         //否則只執行時間讀取操作
              else cnt_main <= cnt_main + 1'b1;

          上面setflag為時間調整標志位,只有按動編碼器在調時間模式時需要用到寫時間數據的操作流程,可以根據按鍵脈沖置位setflag并自鎖,每次完成寫入操作后再將set_flag復位。程序實現如下:

          reg                 set_flag;
          always@(posedge clk or negedge rst_n) begin
              if(!rst_n) set_flag <= 1'b0;
              else if(cnt_main==5'd11) set_flag <= 1'b0;  //完成寫入時間操作復位set_flag
              else if(key_set) set_flag <= 1'b1;          //按鍵脈沖控制set_flag置位
              else set_flag <= set_flag;
              end

          模塊端口如下:

          module DS1340Z_driver
          (
          input clk, rst_n, //系統時鐘和復位 
          input key_set,  //按動脈沖輸入
          input [7:0] adj_hour, adj_min, adj_sec, //時分秒調整輸入
          input [7:0] adj_year, adj_mon, adj_day, adj_week, //年份調整輸入 
          output i2c_scl, //I2C總線SCLinout  i2c_sda, //I2C總線SDA 
          output [7:0] rtc_hour, rtc_min, rtc_sec, //實時時鐘輸出
          output [7:0] rtc_year, rtc_mon, rtc_day, rtc_week //實時年份輸出
          );

          到這里就完成了萬年歷中DS1340Z模塊的驅動設計,宏觀上講,該模塊的功能可以這樣描述:

          • 正常模式下循環讀取時間信息,并把時間數據輸出
          • 由旋轉編碼器按動脈沖信號key_set觸發進行一次寫操作,用于調節時間
          • 每次寫操作調節時間的時間數據由其他模塊提供

          萬年歷控制模塊實現

          控制模塊包含多個功能的設計:模式控制、調時控制、顯示控制,可以細化成多個模塊實現,本實驗例程中就寫在了一個模塊下,我們會針對這三個功能分別講解其實現方法及原理。

          模式控制

          項目要求設計成8個模式(常態、調年、調月、調日、調周、調時、調分、調秒),對8個狀態編碼,常態—0、調秒—1、調分—2、調時—3、調周—4、調日—5、調月—6、調年—7,通過按動旋轉編碼器切換,按照常識調時間從大到小調節,先調節年份最后調秒鐘,所以我們這8個狀態的狀態機跳轉順序是固定的(0→7→6→5→4→3→2→1→0),依次循環跳轉,程序實現如下:

          //時鐘運行狀態控制
          always@(posedge clk or negedge rst_n )
              if(!rst_n) state <= 3'd0;
              else if(O_pulse) //按鍵脈沖控制時鐘運行狀態的跳變,
                  if(state) state <= state - 3'd1;
                  else state <= 3'd7;
              else state <= state;

          調時控制

          調時控制在不同的調節模式對不同時間進行調整,我們分別以常態模式和調秒模式為例進行分析。

          萬年歷時間調節要以當時的時間為基礎,常態模式下不需要調整任何時間,但是可以將實時時鐘讀出的時間數據賦給調節變量,這樣等跳轉到調節模式時對調節變量的控制就是以當時的時間為基礎了,程序實現如下:

          3'd0:       //正常模式
              begin
                  if(O_pulse)begin  //在常態下按動編碼器將當前實時時間賦值給調節寄存器
                      adj_sec  <= rtc_sec;
                      adj_min  <= rtc_min;
                      adj_hour <= rtc_hour;
                      adj_week <= rtc_week;
                      adj_day  <= rtc_day;
                      adj_mon  <= rtc_mon;
                      adj_year <= rtc_year;
                  end
              end

          調秒模式與其他調節模式操作一樣,不同的是調節的規則不同,例如秒和分的調節范圍為0~59,小時調節范圍0~11或0~23,日期調節范圍需要考慮年和月的值(1、3、5、7、8、10、12月范圍1~31,4、6、9、11月范圍1~30,2月平年范圍1~28,2月閏年范圍1~29),周調節范圍1~7,月調節范圍1~12,年調節范圍0~99。對秒鐘數據進行調節,程序實現如下:

          3'd1:       //調秒模式
              begin
                  if(L_pulse) begin    //逆時針轉
                      if(adj_sec[3:0]) adj_sec <= adj_sec - 1'h1;
                      else if(adj_sec[7:4]) adj_sec <= {adj_sec[7:4]-1'h1,4'h9};
                      else adj_sec <= 8'h59;
                  end else if(R_pulse) begin    //順時針轉
                      if(adj_sec[3:0]!=4'h9) adj_sec <= adj_sec + 1'h1;
                      else if(adj_sec[7:4]!=4'h5) adj_sec <= {adj_sec[7:4]+1'h1,4'h0};
                      else adj_sec <= 8'h00;
                  end else adj_sec <= adj_sec;
              end

          顯示控制

          首先來看看一下數碼管要顯示的效果,8位數碼管分兩頁顯示萬年歷數據,第一頁顯示年月日周,第二頁顯示時分秒。

          萬年歷頁碼規劃

          我們看到任何一項時間選項都由兩位數碼管顯示,每頁最多顯示4個時間選項,我們可以使用4位的變量dispen[3:0]控制4個時間選項的點亮或熄滅,dispen[3]控制最左側兩個數碼管,disp_en[0]控制最右側兩個數碼管,我們分別以常態模式和調秒模式為例進行顯示使能控制的分析。

          常態模式下,轉動編碼器控制顯示頁碼,兩個頁碼對應的顯示控制,程序實現如下:

          3'd0:   //正常模式
              if(L_pulse) disp_en <= 4'b1111;   //逆時針轉顯示第一頁,數碼管全亮
              else if(R_pulse) disp_en <= 4'b0111; //順時針轉顯示第二頁,時分秒亮
              else disp_en <= disp_en;

          調秒模式下,小時和分鐘數碼管點亮,秒鐘閃爍顯示,轉動編碼器時秒鐘強制顯示,最后按動旋轉編碼器切到常態模式時,時分秒數碼管都回復顯示,程序實現如下:

          3'd1: begin     //調秒模式
                  disp_en[3:1] <= 3'b011; //時和分顯示
                  if(L_pulse|R_pulse) disp_en[0] <= 1'b1; //轉動時強制顯示
                  else if(sec_pulse) disp_en[0] <= ~disp_en[0]; //秒鐘閃爍顯示
                  else if(O_pulse) disp_en <= 4'b0111; //返回常態時顯示時分秒
                  else disp_en[0] <= disp_en[0];
                end

          系統總體實現

          前面分析了顯示控制,主要對時間選項的點亮還是熄滅做控制,對應到數碼管上就轉化成數碼管位的點亮和熄滅控制。另外還包含顯示數據的控制,而這部分設計我們放到頂層模塊中實現了,我們來分析一下。

          數碼管點亮控制

          數碼管與時間選項是對應關系,每個選項對應兩位數碼管,程序實現如下:

          wire [7:0] data_en = {{2{disp_en[3]}},{2{disp_en[2]}},{2{disp_en[1]}},{2{disp_en[0]}}};    //數碼管位選控制     
          wire [7:0] dot_en  = {1'b0,disp_en[3],1'b0,disp_en[2],1'b0,disp_en[1],1'b0,disp_en[0]};    //數碼管小數點顯示控制

          數碼管內容控制

          萬年歷的顯示分兩頁實現,我們以最右側兩個數碼管顯示內容為例,這兩位數碼管在第一頁中顯示周數據,在第二頁中顯示秒數據,那么我們怎么控制顯示內容呢?分析,萬年歷8中模式,

          1.常態模式下,顯示讀取的實時時鐘數據,具體顯示周還是秒再次細化

          • dispen等于4'b1111的時候,對應第一頁,顯示周數據 * dispen等于4'b0111的時候,對應第二頁,顯示秒數據

          常態模式下,根據disp_en選擇顯示周數據還是秒數據,程序實現如下:

          wire [7:0] data_rtc0 = disp_en[3]? rtc_week:rtc_sec; //常態下數碼管顯示數據

          2.調節模式下,顯示寫入的調節時鐘數據,具體顯示周還是秒再次細化

          • 調年、調月、調日、調周 狀態下(state>=3),對應第一頁,顯示周數據
          • 調時、調分、調秒 狀態下(state<3),對應第二頁,顯示秒數據

          調節模式下,根據state選擇顯示周數據還是秒數據,程序實現如下:

          wire [7:0] data_adj0 = state[2]? adj_week:adj_sec;  //調節狀態下數碼管顯示數據

          3.最后根據常態模式還是調節模式控制數碼管顯示實時時鐘數據還是調節時鐘數據

          根據state選擇顯示實時時鐘數據還是調節時鐘數據,程序實現如下:

          assign {data_7,data_8} = state? data_adj0:data_rtc3;  //根據狀態選擇顯示常態數據還是調節狀態數據

          綜合后的設計框圖如下:

          RTL設計框圖

          實驗步驟

          1. 雙擊打開Quartus Prime工具軟件;
          2. 新建工程:File → New Project Wizard(工程命名,工程目錄選擇,設備型號選擇,EDA工具選擇);
          3. 新建文件:File → New → Verilog HDL File,鍵入設計代碼并保存;
          4. 設計綜合:雙擊Tasks窗口頁面下的Analysis & Synthesis對代碼進行綜合;
          5. 管腳約束:Assignments → Assignment Editor,根據項目需求分配管腳;
          6. 設計編譯:雙擊Tasks窗口頁面下的Compile Design對設計進行整體編譯并生成配置文件;
          7. 程序燒錄:點擊Tools → Programmer打開配置工具,Program進行下載;
          8. 觀察設計運行結果。

          將程序下載到中,按照設計要求的功能操作調節萬年歷的時間,觀察數碼管萬年歷顯示,如圖時間為18年6月27日,周三,19點15分14秒。

          實驗現象

           

          實驗現象



          評論


          相關推薦

          技術專區

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();