mini2440裸机试炼之—RTC闹钟中断,节拍中断
版权声明:博客地址:http://blog.csdn.net/muyang_ren。源代码能够在我的github上找看看 https://blog.csdn.net/muyang_ren/article/details/36238457
环境搭建
硬件环境:J-link v8、mini2440、J-link转接板、串口转USB线
软件环境:windows7(32位)、开发板uboot(NandFlash)、J-link驱动(J-Link ARM V4.10i)、SecureCRT、ADS1.2
其中ADS里的AXD设置:载入JlinkRDI.dll+Options->Configure Interface...,在Session File一页中选择“Run Configuration
Script”,将该name.txt文本文件作为一个脚本加进来,确定。
name.txt内容
Setmem 0x53000000 0x00000000 32
Setmem 0x4A000008 0xFFFFFFFF 32
Setmem 0x4A00001C 0x000007FF 32
Setmem 0x53000000 0x00000000 32
Setmem 0x56000050 0x000055AA 32
Setmem 0x4C000014 0x00000007 32
Setmem 0x4C000000 0x00FFFFFF 32
Setmem 0x4C000004 0x00061012 32
Setmem 0x4C000008 0x00040042 32
Setmem 0x48000000 0x22111120 32
Setmem 0x48000004 0x00002F50 32
Setmem 0x48000008 0x00000700 32
Setmem 0x4800000C 0x00000700 32
Setmem 0x48000010 0x00000700 32
Setmem 0x48000014 0x00000700 32
Setmem 0x48000018 0x0007FFFC 32
Setmem 0x4800001C 0x00018005 32
Setmem 0x48000020 0x00018005 32
Setmem 0x48000024 0x008E0459 32
Setmem 0x48000028 0x00000032 32
Setmem 0x4800002C 0x00000030 32
Setmem 0x48000030 0x00000030 32
RTC实现功能
RTC开节拍中断、闹钟中断。
节拍中断——串口输出时间 XXXX年XX月XX日XX时XX分XX秒 和 LED闪亮
闹钟中断——beep声 和 LED亮 5秒
实时时钟(RTC)单元能够在当系统电源关闭后通过备用电池工作。
RTC能够通过使用STRB/LDRB ARM操
作发送8位二-十进制交换码(BCD)值数据给CPU。
这些数据包含年、月、日、星期、时、分和秒的时间信息。
RTC单元工作在外部32.768kHz晶振而且能够运行闹钟功能。
特性
– BCD数:年、月、日、星期、时、分和秒
– 闰年发生器
– 闹钟功能:闹钟中断或从掉电模式唤醒
– 已解决的2000年问题
– 独立电源引脚(RTCVDD)
– 支持RTOS内核时钟节拍(tick)的毫秒节拍时间中断
由图可知因为RTC秒有RTCRST复位寄存器,当RTC寄存器被赋值后,秒寄存器数值自己主动1s(1s=(1/1HZ),
1HZ为2^15时钟分频器产生的1HZ)加一,秒寄存器到60时被复位寄存器置零,分寄存器加一,以此类推。
RTC实时时钟
实时时钟的值是存放在BCD寄存器里(BCD码)。BCD码是4位二进制码表示1位十进制数。
实时时钟初始化(赋值) RTCCON寄存器的使用
读写BCD 寄存器的时候仅仅须要将RTCCON寄存器RTCEN(读写)使能。其它为初始值
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbXV5YW5nX3Jlbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
实时时钟初始化代码
开BCD读写使能
rRTCCON |=0x01; //RTCCON仅仅控制BCD寄存器,ALM数据寄存器就不须要读写使能了
BCD寄存器赋值。
rBCDSEC =0x0; //14年6月12日1点1分0秒 星期4
rBCDMIN =0x01;
rBCDHOUR =0x01;
rBCDDAY =0x4; //星期
rBCDDATE =0x12;
rBCDMON =0x6;
rBCDYEAR =0x14;
BCD寄存器赋值完毕后必须将读写关闭,防止数据异常
rRTCCON &=~0x01;
之后BCD寄存器里的值開始计时
节拍中断使能
始终节拍发生器能够产生节拍中断,据用户手冊:
RTC节拍时间是用于中断请求。TICNT寄存器有一个中断使能位和中断的计数值。当节拍时间中断发生时计 数值达到'0'。然后中断周期例如以下: — 周期 = ( n+1 ) / 128 秒 — n:节拍时间计数值(1至127) 此RTC时间节拍可能被用于实时操作系统(RTOS)内核时间节拍。 假设时间节拍是由RTC时间节拍所产生的,RTOS与时间的功能将通常同步到实际时间。 |
由此可知节拍中断产生的时间能够精确到(n+1 ) / 128 秒。n为1-127区间的取值。
TICNT [7] 节拍时间中断使能。
TICNT [6:0] 节拍时间计数值(1至127)。
节拍中断使能代码
rTICNT |= (1<<7) | 127; //节拍中断使能 计时寄节拍设置1s 1s=(127+1)/128
注意:这里仅仅是开了中断使能产生节拍中断INT_TICK,并没有开中断
闹钟中断使能
闹钟功能 RTC在掉电模式中或正常工作模式中的指定时间产生一个闹钟信号。在正常工作模式中,仅仅激活闹钟中断(INT_RTC)信号。在掉电模式中,除了INT_RTC 之外还激活电源管理唤醒(PMWKUP)信号。RTC闹钟寄存器(RTCALM)决定了闹钟使能/禁止状态和闹钟时间设置的条件。 |
我们是在正常模式中产生INT_RTC(闹钟)中断信号源的。使能闹钟中断。当ALM寄存器(年、月、日、时、分、秒)的值与BCD寄存器(年、月、日、时、分、秒)值相等时产生中断信号。RTCALM寄存器是决定ALM闹钟使能和闹钟时间的,当RTCALM使能分秒的时候,仅仅确认ALM寄存器(分、秒)的值与BCD寄存器(分、秒)值是否相等即产生中断信号。
ALM寄存器是须要赋值的。但并没有BCD寄存器那样的读写使能。而是直接赋值的。
闹钟中断使能
rRTCALM = 0x41; //全局闹钟使能,秒闹钟使能(0b1000001)
ALM闹钟寄存器赋值
rALMYEAR =0x14; //年
rALMMON =0x06; //月
rALMDATE =0x12; //日
rALMHOUR =0x01; //时
rALMMIN =0x01; //分
rALMSEC =0x03; //秒
中断函数
概述
S3C2440A中的中断控制器接受来自60个中断源的请求。提供这些中断源的是内部外设,如DMA控制器、UART、IIC等等。在这些中断源中,UARTn、AC97和EINTn中断对于中断控制器而言是“或”关系。当从内部外设和外部中断请求引脚收到多个中断请求时,中断控制器在仲裁步骤后请求ARM920T内核的FIQ或IRQ。仲裁步骤由硬件优先级逻辑决定而且写入结果到帮助用户通告是各种中断源中的哪个中断发生了的中断挂起寄存器中。
闹钟中断和节拍中断是没有sub寄存器的,通过图14-1能够看出中断发生是:
中断请求中断服务>>SRCPND>>仲裁>>
INTPND>>irq中断
中断挂起寄存器
S3C2440A有两个中断挂起寄存器:源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND)。 这些挂起寄存器表明一个中断请求是否为挂起。其中断源请求中断服务,SRCPND寄存器的对应位被置位为1。而且同一时候在仲裁步骤后INTPND 寄存器仅有1位自己主动置位为1。假设屏蔽了中断。则SRCPND寄存器的对应位被置位为1。这并不会引起INTPND 寄存器的位的改变。当INTPND 寄存器的挂起位为置位,每当I |
最后一句话能够知道开启中断须要SRCPND和INTPND寄存器清除挂起状态
中断屏蔽开启可服务代码
// 注意点(二)
rINTMSK &= ~(0x1<<8); // 中断屏蔽开启可服务(此中断使能不能放在中断入口函数内,因
// 为中断使能并非中断的操作。而是进中断前的一个控制)
节拍中断函数入口代码
pISR_TICK=(unsigned)tick_interrupt; //告诉中断处理中断函数的入口地址
void __irq alm_interrupt(){ //中断入口函数
rSRCPND|=0x1<<30; //清除中断挂起状态
rINTPND|=0x1<<30; //清除中断挂起状态
//中断功能代码块
Uart_Printf("\n\n ************************************* ");
Uart_Printf("\n 闹钟时刻。5秒 ");
Uart_Printf("\n ************************************* \n");
rGPBDAT=LED_ON; //点亮LED
Beep(2000, 4000); // 因为产生中断会有一秒的时间,所以实际是用了4+1秒这个中断
// 注意点(一)
rSRCPND &=(0x1<<30); // 当产生中断的时候,必须在开了中断功能后关闭中断清除
rINTPND &=(0x1<<30); // 而且关闭中断清除的控制必须在此中断入口函数由此中断控制
// (rSRCPND rINTPND置零,包含没用到的rSUBSRCPND)都应该在中断
// 入口函数里操作,而且入口函数最后也别忘了关闭中断清除
// (rSRCPND rINTPND,rSUBSRCPND置零)
// 假设没有关闭中断,将无限实现闹钟中断功能,其它中断不能进行
}
调试总结
(一) RTC非中断串口打印时间不连续问题(BCD码)
由来:之前写了一个非中断打印RTC实时时钟的代码,发现时间由9跳到16,后面发现是打印格式是十进制的原因,
解决方法:数据在RTC里是BCD码存储。十进制的。可是取出来的时候,BCD码是四位二进制表示,最高位仅仅是9,
10时BCD码(大端存储)是0001 0000。在这时假设採取进制转换成10进制就是16,可是假设继续使用16进制显示就没
问题了。还是10
(二) 调试程序。中断没问题却发生串口代码while(!(rUTRSTAT0 & 0x2));出不来问题
解决方法:
main函数添加:
U32 mpll_val = 0,consoleNum;
Port_Init(); //定义在2440lib.c
mpll_val = (92<<12)|(1<<4)|(1);
//init FCLK=400M,
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3); //定义在2440lib.c
ChangeClockDivider(14, 12); //the result of rCLKDIVN [0:1:0:1] 3-0 bit 定义在2440lib.c
cal_cpu_bus_clk(); //HCLK=100M PCLK=50M
consoleNum = 0; // Uart 1 select for debug.
Uart_Init( 0,115200 ); //定义在2440lib.c
Uart_Select( consoleNum ); //定义在2440lib.c
cal_cpu_bus_clk()定义例如以下:
static U32 UPLL;
static U32 cpu_freq;
//************************[ HCLK=100M PCLK=50M ]***************************
void cal_cpu_bus_clk(void)
{
U32 val;
U8 m, p, s;
val = rMPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
//(m+8)*FIN*2 不要超出32位数!
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100;
val = rCLKDIVN;
m = (val>>1)&3;
p = val&1;
val = rCAMDIVN;
s = val>>8;
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>>1;
break;
case 2:
if(s&2)
HCLK = FCLK>>3;
else
HCLK = FCLK>>2;
break;
case 3:
if(s&1)
HCLK = FCLK/6;
else
HCLK = FCLK/3;
break;
}
if(p)
PCLK = HCLK>>1;
else
PCLK = HCLK;
if(s&0x10)
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON;
m = (val>>12)&0xff;
p = (val>>4)&0x3f;
s = val&3;
UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
UCLK = (rCLKDIVN&8)?
(UPLL>>1):UPLL;
}
RTC闹钟中断,节拍中断代码
Main函数代码
#define GLOBAL_CLK 1
#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h" //函数声明
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"
//功能代码声明处
extern void RTC_Display_TICK_ALM(void);
void Main(void)
{
U32 mpll_val = 0,consoleNum;
Port_Init();
mpll_val = (92<<12)|(1<<4)|(1);
//init FCLK=400M,
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
ChangeClockDivider(14, 12); //the result of rCLKDIVN [0:1:0:1] 3-0 bit
cal_cpu_bus_clk(); //HCLK=100M PCLK=50M
consoleNum = 0; // Uart 1 select for debug.
Uart_Init( 0,115200 );
Uart_Select( consoleNum );
Beep(2000, 100);
//>>>>>>>>>>>>>>下面是功能代码块入口<<<<<<<<<<<<<<<<<<<
RTC_Display_TICK_ALM(); //闹钟中断显示实时时钟,报警中断(调试成功!)
}
RTC_Display_TICK_ALM函数代码
#include "2440addr.h" //引脚宏定义
#include "def.h" // U8 U32宏定义
#include "2440lib.h" //使用Uart_Printf,Dalay声明,Uart_Printf定义在2440lib.c文件
#include "option.h"
#include "mmu.h"
#define LED_OFF (0x0f<<5)
#define LED_ON (~0x0f<<5)
struct Time{ //RTC时间结构
U32 year;
U8 month;
U8 day;
U8 week;
U8 hour;
U8 mi;
U8 sec;
}ttime_rtc;
void RTC_set()
{
rRTCCON |=0x01;
rBCDSEC =0x0; //14年6月12日1点1分0秒 星期4
rBCDMIN =0x01;
rBCDHOUR =0x01;
rBCDDAY =0x4; //星期
rBCDDATE =0x12;
rBCDMON =0x6;
rBCDYEAR =0x14;
rRTCCON &=~0x01;
}
void Led_Init(){
rGPBCON=0x015400; //GPB5 GPB6 GPB7 GPB8 初始化为输出
rGPBDAT=LED_OFF; //熄灭状态
}
//从RTC读取值
void read_for_rtc()
{
rRTCCON |=0x01; //RTCCON仅仅控制BCD寄存器,ALM数据寄存器就不须要读写控制了
ttime_rtc.year =0x2000+rBCDYEAR;
ttime_rtc.month =rBCDMON;
ttime_rtc.day =rBCDDATE;
ttime_rtc.week =rBCDDAY;
ttime_rtc.hour =rBCDHOUR;
ttime_rtc.mi =rBCDMIN;
ttime_rtc.sec =rBCDSEC;
rRTCCON &=~0x01;
}
void ALM_set(){ // 闹钟赋值
rALMYEAR =0x14;
rALMMON =0x06;
rALMDATE =0x12;
rALMHOUR =0x01;
rALMMIN =0x01;
rALMSEC =0x03;
}
void RTC_display(){
Uart_Printf("\n");
Uart_Printf("\n<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n");
Uart_Printf("**************HELLO RTC闹钟中断、节拍中断*****************\n\n");
Uart_Printf("#rTICNT: (1<<7) | 127 同意节拍使能\n",rTICNT);
Uart_Printf("#rRTCALM: 0b1000001 同意闹钟使能 秒精度闹钟\n",rRTCALM);
Uart_Printf("#rINTMSK: ~(0x1<<8) 开启INT_TICK中断源服务\n");
Uart_Printf("#rINTMSK: ~(0x1<<30) 开启INT_RTC 中断源服务\n");
Uart_Printf("#rSRCPND rINTPND 中断控制器清除对应位再关闭\n");
Uart_Printf("#\n#通过RTC节拍中断,串口输出开发板系统时间\n");
Uart_Printf("#XXXX年XX月XX日XX时XX分XX秒 | LED闪亮\n");
Uart_Printf("#而且可设置闹钟,闹钟到时,beep声|LED亮\n");
Uart_Printf("<><><><><><><><><><><><><><><><><><><><><><><><><><><><>\n\n\n\n");
}
void __irq tick_interrupt(){
rSRCPND|=0x1<<8; //清除中断挂起状态
rINTPND|=0x1<<8;
//中断功能代码块
rGPBDAT =~(rGPBDAT>>5)<<5 ; //LED灯 亮闪状态切换(这样运算不会影响到蜂鸣器)
read_for_rtc();
Uart_Printf("\n RTC time: %x年%2x月%02x日--%02x:%02x:%02x 星期%d",ttime_rtc.year,ttime_rtc.month,ttime_rtc.day,ttime_rtc.hour,ttime_rtc.mi,ttime_rtc.sec,ttime_rtc.week);
//rTICNT &= ~(1<<7); //当仅仅使用一次中断的时候关闭模块使能
rSRCPND &=(0x1<<8);
rINTPND &=(0x1<<8);
}
void __irq alm_interrupt(){ //中断入口函数
rSRCPND|=0x1<<30;
rINTPND|=0x1<<30;
//中断功能代码块
Uart_Printf("\n\n ************************************* ");
Uart_Printf("\n 闹钟时刻!
5秒 ");
Uart_Printf("\n ************************************* \n");
rGPBDAT=LED_ON; //点亮LED
Beep(2000, 4000); // 因为产生中断会有一秒的时间,所以实际是用了4+1秒这个中断
// 注意点(一)
rSRCPND &=(0x1<<30); // 当产生中断的时候,必须在开了中断功能后关闭中断清除
rINTPND &=(0x1<<30); // 而且关闭中断清除的控制必须在此中断入口函数由此中断控制
// (rSRCPND rINTPND置零,包含没用到的rSUBSRCPND)都应该在中断
// 入口函数里操作,而且入口函数最后也别忘了关闭中断清除
// (rSRCPND rINTPND,rSUBSRCPND置零)
// 假设没有关闭中断。将无限实现闹钟中断功能。其它中断不能进行
}
void RTC_TICK(){
rTICNT |= (1<<7) | 127; //节拍中断使能 计时寄节拍设置1s
// 注意点(二)
rINTMSK &= ~(0x1<<8); // 中断屏蔽开启可服务(此中断使能不能放在中断入口函数内,因
// 为中断使能并非中断的操作,而是进中断前的一个控制)
pISR_TICK=(unsigned)tick_interrupt; //告诉中断处理中断函数的入口地址
}
void RTC_ALM(){
rRTCALM = 0x41; //全局闹钟使能,秒闹钟使能(0b1000001)
rINTMSK &= ~(0x1<<30);
pISR_RTC =(unsigned)alm_interrupt;
}
void RTC_Display_TICK_ALM() // 子main函数
{
//MMU_EnableICache();这一点至关重要, 不要关闭mmu,否则中断不能正常使用
MMU_Init();
Led_Init(); //led1 2 3 4输出。初始化熄灭状态
RTC_display(); //打印对应信息
RTC_set(); //rtc赋值
ALM_set(); // ALM闹钟赋值
RTC_TICK(); //节拍中断
RTC_ALM(); //闹钟中断
while(1)
{
}
}
输出截图
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbXV5YW5nX3Jlbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
mini2440裸机试炼之—RTC闹钟中断,节拍中断的更多相关文章
- mini2440裸机试炼之——看门狗中断和复位操作
看门狗的工作原理: 设本系统程序完整执行一周期的时间是Tp,看门狗的定时周期为Ti,Ti>Tp,在程序正常执行时,定时器就不会溢出,若因为干扰等原因使系统不能在Tp时刻改动定时器的记数值,定时器 ...
- mini2440裸机试炼之——DMA直接存取 实现Uart(串口)通信
这个仅仅能作为自己初步了解MDA的开门篇 实现功能: 将字符串数据通过DMA0通道传递给UTXH0,然后在终端 显示.传输数据完后.DMA0产生中断,beep声, LED亮. DMA基本知识 计算机系 ...
- mini2440裸机试炼之——Uart与pc端实现文件、字符传输
1. 波特率(Baud rate)即调制速率,1波特即指每秒传输1个符号. 2. 非FIFO模式,即数据传输不利用FIFO缓存,一个字节一个字节地传输. 3. 位能够用来推断发送缓存器中是否为空 ...
- mini2440裸机音乐播放器(非常久曾经的笔记)
[这是好久曾经写的.有点乱,没时间整理.当做记录用的.] 图片粘贴失效.没上传图,想要的直接下载文档吧. 项目目的:通过IIS,触摸屏,LCD模块实现音乐播放器功能(button上一首.下一首.播放. ...
- mini2440裸机之I2C
// File Name : IIC.c // Function : S3C2440 IIC-bus Master Tx/Rx mode Test Program // (I ...
- 软中断与硬中断 & 中断抢占 中断嵌套
参考了这篇文章:http://blog.csdn.net/zhangskd/article/details/21992933 从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通 ...
- linux内核分析笔记----中断和中断处理程序【转】
转自:http://www.cnblogs.com/hanyan225/archive/2011/07/17/2108609.html 中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因 ...
- (转) 中断处理程序&中断服务例程
关于中断处理程序和中断服务例程ISR的区别及联系,之前一直搞混,今天抽时间将两者关系弄弄清楚.ok,下面进入主题. 首先中断处理程序(Interrupt Handler) ...
- linux内核分析笔记----中断和中断处理程序
中断还是中断,我讲了很多次的中断了,今天还是要讲中断,为啥呢?因为在操作系统中,中断是必须要讲的.. 那么什么叫中断呢, 中断还是打断,这样一说你就不明白了.唉,中断还真是有点像打断.我们知道linu ...
随机推荐
- lightswitch Grid 控件添加 CheckBox 多选
ACTIVATING MULTI SELECTION WITH CHECKBOXES IN A LIGHTSWITCH GRID WITH A ONE-LINER 2013/04/02 · by pa ...
- [CF438E] 小朋友和二叉树
Description 给定一个整数集合 \(c\),对于每个 \(i\in[1,m]\),求有多少种不同的带点权的二叉树使得这棵树点权和为 \(i\) 并且顶点的点权全部在集合 \(c\) 中.\( ...
- SpringBoot入门之Thymeleaf的使用
在.net的MVC3 或更高版本等支持 Razor 的框架里使用cshtml,Razor是一种简单的编程语法,用于在网页中嵌入服务器端代码.在使用springboot开发mvc时也有与.net类似的视 ...
- Receiver 和 Direct方式的区别
Kafka direct 跟receiver 方式接收数据的区别? Receiver是使用Kafka的高层次Consumer API来实现的.Receiver从Kafka中获取的数据都是存储在Spar ...
- 【Dubbo&&Zookeeper】3、Failed to read schema document 'http://code.alibabatech.com/schema/dubbo/dubbo.xsd'问题解决方法
转自:http://blog.csdn.net/gaoshanliushui2009/article/details/50469595 我们公司使了阿里的dubbo,但是阿里的开源网站http://c ...
- 【pygame游戏编程】第四篇-----打字测速游戏
下面我们一起用pygame编写一个打字测速游戏 这是一个很实用的有趣的小游戏: 开始之前先来学习几个小函数: 1. ord(ch) python内置函数,传入一个字符,返回字符的ascii码 2.ch ...
- Mysql数据库单表查询
1.单表查询语法 #查询数据的本质:mysql会到你本地的硬盘上找到对应的文件,然后打开文件,按照你的查询条件来找出你需要的数据.下面是完整的一个单表查询的语法 select * from,这个sel ...
- 基于angular2x+ng-bootstrap构建后台管理系统界面
写在前面的话 近来公司要做一个后台管理系统,人手比较少,于是作为一个前端也参与进来,其实据我所知,大部分的公司还是后台自己捣鼓的. 在后台没有到位的情况下,前端应该使用什么技术也着实让我为难了一把.经 ...
- jQuery中bind() live() delegate() on() 的区别
实例 bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数 $("a").bind("click",function(){aler ...
- eclipse显示代码行数
最近做的手机APP正在进行最后一部分了,在一个类中估计要写上千行代码,来回的拉动滚动条太麻烦了,于是发现为什么我得eclipse不显示代码行数呢 其他C什么的编译器都显示的. 于是百度了一下,一下子 ...