《2022年2022年矩阵键盘扫描的C语言实例 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年矩阵键盘扫描的C语言实例 .pdf(16页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、矩阵键盘扫描的C 语言实例1、按键扫描(线反转)/- - / 函数名称:program_SCANkey / 函数功能:程序扫描键盘,/ 有键按下完成按键处理,无键按下直接返回/- void program_SCANkey() unsigned char key_code; if(judge_hitkey() /判断是否有键按下 delay(1000); /延时 20ms左右,消除抖动干扰if(judge_hitkey() /判断是否有效按键 key_code=scan_key();/获取键值while(judge_hitkey(); /等待按键释放 key_manage(key_code);
2、/键盘扫描、键盘散转、按键处理 /- / 函数名称:judge_hitkey / 函数功能:/判断是否有键按下,有返回1,没有返回0 / 列判断,还可以用行判断。/- bit judge_hitkey() /判断是否有键按下,有返回1,没有返回0 unsigned char scancode,keycode; scancode=0 x0F; /开始设定P1.0P1.3 输出全 1(初值)即表明无键闭合KEY=scancode; keycode=KEY; /读取 P1.0P1.3 的真实状态,从而确定有没有键被按下if(keycode=0 x0F) return(0); /全 1 则无键闭合el
3、se return(1); /否则有键闭合 /- / 函数名称:scan_key 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 16 页 - - - - - - - - - / 函数功能:/扫描键盘,返回键值(高四位代表行,低四位代表列) / 说明: scancode 扫描码, keycode 键值 ,keycode_line 行, keycode_row 列/ 过程:先扫描行,确定那行的按键被按下。再扫描列,确定那列的按键被按下,从而确定那个按键被按下。/- unsi
4、gned char scan_key() /扫描键盘,返回键值(高四位代表行,低四位代表列 ) unsigned char scancode,keycode,keycode_line,keycode_row; scancode=0 xF0; /列置低,行置高KEY = scancode; /输入扫描码,扫描行keycode_line=KEY; /KEY 的值是与键盘相连的P 的状态值。若没有按键按下 KEY 的值为 0 xF0,若有按键按下则KEY 的值就不是0 xF0 scancode=0 x0F; /列置高,行置低KEY=scancode; /输入扫描码,扫描列keycode_row=KE
5、Y; /KEY 的值是与键盘相连的P 的状态值。若没有按键按下KEY 的值为 0 x0F,若有按键按下则KEY 的值就不是0 x0F keycode = (keycode_line&0 xF0)|(keycode_row&0 x0F); return(keycode); 2、按键扫描(逐行扫描)/- / 函数名称:kbscan 键盘扫描子程序/ 函数功能:判断是否有键按下,有返回键值,没有返回0 / p1 的高四位为列, 低四位为行P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0 / 列 4 列3 列2 列 1 行 4 行 3 行 2 行 1 / 过程:先根据列判
6、断是否有键按下,没有返回0,有,则逐行扫描以确定按键所在的行,再确定按键所在列/ 从而最终确定该按键。/- uchar kbscan(void) uchar sccode,recode; P1=0 xf0; /置所有行为低电平,行扫描,列线输入(此时 ) if(P1&0 xf0)!=0 xf0) /判断是否有有键按下(读取列的真实状态,若第 4 列有键按下则 P1的值会变成0111 0000) ,有往下执行 delays(); /延时去抖动(10ms)if(P1&0 xf0)!=0 xf0) /再次判断列中是否是干扰信号,不是则向下执行名师资料总结 - - -精品资料欢迎下载 - - - -
7、- - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 16 页 - - - - - - - - - sccode=0 xFE; /逐行扫描初值(即先扫描第1 行)while(sccode&0 x10)!=0) /行扫描完成时(即4 行已经全部扫描完成)sccode为 1110 1111 停止 while 程序 P1=sccode; /输出行扫描码if (P1&0 xf0)!=0 xf0) /本行有键按下 (即 P1(真实的状态) 的高四位不全为 1) recode=(P1&0 xf0)|0 x0f; / 列return(sccode&
8、recode); / 返回行和列 else /所扫描的行没有键按下,则扫描下一行,直到4 行都扫描,此时 sccode值为 1110 1111 退出 while 程序 sccode=(sccode1)|0 x01;/ 行扫描码左移一位 else return 0; /无键按下,返回0 - /*Main.c*/ #include global.c void SystemInit(); void Timer1Init(); void KickDog(); void delay(); unsigned int judge_key(); unsigned int scan_key(); unsigne
9、d char numkey=0; unsigned char DATX,DATY; main() 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 16 页 - - - - - - - - - SystemInit(); /系统初始化MCRA=MCRA & 0 x80FF; /IOPB0-6 设为 IO 口模式PBDATDIR=0 xBFC2; /所有 LED=0, 并置 IOPB6 为输入口Timer1Init(); /定时器初始化asm( CLRC INTM ); wh
10、ile(1) / KeyLed(); if(judge_key()=1) numkey+; void SystemInit() asm( SETC INTM ); /* 关闭总中断*/ asm( CLRC SXM ); /* 禁止符号位扩展*/ asm( CLRC CNF ); /* B0 块映射为on-chip DARAM*/ asm( CLRC OVM ); /* 累加器结果正常溢出*/ SCSR1=0 x83FE; /* 系统时钟CLKOUT=20*2=40M */ WDCR=0 x006F; /* 禁止看门狗 ,看门狗时钟64 分频*/ KickDog(); /* 初始化看门狗*/ I
11、FR=0 xFFFF; /* 清除中断标志*/ IMR=0 x0002; /* 打开中断2*/ void Timer1Init() EVAIMRA=0 x0080; / 定时器 1 周期中断使能EVAIFRA=0 xFFFF; / 清除中断标志GPTCONA=0 x0000; T1PR=2500; / 定时器 1 初值 ,定时 0.4us*2500=1ms T1CNT=0; T1CON=0 x144E; /增模式 , TPS 系数 40M/16=2.5M,T1使能 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 -
12、 - - - - - - 第 4 页,共 16 页 - - - - - - - - - unsigned int judge_key() MCRC=MCRC&0 x81FF; / PFDATDIR=PFDA TDIR|0 x0070; PFDATDIR=PFDA TDIR&0 x8FFF; /设置 456 输入高PFDATDIR=PFDA TDIR&0 xFFF1; PFDATDIR=PFDA TDIR|0 x0E00; /设置 123 输出低if(PFDATDIR&0 x0070)=0 x0070) return(0); else return(1); unsigned int scan_k
13、ey() if(judge_key()=1) delay(); if(judge_key()=1) MCRC=MCRC&0 x81FF; / PFDATDIR=PFDA TDIR|0 x0070; PFDATDIR=PFDA TDIR&0 x8FFF; /设置 456 输入高PFDATDIR=PFDA TDIR&0 xFFF1; PFDATDIR=PFDA TDIR|0 x0E00; /设置 123 输出低delay(); numkey=(PFDATDIR&0 x0070)|(PFDATDIR&0 x000E); / delay(); /MCRC=MCRC&0 x81FF; / PFDATDI
14、R=PFDA TDIR&0 xFF8F; /设置 456 输出低PFDATDIR=PFDA TDIR|0 xE000; PFDATDIR=PFDA TDIR|0 x000E; /设置 123 输入高PFDATDIR=PFDA TDIR&0 xF1FF; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 16 页 - - - - - - - - - delay(); / numkey=(PFDATDIR&0 x0070)|(PFDATDIR&0 x000E); numkey=
15、numkey|(PFDATDIR&0 x000E); return(numkey); void c_int2() /*定时器 1 中断服务程序 */ if(PIVR!=0 x27) asm( CLRC INTM ); return; scan_key() ; EVAIFRA=EV AIFRA&0 x80; asm( CLRC INTM ); void delay() int i; for(i=0;i10000;i+); void KickDog() /* 踢除看门狗*/ WDKEY=0 x5555; WDKEY=0 xAAAA; 名师资料总结 - - -精品资料欢迎下载 - - - - - -
16、 - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 16 页 - - - - - - - - - 矩阵键盘扫描程序集锦2009-08-18 11:24 初学者写的最简单矩阵键盘扫描程序这是站长初学者写的最简单、 最详细、 效率最高的矩阵键盘扫描程序,只用了四条常用命令( MOV/ 送数、JB/高电平转移、 JMP/直接转移、 RET/子程序返回),保证初学者一看就懂! 本程序已经在本站电子实验板上验证通过,占用时间少,效率高,被选作单片机的测试程序!矩阵按键扫描程序是一种节省IO 口的方法 , 按键数目越多节省IO 口就越可观,本程序的思
17、路跟书上一样:先判断某一列(行)是否有按键按下,再判断该行(列)是那一只键按下。但是,在程序的写法上,站长采用了最简单的方法,使得程序效率最高。本程序中,如果检测到某键按下了, 就不再检测其它的按键, 这完全能满足绝大多数需要, 又能节省大量的CPU 时间。另外,本人认为键盘用延时程序来消除抖动,完全是浪费时间。试想,如果不用中断执行(用中断执行需要更多的硬件资源)的方法来扫描键盘, 每秒钟扫描次,每次都要延时的话,我们的单片机还有多少时间做正事呢?其实,延时的这段时间, CPU可以做其它的事呀。所以,本键盘扫描程序的前面后面都可以加入少少代码, 既可以达到完美的消抖动效果, 又可以扩展其它的
18、功能(例如按键封锁、按键长按等按键功能复用!)本键盘扫描子程序名叫key,每次要扫描时用call key调用即可。以下子程序内容:key:mov p0,#00001111b; 上四位和下四位分别为行和列, 所以送出高低电压检查有没有按键按下jmp k10; 跳到 K10处开始扫描, 这里可以改成其它条件转移指令来决定本次扫描是否要继续,例如减1 为 0 转移或者位为 1 或 0 才转移,这主要用来增加功能,确认上一按键功能是否完成?是否相当于经过了延时?是否要封锁键盘?goend:jmp kend; 如果上面判断本次不执行键盘扫描程序,则立即转到程序尾部,不要浪费 CPU 的时间k10:jb
19、p0.0,k20;扫描正式开始,先检查列1 四个键是否有键按下,如果没有,则跳到 K20检查列 2 k11:mov p0,#11101111b; 列 1 有键按下时 ,P0.0 变低, 到底是那一个键按下?现在分别输出各行低电平jb p0.0,k12;该行的键不按下时, p0.0 为高电平 , 跳到到 K12,检查其它的行mov r1,#1; 如果正好是这行的键按下,将寄存器R0写下 1,表示 1 号键按下了k12:mov p0,#11011111b jb p0.0,k13 mov r1,#2; 如果正好是这行的键按下,将寄存器R0写下 2,表示 2 号键按下了k13:mov p0,#1011
20、1111b jb p0.0,k14 mov r1,#3; 如果正好是这行的键按下,将寄存器R0写下 3,表示 3 号键按下了k14:mov p0,#01111111b jb p0.0,kend; 如果现在四个键都没有按下, 可能按键松开或干扰, 退出扫描(以名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 16 页 - - - - - - - - - 后相同)mov r1,#4 如果正好是这行的键按下,将寄存器R0写下 4,表示 4 号键按下了jmp kend; 已经找到按
21、下的键,跳到结尾吧k20:jb p0.1,k30;列 2 检查为高电平再检查列3、4 k21:mov p0,#11101111b; 列 2 有健按下时, P0.0 会变低,到底是那一行的键按下呢?分别输出行的低电平jb p0.1,k22;该行的键不按下时p0.0 为高电平,跳到到K22,检查另外三行mov r1,#5; 如果正好是这行的键按下,将寄存器R0写下 5,表示 5 号键按下了(以后相同,不再重复了)k22:mov p0,#11011111b jb p0.1,k23 mov r1,#6 k23:mov p0,#10111111b jb p0.1,k24 mov r1,#7 k24:mo
22、v p0,#01111111b jb p0.1,kend mov r1,#8 jmp kend; 已经找到按下的键,跳到结尾吧(以后相同,不要重复了)k30:jb p0.2,k40 k31:mov p0,#11101111b jb p0.2,k32 mov r1,#9 k32:mov p0,#11011111b jb p0.2,k33 mov r1,#10 k33:mov p0,#10111111b jb p0.2,k34 mov r1,#11 k34:mov p0,#01111111b jb p0.2,kend mov r1,#12 jmp kend k40:jb p0.3,kend k41
23、:mov p0,#11101111b jb p0.3,k42 mov r1,#13 k42:mov p0,#11011111b jb p0.3,k43 mov r1,#14 k43:mov p0,#10111111b 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 16 页 - - - - - - - - - jb p0.3,k44 mov r1,#15 k44:mov p0,#01111111b jb p0.3,kend mov r1,#16 kend: ret 键盘扫
24、描结束了,寄存器R1的值就直接表示了是那个键按下的,根据不同的键值去执行不同的程序, 从而实现了十六个矩阵键盘扫描,同样原理, 最多可以识别 255 个按键的矩阵扫描。我们可以每次键盘扫描开始时检查R0的值是否为 0,只有在为 0 才扫描键盘,不为 0 就证明刚刚扫描过键值, 相应的按键工作还没有完成。 但是必须记得,每个按键命令执行完成后,要给R0写上 0,表示可以扫描键盘。本键盘扫描程序的优点在于:不用专门的按键延时程序,提高了CPU 效率,也不用中断来扫描键盘,节省了硬件资源。另外,本键盘扫描程序,每次扫描占用 CPU 时最短,不论有键按下或者无键按下都可以在很短的时间完成一次扫描。还有
25、,本程序只使用几条最常用的汇编命令,MOV/JB/JMP/RET ,而这几条命令是最常用、最易懂、最好学的命令!有的键盘扫描程序还用与呀、或呀、移位呀、查表呀,我都还没有看懂。当然,以上只是站长初学单片机的一点个人见解,欢迎广大单片机爱好者指正,希望大家将自己最认可的键盘扫描程序公布出来,让大家一起分享!最后,五一电子祝愿大家学习进步!工作顺利!说明:本站数显无线发射板中虽然不是用矩阵扫描,但是按键消抖动原理和上面相同, 按键功能复用原理也和上面相同,用起来感觉很好! 在键盘的延时过程中,刚好可以去做几件事并在左右做完。所以,产品中凡是要用到按键扫描的, 都可以让去做别的事情, 键盘延时消抖动
26、唯一的好处就是,程序写起来会方便一点。来自-http:/ 4*4 矩阵键盘扫描汇编程序 (基于 51 单片机 );/= ;/ ;/ 程序名称: 4-4keyscan.asm ;/ 程序用途: 4*4 矩阵键盘扫描检测;/ 功能描述:扫描键盘,确定按键值。程序不支持双键同时按下,;/ 如果发生双键同时按下时, 程序将只识别其中先扫描的按键;/ 程序入口: void ;/ 程序出口: KEYNAME,包含按键信息、按键有效信息、当前按键状态;/ 编写人 :黄伟, 2007-12-11 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - -
27、名师精心整理 - - - - - - - 第 9 页,共 16 页 - - - - - - - - - ;/ 最后修改:黄伟, 2007-12-12 ;/ ;/= PROC KEYCHK KEYNAME DATA 40H ;按键名称存储单元 ;(b7-b5纪录按键状态,b4 位为有效位, ;b3-b0纪录按键 ) KEYRTIME DATA 43H ;重复按键时间间隔SIGNAL DATA 50H ;提示信号时间存储单元KEY EQU P3 ;键盘接口 ( 必须完整 I/O 口) KEYPL EQU P0.6 ;指示灯接口RTIME EQU 30 ;重复按键输入等待时间KEYCHK: ;/=按
28、键检测程序= MOV KEY,#0FH ;送扫描信号 MOV A,KEY ;读按键状态 CJNE A,#0FH,NEXT1 ;ACC=0FH ; CLR C ;Acc等于 0FH ,则 CY为 0,无须置 0 NEXT1: ; SETB C ;Acc不等于 0FH ,则 ACC 必小于0FH , ;CY为 1,无须置 1 MOV A,KEYNAME ANL KEYNAME,#1FH ;按键名称屏蔽高三位 RRC A ;ACC带 CY右移一位, 纪录当前按键状态 ANL A,#0E0H ;屏蔽低五位 ORL KEYNAME,A ;保留按键状态;/=判别按键状态,决定是否执行按键扫描= CJNE
29、A,#0C0H,NEXT2 ;110按键稳定闭合,调用按键检测子程序 SJMP KEYSCAN NEXT2: CJNE A,#0E0H,NEXT3 ;111按键长闭合,重复输入允许判断 SJMP WAIT NEXT3: CJNE A,#0A0H,EXIT ;101干扰,当 111长闭合处理名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 16 页 - - - - - - - - - ORL KEYNAME,#0E0H WAIT: MOV A,KEYRTIME JNZ EX
30、IT ;时间没到,退出;/=键盘扫描程序= KEYSCAN: MOV R1,#0 ;初始化列地址 MOV R3,#11110111B ;初始化扫描码LOOP: MOV A,R3 RL A MOV R3,A ;保留扫描码 MOV KEY,A ;送扫描码 MOV A,KEY ;读键盘 ORL A,#0F0H ;屏蔽高四位 CJNE A,#0FFH,NEXT31 ;A不等于 FFH , 说明该列有按键动作 INC R1 ;列地址加 1, 准备扫描下一列 CJNE R1,#4,LOOP ;列地址不等于 4,扫描下一列 SJMP EXIT ;没有按键,退出;/=按键判断对应位等于零,说明该行有按键按下=
31、 NEXT31: JB ACC.0,NEXT32 MOV R2,#0 ;第 0 行有按键 SJMP NEXT5 NEXT32: JB ACC.1,NEXT33 MOV R2,#1 ;第 1 行有按键 SJMP NEXT5 NEXT33: JB ACC.2,NEXT34 MOV R2,#2 ;第 2 行有按键 SJMP NEXT5 NEXT34: MOV R2,#3 ;第 3 行有按键NEXT5: ;计算按键地址 MOV A,R1 RL A RL A ;列地址乘 4(每列对应 4 行) ADD A,R2 ;加行地址 MOV DPTR,#KEYTAB 名师资料总结 - - -精品资料欢迎下载 -
32、- - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 16 页 - - - - - - - - - MOVC A,A+DPTR ANL KEYNAME,#0E0H ORL KEYNAME,A ;送按键 ( 送值的时候已经置按键有效) MOV KEYRTIME,#RTIME ;送重复按键等待时间 CLR KEYPL ;打开指示灯 MOV SIGNAL,#10 ;送信号提示时间 ( 每次按键闪100ms) EXIT: MOV KEY,#0FFH ;置键盘接口高电平 RET ;退出;/=按键名称表= KEYTAB: DB 1A
33、H ;扫描码 0,对应 A * DB 1BH ;扫描码 1,对应 B * * DB 1CH ;扫描码 2,对应 C * I/O口 PX.4 PX.5 PX.6 PX.7 * DB 1DH ;扫描码 3,对应 D * * DB 11H ;扫描码 4,对应 1 * PX.0 A(0) 1(4) 2(8) 3(C) * DB 14H ;扫描码 5,对应 4 * * DB 17H ;扫描码 6,对应 7 * PX.1 B(1) 4(5) 5(9) 6(D) * DB 1EH ;扫描码 7,对应 E * * DB 12H ;扫描码 8,对应 2 * PX.2 C(2) 7(6) 8(A) 9(E) *
34、DB 15H ;扫描码 9,对应 5 * * DB 18H ;扫描码 A,对应 8 * PX.3 D(3) E(7) 0(B) F(F) * DB 10H ;扫描码 B,对应 0 * * DB 13H ;扫描码 C ,对应 3 * DB 16H ;扫描码 D ,对应 6 DB 19H ;扫描码 E,对应 9 DB 1FH ;扫描码 F,对应 F END 来源-http:/ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 16 页 - - - - - - - - - 矩阵
35、式键盘接口技术及编程8031单片机的 P1口用作键盘 I/O 口,键盘的列线接到P1口的低 4 位,键盘的行线接到 P1口的高 4 位。列线 P1.0-P1.3 分别接有 4 个上拉电阻到正电源 +5V,并把列线 P1.0-P1.3 设置为输入线,行线P1.4-P.17 设置为输出线。 4 根行线和4 根列线形成 16 个相交点。1. 检测当前是否有键被按下。检测的方法是P1.4-P1.7 输出全“ 0”,读取P1.0-P1.3 的状态,若 P1.0-P1.3 为全“1”,则无键闭合,否则有键闭合。2. 去除键抖动。当检测到有键按下后, 延时一段时间再做下一步的检测判断。3. 若有键被按下,应
36、识别出是哪一个键闭合。 方法是对键盘的行线进行扫描。P1.4-P1.7 按下述 4 种组合依次输出:P1.7 1 1 1 0 P1.6 1 1 0 1 P1.5 1 0 1 1 P1.4 0 1 1 1 在每组行输出时读取P1.0-P1.3 ,若全为“ 1”,则表示为“ 0”这一行没有键闭合, 否则有键闭合。 由此得到闭合键的行值和列值,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值4. 为了保证键每闭合一次CPU 仅作一次处理,必须却除键释放时的抖动。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理
37、 - - - - - - - 第 13 页,共 16 页 - - - - - - - - - 键盘扫描程序:从以上分析得到键盘扫描程序的流程图如图2 所示。程序如下SCAN: MOV P1,#0FH MOV A,P1 ANL A,#0FH CJNE A,#0FH,NEXT1 SJMP NEXT3 NEXT1: ACALL D20MS 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 16 页 - - - - - - - - - MOV A,#0EFH NEXT2: MOV
38、 R1,A MOV P1,A MOV A,P1 ANL A,#0FH CJNE A,#0FH,KCODE; MOV A,R1 SETB C RLC A JC NEXT2 NEXT3: MOV R0,#00H RET KCODE: MOV B,#0FBH NEXT4: RRC A INC B JC NEXT4 MOV A,R1 SWAP A NEXT5: RRC A INC B INC B INC B INC B JC NEXT5 NEXT6: MOV A,P1 ANL A,#0FH CJNE A,#0FH,NEXT6 MOV R0,#0FFH 键盘处理程序就作这么一个简单的介绍,实际上,键盘、
39、显示处理是很复杂的,名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 15 页,共 16 页 - - - - - - - - - 它往往占到一个应用程序的大部份代码,可见其重要性, 但说到,这种复杂并不来自于单片机的本身, 而是来自于操作者的习惯等等问题,因此,在编写键盘处理程序之前, 最好先把它从逻辑上理清, 然后用适当的算法表示出来, 最后再去写代码,这样,才能快速有效地写好代码。来源-http:/ RET 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 16 页,共 16 页 - - - - - - - - -