给Android设备增加串口功能

环境:

主机:WIN7

开发环境:MDK4.23

功能:

打开Android手机或者平台的蓝牙,通过蓝牙连接蓝牙转串口板,通过蓝牙转串口板的串口与需要调试的串口设备相连

说明:

1.PCB为我同学hunter绘制,他同时是stm32的高手,感谢他提供的支持.

2.制作了一个蓝牙转串口的板子,Android设备连接上这个板子,就相当于增加了一个串口.

3.单片机选用的是STM32F101C8,蓝牙模块选用的是HC05.HC05本身就是一个蓝牙转串口模块,再增加一个单片机的作用是可以通过单片机来配置波特率等参数.

4.蓝牙转串口板可以用MINI USB来供电,或者用3.7V锂电池来供电,板子上带有充电管理芯片,由于没锂电池,充电这块还没有测试.

5.上位机程序(Android上的串口助手)暂时没有时间写,可以在安卓市场上搜索"蓝牙串口"下一个串口助手.

实物图:

电路图:

第1部分:

图片较大,部分没有显示.可以在新窗口打开图片来看到全部内容

第2部分:

下位机程序:

public.h

  1. #ifndef _PUBLIC_H_   
  2. #define _PUBLIC_H_   
  3.   
  4. //公共头文件   
  5. #include "main.h"   
  6. #include "string.h"   
  7. #include "stdlib.h"   
  8. #include "stm32f10x_tim.h"   
  9.   
  10. //宏定义   
  11. #define U8 unsigned char   
  12. #define U16 unsigned short   
  13. #define U32 unsigned long   
  14.   
  15. //蓝牙转串口的缓存长度   
  16. #define LEN_BT_STACK    10   
  17.   
  18. //蓝牙波特率设置命令   
  19. #define BT_BAUD_4800    "AT+UART=4800,0,0"   
  20. #define BT_BAUD_9600    "AT+UART=9600,0,0"   
  21. #define BT_BAUD_19200   "AT+UART=19200,0,0"   
  22. #define BT_BAUD_38400   "AT+UART=38400,0,0"   
  23. #define BT_BAUD_57600   "AT+UART=57600,0,0"   
  24. #define BT_BAUD_115200  "AT+UART=115200,0,0"   
  25. #define DEFAULT_BAUD    9600   
  26.   
  27. //定义flash页大小   
  28. #if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || (STM32F10X_CL) || defined (STM32F10X_XL)   
  29.   #define FLASH_PAGE_SIZE    ((uint16_t)0x800)   
  30.   #define FLASH_PAGES_TO_BE_PROTECTED (FLASH_WRProt_Pages12to13 | FLASH_WRProt_Pages14to15)     
  31. #else   
  32.   #define FLASH_PAGE_SIZE    ((uint16_t)0x400)   
  33.   //需要关闭写保护的页面   
  34.   #define FLASH_PAGES_TO_BE_PROTECTED (FLASH_WRProt_Pages60to63)     
  35. #endif   
  36.   
  37. //定义操作的flash的始末地址63K-64K           
  38. #define BANK1_WRITE_START_ADDR  ((uint32_t)0x0800FC00)   
  39. #define BANK1_WRITE_END_ADDR    ((uint32_t)0x08010000)   
  40.   
  41. //数据结构   
  42.   
  43. //通过蓝牙发过来的串口2的数据堆栈   
  44. //数据结构为循环队列,读写缓冲   
  45. #define LEN_BUF 512   
  46. struct _FIFO_Stack  
  47. {  
  48.     unsigned char buf[LEN_BUF];  
  49.     short ptr_r;  
  50.     short ptr_w;  
  51. };  
  52.   
  53. //数据流式符合字符串头检索   
  54. #define LEN_MATCH_STRING_HEADER 9   
  55. struct _match_string_header  
  56. {  
  57.     char match[LEN_MATCH_STRING_HEADER];  
  58.     int state;  
  59. };  
  60.   
  61. //数据流式符合字符串尾检索,并提取数据结构   
  62. #define LEN_MATCH_STRING_TAIL 3   
  63. struct _match_string_tail  
  64. {  
  65.     char match[LEN_MATCH_STRING_TAIL];  
  66.     int state;              //当前状态/下标   
  67.     int value;              //最后取得的值   
  68.     int max_len;            //数据最大长度   
  69.     char capture_string[10];  
  70.     int capture_index;      //当前捕获数据下标   
  71.     struct _match_string_header match_string_header;    //用来比较尾是否正确   
  72.     int flag;               //捕获数据状态或是捕获字符尾状态   
  73. };  
  74.   
  75. //修改flash   
  76. struct _edit_flash  
  77. {  
  78.     unsigned short buf[512];  
  79.     int flag;       //判断flash是否被修改过   
  80.     int baud;       //需要写入/读出的波特率   
  81. };  
  82.   
  83. //公共变量   
  84. //声明串口结构体   
  85. extern USART_InitTypeDef USART_InitStructure;  
  86.   
  87. //声明FIFO堆栈给UART2使用   
  88. extern struct _FIFO_Stack fifo_uart2;  
  89.   
  90. //声明FIFO堆栈给UART1使用   
  91. extern struct _FIFO_Stack fifo_uart1;  
  92.   
  93. //声明修改flash结构体   
  94. extern struct _edit_flash edit_flash;  
  95.   
  96. //公共函数   
  97. //按照蓝牙转串口的格式发送指令   
  98. void send_bt_cmd(char *str);  
  99.   
  100. //循环缓冲方法   
  101. //初始化   
  102. void init_fifo_stack(struct _FIFO_Stack *stack);  
  103. //读取全部   
  104. //成功返回字节数,失败返回-1   
  105. short read_all_fifo_stack(struct _FIFO_Stack *stack,unsigned char *buf);  
  106. //写入1个字节   
  107. //失败返回-1,成功返回1   
  108. int write_byte_fifo_stack(struct _FIFO_Stack *stack,unsigned char byte);  
  109.   
  110. //数据流式符合字符串头检索方法   
  111. //初始化   
  112. //成功返回1,失败返回0   
  113. int init_match_string_header(struct _match_string_header *m_str,char *buf);  
  114. //返回-1失败,返回0正在运行,返回1成功   
  115. int match_string_header_state(struct _match_string_header *m_str,char ch);  
  116.   
  117. //数据流式符合字符串尾检索,并提取数据结构方法   
  118. //初始化   
  119. //成功返回1,失败返回0   
  120. int init_match_string_tail(struct _match_string_tail *m_str,char *buf,int max_len);  
  121. //返回-1失败,返回0正在运行,成功返回得到的数据   
  122. int match_string_tail_state(struct _match_string_tail *m_str,char ch);  
  123.   
  124. //flash操作   
  125. //打开需要操作页面的写保护   
  126. void open_write_lock();  
  127. //向flash中写入数据,1024字节,512个半字   
  128. //成功返回写入的字节数,失败返回-1   
  129. int write_flash(unsigned short *buf);  
  130. //读取flash,读取1024字节,512半字   
  131. //成功返回读取的字节数,失败返回-1   
  132. int read_flash(unsigned short *buf);  
  133.   
  134. //读取flash,获得flag和baud   
  135. //成功返回波特率,失败返回-1   
  136. int read_baud(struct _edit_flash *edit);  
  137. //写入波特率到flash   
  138. //成功返回1,失败返回0   
  139. int write_baud(struct _edit_flash *edit,int baud);  
  140.   
  141. #endif  


public.c:

  1. #include "public.h"   
  2.   
  3. //公共变量   
  4. //定义串口结构体   
  5. USART_InitTypeDef USART_InitStructure;  
  6.   
  7. //声明FIFO堆栈给UART2使用   
  8. struct _FIFO_Stack fifo_uart2;  
  9.   
  10. //声明FIFO堆栈给UART1使用   
  11. struct _FIFO_Stack fifo_uart1;  
  12.   
  13. //声明修改flash结构体   
  14. struct _edit_flash edit_flash;  
  15.   
  16. //按照蓝牙转串口的格式发送指令   
  17. void send_bt_cmd(char *str)  
  18. {  
  19.     while(*str != '\0')  
  20.     {  
  21.         USART_SendData(USART2,*str++); //发送一位数据   
  22.         while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕       
  23.     }  
  24.   
  25.     USART_SendData(USART2,'\r'); //发送一位数据   
  26.     while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕   
  27.     USART_SendData(USART2,'\n'); //发送一位数据   
  28.     while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){} //等待字符发送完毕           
  29. }  
  30.   
  31. //循环缓冲方法   
  32. //初始化   
  33. void init_fifo_stack(struct _FIFO_Stack *stack)  
  34. {  
  35.     stack->ptr_r = 0;  
  36.     stack->ptr_w = 0;  
  37.     memset(stack->buf,0,LEN_BUF);  
  38. }  
  39.   
  40. //读取全部   
  41. //成功返回字节数,失败返回0   
  42. short read_all_fifo_stack(struct _FIFO_Stack *stack,unsigned char *buf)  
  43. {  
  44.     short i = 0;  
  45.     short j = 0;  
  46.     short len = 0;  
  47.     short len2 = 0;  
  48.   
  49.     //如果已经读完,则不读   
  50.     if (stack->ptr_r - stack->ptr_w == 0 || \  
  51.         stack->ptr_r - stack->ptr_w == -1)  
  52.     {  
  53.         return -1;  
  54.     }  
  55.   
  56.     //如果读指针小于写指针   
  57.     if (stack->ptr_r < stack->ptr_w)  
  58.     {  
  59.         len =  stack->ptr_w - stack->ptr_r;  
  60.         for (i = 0;i < len;i++)  
  61.         {  
  62.            buf[i] = stack->buf[stack->ptr_r++];  
  63.         }  
  64.         return len;  
  65.     }  
  66.     else  
  67.     {  
  68.         //读指针大于写指针的情况   
  69.         len = (LEN_BUF - 1) - stack->ptr_r + 1;  
  70.         len2 = stack->ptr_w;  
  71.         for (i = 0;i < len;i++)  
  72.         {  
  73.             buf[j++] = stack->buf[stack->ptr_r++];      
  74.         }  
  75.         stack->ptr_r = 0;  
  76.         for (i = 0;i < len2;i++)  
  77.         {  
  78.             buf[j++] = stack->buf[stack->ptr_r++];      
  79.         }  
  80.         return (len + len2);  
  81.     }  
  82. }  
  83.   
  84. //写入1个字节   
  85. //失败返回-1,成功返回1   
  86. int write_byte_fifo_stack(struct _FIFO_Stack *stack,unsigned char byte)  
  87. {  
  88.     //如果已经写完,则不写   
  89.     if (stack->ptr_w - stack->ptr_r == -1)  
  90.     {  
  91.         return -1;  
  92.     }  
  93.   
  94.     stack->buf[stack->ptr_w++] = byte;  
  95.   
  96.     //判断是否已经写满   
  97.     if (stack->ptr_w == LEN_BUF)  
  98.     {  
  99.         stack->ptr_w = 0;  
  100.     }  
  101. }  
  102.   
  103. //数据流式符合字符串头检索方法   
  104. //初始化   
  105. //成功返回1,失败返回0   
  106. int init_match_string_header(struct _match_string_header *m_str,char *buf)  
  107. {  
  108.     int len = 0;  
  109.     int i = 0;  
  110.       
  111.     len = strlen(buf);  
  112.     if (len > LEN_MATCH_STRING_HEADER)  
  113.     {  
  114.         return 0;  
  115.     }  
  116.       
  117.     m_str->state = 0;  
  118.     for (i = 0;i < len;i++)  
  119.     {  
  120.         m_str->match[i] = buf[i];  
  121.     }  
  122.     m_str->match[i] = '\0';  
  123.       
  124.     return 1;  
  125. }  
  126.   
  127. //返回-1失败,返回0正在运行,返回1成功   
  128. int match_string_header_state(struct _match_string_header *m_str,char ch)  
  129. {  
  130.     if (ch == m_str->match[m_str->state])  
  131.     {  
  132.         m_str->state++;  
  133.         if (m_str->match[m_str->state] == '\0')  
  134.         {  
  135.             m_str->state = 0;  
  136.               
  137.             return 1;  
  138.         }  
  139.         else  
  140.         {  
  141.             return 0;  
  142.         }  
  143.     }  
  144.     else  
  145.     {  
  146.         m_str->state = 0;  
  147.           
  148.         return -1;  
  149.     }  
  150. }  
  151.   
  152. //数据流式符合字符串尾检索,并提取数据结构方法   
  153. //初始化   
  154. //成功返回1,失败返回0   
  155. int init_match_string_tail(struct _match_string_tail *m_str,char *buf,int max_len)  
  156. {  
  157.     int len = 0;  
  158.     int i = 0;  
  159.       
  160.     len = strlen(buf);  
  161.     if (len > LEN_MATCH_STRING_TAIL)  
  162.     {  
  163.         return 0;  
  164.     }  
  165.       
  166.     m_str->state = 0;  
  167.     m_str->value = 0;  
  168.     m_str->max_len = max_len;  
  169.     m_str->capture_index = 0;  
  170.     m_str->flag = 0;  
  171.     for (i = 0;i < len;i++)  
  172.     {  
  173.         m_str->match[i] = buf[i];  
  174.     }  
  175.     m_str->match[i] = '\0';  
  176.     init_match_string_header(&(m_str->match_string_header),m_str->match);  
  177.       
  178.     return 1;  
  179. }  
  180.   
  181. //返回-1失败,返回0正在运行,成功返回得到的数据   
  182. int match_string_tail_state(struct _match_string_tail *m_str,char ch)  
  183. {  
  184.     int flag = 0;  
  185.       
  186.     //判断是否捕获数据状态还是捕获字符尾状态   
  187.     if (m_str->flag || ch == 'E')  
  188.     {  
  189.         //捕获字符尾状态   
  190.         m_str->flag = 1;  
  191.         flag = match_string_header_state(&(m_str->match_string_header),ch);  
  192.           
  193.         if (flag == -1)  
  194.         {  
  195.             //初始化数据   
  196.             m_str->state = 0;  
  197.             m_str->capture_index = 0;  
  198.             m_str->flag = 0;  
  199.         }  
  200.           
  201.         if (flag == 1)  
  202.         {  
  203.             m_str->capture_string[m_str->capture_index] = '\0';  
  204.             m_str->value = atoi(m_str->capture_string);  
  205.               
  206.             //初始化数据   
  207.             m_str->state = 0;  
  208.             m_str->capture_index = 0;  
  209.             m_str->flag = 0;  
  210.               
  211.             return m_str->value;  
  212.         }  
  213.           
  214.         return flag;  
  215.     }  
  216.     else  
  217.     {  
  218.         //捕获数据状态   
  219.         if (ch < '0' || ch > '9')  
  220.         {  
  221.             return -1;  
  222.         }  
  223.           
  224.         //当已经达到最大数据长度且当前数据不是   
  225.         //当不是数据字符返回错误   
  226.         if (m_str->capture_index >= m_str->max_len)  
  227.         {  
  228.             m_str->state = 0;  
  229.             m_str->capture_index = 0;  
  230.             m_str->flag = 0;  
  231.               
  232.             return -1;  
  233.         }  
  234.         else  
  235.         {  
  236.             m_str->capture_string[m_str->capture_index++] = ch;  
  237.               
  238.             //如果达到最大长度,则置为捕获字符状态   
  239.             if (m_str->capture_index >= m_str->max_len)  
  240.             {  
  241.                 m_str->flag = 1;  
  242.             }  
  243.               
  244.             return 0;  
  245.         }  
  246.     }  
  247. }  
  248.   
  249. //打开需要操作页面的写保护   
  250. void open_write_lock()  
  251. {  
  252.     uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0x0;  
  253.     volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;  
  254.   
  255.     //解锁flash控制器   
  256.     FLASH_Unlock();  
  257.   
  258.     //得到所有已经被写保护的页面号,如果被写保护则置0,没有则置1   
  259.     WRPR_Value = FLASH_GetWriteProtectionOptionByte();  
  260.   
  261.     //需要写保护的页面置1,不需要的置0   
  262.     ProtectedPages = ~(WRPR_Value | FLASH_PAGES_TO_BE_PROTECTED);  
  263.       
  264.     //检查需要的页是否被写保护   
  265.     if((WRPR_Value | (~FLASH_PAGES_TO_BE_PROTECTED)) != 0xFFFFFFFF )  
  266.     {  
  267.         //擦除小信息模块,关闭写保护   
  268.         FLASHStatus = FLASH_EraseOptionBytes();  
  269.           
  270.         //如果不是所有页面都需要打开写保护   
  271.         if(ProtectedPages != 0x0)  
  272.         {  
  273.           //将其他页面置位写保护   
  274.           FLASHStatus = FLASH_EnableWriteProtection(ProtectedPages);  
  275.         }  
  276.         //复位系统,重新载入小信息   
  277.         NVIC_SystemReset();  
  278.     }  
  279. }  
  280.   
  281. //向flash中写入数据,1024字节,512个半字   
  282. //成功返回写入的字节数,失败返回-1   
  283. int write_flash(unsigned short *buf)  
  284. {  
  285.     uint32_t EraseCounter = 0x0,Address = 0x0;  
  286.     uint32_t WRPR_Value = 0xFFFFFFFF;  
  287.     uint32_t NbrOfPage;  
  288.     volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;  
  289.     int i = 0;  
  290.   
  291.     //得到需要操作的页面数   
  292.     NbrOfPage = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FLASH_PAGE_SIZE;  
  293.   
  294.     //得到所有已经被写保护的页面号,如果被写保护则置0,没有则置1   
  295.     WRPR_Value = FLASH_GetWriteProtectionOptionByte();  
  296.       
  297.     //判断此页面是否被写保护,如果没有写保护则进行操作   
  298.     if ( (WRPR_Value & FLASH_PAGES_TO_BE_PROTECTED) != 0x00)  
  299.     {  
  300.         //清除所有等待标志位   
  301.         FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP|FLASH_FLAG_PGERR |FLASH_FLAG_WRPRTERR);   
  302.           
  303.         //擦数指定页面   
  304.         for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)  
  305.         {  
  306.             FLASHStatus = FLASH_ErasePage(BANK1_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));  
  307.         }  
  308.           
  309.         //得到操作flash的起始地址   
  310.         Address = BANK1_WRITE_START_ADDR;  
  311.         //写flash,每次写2个字节   
  312.         while((Address < BANK1_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))  
  313.         {  
  314.             FLASHStatus = FLASH_ProgramHalfWord(Address, buf[i++]);  
  315.             Address = Address + 2;  
  316.         }  
  317.   
  318.         return i;  
  319.     }  
  320.     else  
  321.     {   
  322.         return -1;  
  323.     }  
  324. }  
  325.   
  326. //读取flash,读取1024字节,512半字   
  327. //成功返回读取的字节数,失败返回-1   
  328. int read_flash(unsigned short *buf)  
  329. {  
  330.     uint32_t Address = 0x0;  
  331.     int i = 0;  
  332.   
  333.     //得到操作flash的起始地址   
  334.     Address = BANK1_WRITE_START_ADDR;  
  335.     //读flash,每次读两个字节   
  336.     while((Address < BANK1_WRITE_END_ADDR))  
  337.     {  
  338.         buf[i++] = *(__IO uint16_t*) Address;  
  339.         Address += 2;  
  340.     }  
  341.   
  342.     return i;  
  343. }  
  344.   
  345. //修改flash结构的方法   
  346. //初始化   
  347. void init_edit_flash(struct _edit_flash *edit)  
  348. {  
  349.     edit->flag = 0;  
  350.     edit->baud = 0;  
  351.     memset(edit->buf,0,512);  
  352. }  
  353.   
  354. //读取flash,获得flag和baud   
  355. //成功返回波特率,失败返回-1   
  356. int read_baud(struct _edit_flash *edit)  
  357. {  
  358.     read_flash(edit->buf);  
  359.     edit->flag = edit->buf[0];  
  360.     edit->baud = edit->buf[1] << 16;  
  361.     edit->baud += edit->buf[2];  
  362.   
  363.     if (edit->flag == 0xa5)  
  364.     {  
  365.         return (edit->baud);  
  366.     }  
  367.     else  
  368.     {  
  369.         return -1;  
  370.     }  
  371. }  
  372.   
  373. //写入波特率到flash   
  374. //成功返回1,失败返回0   
  375. int write_baud(struct _edit_flash *edit,int baud)  
  376. {  
  377.     edit->buf[0] = 0xa5;  
  378.     edit->buf[1] = baud >> 16;  
  379.     edit->buf[2] = baud & 0xffff;  
  380.     if (write_flash(edit->buf) > 0)  
  381.     {  
  382.         edit->flag = 0xa5;  
  383.         edit->baud = baud;  
  384.   
  385.         return 1;  
  386.     }  
  387.     else  
  388.     {  
  389.         return 0;  
  390.     }  
  391. }  

stm32f10x_it.c:(串口中断文件)

  1. /** 
  2.   ****************************************************************************** 
  3.   * @file    SysTick/stm32f10x_it.c  
  4.   * @author  MCD Application Team 
  5.   * @version V3.4.0 
  6.   * @date    10/15/2010 
  7.   * @brief   Main Interrupt Service Routines. 
  8.   *          This file provides template for all exceptions handler and peripherals 
  9.   *          interrupt service routine. 
  10.   ****************************************************************************** 
  11.   * @copy 
  12.   * 
  13.   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 
  14.   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 
  15.   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY 
  16.   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 
  17.   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 
  18.   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 
  19.   * 
  20.   * <h2><center>? COPYRIGHT 2010 STMicroelectronics</center></h2> 
  21.   */   
  22.   
  23. /* Includes ------------------------------------------------------------------*/  
  24. #include "stm32f10x_it.h"   
  25. #include "main.h"   
  26. #include "public.h"   
  27.   
  28. /** @addtogroup STM32F10x_StdPeriph_Examples 
  29.   * @{ 
  30.   */  
  31.   
  32. /** @addtogroup SysTick 
  33.   * @{ 
  34.   */  
  35.   
  36. /* Private typedef -----------------------------------------------------------*/  
  37. /* Private define ------------------------------------------------------------*/  
  38. /* Private macro -------------------------------------------------------------*/  
  39. /* Private variables ---------------------------------------------------------*/  
  40. /* Private function prototypes -----------------------------------------------*/  
  41. /* Private functions ---------------------------------------------------------*/  
  42.   
  43. /******************************************************************************/  
  44. /*            Cortex-M3 Processor Exceptions Handlers                         */  
  45. /******************************************************************************/  
  46.   
  47. /** 
  48.   * @brief  This function handles NMI exception. 
  49.   * @param  None 
  50.   * @retval None 
  51.   */  
  52. void NMI_Handler(void)  
  53. {  
  54. }  
  55.   
  56. /** 
  57.   * @brief  This function handles Hard Fault exception. 
  58.   * @param  None 
  59.   * @retval None 
  60.   */  
  61. void HardFault_Handler(void)  
  62. {  
  63.   /* Go to infinite loop when Hard Fault exception occurs */  
  64.   while (1)  
  65.   {  
  66.   }  
  67. }  
  68.   
  69. /** 
  70.   * @brief  This function handles Memory Manage exception. 
  71.   * @param  None 
  72.   * @retval None 
  73.   */  
  74. void MemManage_Handler(void)  
  75. {  
  76.   /* Go to infinite loop when Memory Manage exception occurs */  
  77.   while (1)  
  78.   {  
  79.   }  
  80. }  
  81.   
  82. /** 
  83.   * @brief  This function handles Bus Fault exception. 
  84.   * @param  None 
  85.   * @retval None 
  86.   */  
  87. void BusFault_Handler(void)  
  88. {  
  89.   /* Go to infinite loop when Bus Fault exception occurs */  
  90.   while (1)  
  91.   {  
  92.   }  
  93. }  
  94.   
  95. /** 
  96.   * @brief  This function handles Usage Fault exception. 
  97.   * @param  None 
  98.   * @retval None 
  99.   */  
  100. void UsageFault_Handler(void)  
  101. {  
  102.   /* Go to infinite loop when Usage Fault exception occurs */  
  103.   while (1)  
  104.   {  
  105.   }  
  106. }  
  107.   
  108. /** 
  109.   * @brief  This function handles SVCall exception. 
  110.   * @param  None 
  111.   * @retval None 
  112.   */  
  113. void SVC_Handler(void)  
  114. {  
  115. }  
  116.   
  117. /** 
  118.   * @brief  This function handles Debug Monitor exception. 
  119.   * @param  None 
  120.   * @retval None 
  121.   */  
  122. void DebugMon_Handler(void)  
  123. {  
  124. }  
  125.   
  126. /** 
  127.   * @brief  This function handles PendSV_Handler exception. 
  128.   * @param  None 
  129.   * @retval None 
  130.   */  
  131. void PendSV_Handler(void)  
  132. {  
  133. }  
  134.   
  135. /** 
  136.   * @brief  This function handles SysTick Handler. 
  137.   * @param  None 
  138.   * @retval None 
  139.   */  
  140. void SysTick_Handler(void)  
  141. {  
  142.   TimingDelay_Decrement();  
  143. }  
  144.   
  145. /******************************************************************************/  
  146. /*                 STM32F10x Peripherals Interrupt Handlers                   */  
  147. /*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */  
  148. /*  available peripheral interrupt handler's name please refer to the startup */  
  149. /*  file (startup_stm32f10x_xx.s).                                            */  
  150. /******************************************************************************/  
  151.   
  152. /** 
  153.   * @brief  This function handles PPP interrupt request. 
  154.   * @param  None 
  155.   * @retval None 
  156.   */  
  157. /*void PPP_IRQHandler(void) 
  158. { 
  159. }*/  
  160.   
  161. /** 
  162.   * @} 
  163.   */   
  164.   
  165. /** 
  166.   * @} 
  167.   */   
  168.     //串口1接收中断   
  169.     //与真实串口通信   
  170.     void USART1_IRQHandler(void)                               
  171.     {  
  172.         unsigned char rx_dat;        
  173.   
  174.         if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)              //判断发生接收中断   
  175.         {  
  176.             USART_ClearITPendingBit(USART1,    USART_IT_RXNE);              //清除中断标志   
  177.             rx_dat = USART_ReceiveData(USART1);                             //接收数据,整理除去前两位   
  178.             //写入fifo   
  179.             write_byte_fifo_stack(&fifo_uart1,rx_dat);  
  180.         }  
  181.     }  
  182.   
  183. //返回src中dst字符串的标号,正确返回标号,失败返回-1   
  184. //src:源字符串   
  185. //dst:目标字符串   
  186. //len:源字符串比较的长度   
  187. int index_of_string(char *src,char *dst,int len)  
  188. {  
  189.     int size_dst = 0;  
  190.     int i = 0;  
  191.     int j = 0;  
  192.       
  193.     //获得目标字符串长度   
  194.     size_dst = strlen(dst);  
  195.     //如果len小于目标字符串长度,返回失败   
  196.     if (len < size_dst)  
  197.     {  
  198.         return 0;  
  199.     }  
  200.       
  201.     for (i = 0;i <= len - size_dst;i++)  
  202.     {  
  203.         for (j = 0;j < size_dst;j++)  
  204.         {  
  205.             if (src[i + j] != dst[j])  
  206.             {  
  207.                 break;  
  208.             }  
  209.         }  
  210.         if (j == size_dst)  
  211.         {  
  212.             return i;  
  213.         }  
  214.     }  
  215.       
  216.     return -1;  
  217. }  
  218.   
  219. //串口2接收中断   
  220. //与蓝牙串口模块通信   
  221. void USART2_IRQHandler(void)                               
  222. {  
  223.     unsigned char rx_dat;       
  224.   
  225.     if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)              //判断发生接收中断   
  226.     {  
  227.         //清除中断标志   
  228.         USART_ClearITPendingBit(USART2,    USART_IT_RXNE);         
  229.         //接收数据         
  230.         rx_dat = USART_ReceiveData(USART2);                               
  231.         //写入fifo   
  232.         write_byte_fifo_stack(&fifo_uart2,rx_dat);  
  233.     }  
  234. }  
  235. /******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/ 

main.c:(主文件)

  1. /* 
  2.     功能:蓝牙转串口模块 
  3.     作者:jdh 
  4.     时间:2012-2-27     
  5. */  
  6. #include "public.h"   
  7.   
  8. static __IO uint32_t TimingDelay;  
  9.   
  10. //定义GPIO结构体   
  11. GPIO_InitTypeDef GPIO_InitStructure;  
  12.   
  13. /* Private function prototypes -----------------------------------------------*/  
  14. void Delay(__IO uint32_t nTime);  
  15.   
  16. //初始化内部晶振   
  17. static void RCC_Config(void)  
  18. {  
  19.   //将外设 RCC寄存器重设为缺省值   
  20.   RCC_DeInit();  
  21.   //内部晶振使能   
  22.   RCC_HSICmd(ENABLE);  
  23.   //使能外部晶振   
  24.   //SystemInit();   
  25.   //等待工作稳定   
  26.   while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);  
  27.   
  28.   if(1)  
  29.   {  
  30.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  
  31.     FLASH_SetLatency(FLASH_Latency_2);  
  32.     //高速时钟   
  33.     RCC_HCLKConfig(RCC_SYSCLK_Div1);  
  34.     RCC_PCLK2Config(RCC_HCLK_Div1);  
  35.     RCC_PCLK1Config(RCC_HCLK_Div2);  
  36.     //设置 PLL 时钟源及倍频系数   
  37.     RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_9);  
  38.     //使能或者失能 PLL,这个参数可以取:ENABLE或者DISABLE   
  39.     RCC_PLLCmd(ENABLE);//如果PLL被用于系统时钟,那么它不能被失能   
  40.     //等待指定的 RCC 标志位设置成功 等待PLL初始化成功   
  41.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  
  42.     //设置系统时钟(SYSCLK) 设置PLL为系统时钟源   
  43.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  
  44.     //等待PLL成功用作于系统时钟的时钟源   
  45.     //  0x00:HSI 作为系统时钟    
  46.     //  0x04:HSE作为系统时钟    
  47.     //  0x08:PLL作为系统时钟     
  48.     while(RCC_GetSYSCLKSource() != 0x08);  
  49.   }  
  50. }   
  51.   
  52. //设置串口波特率   
  53. void set_uart_baud(int num,int baud)  
  54. {  
  55.     if (num == 1)  
  56.     {  
  57.         //更新串口波特率   
  58.         USART_Cmd(USART1,DISABLE);  
  59.         USART_InitStructure.USART_BaudRate = baud;  
  60.         USART_Init(USART1,&USART_InitStructure);  
  61.         USART_Cmd(USART1, ENABLE);  
  62.     }  
  63.   
  64.     if (num == 2)  
  65.     {  
  66.         //更新串口波特率   
  67.         USART_Cmd(USART2,DISABLE);  
  68.         USART_InitStructure.USART_BaudRate = baud;  
  69.         USART_Init(USART2,&USART_InitStructure);  
  70.         USART_Cmd(USART2, ENABLE);  
  71.     }  
  72. }  
  73.   
  74. //初始化   
  75. void init()  
  76. {  
  77.     //定义中断结构体   
  78.     NVIC_InitTypeDef NVIC_InitStructure;  
  79.   
  80.     //初始化结构体   
  81.     GPIO_StructInit(&GPIO_InitStructure);  
  82.     //初始化uart2的接收fifo   
  83.     init_fifo_stack(&fifo_uart2);  
  84.     //初始化uart1的接收fifo   
  85.     init_fifo_stack(&fifo_uart1);  
  86.       
  87.     //中断NVIC设置:允许中断,设置优先级    
  88.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;    //更新事件    
  89.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   //抢占优先级0    
  90.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;          //响应优先级1    
  91.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //允许中断    
  92.     NVIC_Init(&NVIC_InitStructure);                             //写入设置    
  93.       
  94.     //RCC_Config();   
  95.     //打开串口对应的外设时钟   
  96.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);   
  97.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE);   
  98.     //初始化参数   
  99.     USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;  
  100.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;  
  101.     USART_InitStructure.USART_StopBits = USART_StopBits_1;  
  102.     USART_InitStructure.USART_Parity = USART_Parity_No;  
  103.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  104.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  105.     //初始化串口   
  106.     USART_Init(USART1,&USART_InitStructure);  
  107.     //初始化参数   
  108.     USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;  
  109.     USART_Init(USART2,&USART_InitStructure);  
  110.     //TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个    
  111.     USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  
  112.     USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);  
  113.   
  114.     //配置UART1中断   
  115.     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;               //通道设置为串口1中断   
  116.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级0   
  117.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级0   
  118.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断   
  119.     NVIC_Init(&NVIC_InitStructure);                                 //初始化   
  120.   
  121.     //配置UART2中断   
  122.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;               //通道设置为串口1中断   
  123.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;       //中断占先等级0   
  124.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              //中断响应优先级0   
  125.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断   
  126.     NVIC_Init(&NVIC_InitStructure);                                 //初始化   
  127.   
  128.     //启动串口   
  129.     USART_Cmd(USART1, ENABLE);   
  130.     USART_Cmd(USART2, ENABLE);   
  131.   
  132.     //设置IO口时钟       
  133.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);    
  134.     //串口1的管脚初始化     
  135.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                       //管脚9   
  136.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                //选择GPIO响应速度   
  137.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //复用推挽输出   
  138.     GPIO_Init(GPIOA, &GPIO_InitStructure);                          //TX初始化   
  139.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                      //管脚10   
  140.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                //选择GPIO响应速度   
  141.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;           //浮空输入   
  142.     GPIO_Init(GPIOA, &GPIO_InitStructure);                          //RX初始化        
  143.       
  144.     //设置IO口时钟       
  145.     //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);     
  146.     //串口2的管脚初始化     
  147.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                       //管脚9   
  148.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                //选择GPIO响应速度   
  149.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //复用推挽输出   
  150.     GPIO_Init(GPIOA, &GPIO_InitStructure);                          //TX初始化   
  151.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                       //管脚10   
  152.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                //选择GPIO响应速度   
  153.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;           //浮空输入   
  154.     GPIO_Init(GPIOA, &GPIO_InitStructure);                          //RX初始化                                                 
  155.   
  156.     /* Setup SysTick Timer for 1 msec interrupts  */  
  157.     if (SysTick_Config(SystemCoreClock / 1000))  
  158.     {   
  159.         /* Capture error */   
  160.         while (1);  
  161.     }  
  162.   
  163.     //设置IO口时钟       
  164.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);   
  165.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                       //管脚9   
  166.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                //选择GPIO响应速度   
  167.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                 //复用推挽输出   
  168.   
  169.     //初始化修改flash结构   
  170.     init_edit_flash(&edit_flash);  
  171.     //打开需要操作页面的写保护   
  172.     open_write_lock();  
  173. }  
  174.   
  175. init_blue(int baud)  
  176. {  
  177.     //置高AT_EN脚   
  178.     GPIO_Init(GPIOB, &GPIO_InitStructure);                            
  179.     GPIO_SetBits(GPIOB,GPIO_Pin_0);  
  180.   
  181.     send_bt_cmd("AT+INIT");  
  182.     Delay(100);  
  183.     send_bt_cmd("AT+CMODE=1");   
  184.     Delay(100);   
  185.     switch (baud)  
  186.     {  
  187.     case 4800:  
  188.         {  
  189.             send_bt_cmd("AT+UART=4800,0,0");   
  190.             Delay(100);   
  191.             break;  
  192.         }  
  193.     case 9600:  
  194.         {  
  195.             send_bt_cmd("AT+UART=9600,0,0");   
  196.             Delay(100);   
  197.             break;  
  198.         }  
  199.     case 19200:  
  200.         {  
  201.             send_bt_cmd("AT+UART=19200,0,0");   
  202.             Delay(100);   
  203.             break;  
  204.         }  
  205.     case 38400:  
  206.         {  
  207.             send_bt_cmd("AT+UART=38400,0,0");   
  208.             Delay(100);   
  209.             break;  
  210.         }  
  211.     case 57600:  
  212.         {  
  213.             send_bt_cmd("AT+UART=57600,0,0");   
  214.             Delay(100);   
  215.             break;  
  216.         }  
  217.     case 115200:  
  218.         {  
  219.             send_bt_cmd("AT+UART=115200,0,0");   
  220.             Delay(100);   
  221.             break;  
  222.         }  
  223.     default:  
  224.         {  
  225.             send_bt_cmd("AT+UART=9600,0,0");   
  226.             Delay(100);   
  227.             break;  
  228.         }  
  229.     }  
  230.       
  231.     //置低AT_EN脚   
  232.     GPIO_Init(GPIOB, &GPIO_InitStructure);                            
  233.     GPIO_ResetBits(GPIOB,GPIO_Pin_0);   
  234. }  
  235.   
  236. int main(void)  
  237. {  
  238.     struct _match_string_header match_string_header;  
  239.     struct _match_string_tail match_string_tail;  
  240.     unsigned char buffer[LEN_BUF];  
  241.     unsigned char buffer1[LEN_BUF];  
  242.     int len = 0;  
  243.     int i = 0;  
  244.     int flag = 0;  
  245.     int flag2 = 0;  
  246.     int flag3 = 0;  
  247.     int baud = 0;  
  248.   
  249.     //初始化系统   
  250.     init();  
  251.     //初始化蓝牙   
  252.     //读取flash中波特率   
  253.     write_baud(&edit_flash,9600);  
  254.     baud = read_baud(&edit_flash);  
  255.     //读取有效   
  256.     if (baud > 0)  
  257.     {  
  258.         set_uart_baud(1,baud);  
  259.         set_uart_baud(2,baud);  
  260.     }  
  261.     else  
  262.     {  
  263.         //设置默认波特率   
  264.         set_uart_baud(1,DEFAULT_BAUD);  
  265.         set_uart_baud(2,DEFAULT_BAUD);  
  266.     }  
  267.   
  268.     //设置默认波特率   
  269.     Delay(10);  
  270.     init_blue(DEFAULT_BAUD);  
  271.     set_uart_baud(1,DEFAULT_BAUD);  
  272.     set_uart_baud(2,DEFAULT_BAUD);  
  273.     Delay(500);  
  274.     init_blue(DEFAULT_BAUD);  
  275.     set_uart_baud(1,DEFAULT_BAUD);  
  276.     set_uart_baud(2,DEFAULT_BAUD);  
  277.   
  278.     //初始化匹配字符   
  279.     init_match_string_header(&match_string_header,"AT+BAUD=");  
  280.     init_match_string_tail(&match_string_tail,"END",8);  
  281.   
  282.     while (1)  
  283.     {  
  284.         //读取fifo_uart1中所有数据   
  285.         len = read_all_fifo_stack(&fifo_uart1,buffer1);  
  286.         //处理   
  287.         for (i = 0;i < len;i++)  
  288.         {  
  289.             USART_SendData(USART2,buffer1[i]);                              //发送数据   
  290.             while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET){}   //等待发送结束   
  291.         }  
  292.   
  293.         //读取fifo_uart2中所有数据   
  294.         len = read_all_fifo_stack(&fifo_uart2,buffer);  
  295.         //处理   
  296.         for (i = 0;i < len;i++)  
  297.         {  
  298.             if (flag == 0)  
  299.             {  
  300.                 flag3 = match_string_header_state(&match_string_header,buffer[i]);  
  301.                 if (flag3 == 1)  
  302.                 {  
  303.                     flag = 1;  
  304.                 }  
  305.             }  
  306.             else  
  307.             {  
  308.                 flag2 = match_string_tail_state(&match_string_tail,buffer[i]);  
  309.                 if (flag2 > 0)  
  310.                 {  
  311.                     if (flag2 == 4800 || flag2 == 9600 || flag2 == 19200 || flag2 == 38400 || flag2 == 115200)  
  312.                     {  
  313.                         //重启蓝牙   
  314.                         init_blue(flag2);  
  315.                         //更新串口波特率   
  316.                         set_uart_baud(1,flag2);  
  317.                         //写入到flash   
  318.                         write_baud(&edit_flash,flag2);  
  319.   
  320.                         //返回成功   
  321.                         send_bt_cmd("set baud successful\n");  
  322.                         flag = 0;  
  323.                         continue;  
  324.                     }  
  325.                     else  
  326.                     {  
  327.                         send_bt_cmd("set baud fail\n");  
  328.                     }  
  329.                 }  
  330.             }  
  331.               
  332.             //转发数据   
  333.             USART_SendData(USART1,buffer[i]);                               //发送数据   
  334.             while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}   //等待发送结束       
  335.         }  
  336.     }  
  337. }  
  338.   
  339. /** 
  340.   * @brief  Inserts a delay time. 
  341.   * @param  nTime: specifies the delay time length, in milliseconds. 
  342.   * @retval None 
  343.   */  
  344. void Delay(__IO uint32_t nTime)  
  345. {   
  346.   TimingDelay = nTime;  
  347.   
  348.   while(TimingDelay != 0);  
  349. }  
  350.   
  351. /** 
  352.   * @brief  Decrements the TimingDelay variable. 
  353.   * @param  None 
  354.   * @retval None 
  355.   */  
  356. void TimingDelay_Decrement(void)  
  357. {  
  358.   if (TimingDelay != 0x00)  
  359.   {   
  360.     TimingDelay--;  
  361.   }  
  362. }  
  363.   
  364. #ifdef  USE_FULL_ASSERT   
  365. /** 
  366.   * @brief  Reports the name of the source file and the source line number 
  367.   *         where the assert_param error has occurred. 
  368.   * @param  file: pointer to the source file name 
  369.   * @param  line: assert_param error line source number 
  370.   * @retval None 
  371.   */  
  372. void assert_failed(uint8_t* file, uint32_t line)  
  373. {   
  374.   /* User can add his own implementation to report the file name and line number, 
  375.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  
  376.   
  377.   /* Infinite loop */  
  378.   while (1)  
  379.   {  
  380.   }  
  381. }  
  382. #endif  


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android串口调试助手代码是一段用于实现串口通信的Android应用程序的代码。它可以实现通过手机与硬件设备的串行通信,方便用户进行串口调试和数据交互。 首先,代码应该包含相关的依赖库和权限声明。例如,需要在AndroidManifest.xml文件声明使用串口的权限,如访问USB设备等。 接下来,代码需要通过打开串口来建立与硬件设备的连接。这可以通过设置串口的波特率、数据位、停止位和校验位等参数来实现。 然后,代码应该监听串口数据的接收,并将接收到的数据显示在应用程序的界面上。可以使用Android的TextView或者RecyclerView等控件来实现数据的显示。 此外,代码还应该提供一些串口操作的功能,如发送数据、清除接收缓存、关闭串口等。用户可以通过点击按钮或者其他操作来触发这些功能。 最后,代码应该考虑异常处理和错误提示。例如,如果出现打开串口失败或者接收数据错误等情况,应该给用户提供相应的提示信息,方便用户进行故障排查。 为了增加用户体验,代码可以进一步完善,如添加历史记录功能、支持多种编码格式、支持自定义串口参数等。 综上所述,Android串口调试助手的代码主要包括串口连接、数据显示、串口操作功能和异常处理等部分。通过该代码实现的应用程序可以方便用户进行串口调试和数据交互,提高工程师的工作效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值