基于STM32的无线抄表系统

目录

一、项目描述

二、原理图

三、实物

 四、代码

六、论文

七、资料清单

资料下载地址:基于STM32无线抄表系统

一、项目描述

1.通过串口获取电表数据,并在OLED液晶上显示;
2. 通过ESP8266WIFI模块将电表数据上传到云平台和手机APP上

二、原理图

三、实物

 

手机APP

 

云平台 

 四、代码

    ESP8266代码

#include "bsp_esp8266.h"
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "bsp_SysTick.h"
#include "test.h"
#include "bsp_usart1.h"
/*
     管脚连接关系
     ESP8266                  单片机
      VCC      ----------     5V
      GND      ----------     GND
      TXD      ----------     PB11 (RX)
			RXD      ----------     PB10 (TX)
			RST      ----------     PA8 (可以不连接)
			IO_0     ----------     未连接

模块的 RST引脚和IO_0引脚 默认为高电平,	所以RST引脚不连接也可以正常使用。
模块必须5V供电,3.3V供电时不能正常工作。
*/


static void                   ESP8266_GPIO_Config                 ( void );
static void                   ESP8266_USART_Config                ( void );
static void                   ESP8266_USART_NVIC_Configuration    ( void );

struct  STRUCT_USARTx_Fram strEsp8266_Fram_Record = { 0 };			//ESP8266接收数据结构体

/**
  * @brief  ESP8266初始化函数
  * @param  无
  * @retval 无
  */
void ESP8266_Init ( void )
{
    ESP8266_GPIO_Config ();								//ESP8266模块使用到的IO口初始化
    ESP8266_USART_Config ();							//与ESP8266模块连接的串口初始化
    macESP8266_RST_HIGH_LEVEL();					//ESP8266模块 复位脚设置为高电平
    macESP8266_CH_DISABLE();							//片选引脚不选中
}
/**
  * @brief  初始化ESP8266用到的GPIO引脚
  * @param  无
  * @retval 无
  */
static void ESP8266_GPIO_Config ( void )
{
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 配置 CH_PD 引脚*/
    macESP8266_CH_PD_APBxClock_FUN ( macESP8266_CH_PD_CLK, ENABLE );
    GPIO_InitStructure.GPIO_Pin = macESP8266_CH_PD_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init ( macESP8266_CH_PD_PORT, & GPIO_InitStructure );

    /* 配置 RST 引脚*/
    macESP8266_RST_APBxClock_FUN ( macESP8266_RST_CLK, ENABLE );
    GPIO_InitStructure.GPIO_Pin = macESP8266_RST_PIN;
    GPIO_Init ( macESP8266_RST_PORT, & GPIO_InitStructure );
}
/**
  * @brief  初始化ESP8266用到的 USART
  * @param  无
  * @retval 无
  */
static void ESP8266_USART_Config ( void )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    /* config USART clock */
    macESP8266_USART_APBxClock_FUN ( macESP8266_USART_CLK, ENABLE );
    macESP8266_USART_GPIO_APBxClock_FUN ( macESP8266_USART_GPIO_CLK, ENABLE );

    /* USART GPIO config */
    /* Configure USART Tx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin =  macESP8266_USART_TX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( macESP8266_USART_TX_PORT, &GPIO_InitStructure );

    /* Configure USART Rx as input floating */
    GPIO_InitStructure.GPIO_Pin = macESP8266_USART_RX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init( macESP8266_USART_RX_PORT, &GPIO_InitStructure );

    /* USART1 mode config */
    USART_InitStructure.USART_BaudRate = macESP8266_USART_BAUD_RATE;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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( macESP8266_USARTx, &USART_InitStructure );

    /* 中断配置 */
    USART_ITConfig ( macESP8266_USARTx, USART_IT_RXNE, ENABLE ); //使能串口接收中断
    USART_ITConfig ( macESP8266_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断

    ESP8266_USART_NVIC_Configuration ();

    USART_Cmd( macESP8266_USARTx, ENABLE );
}
/**
  * @brief  配置 ESP8266 USART 的 NVIC 中断
  * @param  无
  * @retval 无
  */
static void ESP8266_USART_NVIC_Configuration ( void )
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Configure the NVIC Preemption Priority Bits */
    NVIC_PriorityGroupConfig ( macNVIC_PriorityGroup_x );

    /* Enable the USART2 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = macESP8266_USART_IRQ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );
}
/**
  * @brief   ESP8266 USART 中断函数
  * @param  无
  * @retval 无
  */
void macESP8266_USART_INT_FUN ( void )
{
//		char * pCh;
//		char cStr [ 100 ] = { 0 };
    uint8_t ucCh;
    if ( USART_GetITStatus ( macESP8266_USARTx, USART_IT_RXNE ) != RESET )					//若串口中有数据进来,存储接收到的数据
    {
        ucCh  = USART_ReceiveData( macESP8266_USARTx );
        if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) )                       //预留1个字节写结束符
            strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ]  = ucCh;
    }
    //进入空闲中断,说明一组数据接收完成
    if ( USART_GetITStatus( macESP8266_USARTx, USART_IT_IDLE ) == SET )              //数据帧接收完毕
    {
        strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;													//设置数据接收完成标志
        ucCh = USART_ReceiveData( macESP8266_USARTx );                              //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)
        USART_ClearITPendingBit( macESP8266_USARTx, USART_IT_IDLE );
        //检测与服务器的连接是否断开  只在Station模式下使用
        ucTcpClosedFlag = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;
    }
		    

}
/*
 * 函数名:ESP8266_Rst
 * 描述  :重启WF-ESP8266模块
 * 输入  :无
 * 返回  : 无
 * 调用  :被 ESP8266_AT_Test 调用
 */
void ESP8266_Rst ( void )
{
#if 1
    ESP8266_Cmd ( "AT+RST", "OK", "ready", 2500 );
#else
    macESP8266_RST_LOW_LEVEL();
    Delay_ms ( 500 );
    macESP8266_RST_HIGH_LEVEL();
#endif
}
/*
 * 函数名:ESP8266_Cmd
 * 描述  :对WF-ESP8266模块发送AT指令
 * 输入  :cmd,待发送的指令
 *         reply1,reply2,期待的响应,为NULL表不需响应,两者为或逻辑关系
 *         waittime,等待响应的时间
 * 返回  : 1,指令发送成功
 *         0,指令发送失败
 * 调用  :被外部调用
 */
bool ESP8266_Cmd ( char * cmd, char * reply1, char * reply2, u32 waittime )
{
    strEsp8266_Fram_Record .InfBit .FramLength = 0;               //接收缓冲区数据长度清0

    macESP8266_Usart ( "%s\r\n", cmd );														//向模块发送命令
    if ( ( reply1 == 0 ) && ( reply2 == 0 ) )                      //不需要接收数据
        return true;
    Delay_ms ( waittime );                 												//延时  等待接收模块返回的指令
    strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ]  = '\0';			//接收到的字符串末尾加入 结束符
    macPC_Usart ( "%s", strEsp8266_Fram_Record .Data_RX_BUF );		//调试口打印接收到模块的指令
    if ( ( reply1 != 0 ) && ( reply2 != 0 ) )
        return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) ||
                 ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
    else if ( reply1 != 0 )
        return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply1 ) );
    else
        return ( ( bool ) strstr ( strEsp8266_Fram_Record .Data_RX_BUF, reply2 ) );
}

/*
 * 函数名:ESP8266_AT_Test
 * 描述  :对WF-ESP8266模块进行AT测试启动
 * 输入  :无
 * 返回  : 无
 * 调用  :被外部调用
 */
//void ESP8266_AT_Test ( void )
//{
//	macESP8266_RST_HIGH_LEVEL();
//
//	Delay_ms ( 1000 );
//
//	while ( ! ESP8266_Cmd ( "AT", "OK", NULL, 200 ) ) ESP8266_Rst ();

//}
void ESP8266_AT_Test ( void )
{
    char count = 0;

    macESP8266_RST_HIGH_LEVEL();
    Delay_ms ( 1000 );
    while ( count < 10 )
    {
        if( ESP8266_Cmd ( "AT", "OK", NULL, 500 ) ) return;				//如果接收到模块返回的OK指令,就直接返回
        ESP8266_Rst();																						//否则复位模块,重新发送AT测试指令
        ++ count;
		//Main_Uart2();
    }
}
/*
 * 函数名:ESP8266_Net_Mode_Choose
 * 描述  :选择WF-ESP8266模块的工作模式
 * 输入  :enumMode,工作模式
 * 返回  : 1,选择成功
 *         0,选择失败
 * 调用  :被外部调用
 */
bool ESP8266_Net_Mode_Choose ( ENUM_Net_ModeTypeDef enumMode )
{
    switch ( enumMode )
    {
    case STA:
        return ESP8266_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 );
    case AP:
        return ESP8266_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 );
    case STA_AP:
        return ESP8266_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 );
    default:
        return false;
    }
}
/*
 * 函数名:ESP8266_JoinAP
 * 描述  :WF-ESP8266模块连接外部WiFi
 * 输入  :pSSID,WiFi名称字符串
 *       :pPassWord,WiFi密码字符串
 * 返回  : 1,连接成功
 *         0,连接失败
 * 调用  :被外部调用
 */
bool ESP8266_JoinAP ( char * pSSID, char * pPassWord )
{
    char cCmd [120];
    sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );
    return ESP8266_Cmd ( cCmd, "OK", NULL, 5000 );
}
/*
 * 函数名:ESP8266_BuildAP
 * 描述  :WF-ESP8266模块创建WiFi热点
 * 输入  :pSSID,WiFi名称字符串
 *       :pPassWord,WiFi密码字符串
 *       :enunPsdMode,WiFi加密方式代号字符串
 * 返回  : 1,创建成功
 *         0,创建失败
 * 调用  :被外部调用
 */
bool ESP8266_BuildAP ( char * pSSID, char * pPassWord, ENUM_AP_PsdMode_TypeDef enunPsdMode )
{
    char cCmd [120];
    sprintf ( cCmd, "AT+CWSAP=\"%s\",\"%s\",1,%d", pSSID, pPassWord, enunPsdMode );//名称、密码、通道号(默认为1)、加密方式
    return ESP8266_Cmd ( cCmd, "OK", 0, 1000 );
}
/*
 * 函数名:ESP8266_Enable_MultipleId
 * 描述  :WF-ESP8266模块启动多连接
 * 输入  :enumEnUnvarnishTx,配置是否多连接
 * 返回  : 1,配置成功
 *         0,配置失败
 * 调用  :被外部调用
 */
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx )
{
    char cStr [20];
    sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );
    return ESP8266_Cmd ( cStr, "OK", 0, 500 );
}
/*
 * 函数名:ESP8266_Link_Server
 * 描述  :WF-ESP8266模块连接外部服务器
 * 输入  :enumE,网络协议
 *       :ip,服务器IP字符串
 *       :ComNum,服务器端口字符串
 *       :id,模块连接服务器的ID
 * 返回  : 1,连接成功
 *         0,连接失败
 * 调用  :被外部调用
 */
bool ESP8266_Link_Server ( ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id )
{
    char cStr [100] = { 0 }, cCmd [120];
    switch (  enumE )
    {
    case enumTCP:
        sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );
        break;
    case enumUDP:
        sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );
        break;
    default:
        break;
    }
    if ( id < 5 )
        sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr );
    else
        sprintf ( cCmd, "AT+CIPSTART=%s", cStr );
    return ESP8266_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );
}
/*
 * 函数名:ESP8266_StartOrShutServer
 * 描述  :WF-ESP8266模块开启或关闭服务器模式
 * 输入  :enumMode,开启/关闭
 *       :pPortNum,服务器端口号字符串
 *       :pTimeOver,服务器超时时间字符串,单位:秒
 * 返回  : 1,操作成功
 *         0,操作失败
 * 调用  :被外部调用
 */
bool ESP8266_StartOrShutServer ( FunctionalState enumMode, char * pPortNum, char * pTimeOver )
{
    char cCmd1 [120], cCmd2 [120];
    if ( enumMode )													//开启服务
    {
        sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 1, pPortNum );
        sprintf ( cCmd2, "AT+CIPSTO=%s", pTimeOver );
        return ( ESP8266_Cmd ( cCmd1, "OK", 0, 500 ) &&
                 ESP8266_Cmd ( cCmd2, "OK", 0, 500 ) );
    }
    else																		//关闭服务
    {
        sprintf ( cCmd1, "AT+CIPSERVER=%d,%s", 0, pPortNum );
        return ESP8266_Cmd ( cCmd1, "OK", 0, 500 );
    }
}
/*
 * 函数名:ESP8266_Get_LinkStatus
 * 描述  :获取 WF-ESP8266 的连接状态,较适合单端口时使用
 * 输入  :无
 * 返回  : 2,获得ip
 *         3,建立连接
 *         3,失去连接
 *         0,获取状态失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_Get_LinkStatus ( void )
{
    if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
    {
        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:2\r\n" ) )							//获得ip
            return 2;
        else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:3\r\n" ) )				//建立连接
            return 3;

        else if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "STATUS:4\r\n" ) )				//失去连接
            return 4;
    }
    return 0;
}
/*
 * 函数名:ESP8266_Get_IdLinkStatus
 * 描述  :获取 WF-ESP8266 的端口(Id)连接状态,较适合多端口时使用
 * 输入  :无
 * 返回  : 端口(Id)的连接状态,低5位为有效位,分别对应Id5~0,某位若置1表该Id建立了连接,若被清0表该Id未建立连接
 * 调用  :被外部调用
 */
uint8_t ESP8266_Get_IdLinkStatus ( void )
{
    uint8_t ucIdLinkStatus = 0x00;
    if ( ESP8266_Cmd ( "AT+CIPSTATUS", "OK", 0, 500 ) )
    {
        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:0," ) )
            ucIdLinkStatus |= 0x01;
        else
            ucIdLinkStatus &= ~ 0x01;

        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:1," ) )
            ucIdLinkStatus |= 0x02;
        else
            ucIdLinkStatus &= ~ 0x02;

        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:2," ) )
            ucIdLinkStatus |= 0x04;
        else
            ucIdLinkStatus &= ~ 0x04;

        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:3," ) )
            ucIdLinkStatus |= 0x08;
        else
            ucIdLinkStatus &= ~ 0x08;

        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+CIPSTATUS:4," ) )
            ucIdLinkStatus |= 0x10;
        else
            ucIdLinkStatus &= ~ 0x10;
    }
    return ucIdLinkStatus;
}
/*
 * 函数名:ESP8266_Inquire_ApIp
 * 描述  :获取 F-ESP8266 的 AP IP
 * 输入  :pApIp,存放 AP IP 的数组的首地址
 *         ucArrayLength,存放 AP IP 的数组的长度
 * 返回  : 0,获取失败
 *         1,获取成功
 * 调用  :被外部调用
 */
uint8_t ESP8266_Inquire_ApIp ( char * pApIp, uint8_t ucArrayLength )
{
    char uc;
    char * pCh;
    ESP8266_Cmd ( "AT+CIFSR", "OK", 0, 500 );
    pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "APIP,\"" );
    if ( pCh )
        pCh += 6;
    else
        return 0;
    for ( uc = 0; uc < ucArrayLength; uc ++ )
    {
        pApIp [ uc ] = * ( pCh + uc );

        if ( pApIp [ uc ] == '\"' )
        {
            pApIp [ uc ] = '\0';
            break;
        }
    }
    return 1;
}
/*
 * 函数名:ESP8266_UnvarnishSend
 * 描述  :配置WF-ESP8266模块进入透传发送
 * 输入  :无
 * 返回  : 1,配置成功
 *         0,配置失败
 * 调用  :被外部调用
 */
bool ESP8266_UnvarnishSend ( void )
{
    if ( ! ESP8266_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ) )
        return false;
    return
        ESP8266_Cmd ( "AT+CIPSEND", "OK", ">", 500 );
}
/*
 * 函数名:ESP8266_ExitUnvarnishSend
 * 描述  :配置WF-ESP8266模块退出透传模式
 * 输入  :无
 * 返回  : 无
 * 调用  :被外部调用
 */
void ESP8266_ExitUnvarnishSend ( void )
{
    Delay_ms ( 1000 );
    macESP8266_Usart ( "+++" );
    Delay_ms ( 500 );
}
/*
 * 函数名:ESP8266_SendString
 * 描述  :WF-ESP8266模块发送字符串
 * 输入  :enumEnUnvarnishTx,声明是否已使能了透传模式
 *       :pStr,要发送的字符串
 *       :ulStrLength,要发送的字符串的字节数
 *       :ucId,哪个ID发送的字符串
 * 返回  : 1,发送成功
 *         0,发送失败
 * 调用  :被外部调用
 */
bool ESP8266_SendString ( FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
    char cStr [20];
    bool bRet = false;
    if ( enumEnUnvarnishTx )
    {
        macESP8266_Usart ( "%s", pStr );
        bRet = true;
    }
    else
    {
        if ( ucId < 5 )
            sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );
        else
            sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );

        ESP8266_Cmd ( cStr, "> ", 0, 1000 );
        bRet = ESP8266_Cmd ( pStr, "SEND OK", 0, 1000 );
    }
    return bRet;
}
/*
 * 函数名:ESP8266_ReceiveString
 * 描述  :WF-ESP8266模块接收字符串
 * 输入  :enumEnUnvarnishTx,声明是否已使能了透传模式
 * 返回  : 接收到的字符串首地址
 * 调用  :被外部调用
 */
char * ESP8266_ReceiveString ( FunctionalState enumEnUnvarnishTx )
{
    char * pRecStr = 0;

    strEsp8266_Fram_Record .InfBit .FramLength = 0;
    strEsp8266_Fram_Record .InfBit .FramFinishFlag = 0;

    while ( ! strEsp8266_Fram_Record .InfBit .FramFinishFlag );
    strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ] = '\0';

    if ( enumEnUnvarnishTx )
        pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
    else
    {
        if ( strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "+IPD" ) )
            pRecStr = strEsp8266_Fram_Record .Data_RX_BUF;
    }
    return pRecStr;
}
/*
 * 函数名:ESP8266_CWLIF
 * 描述  :查询已接入设备的IP
 * 输入  :pStaIp,存放已接入设备的IP
 * 返回  : 1,有接入设备
 *         0,无接入设备
 * 调用  :被外部调用
 */
uint8_t ESP8266_CWLIF ( char * pStaIp )
{
    uint8_t uc, ucLen;
    char * pCh, * pCh1;
    ESP8266_Cmd ( "AT+CWLIF", "OK", 0, 100 );
    pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "," );
    if ( pCh )
    {
        pCh1 = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "AT+CWLIF\r\r\n" ) + 11;
        ucLen = pCh - pCh1;
    }
    else
        return 0;
    for ( uc = 0; uc < ucLen; uc ++ )
        pStaIp [ uc ] = * ( pCh1 + uc );

    pStaIp [ ucLen ] = '\0';
    return 1;
}
/*
 * 函数名:ESP8266_CIPAP
 * 描述  :设置模块的 AP IP
 * 输入  :pApIp,模块的 AP IP
 * 返回  : 1,设置成功
 *         0,设置失败
 * 调用  :被外部调用
 */
uint8_t ESP8266_CIPAP ( char * pApIp )
{
    char cCmd [ 30 ];
    sprintf ( cCmd, "AT+CIPAP=\"%s\"", pApIp );
    if ( ESP8266_Cmd ( cCmd, "OK", 0, 5000 ) )
        return 1;
    else
        return 0;
}

六、论文

七、资料清单

  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森旺电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值