找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2466|回复: 0
打印 上一主题 下一主题
收起左侧

51单片机Timer2模拟半双工串口的C语言和汇编代码及注释说明

[复制链接]
跳转到指定楼层
楼主
ID:431063 发表于 2018-11-22 11:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用51单片机Timer2模拟一个半双工串口的c语言代码
  1. /*************        功能说明        **************

  2. 使用STC15系列的Timer2做的模拟串口. P3.0接收, P3.1发送, 半双工.
  3. 假定测试芯片的工作频率为22118400Hz. 时钟为5.5296MHZ ~ 35MHZ.
  4. 波特率高,则时钟也要选高, 优先使用 22.1184MHZ, 11.0592MHZ.
  5. 测试方法: 上位机发送数据, MCU收到数据后原样返回.
  6. 串口固定设置: 1位起始位, 8位数据位, 1位停止位,  波特率在范围如下.

  7. 1200 ~ 115200 bps @ 33.1776MHZ
  8. 600 ~ 115200 bps @ 22.1184MHZ
  9. 600 ~  76800 bps @ 18.4320MHZ
  10. 300 ~  57600 bps @ 11.0592MHZ
  11. 150 ~  19200 bps @  5.5296MHZ

  12. ******************************************/

  13. #include        <reg52.h>

  14. #define MAIN_Fosc                22118400UL        //定义主时钟
  15. #define        UART3_Baudrate        115200UL        //定义波特率
  16. #define        RX_Lenth                32                        //接收长度

  17. #define        UART3_BitTime        (MAIN_Fosc / UART3_Baudrate)

  18. typedef         unsigned char        u8;
  19. typedef         unsigned int        u16;
  20. typedef         unsigned long        u32;

  21. sfr IE2  = 0xAF;
  22. sfr        AUXR = 0x8E;
  23. sfr INT_CLKO = 0x8F;
  24. sfr        T2H  = 0xD6;
  25. sfr        T2L  = 0xD7;

  26. u8        Tx3_read;                        //发送读指针
  27. u8        Rx3_write;                        //接收写指针
  28. u8         idata        buf3[RX_Lenth];        //接收缓冲

  29. u16        RxTimeOut;
  30. bit        B_RxOk;                //接收结束标志


  31. //===================== 模拟串口相关===========================
  32. sbit P_RX3 = P3^0;        //定义模拟串口接收IO
  33. sbit P_TX3 = P3^1;        //定义模拟串口发送IO

  34. u8  Tx3_DAT;                // 发送移位变量, 用户不可见
  35. u8  Rx3_DAT;                // 接收移位变量, 用户不可见
  36. u8  Tx3_BitCnt;                // 发送数据的位计数器, 用户不可见
  37. u8  Rx3_BitCnt;                // 接收数据的位计数器, 用户不可见
  38. u8        Rx3_BUF;                // 接收到的字节, 用户读取
  39. u8        Tx3_BUF;                // 要发送的字节, 用户写入
  40. bit        Rx3_Ring;                // 正在接收标志, 低层程序使用, 用户程序不可见
  41. bit        Tx3_Ting;                // 正在发送标志, 用户置1请求发送, 底层发送完成清0
  42. bit        RX3_End;                // 接收到一个字节, 用户查询 并清0
  43. //=============================================================

  44. void        UART_Init(void);


  45. /******************** 主函数 **************************/
  46. void main(void)
  47. {
  48.        
  49.         UART_Init();        //PCA初始化
  50.         EA = 1;
  51.        
  52.         while (1)                //user's function
  53.         {
  54.                 if (RX3_End)                // 检测是否收到一个字节
  55.                 {
  56.                         RX3_End = 0;        // 清除标志
  57.                         buf3[Rx3_write] = Rx3_BUF;        // 写入缓冲
  58.                         if(++Rx3_write >= RX_Lenth)        Rx3_write = 0;        // 指向下一个位置,  溢出检测
  59.                         RxTimeOut = 1000;        //装载超时时间
  60.                 }
  61.                 if(RxTimeOut != 0)                // 超时时间是否非0?
  62.                 {
  63.                         if(--RxTimeOut == 0)        // (超时时间  - 1) == 0?
  64.                         {
  65.                                 B_RxOk = 1;
  66.                                 AUXR &=  ~(1<<4);        //Timer2 停止运行
  67.                                 INT_CLKO &= ~(1 << 6);        //禁止INT4中断
  68.                                 T2H = (65536 - UART3_BitTime) / 256;        //数据位
  69.                                 T2L = (65536 - UART3_BitTime) % 256;        //数据位
  70.                                 AUXR |=  (1<<4);        //Timer2 开始运行
  71.                         }
  72.                 }
  73.                
  74.                 if(B_RxOk)                // 检测是否接收OK?
  75.                 {
  76.                         if (!Tx3_Ting)                // 检测是否发送空闲
  77.                         {
  78.                                 if (Tx3_read != Rx3_write)        // 检测是否收到过字符
  79.                                 {
  80.                                         Tx3_BUF = buf3[Tx3_read];        // 从缓冲读一个字符发送
  81.                                         Tx3_Ting = 1;                                // 设置发送标志
  82.                                         if(++Tx3_read >= RX_Lenth)        Tx3_read = 0;        // 指向下一个位置,  溢出检测
  83.                                 }
  84.                                 else
  85.                                 {
  86.                                         B_RxOk = 0;
  87.                                         AUXR &=  ~(1<<4);                //Timer2 停止运行
  88.                                         INT_CLKO |=  (1 << 6);        //允许INT4中断
  89.                                 }
  90.                         }
  91.                 }
  92.         }
  93. }


  94. //========================================================================
  95. // 函数: void        UART_Init(void)
  96. // 描述: UART初始化程序.
  97. // 参数: none
  98. // 返回: none.
  99. // 版本: V1.0, 2013-11-22
  100. //========================================================================
  101. void        UART_Init(void)
  102. {
  103.         Tx3_read  = 0;
  104.         Rx3_write = 0;
  105.         Tx3_Ting  = 0;
  106.         Rx3_Ring  = 0;
  107.         RX3_End   = 0;
  108.         Tx3_BitCnt = 0;
  109.         RxTimeOut = 0;
  110.         B_RxOk = 0;

  111.         AUXR &=  ~(1<<4);                // Timer2 停止运行
  112.         T2H = (65536 - UART3_BitTime) / 256;        // 数据位
  113.         T2L = (65536 - UART3_BitTime) % 256;        // 数据位
  114.         INT_CLKO |=  (1 << 6);        // 允许INT4中断
  115.         IE2  |=  (1<<2);                // 允许Timer2中断
  116.         AUXR |=  (1<<2);                // 1T
  117. }
  118. //======================================================================

  119. //========================================================================
  120. // 函数: void        timer2_int (void) interrupt 12
  121. // 描述: Timer2中断处理程序.
  122. // 参数: None
  123. // 返回: none.
  124. // 版本: V1.0, 2012-11-22
  125. //========================================================================
  126. void        timer2_int (void) interrupt 12
  127. {
  128.         if(Rx3_Ring)                //已收到起始位
  129.         {
  130.                 if (--Rx3_BitCnt == 0)                //接收完一帧数据
  131.                 {
  132.                         Rx3_Ring = 0;                        //停止接收
  133.                         Rx3_BUF = Rx3_DAT;                //存储数据到缓冲区
  134.                         RX3_End = 1;
  135.                         AUXR &=  ~(1<<4);        //Timer2 停止运行
  136.                         INT_CLKO |=  (1 << 6);        //允许INT4中断
  137.                 }
  138.                 else
  139.                 {
  140.                         Rx3_DAT >>= 1;                                          //把接收的单b数据 暂存到 RxShiftReg(接收缓冲)
  141.                         if(P_RX3) Rx3_DAT |= 0x80;          //shift RX data to RX buffer
  142.                 }
  143.         }

  144.         if(Tx3_Ting)                                        // 不发送, 退出
  145.         {
  146.                 if(Tx3_BitCnt == 0)                        //发送计数器为0 表明单字节发送还没开始
  147.                 {
  148.                         P_TX3 = 0;                                //发送开始位
  149.                         Tx3_DAT = Tx3_BUF;                //把缓冲的数据放到发送的buff
  150.                         Tx3_BitCnt = 9;                        //发送数据位数 (8数据位+1停止位)
  151.                 }
  152.                 else                                                //发送计数器为非0 正在发送数据
  153.                 {
  154.                         if (--Tx3_BitCnt == 0)        //发送计数器减为0 表明单字节发送结束
  155.                         {
  156.                                 P_TX3 = 1;                        //送停止位数据
  157.                                 Tx3_Ting = 0;                //发送停止
  158.                         }
  159.                         else
  160.                         {
  161.                                 Tx3_DAT >>= 1;                //把最低位送到 CY(益处标志位)
  162.                                 P_TX3 = CY;                        //发送一个bit数据
  163.                         }
  164.                 }
  165.         }
  166. }


  167. /********************* INT4中断函数 *************************/
  168. void Ext_INT4 (void) interrupt 16
  169. {
  170.         AUXR &=  ~(1<<4);        //Timer2 停止运行
  171.         T2H = (65536 - (UART3_BitTime / 2 + UART3_BitTime)) / 256;        //起始位 + 半个数据位
  172.         T2L = (65536 - (UART3_BitTime / 2 + UART3_BitTime)) % 256;        //起始位 + 半个数据位
  173.         AUXR |=  (1<<4);        //Timer2 开始运行
  174.         Rx3_Ring = 1;                //标志已收到起始位
  175.         Rx3_BitCnt = 9;                //初始化接收的数据位数(8个数据位+1个停止位)
  176.        
  177.         INT_CLKO &= ~(1 << 6);        //禁止INT4中断
  178.         T2H = (65536 - UART3_BitTime) / 256;        //数据位
  179.         T2L = (65536 - UART3_BitTime) % 256;        //数据位
  180. }
复制代码

汇编语言:
  1. ;*************        功能说明        **************

  2. ;使用STC15系列的Timer2做的模拟串口. P3.0接收, P3.1发送, 半双工.

  3. ;假定测试芯片的工作频率为22118400Hz. 时钟为5.5296MHZ ~ 35MHZ.

  4. ;波特率高,则时钟也要选高, 优先使用 22.1184MHZ, 11.0592MHZ.

  5. ;测试方法: 上位机发送数据, MCU收到数据后原样返回.

  6. ;串口固定设置: 1位起始位, 8位数据位, 1位停止位,  波特率在范围如下.

  7. ;******************************************

  8. ;UART3_BitTime        EQU                9216        ; 1200bps @ 11.0592MHz        UART3_BitTime = (MAIN_Fosc / Baudrate)
  9. ;UART3_BitTime        EQU                4608        ; 2400bps @ 11.0592MHz
  10. ;UART3_BitTime        EQU                2304        ; 4800bps @ 11.0592MHz
  11. ;UART3_BitTime        EQU                1152        ; 9600bps @ 11.0592MHz
  12. ;UART3_BitTime        EQU                 576        ;19200bps @ 11.0592MHz
  13. ;UART3_BitTime        EQU                 288        ;38400bps @ 11.0592MHz
  14. ;UART3_BitTime        EQU                 192        ;57600bps @ 11.0592MHz

  15. ;UART3_BitTime        EQU                15360        ; 1200bps @ 18.432MHz
  16. ;UART3_BitTime        EQU                7680        ; 2400bps @ 18.432MHz
  17. ;UART3_BitTime        EQU                3840        ; 4800bps @ 18.432MHz
  18. ;UART3_BitTime        EQU                1920        ; 9600bps @ 18.432MHz
  19. ;UART3_BitTime        EQU                960                ;19200bps @ 18.432MHz
  20. ;UART3_BitTime        EQU                480                ;38400bps @ 18.432MHz
  21. ;UART3_BitTime        EQU                320                ;57600bps @ 18.432MHz

  22. ;UART3_BitTime        EQU                18432        ; 1200bps @ 22.1184MHz
  23. ;UART3_BitTime        EQU                9216        ; 2400bps @ 22.1184MHz
  24. ;UART3_BitTime        EQU                4608        ; 4800bps @ 22.1184MHz
  25. ;UART3_BitTime        EQU                2304        ; 9600bps @ 22.1184MHz
  26. ;UART3_BitTime        EQU                1152        ;19200bps @ 22.1184MHz
  27. ;UART3_BitTime        EQU                576                ;38400bps @ 22.1184MHz
  28. ;UART3_BitTime        EQU                384                ;57600bps @ 22.1184MHz
  29. UART3_BitTime        EQU                192                ;115200bps @ 22.1184MHz

  30. ;UART3_BitTime        EQU                27648        ; 1200bps @ 33.1776MHz
  31. ;UART3_BitTime        EQU                13824        ; 2400bps @ 33.1776MHz
  32. ;UART3_BitTime        EQU                6912        ; 4800bps @ 33.1776MHz
  33. ;UART3_BitTime        EQU                3456        ; 9600bps @ 33.1776MHz
  34. ;UART3_BitTime        EQU                1728        ;19200bps @ 33.1776MHz
  35. ;UART3_BitTime        EQU                864                ;38400bps @ 33.1776MHz
  36. ;UART3_BitTime        EQU                576                ;57600bps @ 33.1776MHz
  37. ;UART3_BitTime        EQU                288                ;115200bps @ 33.1776MHz

  38. IE2                        DATA         0AFH
  39. AUXR                DATA         08EH
  40. INT_CLKO        DATA         08FH
  41. T2H                        DATA         0D6H
  42. T2L                        DATA         0D7H


  43. ;===================== 模拟串口相关 ===========================
  44. P_RX3                 BIT         P3.0        ; 定义模拟串口接收IO
  45. P_TX3                 BIT         P3.1        ; 定义模拟串口发送IO

  46. Rx3_Ring        BIT                20H.0        ; 正在接收标志, 低层程序使用, 用户程序不可见
  47. Tx3_Ting        BIT                20H.1        ; 正在发送标志, 用户置1请求发送, 底层发送完成清0
  48. RX3_End                BIT                20H.2        ; 接收到一个字节, 用户查询 并清0
  49. B_RxOk                BIT                20H.3        ; 接收结束标志

  50. Tx3_DAT                DATA        30H                ; 发送移位变量, 用户不可见
  51. Rx3_DAT                DATA        31H                ; 接收移位变量, 用户不可见
  52. Tx3_BitCnt        DATA        32H                ; 发送数据的位计数器, 用户不可见
  53. Rx3_BitCnt        DATA        33H                ; 接收数据的位计数器, 用户不可见
  54. Rx3_BUF                DATA        34H                ; 接收到的字节, 用户读取
  55. Tx3_BUF                DATA        35H                ; 要发送的字节, 用户写入

  56. ;=================================================================
  57. RxTimeOutH        DATA        36H                ;
  58. RxTimeOutL        DATA        37H                ;

  59. Tx3_read        DATA        38H                ; 发送读指针
  60. Rx3_write        DATA        39H                ; 接收写指针

  61. RX_Lenth        EQU                32                ; 接收长度
  62. buf3                EQU                40H                ; 40H ~ 5FH        接收缓冲

  63. STACK_POIRTER        EQU                0D0H        ;堆栈开始地址

  64. ;*******************************************************************
  65. ;*******************************************************************
  66.                 ORG                00H                                ;reset
  67.                 LJMP        F_Main

  68.                 ORG                63H                                ;12  Timer2 interrupt
  69.                 LJMP        F_Timer2_Interrupt

  70.                 ORG                83H                                ;16  INT4 interrupt
  71.                 LJMP        F_INT4_Interrupt

  72. ;******************** 主程序 **************************/
  73. F_Main:
  74.        
  75.         MOV                SP, #STACK_POIRTER
  76.         MOV                PSW, #0
  77.         USING        0                ;选择第0组R0~R7

  78. ;================= 用户初始化程序 ====================================
  79.         LCALL        F_UART_Init                ;UART初始化
  80.         SETB        EA
  81.        
  82.                
  83. ;=================== 主循环 ==================================
  84. L_MainLoop:
  85.         JNB                RX3_End, L_QuitRx3        ; 检测是否收到一个字节
  86.         CLR                RX3_End                                ; 清除标志
  87.         MOV                A, #buf3
  88.         ADD                A, Rx3_write
  89.         MOV                R0, A
  90.         MOV                @R0, Rx3_BUF                ; 写入缓冲
  91.         MOV                RxTimeOutH, #HIGH 1000        ; 装载超时时间
  92.         MOV                RxTimeOutL, #LOW  1000        ;
  93.         INC                Rx3_write                        ; 指向下一个位置
  94.         MOV                A, Rx3_write
  95.         CLR                C
  96.         SUBB        A, #RX_Lenth                ; 溢出检测
  97.         JC                L_QuitRx3
  98.         MOV                Rx3_write, #0
  99. L_QuitRx3:

  100.         MOV                A, RxTimeOutL
  101.         ORL                A, RxTimeOutH
  102.         JZ                L_QuitTimeOut        ; 超时时间是否非0?
  103.         MOV                A, RxTimeOutL
  104.         DEC                RxTimeOutL                ; (超时时间  - 1) == 0?
  105.         JNZ                $+4
  106.         DEC                RxTimeOutH
  107.         DEC                A
  108.         ORL                A, RxTimeOutH
  109.         JNZ                L_QuitTimeOut
  110.        
  111.         SETB        B_RxOk                                                ; 超时, 标志接收完成
  112.         ANL                AUXR, #NOT (1 SHL 4)                ; Timer2 停止运行
  113.         ANL                INT_CLKO, #NOT (1 SHL 6)        ; 禁止INT4中断
  114.         MOV                T2H, #HIGH (65536 - UART3_BitTime)        ;数据位
  115.         MOV                T2L, #LOW (65536 - UART3_BitTime)        ;
  116.         ORL                AUXR, #(1 SHL 4)                        ; Timer2 开始运行
  117. L_QuitTimeOut:       

  118.         JNB                B_RxOk, L_QuitTx3        ; 检测是否接收OK?
  119.         JB                Tx3_Ting, L_QuitTx3        ; 检测是否发送空闲
  120.         MOV                A, Tx3_read
  121.         XRL                A, Rx3_write
  122.         JZ                L_TxFinish                        ; 检测是否发送完毕

  123.         MOV                A, #buf3
  124.         ADD                A, Tx3_read
  125.         MOV                R0, A
  126.         MOV                Tx3_BUF, @R0                ; 从缓冲读一个字符发送
  127.         SETB        Tx3_Ting                        ; 设置发送标志
  128.         INC                Tx3_read                        ; 指向下一个字符位置
  129.         MOV                A, Tx3_read
  130.         CLR                C
  131.         SUBB        A, #RX_Lenth
  132.         JC                L_QuitTx3                        ; 溢出检测
  133.         MOV                Tx3_read, #0
  134.         SJMP        L_QuitTx3

  135. L_TxFinish:
  136.         CLR                B_RxOk
  137.         ANL                AUXR, #NOT (1 SHL 4)        ; Timer2 停止运行
  138.         ORL                INT_CLKO, #(1 SHL 6)        ; 允许INT4中断

  139. L_QuitTx3:

  140.         LJMP        L_MainLoop

  141. ;=================== 主程序结束 ==================================

  142. ;========================================================================
  143. ; 函数: F_UART_Init
  144. ; 描述: UART初始化程序.
  145. ; 参数: none
  146. ; 返回: none.
  147. ; 版本: V1.0, 2013-11-22
  148. ;========================================================================
  149. F_UART_Init:
  150.         MOV                Tx3_read,  #0
  151.         MOV                Rx3_write, #0
  152.         CLR                Tx3_Ting
  153.         CLR                RX3_End
  154.         CLR                Rx3_Ring
  155.         MOV                Tx3_BitCnt, #0

  156.         MOV                RxTimeOutH, #0
  157.         MOV                RxTimeOutL, #0
  158.         CLR                B_RxOk

  159.         ANL                AUXR, #NOT(1 SHL 4)                ; Timer2 停止运行
  160.         MOV                T2H, #HIGH (65536 - UART3_BitTime)        ; 数据位
  161.         MOV                T2L, #LOW (65536 - UART3_BitTime)        ; 数据位
  162.         ORL                INT_CLKO, #(1 SHL 6)        ; 允许INT4中断
  163.         ORL                IE2, #(1 SHL 2)                        ; 允许Timer2中断
  164.         ORL                AUXR, #(1 SHL 2)                ; 1T模式
  165.         RET

  166. ;======================================================================

  167. ;========================================================================
  168. ; 函数: void        F_Timer2_Interrupt
  169. ; 描述: Timer2中断处理程序.
  170. ; 参数: None
  171. ; 返回: none.
  172. ; 版本: V1.0, 2012-11-22
  173. ;========================================================================
  174. F_Timer2_Interrupt:
  175.         PUSH        PSW
  176.         PUSH        ACC

  177.         JNB                Rx3_Ring, L_QuitRx        ; 已收到起始位
  178.         DJNZ        Rx3_BitCnt, L_RxBit        ; 接收完一帧数据
  179.        
  180.         CLR                Rx3_Ring                        ; 停止接收
  181.         MOV                Rx3_BUF, Rx3_DAT        ; 存储数据到缓冲区
  182.         SETB        RX3_End                                ;
  183.         ANL                AUXR, #NOT (1 SHL 4); Timer2 停止运行
  184.         ORL                INT_CLKO, #(1 SHL 6); 允许INT4中断
  185.         SJMP        L_QuitRx
  186.        
  187. L_RxBit:
  188.         MOV                A, Rx3_DAT                        ; 把接收的单b数据 暂存到 RxShiftReg(接收缓冲)
  189.         MOV                C, P_RX3
  190.         RRC                A
  191.         MOV                Rx3_DAT, A
  192. L_QuitRx:

  193.         JNB                Tx3_Ting, L_QuitTx        ; 不发送, 退出
  194.         MOV                A, Tx3_BitCnt
  195.         JNZ                L_TxData                        ; 发送计数器为0 表明单字节发送还没开始
  196.         CLR                P_TX3                                ; 发送开始位
  197.         MOV                Tx3_DAT, Tx3_BUF        ; 把缓冲的数据放到发送的buff
  198.         MOV                Tx3_BitCnt, #9                ; 发送数据位数 (8数据位+1停止位)
  199.         SJMP        L_QuitTx
  200. L_TxData:                                                ; 发送计数器为非0 正在发送数据
  201.         DJNZ        Tx3_BitCnt, L_TxBit        ; 发送计数器减为0 表明单字节发送结束
  202.         SETB        P_TX3                                ; 送停止位数据
  203.         CLR                Tx3_Ting                        ; 发送停止
  204.         SJMP        L_QuitTx
  205. L_TxBit:
  206.         MOV                A, Tx3_DAT                        ; 把最低位送到 CY(益处标志位)
  207.         RRC                A
  208.         MOV                P_TX3, C                        ; 发送一个bit数据
  209.         MOV                Tx3_DAT, A
  210. L_QuitTx:

  211.         POP                ACC
  212.         POP                PSW

  213.         RETI
  214.        

  215. ;===================== INT4中断函数 ==================================
  216. F_INT4_Interrupt:
  217.         PUSH        PSW
  218.         PUSH        ACC

  219.         ANL                AUXR, #NOT(1 SHL 4)        ;Timer2 停止运行
  220.         MOV                T2H, #HIGH (65536 - (UART3_BitTime / 2 + UART3_BitTime))        ; 起始位 + 半个数据位
  221.         MOV                T2L, #LOW (65536 - (UART3_BitTime / 2 + UART3_BitTime))                ; 起始位 + 半个数据位
  222.         ORL                AUXR, #(1 SHL 4)        ;Timer2 开始运行
  223.         SETB        Rx3_Ring                        ; 标志已收到起始位
  224.         MOV                Rx3_BitCnt, #9                ; 初始化接收的数据位数(8个数据位+1个停止位)
  225.        
  226.         ANL                INT_CLKO,  #NOT(1 SHL 6);        //禁止INT4中断
  227.         MOV                T2H, #HIGH (65536 - UART3_BitTime)        ; 数据位
  228.         MOV                T2L, #LOW (65536 - UART3_BitTime)        ; 数据位

  229.         POP                ACC
  230.         POP                PSW
  231.         RETI

  232.         END
复制代码


所有资料51hei提供下载:
使用51单片机Timer2模拟一个半双工串口.rar (18.4 KB, 下载次数: 12)


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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