• 九、stm32-蓝牙HC_05(接发通信、控制LED亮灭)


    一、固件库模板

    见博客:stm32f103c8t6新建固件库模板(可自取)

    二、准备资料

    1. 固件库模板

    2. MDK5开发环境

    3. stm32参考手册

    4. UART串口协议

    5. stm32中断概念

    6. HC-05命令集

    7. 利用固件库模板点灯工程(下面第三行,手动狗头)

    8. CH340 USB→TTL模块

    9. 蓝牙HC-05模块

    10. 手机软件

    实验程序已经发布到百度网盘,本文末有链接可以自取

    stm32参考手册

    串口协议查看这篇博客USART串口协议

    stm32中断概念STM32中断应用概括

    HC-05命令文件:HC-05命令

    串口调试工具
    https://pan.baidu.com/s/1V-jRJzb0INDXDLo9I4CJ6A 提取码:0000

    手机软件管家下载下面两个工具在这里插入图片描述

    三、简介

    在这里插入图片描述

    1. 引脚

    标号PIN引脚说明
    1STATE状态引出引脚(未连接时输出低电平,连接时输出高电平)
    2RXD接收端
    3TXD发送端
    4GND模块供电负极
    5VCC模块供电正极
    6EN使能端,需要进入命令模式时接3.3V

    本模块使用USART协议,具体请看下面两个博客,这里就不继续讲解了
    USART串口协议
    四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)

    2. AT: 设置工作模式

    工作模式: 自动连接(automatic connection) ,又称为透传模式;命令回应(order-response) ,又称为AT模式(AT mode)
    进入 AT 命令有二种方法:

    1. 按住按键EN脚拉高,此时灯是慢闪, SPP-05进入AT命令模式,默认波特率是38400;
      此模式我们叫原始模式。原始模式下一直处于AT命令模式状态。
    2. HC-05上电开机,红灯快闪,按住按键或EN拉高, HC-05进入AT命令模式,默认波特率是9600;此模式我们叫正常模式。正常模式下只有按住按键或拉高EN才处于AT命令模式状态。
      注意:如果波特率没有设备正确, AT命令是执行无效的。

    3. 基本配置(所有AT指令都必须换行)

    正常模式是9600、AT模式波特率固定38400,8位数据位、1位停止位、无奇偶校验的通信格式。
    (1)发送AT\r\n,回复OK;
    (2)发送AT+UART?\r\n,回复+UART 9600,0,0
    (3)发送AT+UART=115200,0,0\r\n,回复OK。即为波特率配置成功。

    • AT+NAME= “XXX” 修改蓝牙模块名称为XXX
    • AT+ROLE=0 蓝牙模式为从模式
    • AT+CMODE=1 蓝牙连接模式为任意地址连接模式,也就是说该模块可以被任意蓝牙设备连接
    • AT+PSWD=1234 蓝牙配对密码为1234
    • AT+UART=9600,0,0 蓝牙通信串口波特率为9600,停止位1位,无校验位
      配置完,需带电重启一次。

    4. AT命令的详细说明

    1. AT+ROLE设置主从模式: AT+ROLE?是查询主从状态;AT+ROLE=1是设成主, AT+ROLE=0是设成从, AT+ROLE=2设成回环角色(Slave-Loop(回环角色)——被动连接,接收远程蓝牙主设备数据并将数据原样返回给远程蓝牙)。
    2. AT+RESET: HC-05复位
    3. AT+VERSION? :获取HC-05的软件版本号,只能获取,不能修改。
    4. AT+ORGL:恢复出厂默认设置,当把模块设置乱了,使用此命令进行恢复默认值。
    5. AT+ADDR? :获取HC-05的蓝牙地址码,只能获取,不能修改。
    6. AT+NAME? :获取HC-05的名字,AT+NAME=BSP-06,修改模块的名字为BSP-06,具体名字自行修改。
    7. AT+CLASS? :设置查询设备的类型,尽量不要去修改此参数。默认是1F00。
    8. AT+IAC? :查询设置查询访问码,默认是9E8B33,尽量不要去修改此参数。
    9. AT+PSWD? :查询设置配对密码,AT+PSWD=”0000”,密码要有双引号,密码是四位数字.
    10. AT+UART: AT+UART?是查询当前模块的波特率, AT+UART=波特率是设置.
    11. AT+CMODE: AT+CMODE?是查询当前连接模式。 AT+CMODE=0, 1, 2(0——指定蓝牙地址连接模式(指定蓝牙地址由绑定指令设置) 1——任意蓝牙地址连接模式(不受绑定指令设置地址的约束)2——回环角色(Slave-Loop) 默认连接模式:0) 。
    12. AT+BIND:AT+BIND?查询当前绑定地址,AT+BIND=NAP, UAP, LAP (用逗号隔开)。
    13. AT+RMADD:从蓝牙配对列表中删除所有认证设备.
    14. AT+STATE? :获取蓝牙模块工作状态.
    15. AT+LINK=NAP,UAP,LAP:与远程设备建立连接。
    16. AT+DISC:断开连接.
    17. AT+RNAME? NAP, UAP, LAP:获取远程蓝牙设备名称.
    18. AT+ADCN? :获取蓝牙配对列表中认证设备数。
    19. AT+MRAD?获取最近使用过的蓝牙认证设备地址。
    20. AT+INQM:设置查询模式,AT+INQM=1, 9, 48(1-带RSSI信号强度指示,9-超过9个蓝牙设备响应则终止查询,48-设定超时为48*1.28=61.44秒)

    四、实验

    1.硬件设计

    1. 手机与HC-05通信
      GND接GND
      VCC接3.3
      RXD—CH340的TXD
      TXD—CH340的RXD
    2. 用HC-05控制mcu
      CH340的TXD-----USART1的RX引脚相连(c8t6 的PA10)
      CH340的RXD-----USART1的TX引脚相连(c8t6 的PA9)
      HC-05的TXD-----USART2的RX引脚相连(c8t6 的PA3)
      HC-05的RXD-----USART2的TX引脚相连(c8t6 的PA2)

    2.软件设计

    1. 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;

    2. 初始化 GPIO,并将 GPIO 复用到 USART 上;

    3. 配置 USART 参数;

    4. 配置中断控制器并使能 USART 接收中断;

    5. 使能 USART;

    6. 在 USART 接收中断服务函数实现数据接收和发送。

    2.1 复制工程 (复制stm32-USART串口通讯工程)

    四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)

    2.2 新建hc_05文件(打开工程)

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.3 编写代码

    1. 配置HC-05

    1. 进入AT模式,前面已经讲过了,
    2. AT+ORGL(先将AT恢复出厂设置,避免之前影响)
    3. 在这里插入图片描述

    这里已经勾选发送新行,直接AT就行,否则为AT\r\n
    4. 发送AT,回复OK;
    5. 发送AT+UART?,回复+UART 9600,0,0
    6. 发送AT+UART=115200,0,0,回复OK。即为波特率配置成功。
    7. AT+NAME= "XXX"修改蓝牙模块名称为XXX
    8. AT+ROLE=0 蓝牙模式为从模式
    9. AT+CMODE=1蓝牙连接模式为任意地址连接模式,也就是说该模块可以被任意蓝牙设备连接
    10. AT+PSWD= "1234"蓝牙配对密码为1234
    11. AT+UART=9600,0,0 蓝牙通信串口波特率为9600,停止位1位,无校验位.

    配置结束,需带电重启一次。

    2. 手机和串口接发通信

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    1. 手机寻找蓝牙,并填写配对码
    2. 蓝牙调试宝连接对应蓝牙
    3. 发送数据,串口接收,串口发送,手机接收

    3. 使用HC-05控制mcu

    stm32f103c8t6自带一个led灯,使用PC13引脚就行了,

    切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常

    led.c
    #include "led.h"	//绑定led.h
    
    void LED_GPIO_Config(void) {
        GPIO_InitTypeDef GPIO_InitStruct; //初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。
        //开启RCC时钟
        RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK, ENABLE);
    
        //配置初始化,推挽输出方式和LED_G_GPIO_PIN管脚、赫兹
        GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_PIN;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        //GPIO口初始化
        GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    led.h
    #ifndef __LED_H_
    #define __LED_H_
    
    #include "stm32f10x.h"
    #include "sys.h"
    
    #define LED_G_GPIO_PIN         GPIO_Pin_13
    #define LED_G_GPIO_PORT        GPIOC
    #define LED_G_GPIO_CLK         RCC_APB2Periph_GPIOC
    //使用位带操作来实现操作某个IO口的 1个位,由sys.h实现
    #define LED 				   PCout(13)
    
    void LED_GPIO_Config(void); //函数定义
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    usart.c

    在USART1_IRQHandler方法下面添加 usart2的初始化和中断

    struct  STRUCT_USARTx_Fram strHC05_Fram_Record = { 0 };
    
    
    void uart2_init(u32 bound) {
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
        //USART2_TX   GPIOA.2
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA2
    
        //USART2_RX	  GPIOA.3初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3
    
        //Usart2 NVIC 配置
    	  NVIC_PriorityGroupConfig(macNVIC_PriorityGroup_x);
    	
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		//子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
    
        //USART 初始化设置
    
        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    
        USART_Init(USART2, &USART_InitStructure); //初始化串口1
        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
    		USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//使能串口总线空闲中断
    		
        USART_Cmd(USART2, ENABLE);
    }
    
    void USART2_IRQHandler(void)                	//串口1中断服务程序
    {
        u8 Res;
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
        {
            Res =USART_ReceiveData(USART2);	//读取接收到的数据
    			  //USART_SendData(USART1,Res);
            if ( strHC05_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) )                       //预留1个字节写结束符
                strHC05_Fram_Record .Data_RX_BUF [ strHC05_Fram_Record .InfBit .FramLength ++ ]  = Res;
        }
    
        if ( USART_GetITStatus( USART2, USART_IT_IDLE ) == SET )                                         //数据帧接收完毕
        {
            strHC05_Fram_Record .InfBit .FramFinishFlag = 1;
            Res = USART_ReceiveData( USART2 );
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    usart.h

    添加strHC05_Fram_Record结构体和uart2_init(u32 bound)函数

    extern struct  STRUCT_USARTx_Fram                                  //串口数据帧的处理结构体
    {
        //STRUCT_USARTx_Fram 读取的数据
        char  Data_RX_BUF [ RX_BUF_MAX_LEN ];
    
        union {
            __IO u16 InfAll;
            struct {
                __IO u16 FramLength       :15;                               // 14:0
                __IO u16 FramFinishFlag   :1;                                // 15
            } InfBit;
        };
    
    }strUSART_Fram_Record,strHC05_Fram_Record;
    
    //如果想串口中断接收,请不要注释以下宏定义
    void uart1_init(u32 bound);
    void uart2_init(u32 bound);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    hc_05.c
    #include "hc_05.h"
    #include "delay.h"
    #include "usart.h"
    #include "stdbool.h"
    #include 
    
    bool HC05_AT_Test ( void )
    {
        char count = 0;
    
        printf("\r\nAT测试.....\r\n");
        Delay_ms ( 2000 );
        while ( count < 10 )
        {
            printf("\r\nAT测试次数 %d......\r\n", count);
            if( HC05_Set_Cmd ( "AT", "OK", NULL, 500 ) )
            {
                printf("\r\nAT测试启动成功 %d......\r\n", count);
                return 1;
            }
            ++ count;
        }
        return 0;
    }
    
    
    /**
      * @brief  HC05 配置测试函数
      * @param  无
      * @retval 无
      */
    void HC05_ConfigTest(void)
    {
        printf( "\r\n正在配置 HC05 ......\r\n" );
        printf( "\r\n请按住按钮 ......\r\n" );
        while( ! HC05_AT_Test() );
        printf ( "\r\n连接成功......\r\n" );
    }
    
    /*
     * 函数名:hc05_Cmd
     * 描述  :对hc05模块发送AT指令
     * 输入  :cmd,待发送的指令
     *         reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
     *         waittime,等待响应的时间
     * 返回  : 1,指令发送成功
     *         0,指令发送失败
     * 调用  :被外部调用
     */
    bool HC05_Set_Cmd( char *cmd, char *reply1, char *reply2, u32 waittime )
    {
        strHC05_Fram_Record .InfBit .FramLength = 0;              		 //从新开始接收新的数据包
        hc05_Usart ( "%s\r\n", cmd );
        if ( ( reply1 == 0 ) && ( reply2 == 0 ) )                      //不需要接收数据
            return true;
        Delay_ms ( waittime );                 //延时
        //增加一个结束符。
        strHC05_Fram_Record .Data_RX_BUF [ strHC05_Fram_Record .InfBit .FramLength ]  = '\0';
        //将USART2接收到的东西全部打印出来,接收到的保存在这个数组里,
        //通过串口1发送出来,这样就能看到,我们发送的指令的响应,是否出错,
        //例如:发送AT,响应是OK, HC05_USART接收到的数据是AT OK.在交给USART1发送,在PC机的串口调试助手可以看到这些信息,
        PC_Usart ( "%s", strHC05_Fram_Record .Data_RX_BUF );
    
        strHC05_Fram_Record .InfBit .FramLength = 0;                             //清除接收标志
        strHC05_Fram_Record.InfBit.FramFinishFlag = 0;
        if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
            return ( ( bool ) strstr ( strHC05_Fram_Record .Data_RX_BUF, reply1 ) ||
                     ( bool ) strstr ( strHC05_Fram_Record .Data_RX_BUF, reply2 ) );
        else if ( reply1 != 0 )
            return ( ( bool ) strstr ( strHC05_Fram_Record .Data_RX_BUF, reply1 ) );
    
        else
            return ( ( bool ) strstr ( strHC05_Fram_Record .Data_RX_BUF, reply2 ) );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    hc_05.h
    
    #ifndef __HC_05_H_
    #define __HC_05_H_
    
    #include "stm32f10x.h"
    #include "stdbool.h"
    #include "sys.h"
    
    
    /*********************************************** HC05 函数宏定义 *******************************************/
    #define     hc05_Usart( fmt, ... )           USART_printf ( USART2, fmt, ##__VA_ARGS__ )
    #define     PC_Usart( fmt, ... )             printf ( fmt, ##__VA_ARGS__ )
    //#define     macPC_Usart( fmt, ... )
    
    bool HC05_Set_Cmd( char *cmd, char *reply1, char *reply2, u32 waittime );
    bool HC05_AT_Test ( void );
    void HC05_ConfigTest(void);
    
    #endif
    /******************************** END OF FILE *********************************/
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    main.c

    
    #include "delay.h"
    #include "sys.h"
    #include "usart.h"
    #include "stm32f10x.h"
    #include "led.h"
    #include "hc_05.h"
    
    /*
    
     CH340的TXD-----USART1的RX引脚相连(c8t6 的PA10)
     CH340的RXD-----USART1的TX引脚相连(c8t6 的PA9)
     HC-05的TXD-----USART2的RX引脚相连(c8t6 的PA3)
     HC-05的RXD-----USART2的TX引脚相连(c8t6 的PA2)
    
    
    */
    int main()
    {
        /********************************************************************************
        *    Delay_init();				  //本实验使用的是SysTick时钟
        *    CPU_TS_TmrInit();      //已经使能宏,不需要初始化
        *    uart1_init(115200);	 	//串口初始化为115200,需要在usart.h中使能
        ********************************************************************************/
    
        /* 初始化 */
        uart1_init(115200);		//usart1初始化,
    	uart2_init(9600);		//usart2初始化,
        LED_GPIO_Config();		//初始化led使用的GPIO口
        printf("--HC_05初始化完成--");
    	HC05_ConfigTest();	//看看HC-05AT命令是否有效
        while (1)
        {
            if(strHC05_Fram_Record .InfBit .FramFinishFlag)  	//如果串口接收到数据,并结束
            {
                //增加一个结束符。
                strHC05_Fram_Record .Data_RX_BUF [ strHC05_Fram_Record .InfBit .FramLength ]  = '\0';
                //将HC05接收到的东西全部打印出来,接收到的保存在这个数组里,再通过串口1发送出来,这样就能看到,我们发送的指令的响应,是否出错,
                printf( "\r\n%s\r\n", strHC05_Fram_Record .Data_RX_BUF );
                if(strstr ( strHC05_Fram_Record .Data_RX_BUF, "LED=1" ))	//如果手机发送的数据存在LED=1,则if成立
                {
                    PCout(13) = 1; //PC口13引脚输出,高电平
    								printf("\r\nLED灭\r\n");
                    Delay_ms(500);		//已经在delay.h中初始化
    
                }
    					 else	if(strstr ( strHC05_Fram_Record .Data_RX_BUF, "LED=0" ))
                {
                    PCout(13) = 0; //PC口13引脚输出,低电平
    								printf("\r\nLED亮\r\n");
    								Delay_ms(500);
    
                }
                strHC05_Fram_Record .InfBit .FramLength = 0;                             //清除接收标志
                strHC05_Fram_Record.InfBit.FramFinishFlag = 0;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    3. 编译

    编译成功
    在这里插入图片描述

    4. 选择烧录工具并配置MDK

    本文选择的是ST_Link烧录工具
    在这里插入图片描述
    在这里插入图片描述
    如果没有ID号看博客:ST-Link V2烧录问题(已解决)
    在这里插入图片描述
    在这里插入图片描述

    5. 成品

    1. 测试stm32向hc-05发送AT命令

    在这里插入图片描述

    2. 通过hc-05控制mcu

    在这里插入图片描述
    在这里插入图片描述
    这里PC13已经亮灭了就没有上传截图,大家自己可以试试

    工程链接

    链接:https://pan.baidu.com/s/1QkiPecASH7St9YDvSWHfpA 提取码:0000

  • 相关阅读:
    状态保持-JWT
    html2canvas 行内元素边框样式生成问题解决(根据文字生成图片)
    springboot游戏道具在线交易平台毕业设计源码171956
    企业级git工作流程
    配置haproxy负载均衡http
    大数据ClickHouse(六):Log系列表引擎
    【QT进阶】Qt http编程之http相关类的简单介绍
    我没能实现始终在一个线程上运行 task
    容器编排学习(六)服务管理与用户权限管理
    每天一个数据分析题(一百六十八)
  • 原文地址:https://blog.csdn.net/weixin_55999942/article/details/126376221