学习目标

  1. 掌握封装抽取流程
  2. 掌握抽取封装策略

    学习内容

    开发流程

  3. 在文件系统中,创建中间件功能文件目录

  4. 在keil工程中,创建分组管理中间件
  5. 编写中间件逻辑
  6. 使用中间件

    文件目录创建

    在工程根目录,创建Middleware目录,在这个目录中,创建具体的功能目录,当前是做串口功能,我们新建usart
    188.png

    分组创建

  7. 创建Middleware分组。右键进入Manage Project Items

创建Middleware.gif

  1. 创建头文件和c文件

189.png
创建头文件
创建Usart0.h.gif
创建c文件
创建Usart0.c.gif
添加include引入
添加Include.gif

接口定义

发送功能定义

  1. void Usart0_init();
  2. void Usart0_send_data(uint8_t data);
  3. void Usart0_send_string(char *data);

接收回调定义

  1. #define USART0_RECV_CALLBACK 1
  2. #if USART0_RECV_CALLBACK
  3. extern void Usart0_recv(uint8_t *data, uint32_t len);
  4. #endif
  1. ...
  2. // TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度
  3. #if USART0_RECV_CALLBACK
  4. Usart0_recv(g_recv_buff, g_recv_length);
  5. #endif
  6. ...
  • 通过宏定义做开关

系统printf打印定义

  1. #define USART0_PRINTF 1
  2. #if USART0_PRINTF
  3. #include <stdio.h>
  4. #endif
  1. #if USART0_PRINTF
  2. //重写fputc方法 调用printf,会自动调用这个方法实现打印
  3. int fputc(int ch, FILE *f) {
  4. Usart0_send_data((uint8_t)ch);
  5. return ch;
  6. }
  7. #endif

完整代码

  1. #ifndef __USART0_H__
  2. #define __USART0_H__
  3. #include "gd32f4xx.h"
  4. #include "systick.h"
  5. #define USART0_RECV_CALLBACK 1
  6. #define USART0_PRINTF 1
  7. #if USART0_PRINTF
  8. #include <stdio.h>
  9. #endif
  10. void Usart0_init();
  11. void Usart0_send_data(uint8_t data);
  12. void Usart0_send_string(char *data);
  13. #if USART0_RECV_CALLBACK
  14. extern void Usart0_recv(uint8_t *data, uint32_t len);
  15. #endif
  16. #endif
  1. #include "Usart0.h"
  2. #define USART0_RECEIVE_LENGTH 1024
  3. //串口接收缓冲区大小
  4. static uint8_t g_recv_buff[USART0_RECEIVE_LENGTH]; // 接收缓冲区
  5. //接收到字符存放的位置
  6. static int g_recv_length = 0;
  7. void Usart0_init() {
  8. uint32_t usartx_tx_rcu = RCU_GPIOA;
  9. uint32_t usartx_tx_port = GPIOA;
  10. uint32_t usartx_tx_pin = GPIO_PIN_9;
  11. uint32_t usartx_tx_af = GPIO_AF_7;
  12. uint32_t usartx_rx_rcu = RCU_GPIOA;
  13. uint32_t usartx_rx_port = GPIOA;
  14. uint32_t usartx_rx_pin = GPIO_PIN_10;
  15. uint32_t usartx_rx_af = GPIO_AF_7;
  16. uint32_t usartx = USART0;
  17. uint32_t usartx_rcu = RCU_USART0;
  18. uint32_t usartx_irqn = USART0_IRQn;
  19. uint32_t usartx_p_baudrate = 115200;
  20. uint32_t usartx_p_parity = USART_PM_NONE;
  21. uint32_t usartx_p_wl = USART_WL_8BIT;
  22. uint32_t usartx_p_stop_bit = USART_STB_1BIT;
  23. uint32_t usartx_p_data_first = USART_MSBF_LSB;
  24. /************** gpio config **************/
  25. // tx
  26. rcu_periph_clock_enable(usartx_tx_rcu); // 配置时钟
  27. gpio_mode_set(usartx_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_tx_pin);
  28. gpio_af_set(usartx_tx_port, usartx_tx_af, usartx_tx_pin);
  29. gpio_output_options_set(usartx_tx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_tx_pin);
  30. // rx
  31. rcu_periph_clock_enable(usartx_rx_rcu); // 配置时钟
  32. gpio_mode_set(usartx_rx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, usartx_rx_pin);
  33. gpio_af_set(usartx_rx_port, usartx_rx_af, usartx_rx_pin);
  34. //gpio_output_options_set(usartx_rx_port, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, usartx_rx_pin);
  35. /************** usart config **************/
  36. // 串口时钟
  37. rcu_periph_clock_enable(RCU_USART0);
  38. // USART复位
  39. usart_deinit(usartx);
  40. usart_baudrate_set(usartx, usartx_p_baudrate); // 波特率
  41. usart_parity_config(usartx, usartx_p_parity); // 校验位
  42. usart_word_length_set(usartx, usartx_p_wl); // 数据位数
  43. usart_stop_bit_set(usartx, usartx_p_stop_bit); // 停止位
  44. usart_data_first_config(usartx, usartx_p_data_first); // 先发送高位还是低位
  45. // 发送功能配置
  46. usart_transmit_config(usartx, USART_TRANSMIT_ENABLE);
  47. // 接收功能配置
  48. usart_receive_config(usartx, USART_RECEIVE_ENABLE);
  49. // 接收中断配置
  50. nvic_irq_enable(usartx_irqn, 2, 2);
  51. // usart int rbne
  52. usart_interrupt_enable(usartx, USART_INT_RBNE);
  53. usart_interrupt_enable(usartx, USART_INT_IDLE);
  54. // 使能串口
  55. usart_enable(usartx);
  56. }
  57. void Usart0_send_data(uint8_t data) {
  58. //通过USART发送
  59. usart_data_transmit(USART0, data);
  60. //判断缓冲区是否已经空了
  61. //FlagStatus state = usart_flag_get(USART_NUM,USART_FLAG_TBE);
  62. while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
  63. }
  64. void Usart0_send_string(char *data) {
  65. //满足: 1.data指针不为空 2.发送的数据不是\0结束标记
  66. while(data && *data) {
  67. Usart0_send_data((uint8_t)(*data));
  68. data++;
  69. }
  70. }
  71. #if USART0_PRINTF
  72. //重写fputc方法 调用printf,会自动调用这个方法实现打印
  73. int fputc(int ch, FILE *f) {
  74. Usart0_send_data((uint8_t)ch);
  75. return ch;
  76. }
  77. #endif
  78. void USART0_IRQHandler(void) {
  79. if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {
  80. uint16_t value = usart_data_receive(USART0);
  81. g_recv_buff[g_recv_length] = value;
  82. g_recv_length++;
  83. }
  84. if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
  85. //读取缓冲区,清空缓冲区
  86. usart_data_receive(USART0);
  87. g_recv_buff[g_recv_length] = '\0';
  88. // TODO: g_recv_buff为接收的数据,g_recv_length为接收的长度
  89. #if USART0_RECV_CALLBACK
  90. Usart0_recv(g_recv_buff, g_recv_length);
  91. #endif
  92. g_recv_length = 0;
  93. }
  94. }

练习题

  1. 实现串口驱动定义