搜索
bottom↓
回复: 0

《ATK-DFPGL22G之FPGA开发指南_V1.0》第三十一章

[复制链接]

出0入234汤圆

发表于 2023-2-15 09:40:45 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2023-2-15 09:40 编辑

1)实验平台:正点原子紫光PGL22G开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340253-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:435699340 lQLPJxaFi2zaB4UWWrDAMgIsFEW2pwLb3abnwDMA_90_22.png
lQDPJxaFi2nfFizMjM0CbLCPlxn_FVheIQLb3aGrwFQA_620_140.jpg

lQLPJxaFi2nfFhLMkM0BXrDNvOUyeU_FPgLb3aGvQNIA_350_144.png

第三十一章RTC实时时钟数码管显示实验

PCF8563是一款多功能时钟/日历芯片。因其功耗低、控制简单、封装小而广泛应用于电表、水表、传真机、便携式仪器等产品中。本章我们将使用开发板上的 PCF8563 器件实现实时时钟的显示。
    本章包括以下几个部分:
31.1PCF8563简介
31.2实验任务
31.3硬件设计
31.4程序设计
31.5下载验证


31.1PCF8563简介

PCF8563是PHILIPS公司推出的一款工业级多功能时钟/日历芯片,具有报警功能、定时器功能、时钟输出功能以及中断输出功能,能完成各种复杂的定时服务。其内部功能模块的框图如下图所示:
RTC实时时钟数码管显示实验264.png
图 31.1.1 PCF8563功能框图

PCF8563有16个可寻址的8位寄存器,但不是所有位都有用到。前两个寄存器(内存地址00H、01H)用作控制寄存器和状态寄存器(CONTROL_STATUS);内存地址02H~08H用作TIME计时器(秒~年计时器);地址09H~0CH用于报警(ALARM)寄存器(定义报警条件);地址0DH控制CLKOUT管脚的输出频率;地址0EH和0FH分别用于定时器控制寄存器和定时器寄存器。
秒、分钟、小时、日、月、年、分钟报警、小时报警、日报警寄存器中的数据编码格式为BCD,只有星期和星期报警寄存器中的数据不以BCD格式编码。BCD码(Binary-Coded Decimal‎)是一种二进制的数字编码形式,用四个二进制位来表示一位十进制数(0~9),能够使二进制和十进制之间的转换得以快捷的进行。
PCF8563通过I2C接口与FPGA进行通信。使用该器件时,FPGA先通过I2C接口向该器件相应的寄存器写入初始的时间数据(秒~年),然后通过I2C接口读取相应的寄存器的时间数据。有关I2C总线协议详细的介绍请大家参考“EEPROM读写实验”。
下面我们对本次实验用到的寄存器做简要的描述和说明,其他寄存器的描述和说明,请大家参考PCF8563的数据手册。
秒寄存器的的地址为02h,说明如下表所示:
表 31.1.1 秒寄存器描述(地址02h)
lQLPJwt0DxDu0ORxzQOksCBjsiWG8u9hA-ZInhmAWQA_932_113.png

当电源电压低于PCF8563器件的最低供电电压时,VL为“1”,表明内部完整的时钟周期信号不能被保证,可能导致时钟/日历数据不准确。
BCD编码的秒数值如下表所示:
表 31.1.2 秒数值的BCD编码
RTC实时时钟数码管显示实验1165.png

寄存器的地址为03h,说明如下表所示:
表 31.1.3 分钟寄存器描述(地址03h)
lQLPJyKU3pWiASRlzQOmsPe0VWrRRIcEA-ZIs8QApQA_934_101.png

小时寄存器的地址为04h,说明如下表所示:
表 31.1.4 小时寄存器描述(地址04h)
lQLPJxKhPO3m6yRdzQOlsK16v4Msw4_NA-ZIxHKAMwA_933_93.png

天寄存器的地址为05h,说明如下表所示:
表 31.1.5 天寄存器描述(地址05h)
lQLPJxse7jIRWSRmzQOlsHfrrH9ZwFfbA-ZI2OYAWQA_933_102.png


表 31.1.6 月份表
lQLPJxp7OKk9ZSTNAX7NAYGwSnkI_bvz_QAD5kjqmsClAA_385_382.png

年寄存器的地址为08h,说明如下表所示:
表 31.1.7 寄存器(地址08h)

lQLPJw4L_Y17GCRCzQOksGIDN7FAEFFvA-ZJA-zAMwA_932_66.png

31.2实验任务
本节的实验任务是通过ATK-DFPGL22G开发板上的PCF8563实时时钟芯片,根据输入按键KEY0来切换数码管显示时间或者日期。
31.3硬件设计
ATK-DFPGL22G开发板上PCF8563接口部分的原理图如下图所示。
RTC实时时钟数码管显示实验2049.png
图 31.3.1 PCF8563接口原理图

PCF8563作为I2C接口的从器件与EEPROM等模块统一挂接在ATK-DFPGL22G开发板上的IIC总线上。 OSCI、OSCO与外部32.768KHz的晶振相连,为芯片提供驱动时钟;SCL和SDA分别是I2C总线的串行时钟接口和串行数据接口。
本实验中,各管脚分配如下表所示:
表 31.3.1 RTC实时时钟数码管显示管脚分配
lQLPJwFdGADzA-TNAmzNAdSwnUTWyBOlKCwD5kkvNIBZAA_468_620.png

31.4程序设计
根据实验任务,我们可以大致规划出系统的控制流程:首先通过I2C总线向PCF8563写入初始日期值(年月日)和时间值(时分秒),然后不断地读取日期和时间数据,并根据输入的按键,选择将日期或者时间数据显示到数码管上。由此画出系统的功能框图如下图所示:
RTC实时时钟数码管显示实验3221.png
图 31.4.1 系统框图

由系统框图可知,FPGA顶层模块例化了以下五个模块、分别是IIC驱动模块(i2c_dri)、PCF8563控制模块(pcf8563_ctrl)、按键消抖模块(key_debounce)、显示值切换模块(key_sw_disp)以及数码管BCD驱动模块(seg_bcd_dri)。
PCF8563控制模块通过调用IIC驱动模块来实现对PCF8563实时时钟数据的配置和读取;而显示值切换模块根据按键消抖模块输出的按键数据(key_value)选择显示日期或者时间(年月日/时分秒),并将其传递给数码管BCD驱动模块(seg_bcd_dri),最终在数码管上显示日期或者时间。
顶层模块的代码如下:
1   module rtc_seg_led(
2       input                sys_clk,     //系统时钟
3       input                sys_rst_n,   //系统复位
4   
5       //按键
6       input                key,         //输入按键KEY0
7      
8       //数码管
9       output        [5:0]  seg_sel,     //数码管位选信号
10      output        [7:0]  seg_led,     //数码管段选信号
11      
12      //RTC实时时钟
13      output               iic_scl,     //RTC的时钟线scl
14      inout                iic_sda      //RTC的数据线sda   
15      );                                                      
16  
17  //parameter define
18  parameter    SLAVE_ADDR = 7'b101_0001   ; //器件地址(SLAVE_ADDR)
19  parameter    BIT_CTRL   = 1'b0          ; //字地址位控制参数(16b/8b)
20  parameter    CLK_FREQ   = 26'd50_000_000; //i2c_dri模块的驱动时钟频率(CLK_FREQ)
21  parameter    I2C_FREQ   = 18'd250_000   ; //I2C的SCL时钟频率
22  parameter    TIME_INIT  = 48'h20_04_01_09_30_00;//初始时间
23  
24  //wire define
25  wire          dri_clk   ;   //I2C操作时钟
26  wire          i2c_exec  ;   //I2C触发控制
27  wire  [15:0]  i2c_addr  ;   //I2C操作地址
28  wire  [ 7:0]  i2c_data_w;   //I2C写入的数据
29  wire          i2c_done  ;   //I2C操作结束标志
30  wire          i2c_ack   ;   //I2C应答标志 0:应答 1:未应答
31  wire          i2c_rh_wl ;   //I2C读写控制
32  wire  [ 7:0]  i2c_data_r;   //I2C读出的数据
33  
34  wire    [7:0]  sec      ;   //秒
35  wire    [7:0]  min      ;   //分
36  wire    [7:0]  hour     ;   //时
37  wire    [7:0]  day      ;   //日
38  wire    [7:0]  mon      ;   //月
39  wire    [7:0]  year     ;   //年
40  
41  wire           key_value;   //消抖后的按键值
42  wire    [5:0]  point    ;   //数码管小数点控制
43  wire    [23:0] disp_data;   //数码管显示的数值控制
44  
45  //*****************************************************
46  //**                    main code
47  //*****************************************************
48  
49  //i2c驱动模块
50  i2c_dri #(
51      .SLAVE_ADDR  (SLAVE_ADDR),  //从机地址
52      .CLK_FREQ    (CLK_FREQ  ),  //模块输入的时钟频率
53      .I2C_FREQ    (I2C_FREQ  )   //IIC_SCL的时钟频率
54  ) u_i2c_dri(
55      .clk         (sys_clk   ),  
56      .rst_n       (sys_rst_n ),  
57      //i2c interface
58      .i2c_exec    (i2c_exec  ),
59      .bit_ctrl    (BIT_CTRL  ),
60      .i2c_rh_wl   (i2c_rh_wl ),
61      .i2c_addr    (i2c_addr  ),
62      .i2c_data_w  (i2c_data_w),
63      .i2c_data_r  (i2c_data_r),
64      .i2c_done    (i2c_done  ),
65      .i2c_ack     (i2c_ack   ),
66      .scl         (iic_scl   ),
67      .sda         (iic_sda   ),
68      //user interface
69      .dri_clk     (dri_clk   )  
70  );
71  
72  //PCF8563控制模块
73  pcf8563_ctrl #(
74      .TIME_INIT (TIME_INIT)
75     )u_pcf8563_ctrl(
76      .clk         (dri_clk   ),
77      .rst_n       (sys_rst_n ),
78      //IIC
79      .i2c_rh_wl   (i2c_rh_wl ),
80      .i2c_exec    (i2c_exec  ),
81      .i2c_addr    (i2c_addr  ),
82      .i2c_data_w  (i2c_data_w),
83      .i2c_data_r  (i2c_data_r),
84      .i2c_done    (i2c_done  ),
85      //时间和日期
86      .sec         (sec       ),
87      .min         (min       ),
88      .hour        (hour      ),
89      .day         (day       ),
90      .mon         (mon       ),
91      .year        (year      )
92      );
93  
94  //消抖模块
95  key_debounce u_key_debounce(
96      .sys_clk     (sys_clk   ),    //外部50M时钟
97      .sys_rst_n   (sys_rst_n ),    //外部复位信号,低有效
98      .key         (key       ),    //外部按键输入
99      .key_value   (key_value ),    //按键消抖后的数据
100     .key_flag    ()               //按键数据有效信号
101 );
102
103 //显示值切换模块
104 key_sw_disp u_key_sw_disp(
105     .clk          (sys_clk),
106     .rst_n        (sys_rst_n),
107              
108     .key_value    (key_value),
109     .sec          (sec ),
110     .min          (min ),
111     .hour         (hour),
112     .day          (day ),
113     .mon          (mon ),
114     .year         (year),
115               
116     .point        (point),
117     .disp_data    (disp_data)
118     );
119
120 //数码管驱动模块
121 seg_bcd_dri u_seg_bcd_dri(
122    //input
123    .clk          (sys_clk   ),    //时钟信号
124    .rst_n        (sys_rst_n ),    //复位信号
125    .data         (disp_data ),    //6个数码管要显示的数值
126    .point        (point     ),    //小数点具体显示的位置,从左往右,高有效
127    //output
128    .seg_sel      (seg_sel   ),    //数码管位选
129    .seg_led      (seg_led   )     //数码管段选
130 );   
131     
132 endmodule
程序中第18行至第22行定义了一些参数,其中TIME_INIT表示PCF8563初始化时的时间数据,可以通过修改此参数值使PCF8563从不同的时间开始计时,例如从2020年4月1号09:30:00开始计时,需要将该参数值设置为48’h20_04_01_09_30_00。
顶层模块中主要完成对其余模块的例化。其中I2C驱动模块(i2c_dri)程序与“EEPROM读写实验”章节中的IIC驱动模块(i2c_dri)程序完全相同,有关IIC驱动模块的详细介绍请大家参考“EEPROM读写实验”。按键消抖模块可参考“按键控制蜂鸣器实验”。
PCF8563实时时钟控制模块的代码如下所示:
1   module pcf8563_ctrl #(
2       // 初始时间设置,从高到低为年到秒,各占8bit
3       parameter  TIME_INIT = 48'h20_10_26_09_30_00)(
4       input                 clk       , //时钟信号
5       input                 rst_n     , //复位信号
6   
7       //i2c interface
8       output   reg          i2c_rh_wl , //I2C读写控制信号
9       output   reg          i2c_exec  , //I2C触发执行信号
10      output   reg  [15:0]  i2c_addr  , //I2C器件内地址
11      output   reg  [7:0]   i2c_data_w, //I2C要写的数据
12      input         [7:0]   i2c_data_r, //I2C读出的数据
13      input                 i2c_done  , //I2C一次操作完成
14  
15      //PCF8563T的秒、分、时、日、月、年数据
16      output   reg   [7:0]  sec,        //秒
17      output   reg   [7:0]  min,        //分
18      output   reg   [7:0]  hour,       //时
19      output   reg   [7:0]  day,        //日
20      output   reg   [7:0]  mon,        //月
21      output   reg   [7:0]  year        //年
22  );
23  
24  //reg define
25  reg   [3:0]     flow_cnt  ;            // 状态流控制
26  reg   [12:0]    wait_cnt  ;            // 计数等待
27  
28  //*****************************************************
29  //**                    main code
30  //*****************************************************
31  
32  //先向PCF8563中写入初始化日期和时间,再从中读出日期和时间
33  always @(posedge clk or negedge rst_n) begin
34      if(!rst_n) begin
35          sec        <= 8'h0;
36          min        <= 8'h0;
37          hour       <= 8'h0;
38          day        <= 8'h0;
39          mon        <= 8'h0;
40          year       <= 8'h0;
41          i2c_exec   <= 1'b0;
42          i2c_rh_wl  <= 1'b0;
43          i2c_addr   <= 8'd0;
44          i2c_data_w <= 8'd0;
45          flow_cnt   <= 4'd0;
46          wait_cnt   <= 13'd0;
47      end
48      else begin
49          i2c_exec <= 1'b0;
50          case(flow_cnt)
51              //上电初始化
52              4'd0: begin
53                  if(wait_cnt == 13'd8000) begin
54                      wait_cnt<= 12'd0;
55                      flow_cnt<= flow_cnt + 1'b1;
56                  end
57                  else
58                      wait_cnt<= wait_cnt + 1'b1;
59              end
60              //写读秒
61              4'd1: begin
62                  i2c_exec  <= 1'b1;
63                  i2c_addr  <= 8'h02;
64                  flow_cnt  <= flow_cnt + 1'b1;
65                  i2c_data_w<= TIME_INIT[7:0];
66              end
67              4'd2: begin
68                  if(i2c_done == 1'b1) begin
69                      sec     <= i2c_data_r[6:0];
70                      flow_cnt<= flow_cnt + 1'b1;
71                  end
72              end
73              //写读分
74              4'd3: begin
75                  i2c_exec  <= 1'b1;
76                  i2c_addr  <= 8'h03;
77                  flow_cnt  <= flow_cnt + 1'b1;
78                  i2c_data_w<= TIME_INIT[15:8];
79              end
80              4'd4: begin
81                  if(i2c_done == 1'b1) begin
82                      min     <= i2c_data_r[6:0];
83                      flow_cnt<= flow_cnt + 1'b1;
84                  end
85              end
86              //写读时
87              4'd5: begin
88                  i2c_exec  <= 1'b1;
89                  i2c_addr  <= 8'h04;
90                  flow_cnt  <= flow_cnt + 1'b1;
91                  i2c_data_w<= TIME_INIT[23:16];
92              end
93              4'd6: begin
94                  if(i2c_done == 1'b1) begin
95                      hour    <= i2c_data_r[5:0];
96                      flow_cnt<= flow_cnt + 1'b1;
97                  end
98              end
99              //写读天
100             4'd7: begin
101                 i2c_exec  <= 1'b1;
102                 i2c_addr  <= 8'h05;
103                 flow_cnt  <= flow_cnt + 1'b1;
104                 i2c_data_w<= TIME_INIT[31:24];
105             end
106             4'd8: begin
107                 if(i2c_done == 1'b1) begin
108                     day     <= i2c_data_r[5:0];
109                     flow_cnt<= flow_cnt + 1'b1;
110                 end
111             end
112             //写读月
113             4'd9: begin
114                 i2c_exec  <= 1'b1;
115                 i2c_addr  <= 8'h07;
116                 flow_cnt  <= flow_cnt + 1'b1;
117                 i2c_data_w<= TIME_INIT[39:32];
118             end
119             4'd10: begin
120                 if(i2c_done == 1'b1) begin
121                     mon     <= i2c_data_r[4:0];
122                     flow_cnt<= flow_cnt + 1'b1;
123                 end
124             end
125             //写读年
126             4'd11: begin
127                 i2c_exec  <= 1'b1;
128                 i2c_addr  <= 8'h08;
129                 flow_cnt  <= flow_cnt + 1'b1;
130                 i2c_data_w<= TIME_INIT[47:40];
131             end
132             4'd12: begin
133                 if(i2c_done == 1'b1) begin
134                     year     <= i2c_data_r;
135                     i2c_rh_wl<= 1'b1;
136                     flow_cnt <= 4'd1;
137                 end
138             end
139             default: flow_cnt <= 4'd0;
140         endcase
141     end
142 end
143
144 endmodule
程序中定义了一个状态流控制计数器(flow_cnt),flow_cnt初始值为0,在flow_cnt等于0进行延时,随后从0开始累加至12,将初始日期和时间(TIME_INIT)写入PCF8563中;在flow_cnt等于12时,i2c_rh_wl(I2C读写控制信号)由低电平改为高电平,即IIC由写操作切换成读操作,与此同时,flow_cnt赋值为1,循环从PCF8563中读取秒、分、时、日、月和年。
下图为Fabric Debugger抓取的波形图,从图中可以看到当前读到的时间为20年4月1日09:31:08。需要说明的是,flow_cnt在循环从0累加至12,其中flow_cnt等于奇数的时间很短,所以需要放大波形才能便于观察。
RTC实时时钟数码管显示实验13517.png
图 31.4.2 Fabric Debugger波形图

显示值切换模块代码如下:
1  module key_sw_disp(                                                            
2      input                clk       , //时钟   
3      input                rst_n     , //复位  
4                                                            
5      input                key_value , //按键
6      input       [7:0]    sec       , //秒
7      input       [7:0]    min       , //分钟
8      input       [7:0]    hour      , //小时
9      input       [7:0]    day       , //日
10     input       [7:0]    mon       , //月
11     input       [7:0]    year      , //年
12     
13     output      [5:0]    point     , //数码管小数点控制
14     output      [23:0]   disp_data   //数码管显示的数值控制
15      );
16
17 //reg define
18 reg    sw_flag     ;
19 reg    key_value_d0;
20 reg    key_value_d1;
21
22 //wire define
23 wire   neg_key_value;
24      
25 //*****************************************************
26 //**                    main code
27 //*****************************************************     
28
29 //采集输入信号的下降沿
30 assign neg_key_value = key_value_d1 & (~key_value_d0);
31 //切换输出数码管要显示的数据
32 assign disp_data = (sw_flag == 1'b0) ? {sec,min,hour} : {day,mon,year};
33 //数码管小数点显示位置
34 assign point = (sw_flag == 1'b0) ? 6'b010100 : 6'b000100;
35
36 //对输入的按键信号打两拍
37 always @(posedge clk or negedge rst_n) begin
38     if(!rst_n) begin
39         key_value_d0 <= 1'b0;
40         key_value_d1 <= 1'b0;
41     end
42     else begin
43         key_value_d0 <= key_value;
44         key_value_d1 <= key_value_d0;
45     end
46 end
47
48 //控制sw_flag信号翻转
49 always @(posedge clk or negedge rst_n) begin
50     if(!rst_n)
51         sw_flag <= 1'b0;
52     else if(neg_key_value)
53         sw_flag <= ~sw_flag;
54 end        
55
56 endmodule
由于数码管总共可以显示6位数据,没有办法同时显示日期和时间,因此根据输入的按键来切换数码管显示日期和时间。
sw_flag信号用来切换数码管显示日期和时间,sw_flag初始值为0,当检查到输入按键的下降沿后,sw_flag取反,如程序中第49至54行所示。当sw_flag等于0时,数码管显示时间值;当sw_flag等于1时,数码管显示日期值,如程序中第32行代码所示。
数码管BCD驱动模块的代码如下所示:
1   module seg_bcd_dri(
2      //input
3      input                  clk    ,         // 时钟信号
4      input                  rst_n  ,         // 复位信号
5      input        [23:0]    data   ,         // 6个数码管要显示的数值
6      input        [5:0]     point  ,         // 小数点具体显示的位置,从高到低,高有效
7      input                  en,
8   
9      //output
10     output  reg  [5:0]     seg_sel,         // 数码管位选
11     output  reg  [7:0]     seg_led          // 数码管段选
12  );
13  
14  //parameter define
15  localparam  CLK_DIVIDE = 4'd10     ;       // 时钟分频系数
16  localparam  MAX_NUM    = 13'd5000  ;       // 对数码管驱动时钟(5MHz)计数1ms所需的计数值
17  
18  
19  //reg define
20  reg    [15:0]             cnt0     ;       // 1ms计数
21  reg    [7:0]              cnt      ;       // 切换显示数码管用
22  reg    [3:0]              data1    ;       // 送给要显示的数码管,要亮的灯
23  reg                       point1   ;       // 要显示的小数点
24  reg    [3:0]              clk_cnt  ;       // 时钟分频计数器
25  reg                       dri_clk  ;       // 数码管的驱动时钟,5MHz
26  reg    [12:0]             cnt0     ;       // 数码管驱动时钟计数器
27  reg                       flag     ;       // 标志信号(标志着cnt0计数达1ms)
28  reg    [7:0]              cnt_sel  ;       // 数码管位选计数器
29  
30  //*****************************************************
31  //**                    main code
32  //*****************************************************
33  
34  //对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
35  always @(posedge clk or negedge rst_n) begin
36     if(!rst_n) begin
37         clk_cnt <= 4'd0;
38         dri_clk <= 1'b1;
39     end
40     else if(clk_cnt == CLK_DIVIDE / 2 - 1) begin
41         clk_cnt <= 4'd0;
42         dri_clk <= ~dri_clk;
43     end
44     else begin
45         clk_cnt <= clk_cnt + 1'b1;
46         dri_clk <= dri_clk;
47     end
48  end
49  
50  //每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
51  always @ (posedge dri_clk or negedge rst_n) begin
52      if (rst_n == 1'b0) begin
53          cnt0 <= 13'b0;
54          flag <= 1'b0;
55       end
56      else if (cnt0 < MAX_NUM - 1'b1) begin
57          cnt0 <= cnt0 + 1'b1;
58          flag <= 1'b0;
59       end
60      else begin
61          cnt0 <= 13'b0;
62          flag <= 1'b1;
63       end
64  end
65  
66  //cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
67  always @ (posedge dri_clk or negedge rst_n) begin
68      if (rst_n == 1'b0)
69          cnt_sel <= 8'b0;
70      else if(flag) begin
71          if(cnt_sel < 8'd11)
72              cnt_sel <= cnt_sel + 1'b1;
73          else
74              cnt_sel <= 8'b0;
75      end
76      else
77          cnt_sel <= cnt_sel;
78  end
79  
80  //控制数码管位选信号,使6位数码管轮流显示
81  always @ (posedge dri_clk or negedge rst_n) begin
82      if(!rst_n) begin
83          seg_sel <= 6'b000000;              //位选信号低电平有效
84          data1 <= 4'b0;           
85          point1 <= 1'b1;                     //共阳极数码管,低电平导通
86      end
87      else begin
88          if(en) begin
89              case (cnt_sel)
90                  8'd0 :begin
91                      seg_sel <= 6'b000001;  //显示数码管最低位
92                      data1 <= data[7:4] ;    //显示的数据
93                      point1 <= ~point[5];    //显示的小数点
94                  end
95                  8'd1 :begin
96                      seg_sel <= 6'b000000;  //清空使MOS放电
97                      data1 <= 4'd10;
98                  end
99                  8'd2 :begin
100                     seg_sel <= 6'b000010;  //显示数码管第1位
101                     data1 <= data[3:0] ;
102                     point1 <= ~point[4];
103                 end
104                 8'd3 :begin
105                     seg_sel <= 6'b000000;  //清空使MOS放电
106                     data1 <= 4'd10;
107                 end
108                 8'd4 :begin
109                     seg_sel <= 6'b000100;  //显示数码管第2位
110                     data1 <= data[15:12];
111                     point1 <= ~point[3];
112                 end
113                 8'd5 :begin
114                     seg_sel <= 6'b000000;   //清空使MOS放电
115                     data1 <= 4'd10;
116                 end
117                 8'd6 :begin
118                     seg_sel <= 6'b001000;   //显示数码管第3位
119                     data1 <= data[11:8];
120                     point1 <= ~point[2];
121                 end
122                 8'd7 :begin
123                     seg_sel <= 6'b000000;   //清空使MOS放电
124                     data1 <= 4'd10;
125                 end
126                 8'd8 :begin
127                     seg_sel <= (6'b010000); //显示数码管第4位
128                     data1 <= data[23:20];
129                     point1 <= ~point[1];
130                 end
131                 8'd9 :begin
132                     seg_sel <= 6'b000000;   //清空使MOS放电
133                     data1 <= 4'd10;
134                 end
135                 8'd10 :begin
136                     seg_sel <= 6'b100000;   //显示数码管最高位
137                     data1 <= data[19:16];
138                     point1 <= ~point[0];
139                 end
140                 8'd11 :begin
141                     seg_sel <= 6'b000000;  //清空使MOS放电
142                     data1 <= 4'd10;
143                 end
144                 default :begin
145                     seg_sel <= 6'b000000;
146                     data1 <= 4'b0;
147                     point1 <= 1'b1;
148                 end
149             endcase
150         end
151         else begin
152             seg_sel <= 6'b000000;          //使能信号为0时,所有数码管均不显示
153             data1 <= 4'b0;
154             point1 <= 1'b1;
155         end
156     end
157 end
158
159 //数码管显示数据
160 always @ (posedge dri_clk or negedge rst_n) begin
161     if(rst_n == 1'b0)
162         seg_led <= ~(8'hc0);
163     else begin
164         case(data1)
165             4'd0: seg_led <= ~{point1,7'b1000000};
166             4'd1: seg_led <= ~{point1,7'b1111001};
167             4'd2: seg_led <= ~{point1,7'b0100100};
168             4'd3: seg_led <= ~{point1,7'b0110000};
169             4'd4: seg_led <= ~{point1,7'b0011001};
170             4'd5: seg_led <= ~{point1,7'b0010010};
171             4'd6: seg_led <= ~{point1,7'b0000010};
172             4'd7: seg_led <= ~{point1,7'b1111000};
173             4'd8: seg_led <= ~{point1,7'b0000000};
174             4'd9: seg_led <= ~{point1,7'b0010000};
175             4'd10: seg_led <= ~8'b11111111;           //不显示任何字符
176             default: seg_led <= ~{point1,7'b1000000};
177         endcase
178     end
179 end
180 endmodule
由于是PCF8563的数据是BCD编码,从低到高每4位二进制数代表一位十进制数,所以在第89行的case语句块中,我们只需把data信号相应位的值赋给data1即可。有关数码管显示更详细的解释可参考“动态数码管显示实验”。
31.5下载验证
首先我们将下载器与开发板上的JTAG接口连接,下载器另外一端与电脑连接,然后连接电源线并打开电源开关。
最后我们下载程序,验证RTC实时时钟数码管显示功能。程序下载完成后观察到开发板上数码管显示的值为我们设置的初始日期值,并且在不断实时变化;当按下KEY0按键后,数码管显示年月日,说明PCF8563实时时钟数码管显示实验程序下载验证成功。
数码管显示的日期如下图所示:
RTC实时时钟数码管显示实验22250.png
图 31.5.1 数码管显示日期

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-2 20:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表