前段时间有个高中老同学要我帮他做个单片机课程设计。课题是《单片机系统在线参数设置装置》。这个所谓的“在线系统参数设置”我想应该就是用外部键盘来设置或查询单片机内部内存单元的值吧!现实意义是有的,在设计仪单片机为可信的智能仪器,仪表及在线参数检测与控制装置的过程中,参数设定是一项不可缺少的内容。为了实现在线对系统参数进行设定或修改,通常采用微动开关,拨码盘等器件。然而,在某些情况下,当设定的数据较多,或设置参数后,还需要进行显示检查,若采用上述器件是不方便的,有时还影响系统的正常工作。
于是我就做了一个用外部键盘修改和查询单片机指定内存单元的内容的装置。硬件比较简单。由于要访问指定内存单元,软件如果用C写的话主要的难度我想应该是涉及到了C与ASM的混编。
下面主要来讲讲在KEIL中的混编过程。
混合编程是要遵守一定的规矩的。本次是在C中嵌入汇编。方法的思想是:
工程的绝大部分用 C实现,至于那些不得不用汇编实现的部分,就用汇编来实现。在C中调用汇编子函数是个很好的方法。显然此方法就是要解决被调用的汇编函数的参数传递问题。利用KEIL编译器的反汇编功能很容易解决此问题。先用C写好一个空的函数框架,并在工程中调用它。之后利用利用编译器将那个空函数反汇编生成.src文件。显然其相关的参数利用的寄存器就在src文件中写出来了。在该文件中加入想要实现的功能的汇编代码就行了。最后将该文件改为.a51文件,加入工程编译即可了。
下面来个具体的列子(是引用的别人的帖子):
有关c51调用汇编的方法已经有很多帖子讲到,但是一般只讲要点,很少有对整个过程作详细描述,对于初学者是不够的,这里笔者
通过一个简单例子对这个过程进行描述,希望能对初学者有所帮助。几年来,在这个论坛里笔者得到很多热心人指导,因此也希望
藉此尽一点绵薄之力。
在这个例子里,阐述了编写c51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是
一个整型变量。例中,先用c51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所
要的汇编函数。该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。
step1. 按写普通c51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。
相关文件如下:
//main.c文件
#include < reg51.h >
#define uchar unsigned char
#define uint unsigned int
extern uint AFUNC(uchar v_achr,bit v_bflag);
void main()
{
bit BFLAG;
uchar mav_chr;
uint mvintrslt;
mav_chr=0xd4; BFLAG="1";
mvintrslt="AFUNC"(mav_chr,BFLAG);
}
//CFUNC.c文件
#define uchar unsigned char
#define uint unsigned int
uint AFUNC(uchar v_achr,bit v_bflag)
{
uchar tmp_vchr;
uint tp_vint;
tmp_vchr=v_achr;
tp_vint=(uint)v_bflag;
return tmp_vchr+(tp_vint<<8);
}
step2. 在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for ...”,点击右边的“Generate Assembler SRC
File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
step3. 根据选择的编译模式,把相应的库文件(如 Small 模式时,是 KeilC51LibC51S.Lib)加入工程中,该文件必须作为工 程的最后文件;
step4. build这个工程后将会产生一个CFUNC.SRC的文件,将这个文件改名为CFUNC.A51(也可以通过编译选项直接产生CFUNC.A51文
件),然后在工程里去掉库文件(如C51S.Lib)和CFUNC.c,而将CFUNC.A51添加到工程里。
//CFUNC.SRC文件如下
.CFUNC.SRC generated from: CFUNC.c
NAME CFUNC
?PR?_AFUNC?CFUNC SEGMENT CODE
?BI?_AFUNC?CFUNC SEGMENT BIT OVERLAYABLE
PUBLIC ?_AFUNC?BIT
PUBLIC _AFUNC
RSEG ?BI?_AFUNC?CFUNC
?_AFUNC?BIT:
v_bflag?041: DBIT 1
; #define uchar unsigned char
; #define uint unsigned int
;
; uint AFUNC(uchar v_achr,bit v_bflag)
RSEG ?PR?_AFUNC?CFUNC
_AFUNC:
USING 0
; SOURCE LINE # 5
;---- Variable 'v_achr?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 6
; uchar tmp_vchr;
; uint tp_vint;
;
; tmp_vchr=v_achr;
; SOURCE LINE # 10
;---- Variable 'tmp_vchr?042' assigned to Register 'R5' ----
MOV R5,AR7
; tp_vint=(uint)v_bflag;
; SOURCE LINE # 11
MOV C,v_bflag?041
CLR A
RLC A
;---- Variable 'tp_vint?043' assigned to Register 'R6/R7' ----
; return tmp_vchr+(tp_vint<<8);
; SOURCE LINE # 12
MOV R6,A
MOV R4,#00H
CLR A
ADD A,R5
MOV R7,A
MOV A,R4
ADDC A,R6
MOV R6,A
; }
; SOURCE LINE # 13
?C0001:
RET
; END OF _AFUNC
END
step5. 检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状
态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。
以下是在线参数设置系统在PROTEUS中的仿真实现:
硬件图如下:
代码如下:
//test.c文件
/*----------------------------------------------------------
课程设计:单片机系统在线参数设置系统源代码
功能: 能在线查询和修改指定内存单元的值
water-2008-5-30-first
water-2008-5-31-secend
------------------------------------------------------------*/
//-----------------------变量声明------------------------------------------------
#include
#define KEY P1
sbit P2_0=P2^0 ;
sbit P2_1=P2^1;
sbit P2_2=P2^2 ;
sbit P2_3=P2^3;
sbit P3_0=P3^0;
sbit P3_1=P3^1;
unsigned char led1=16,led2=16,led3=16,led4=16,num=0,flag_fun=0,flag_in=0; //led1~4分别表示四个数码管的显示值
char key_v=16;
unsigned char code water[17]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0x0C6,0xA1,0x86,0x8E,0xff}; //数码管显示表
//-----------------------函数声明----------------------------------------------------------
void program_SCANkey(); //程序扫描键盘,供主程序调用
void delay(unsigned int N) ;//延时子程序,实现(16*N+24)us的延时
bit judge_hitkey(); //判断是否有键按下,有返回1,没有返回0
unsigned char scan_key(); //扫描键盘,返回键值(高四位代表行,低四位代表列)
void key_manage(unsigned char keycode); //键盘散转
extern unsigned char pass(unsigned char ) ; //返回指定内存单元内容的高位汇编函数
extern unsigned char pass2(unsigned char ) ; //返回指定内存单元内容的低位汇编函数
extern void pass_to_ram(unsigned char,unsigned char); //送往指定内存单元,指定的值的汇编函数
//-------------------------------- --------------------------------------------------------
// 函数名称: program_SCANkey
// 函数功能: 程序扫描键盘,
// 有键按下完成按键处理,无键按下直接返回
//-----------------------------------------------------------------------------------------
void program_SCANkey()
{
unsigned char key_code;
if(judge_hitkey()) //判断是否有键按下
{
delay(100); //延时20ms左右,消除抖动干扰
if(judge_hitkey()) //判断是否有效按键
{
key_code=scan_key();
while(judge_hitkey()); //等待按键释放
key_manage(key_code); //键盘扫描、键盘散转、按键处理
}
}
}
//-------------------------------- --------------------------------------------------------
/// 函数名称: delay
// 入口参数: N
// 函数功能:延时子程序,实现(16*N+24)us的延时
// 系统采用11.0592MHz的时钟时,延时满足要求,其它情况需要改动
//-----------------------------------------------------------------------------------------
//---------
void delay(unsigned int N)
{
int i;
for(i=0;i< P>
}
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
// 函数名称: judge_hitkey
// 函数功能: //判断是否有键按下,有返回1,没有返回0
//-----------------------------------------------------------------------------------------
bit judge_hitkey() //判断是否有键按下,有返回1,没有返回0
{
unsigned char scancode,keycode;
scancode="0x0f"; //P1.4~P1.7输出全1全1则无键闭合
KEY="scancode";
keycode="KEY"; //读P1.0~P1.3的状态
if(keycode==0x0f)
return(0); //全1则无键闭合
else
return(1); //否则有键闭合
}
//-----------------------------------------------------------------------------------------
// 函数名称: scan_key
// 函数功能: //扫描键盘,返回键值(高四位代表行,低四位代表列)
//-----------------------------------------------------------------------------------------
unsigned char scan_key() //扫描键盘,返回键值(高四位代表列,低四位代表行)
{
unsigned char scancode,keycode;
scancode="0xef"; //键盘扫描码,采用逐列扫描的方法
while(scancode!=0xff)
{
KEY="scancode"; //输入扫描码,扫描P1.4对应的行
keycode="KEY"; //读出数据,看是否在此行上的某列键盘被按下
if((keycode&0x0f)!=0x0f)
break; //扫描到按下的键,则退出
scancode=(keycode<<1)|0x0f; //否则,更新扫描码继续扫描
}
keycode=~keycode;
return(keycode);
}
//-----------------------------------------------------------------------------------------
// 函数名称: key_manage
// 入口参数: keycode 扫描键盘返回的键值(高四位代表行,低四位代表列)
// 函数功能: 键盘散转,使指定的键值完成指定的功能
//-----------------------------------------------------------------------------------------
void key_manage(unsigned char keycode)
{
switch(keycode)
{
case 0x11:num=(++num)%2;
if(flag_fun==1) key_v=10;
else key_v=0;
break;
case 0x12:num=(++num)%2;if(flag_fun==1) key_v=11;
else key_v=1;
break;
case 0x14: num=(++num)%2;if(flag_fun==1) key_v=12;
else key_v=2;
break;
case 0x18: num=(++num)%2;if(flag_fun==1) key_v=13;
else key_v=3;
break;
case 0x21: num=(++num)%2;if(flag_fun==1) key_v=14;
else key_v=4;
break;
case 0x22: num=(++num)%2;if(flag_fun==1) key_v=15;
else key_v=5;
break;
case 0x28:num=(++num)%2; key_v=7;break;
case 0x24: num=(++num)%2;key_v=6;break;
case 0x41:num=(++num)%2; key_v=8;break;
case 0x42:num=(++num)%2; key_v=9;break;
case 0x44: key_v++;if(key_v==16) key_v=0;break;
case 0x48: key_v--;if(key_v<0) key_v=15;break;
case 0x81: pass_to_ram(led1*16+led2,led3*16+led4);break;//确认将数据写入内存
case 0x82: if(flag_in==1) //将要向内存中写入数据
{
num="0";key_v=led2;
flag_in=0;
}
else
{
flag_in++;
num="0";
led3=16;
key_v=16;
}
break;
case 0x84: key_v=led2;num=0;led3=pass(led1*16+led2);led4=pass2(led1*16+led2);break;//确认显示当前内存的值
case 0x88: if(flag_fun==1) flag_fun=0; //数字键的复用按纽
else flag_fun++ ;
break;
}
if(flag_in==1)
{
if(num==1)
led3=key_v;
if(num==0)
led4=key_v;
}
else
{
if(num==1)
led1=key_v;
if(num==0)
led2=key_v;
}
}
void display(void) //四位一体数码管显示函数
{
P0=0xff;
P2=P2||0x0f;
P2_0=0;
P0=water[led1];
delay(30);
P2_0=1;
P0=0XFF;
P2_1=0;
P0=water[led2];
delay(30);
P2_1=1;
P0=0xff;
P2_2=0;
P0=water[led3];
delay(30);
P2_2=1;
P0=0xff;
P2_3=0;
P0=water[led4];
delay(30);
P2_3=1;
P0=0xff;
if(flag_in==1)
P3_1=0;
else P3_1=1;
if(flag_fun==1)
P3_0=0;
else P3_0=1;
}
void main() //主函数
{
while(1)
{
program_SCANkey();
display();
}
}
//cff.a51文件
; .cff.SRC generated from: cff.c
; COMPILER INVOKED BY:
; E:professionkeil750C51BINC51.EXE cff.c ROM(SMALL) BROWSE DEBUG OBJECTEXTEND SRC(.cff.SRC)
;extern unsigned char pass(unsigned char ) ; //返回指定内存单元内容的高位汇编函数
$NOMOD51
NAME CFF
P0 DATA 080H
P1 DATA 090H
P2 DATA 0A0H
P3 DATA 0B0H
T0 BIT 0B0H.4
AC BIT 0D0H.6
T1 BIT 0B0H.5
T2 BIT 090H.0
EA BIT 0A8H.7
IE DATA 0A8H
EXF2 BIT 0C8H.6
RD BIT 0B0H.7
ES BIT 0A8H.4
IP DATA 0B8H
RI BIT 098H.0
INT0 BIT 0B0H.2
CY BIT 0D0H.7
TI BIT 098H.1
INT1 BIT 0B0H.3
RCAP2H DATA 0CBH
PS BIT 0B8H.4
SP DATA 081H
T2EX BIT 090H.1
OV BIT 0D0H.2
RCAP2L DATA 0CAH
C_T2 BIT 0C8H.1
WR BIT 0B0H.6
RCLK BIT 0C8H.5
TCLK BIT 0C8H.4
SBUF DATA 099H
PCON DATA 087H
SCON DATA 098H
TMOD DATA 089H
TCON DATA 088H
IE0 BIT 088H.1
IE1 BIT 088H.3
B DATA 0F0H
CP_RL2 BIT 0C8H.0
ACC DATA 0E0H
ET0 BIT 0A8H.1
ET1 BIT 0A8H.3
TF0 BIT 088H.5
ET2 BIT 0A8H.5
TF1 BIT 088H.7
TF2 BIT 0C8H.7
RB8 BIT 098H.2
TH0 DATA 08CH
EX0 BIT 0A8H.0
IT0 BIT 088H.0
TH1 DATA 08DH
TB8 BIT 098H.3
EX1 BIT 0A8H.2
IT1 BIT 088H.2
TH2 DATA 0CDH
P BIT 0D0H.0
SM0 BIT 098H.7
TL0 DATA 08AH
SM1 BIT 098H.6
TL1 DATA 08BH
SM2 BIT 098H.5
TL2 DATA 0CCH
PT0 BIT 0B8H.1
PT1 BIT 0B8H.3
RS0 BIT 0D0H.3
PT2 BIT 0B8H.5
TR0 BIT 088H.4
RS1 BIT 0D0H.4
TR1 BIT 088H.6
TR2 BIT 0C8H.2
PX0 BIT 0B8H.0
PX1 BIT 0B8H.2
DPH DATA 083H
DPL DATA 082H
EXEN2 BIT 0C8H.3
REN BIT 098H.4
T2CON DATA 0C8H
RXD BIT 0B0H.0
TXD BIT 0B0H.1
F0 BIT 0D0H.5
PSW DATA 0D0H
?PR?_pass?CFF SEGMENT CODE INBLOCK
?DT?_pass?CFF SEGMENT DATA OVERLAYABLE
PUBLIC _pass
RSEG ?DT?_pass?CFF
?_pass?BYTE:
temp?042: DS 1
; #include
; unsigned char pass(unsigned char value)
RSEG ?PR?_pass?CFF
_pass:
USING 0
; SOURCE LINE # 2
;---- Variable 'value?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 3
; unsigned char good,temp=value;
; SOURCE LINE # 4
MOV temp?042,R7
MOV R0,temp?042
MOV A,@R0
MOV B,#16
DIV AB
MOV R7,A ;A为商,即为十六进制的高位
; good="3";
; SOURCE LINE # 5
;---- Variable 'good?041' assigned to Register 'R7' ----
; MOV R7,#04H
; return good ;
; SOURCE LINE # 6
;
; } ; SOURCE LINE # 8
?C0001:
RET
; END OF _pass
END
//cpass.A51文件
; .cpass2.SRC generated from: cpass2.c
; COMPILER INVOKED BY:
; E:professionkeil750C51BINC51.EXE cpass2.c ROM(SMALL) BROWSE DEBUG OBJECTEXTEND SRC(.cpass2.SRC)
;extern unsigned char pass2(unsigned char ) ; //返回指定内存单元内容的低位汇编函数
$NOMOD51
NAME CPASS2
P0 DATA 080H
P1 DATA 090H
P2 DATA 0A0H
P3 DATA 0B0H
T0 BIT 0B0H.4
AC BIT 0D0H.6
T1 BIT 0B0H.5
T2 BIT 090H.0
EA BIT 0A8H.7
IE DATA 0A8H
EXF2 BIT 0C8H.6
RD BIT 0B0H.7
ES BIT 0A8H.4
IP DATA 0B8H
RI BIT 098H.0
INT0 BIT 0B0H.2
CY BIT 0D0H.7
TI BIT 098H.1
INT1 BIT 0B0H.3
RCAP2H DATA 0CBH
PS BIT 0B8H.4
SP DATA 081H
T2EX BIT 090H.1
OV BIT 0D0H.2
RCAP2L DATA 0CAH
C_T2 BIT 0C8H.1
WR BIT 0B0H.6
RCLK BIT 0C8H.5
TCLK BIT 0C8H.4
SBUF DATA 099H
PCON DATA 087H
SCON DATA 098H
TMOD DATA 089H
TCON DATA 088H
IE0 BIT 088H.1
IE1 BIT 088H.3
B DATA 0F0H
CP_RL2 BIT 0C8H.0
ACC DATA 0E0H
ET0 BIT 0A8H.1
ET1 BIT 0A8H.3
TF0 BIT 088H.5
ET2 BIT 0A8H.5
TF1 BIT 088H.7
TF2 BIT 0C8H.7
RB8 BIT 098H.2
TH0 DATA 08CH
EX0 BIT 0A8H.0
IT0 BIT 088H.0
TH1 DATA 08DH
TB8 BIT 098H.3
EX1 BIT 0A8H.2
IT1 BIT 088H.2
TH2 DATA 0CDH
P BIT 0D0H.0
SM0 BIT 098H.7
TL0 DATA 08AH
SM1 BIT 098H.6
TL1 DATA 08BH
SM2 BIT 098H.5
TL2 DATA 0CCH
PT0 BIT 0B8H.1
PT1 BIT 0B8H.3
RS0 BIT 0D0H.3
PT2 BIT 0B8H.5
TR0 BIT 088H.4
RS1 BIT 0D0H.4
TR1 BIT 088H.6
TR2 BIT 0C8H.2
PX0 BIT 0B8H.0
PX1 BIT 0B8H.2
DPH DATA 083H
DPL DATA 082H
EXEN2 BIT 0C8H.3
REN BIT 098H.4
T2CON DATA 0C8H
RXD BIT 0B0H.0
TXD BIT 0B0H.1
F0 BIT 0D0H.5
PSW DATA 0D0H
?PR?_pass2?CPASS2 SEGMENT CODE INBLOCK
?DT?_pass2?CPASS2 SEGMENT DATA OVERLAYABLE
PUBLIC _pass2
RSEG ?DT?_pass2?CPASS2
?_pass2?BYTE:
temp?042: DS 1
; #include
; unsigned char pass2(unsigned char value2)
RSEG ?PR?_pass2?CPASS2
_pass2:
USING 0
; SOURCE LINE # 2
;---- Variable 'value2?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 3
; unsigned char good2,temp=value2;
; SOURCE LINE # 4
MOV temp?042,R7
MOV R0,temp?042
MOV A,@R0
MOV B,#16
DIV AB
MOV R7,B ;B为十六进制的低位
; good2=3;
; SOURCE LINE # 5
;---- Variable 'good2?041' assigned to Register 'R7' ----
; MOV R7,#03H
; return good2 ;
; SOURCE LINE # 6
;
; } ; SOURCE LINE # 8
?C0001:
RET
; END OF _pass2
END
//cpass_to_ram.A51文件
; .cpass_to_ram.SRC generated from: cpass_to_ram.c
; COMPILER INVOKED BY:
; E:professionkeil750C51BINC51.EXE cpass_to_ram.c ROM(SMALL) BROWSE DEBUG OBJECTEXTEND SRC(.cpass_to_ram.SRC)
;extern void pass_to_ram(unsigned char,unsigned char); //送往指定内存单元,指定的值的汇编函数
$NOMOD51
NAME CPASS_TO_RAM
P0 DATA 080H
P1 DATA 090H
P2 DATA 0A0H
P3 DATA 0B0H
T0 BIT 0B0H.4
AC BIT 0D0H.6
T1 BIT 0B0H.5
T2 BIT 090H.0
EA BIT 0A8H.7
IE DATA 0A8H
EXF2 BIT 0C8H.6
RD BIT 0B0H.7
ES BIT 0A8H.4
IP DATA 0B8H
RI BIT 098H.0
INT0 BIT 0B0H.2
CY BIT 0D0H.7
TI BIT 098H.1
INT1 BIT 0B0H.3
RCAP2H DATA 0CBH
PS BIT 0B8H.4
SP DATA 081H
T2EX BIT 090H.1
OV BIT 0D0H.2
RCAP2L DATA 0CAH
C_T2 BIT 0C8H.1
WR BIT 0B0H.6
RCLK BIT 0C8H.5
TCLK BIT 0C8H.4
SBUF DATA 099H
PCON DATA 087H
SCON DATA 098H
TMOD DATA 089H
TCON DATA 088H
IE0 BIT 088H.1
IE1 BIT 088H.3
B DATA 0F0H
CP_RL2 BIT 0C8H.0
ACC DATA 0E0H
ET0 BIT 0A8H.1
ET1 BIT 0A8H.3
TF0 BIT 088H.5
ET2 BIT 0A8H.5
TF1 BIT 088H.7
TF2 BIT 0C8H.7
RB8 BIT 098H.2
TH0 DATA 08CH
EX0 BIT 0A8H.0
IT0 BIT 088H.0
TH1 DATA 08DH
TB8 BIT 098H.3
EX1 BIT 0A8H.2
IT1 BIT 088H.2
TH2 DATA 0CDH
P BIT 0D0H.0
SM0 BIT 098H.7
TL0 DATA 08AH
SM1 BIT 098H.6
TL1 DATA 08BH
SM2 BIT 098H.5
TL2 DATA 0CCH
PT0 BIT 0B8H.1
PT1 BIT 0B8H.3
RS0 BIT 0D0H.3
PT2 BIT 0B8H.5
TR0 BIT 088H.4
RS1 BIT 0D0H.4
TR1 BIT 088H.6
TR2 BIT 0C8H.2
PX0 BIT 0B8H.0
PX1 BIT 0B8H.2
DPH DATA 083H
DPL DATA 082H
EXEN2 BIT 0C8H.3
REN BIT 098H.4
T2CON DATA 0C8H
RXD BIT 0B0H.0
TXD BIT 0B0H.1
F0 BIT 0D0H.5
PSW DATA 0D0H
?PR?_pass_to_ram?CPASS_TO_RAM SEGMENT CODE INBLOCK
?DT?_pass_to_ram?CPASS_TO_RAM SEGMENT DATA OVERLAYABLE
PUBLIC _pass_to_ram
RSEG ?DT?_pass_to_ram?CPASS_TO_RAM
?_pass_to_ram?BYTE:
temp1?042: DS 1
temp2?043: DS 1
; #include
; void pass_to_ram(unsigned char value1,unsigned char value2)
RSEG ?PR?_pass_to_ram?CPASS_TO_RAM
_pass_to_ram:
; SOURCE LINE # 2
;---- Variable 'value2?041' assigned to Register 'R5' ----
;---- Variable 'value1?040' assigned to Register 'R7' ----
; {
; SOURCE LINE # 3
; unsigned char temp1=value1;
; SOURCE LINE # 4
MOV temp1?042,R7
MOV R0,temp1?042
; unsigned char temp2=value2;
; SOURCE LINE # 5
MOV temp2?043,R5
MOV A, temp2?043
MOV @R0,A
;
;
;
;
;
; } ; SOURCE LINE # 11
RET
; END OF _pass_to_ram
END
用户846366 2009-12-11 18:56
用户157656 2008-7-29 09:51