26-ESP8266 SDK開發基礎入門篇--編寫WIFI模塊 SmartConfig/Airkiss 一鍵配網


https://www.cnblogs.com/yangfengwu/p/11427504.html

 

SmartConfig/Airkiss 配網需要APP/微信公眾號,這節大家先使用我做好的APP/微信公眾號

APP下載: 

https://www.cnblogs.com/yangfengwu/p/11249674.html

 

 

 微信公眾號: 掃描這個二維碼關注我的公眾號

    

其余的步驟等寫完8266的配網程序,在下面演示.

 

 如果想自己實現微信綁定可以看↓ (注:配置過程和源碼全部是公開的,大家看文章即可實現)

 

如果你已經有做網頁的經驗了,可以直接

 

 

 

 如果你沒有做過網頁,你需要先看

  

 

 

然后需要把微信小程序篇的所有章節從頭到尾看一遍

 

 

現在開始寫WIFI的配網程序

其實官方給了例子

 

 

 咱把例子寫個單獨的.C和.H文件,方便咱后期使用

 

 

 

 

 

 

 

 

 

 smart_config.c

 

#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "espressif/espconn.h"
#include "espressif/airkiss.h"

#define server_ip "192.168.101.142"
#define server_port 9669


#define DEVICE_TYPE         "gh_9e2cff3dfa51" //wechat public number
#define DEVICE_ID             "122475" //model ID

#define DEFAULT_LAN_PORT     12476

LOCAL esp_udp ssdp_udp;
LOCAL struct espconn pssdpudpconn;
LOCAL os_timer_t ssdp_time_serv;

uint8  lan_buf[200];
uint16 lan_buf_len;
uint8  udp_sent_cnt = 0;

const airkiss_config_t akconf =
{
    (airkiss_memset_fn)&memset,
    (airkiss_memcpy_fn)&memcpy,
    (airkiss_memcmp_fn)&memcmp,
    0,
};

LOCAL void ICACHE_FLASH_ATTR
airkiss_wifilan_time_callback(void)
{
    uint16 i;
    airkiss_lan_ret_t ret;

    if ((udp_sent_cnt++) >30) {
        udp_sent_cnt = 0;
        os_timer_disarm(&ssdp_time_serv);//s
        //return;
    }

    ssdp_udp.remote_port = DEFAULT_LAN_PORT;
    ssdp_udp.remote_ip[0] = 255;
    ssdp_udp.remote_ip[1] = 255;
    ssdp_udp.remote_ip[2] = 255;
    ssdp_udp.remote_ip[3] = 255;
    lan_buf_len = sizeof(lan_buf);
    ret = airkiss_lan_pack(AIRKISS_LAN_SSDP_NOTIFY_CMD,
        DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);
    if (ret != AIRKISS_LAN_PAKE_READY) {
        os_printf("Pack lan packet error!");
        return;
    }

    ret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
    if (ret != 0) {
        os_printf("UDP send error!");
    }
    os_printf("Finish send notify!\n");
}

LOCAL void ICACHE_FLASH_ATTR
airkiss_wifilan_recv_callbk(void *arg, char *pdata, unsigned short len)
{
    uint16 i;
    remot_info* pcon_info = NULL;

    airkiss_lan_ret_t ret = airkiss_lan_recv(pdata, len, &akconf);
    airkiss_lan_ret_t packret;

    switch (ret){
    case AIRKISS_LAN_SSDP_REQ:
        espconn_get_connection_info(&pssdpudpconn, &pcon_info, 0);
        os_printf("remote ip: %d.%d.%d.%d \r\n",pcon_info->remote_ip[0],pcon_info->remote_ip[1],
                                                pcon_info->remote_ip[2],pcon_info->remote_ip[3]);
        os_printf("remote port: %d \r\n",pcon_info->remote_port);

        pssdpudpconn.proto.udp->remote_port = pcon_info->remote_port;
        memcpy(pssdpudpconn.proto.udp->remote_ip,pcon_info->remote_ip,4);
        ssdp_udp.remote_port = DEFAULT_LAN_PORT;

        lan_buf_len = sizeof(lan_buf);
        packret = airkiss_lan_pack(AIRKISS_LAN_SSDP_RESP_CMD,
            DEVICE_TYPE, DEVICE_ID, 0, 0, lan_buf, &lan_buf_len, &akconf);

        if (packret != AIRKISS_LAN_PAKE_READY) {
            os_printf("Pack lan packet error!");
            return;
        }

        os_printf("\r\n\r\n");
        for (i=0; i<lan_buf_len; i++)
            os_printf("%c",lan_buf[i]);
        os_printf("\r\n\r\n");

        packret = espconn_sendto(&pssdpudpconn, lan_buf, lan_buf_len);
        if (packret != 0) {
            os_printf("LAN UDP Send err!");
        }

        break;
    default:
        os_printf("Pack is not ssdq req!%d\r\n",ret);
        break;
    }
}

void ICACHE_FLASH_ATTR
airkiss_start_discover(void)
{
    ssdp_udp.local_port = DEFAULT_LAN_PORT;
    pssdpudpconn.type = ESPCONN_UDP;
    pssdpudpconn.proto.udp = &(ssdp_udp);
    espconn_regist_recvcb(&pssdpudpconn, airkiss_wifilan_recv_callbk);
    espconn_create(&pssdpudpconn);

    os_timer_disarm(&ssdp_time_serv);
    os_timer_setfn(&ssdp_time_serv, (os_timer_func_t *)airkiss_wifilan_time_callback, NULL);
    os_timer_arm(&ssdp_time_serv, 1000, 1);//1s
}


void ICACHE_FLASH_ATTR
smartconfig_done(sc_status status, void *pdata)
{
    switch(status) {
        case SC_STATUS_WAIT:
            printf("SC_STATUS_WAIT\n");
            break;
        case SC_STATUS_FIND_CHANNEL:
            printf("SC_STATUS_FIND_CHANNEL\n");
            break;
        case SC_STATUS_GETTING_SSID_PSWD:
            printf("SC_STATUS_GETTING_SSID_PSWD\n");
            sc_type *type = pdata;
            if (*type == SC_TYPE_ESPTOUCH) {
                printf("SC_TYPE:SC_TYPE_ESPTOUCH\n");
            } else {
                printf("SC_TYPE:SC_TYPE_AIRKISS\n");
            }
            break;
        case SC_STATUS_LINK:
            printf("SC_STATUS_LINK\n");
            struct station_config *sta_conf = pdata;

            wifi_station_set_config(sta_conf);
            wifi_station_disconnect();
            wifi_station_connect();
            break;
        case SC_STATUS_LINK_OVER:
            printf("SC_STATUS_LINK_OVER\n");
            if (pdata != NULL) {
                //SC_TYPE_ESPTOUCH
                uint8 phone_ip[4] = {0};

                memcpy(phone_ip, (uint8*)pdata, 4);
                printf("Phone ip: %d.%d.%d.%d\n",phone_ip[0],phone_ip[1],phone_ip[2],phone_ip[3]);
            } else {
                //SC_TYPE_AIRKISS - support airkiss v2.0
                airkiss_start_discover();
            }
            smartconfig_stop();
            break;
    }
}

void ICACHE_FLASH_ATTR
smartconfig_task(void *pvParameters)
{
    smartconfig_start(smartconfig_done);
    vTaskDelete(NULL);
}

 

 smart_config.h

 

#ifndef APP_INCLUDE_SMART_CONFIG_H_
#define APP_INCLUDE_SMART_CONFIG_H_

void smartconfig_task(void *pvParameters);

#endif /* APP_INCLUDE_SMART_CONFIG_H_ */

 

 

然后主函數

 

 

 

    wifi_station_disconnect();

    wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb);

    wifi_set_opmode(STATION_MODE);
    smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);//SmartConfig  +  AirKiss
    xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);

 

 現在是模塊一啟動就進去配網...

編譯出錯

加上    -lairkiss\

 

下載進去,咱先測試下

 

SmartConfig:

    

 

 下載完WIFI的程序,復位下WIFI

 

                                                                                                                      

      

 

 這個APP是我做的一個面向開發使用的,該APP源碼獲取方式:  https://www.cnblogs.com/yangfengwu/p/11249674.html

 

 

 AirKiss :  關注我的這個測試用的公眾號

復位WIFI模塊

    

 

 

 

 好,現在優化下

按下固件按鈕(GPIO0)大約3S, 讓GPIO2那個燈快閃,進入配網模式,然后60S超時檢測.還有就是不讓WIFI打印官方內部寫的東西(打印的東西太多了...)

 

 

 

 

 

            

 

 

#include "esp_common.h"
#include "gpio.h"
#include "uart.h"
#include "esp_timer.h"
#include "hw_timer.h"
#include "pwm.h"
#include  "data_dispose.h"
#include  "espconn.h"
#include  "esp_wifi.h"
#include "lwip/api.h"

#include "crc.h"
#include "smart_config.h"


LOCAL os_timer_t public_timer;//定時器
u32 public_timer_cnt=0;//累加
u32 public_timer_state=0;//狀態
u32 public_timer_out=0;//超時
u32 public_timer_cnt1=0;//累加


extern u8  Usart1ReadBuff[Usart1ReadLen];//接收數據的數組
extern u32 Usart1ReadCnt;//串口1接收到的數據個數
extern u32 Usart1ReadCntCopy;//串口1接收到的數據個數拷貝
extern u8  Usart1ReadFlage;//串口1接收到一條完整數據


#define  SSID "Learn8266" //無線名稱
#define     PWD "11223344"     //密碼
struct softap_config soft_ap_Config;//AP模式配置


ResolveData ResolveDataTest;//解析數據IEEE754
//uint32 pin_info_list[1][3]={PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5,5};//配置GPIO5作為PWM輸出
//int duty[1]={0};//高電平時間是0us


/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don't know which sector is free in user's application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
*******************************************************************************/
uint32 user_rf_cal_sector_set(void)
{
    flash_size_map size_map = system_get_flash_size_map();
    uint32 rf_cal_sec = 0;

    switch (size_map) {
        case FLASH_SIZE_4M_MAP_256_256:
            rf_cal_sec = 128 - 5;
            break;

        case FLASH_SIZE_8M_MAP_512_512:
            rf_cal_sec = 256 - 5;
            break;

        case FLASH_SIZE_16M_MAP_512_512:
        case FLASH_SIZE_16M_MAP_1024_1024:
            rf_cal_sec = 512 - 5;
            break;

        case FLASH_SIZE_32M_MAP_512_512:
        case FLASH_SIZE_32M_MAP_1024_1024:
            rf_cal_sec = 1024 - 5;
            break;

        default:
            rf_cal_sec = 0;
            break;
    }

    return rf_cal_sec;
}

//串口調用此函數就說明接收到了一條完整的數據,就可以去處理了
void UartReadCallback()//定義一個函數
{

}


static void wifi_event_monitor_handle_event_cb(System_Event_t *evt)
{
  switch (evt->event_id)
  {
    case EVENT_STAMODE_CONNECTED://連接上路由器
        printf("\n\tSTAMODE_CONNECTED\n");

        printf("\tConnected to SSID %s, Channel %d\n",
          evt->event_info.connected.ssid,
          evt->event_info.connected.channel);
      break;

    case EVENT_STAMODE_DISCONNECTED://和路由器斷開
        printf("\n\tSTAMODE_DISCONNECTED\n");

        printf("\tDisconnect from SSID %s, reason %d\n",
          evt->event_info.disconnected.ssid,
          evt->event_info.disconnected.reason);
      break;

    case EVENT_STAMODE_AUTHMODE_CHANGE://這個是 啥..
        printf("\n\tSTAMODE_AUTHMODE_CHANGE\n");

        printf("\tAuthmode: %u -> %u\n",
          evt->event_info.auth_change.old_mode,
          evt->event_info.auth_change.new_mode);
      break;

    case EVENT_STAMODE_GOT_IP://連接上路由器,並獲取了IP
        printf("\n\tGOT_IP\n");

        printf("\tIP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "\n",
          IP2STR(&evt->event_info.got_ip.ip),
          IP2STR(&evt->event_info.got_ip.mask),
          IP2STR(&evt->event_info.got_ip.gw));
      break;

    case EVENT_STAMODE_DHCP_TIMEOUT://連接上路由器,但是路由器給WIFI模塊分配IP等信息超時了
        printf("\n\tSTAMODE_DHCP_TIMEOUT\n");
      break;

    case EVENT_SOFTAPMODE_STACONNECTED://AP模式下,有設備連接WIFI模塊的無線
        printf("\n\tSOFTAPMODE_STACONNECTED\n");

        printf("\tStation: " MACSTR "join, AID = %d\n",
          MAC2STR(evt->event_info.sta_connected.mac),
          evt->event_info.sta_connected.aid);
      break;

    case EVENT_SOFTAPMODE_STADISCONNECTED://AP模式下,有設備斷開和WIFI模塊的無線連接
        printf("\n\tSOFTAPMODE_STADISCONNECTED\n");

        printf("\tstation: " MACSTR "leave, AID = %d\n",
          MAC2STR(evt->event_info.sta_disconnected.mac),
          evt->event_info.sta_disconnected.aid);
      break;

    case EVENT_SOFTAPMODE_PROBEREQRECVED://這是啥??,,,信號強度改變了
        printf("\n\tSOFTAPMODE_PROBEREQRECVED\n");

        printf("Station PROBEREQ: " MACSTR " RSSI = %d\n",
          MAC2STR(evt->event_info.ap_probereqrecved.mac),
          evt->event_info.ap_probereqrecved.rssi);
      break;

    default://其它錯誤
        printf("\n\tswitch/case default\n");
      break;
  }
}

//所有需要定時操作的函數在此函數中執行
LOCAL void ICACHE_FLASH_ATTR
public_timer_callback(void)
{
    if(GPIO_INPUT_GET(0) == 0)//按鍵按下
    {
        public_timer_cnt++;
        if(public_timer_cnt>=300 && public_timer_state==0)//3S
        {
            printf("\nstartsmart\n");
            public_timer_state=1;
            wifi_station_disconnect();
            wifi_set_opmode(STATION_MODE);
            smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS);//SmartConfig  +  AirKiss
            xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
        }
    }
    else
    {
        if(public_timer_state!=1 && public_timer_cnt>0 && public_timer_cnt<300)//短按復位
        {
            printf("\nsystem_restart\n");
            system_restart();//復位
        }
        public_timer_cnt=0;
    }

    switch(public_timer_state)
    {
        case 0:break;
        case 1:
            public_timer_out++;
            public_timer_cnt1++;
            if(public_timer_out>=6000)//60S配網超時
            {
                printf("\nsmartconfig_timeout\n");
                system_restart();//復位
            }
            if(public_timer_cnt1>10)//LED快閃
            {
                public_timer_cnt1=0;
                GPIO_OUTPUT_SET(2, 1-GPIO_INPUT_GET(2));//LED快閃
            }
            break;
        default:break;
    }
}


/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void user_init(void)
{
    GPIO_OUTPUT_SET(5, 1);
    GPIO_OUTPUT_SET(2, 0);
    GPIO_OUTPUT_SET(0, 1);
    uart_init_new();
    printf("SDK version:%s\n", system_get_sdk_version());

    wifi_set_opmode(STATIONAP_MODE);//配置WiFi的模式STATION + AP AP--連接WIFI自身的無線實現通信  STATION--wifi連接路由器,手機或者電腦也連接路由器,實現通信
    soft_ap_Config.ssid_len = strlen(SSID);//熱點名稱長度,與你實際的名稱長度一致就好
    memcpy(soft_ap_Config.ssid,SSID,soft_ap_Config.ssid_len);//實際熱點名稱設置,可以根據你的需要來
    memcpy(soft_ap_Config.password,PWD,strlen(PWD));//熱點密碼設置
    soft_ap_Config.authmode = AUTH_WPA2_PSK;//加密模式
    soft_ap_Config.channel = 1;//信道,共支持1~13個信道
    soft_ap_Config.max_connection = 4;//最大連接數量,最大支持四個,默認四個

    wifi_softap_set_config_current(&soft_ap_Config);//設置 Wi-Fi SoftAP 接口配置,不保存到 Flash
    //    wifi_softap_set_config(&soft_ap_Config);//設置 Wi-Fi SoftAP 接口配置,保存到 Flash
    UartCallbackRegister(UartReadCallback);//把 UartReadCallback 函數地址傳過去,在串口里面調用



    os_timer_disarm(&public_timer);
    os_timer_setfn(&public_timer, (os_timer_func_t *)public_timer_callback, NULL);
    os_timer_arm(&public_timer, 10, 1);//10ms

    wifi_set_event_handler_cb(wifi_event_monitor_handle_event_cb);
}

 

然后還有兩個地方,無論是SmartConfig 還是 Airkiss 配網,配完網以后都重啟下

 

 

 

 

 

 好,測試

按下大約3S,指示燈快閃

 

 軟件就不截圖了,按照上面的步驟操作

SmartConfig 打印的信息

 

 

 

 Airkiss 打印的信息

 

startsmart                ------------------------------------------
state: 5 -> 0 (0)
rm 0
bcn 0
del if1
mode : sta(68:c6:3a:d6:62:54)

    STAMODE_DISCONNECTED
    Disconnect from SSID qqqqq, reason 8
SC version: V2.5.4
scandone
scandone
SC_STATUS_FIND_CHANNEL
TYPE: AIRKISS
T|AP MAC: 34 96 72 16 9e 42
SC_STATUS_GETTING_SSID_PSWD
SC_TYPE:SC_TYPE_AIRKISS                         ------------------------------------------------------
T|pswd : 11223344
T|ssid : qqqqq
SC_STATUS_LINK
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 1
pm open phy_2,type:2 0 0
cnt 

connected with qqqqq, channel 11
dhcp client start...

    STAMODE_CONNECTED
    Connected to SSID qqqqq, Channel 11
ip:192.168.0.100,mask:255.255.255.0,gw:192.168.0.1

    GOT_IP
    IP:192.168.0.100,Mask:255.255.255.0,GW:192.168.0.1
SC_STATUS_LINK_OVER
Finish send notify!

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)                       配網以后重啟

load 0x40100000, len 2408, room 16 
tail 8
chksum 0xe5
load 0x3ffe8000, len 776, room 0 
tail 8
chksum 0x84
load 0x3ffe8310, len 632, room 0 
tail 8
chksum 0xd8
csum 0xd8

2nd boot version : 1.6
  SPI Speed      : 40MHz
  SPI Mode       : DIO
  SPI Flash Size & Map: 32Mbit(512KB+512KB)
jump to run user1 @ 1000

?;?榗専銓#l腸{|$#溿?b|?鞄囙c瀦o飥ng?宭'?弻d寧l$屇d屼?$ ?n?倪銊cdd噞p劅銓bl刢?$s$勩?僩鋼{凔'|?ll$l`?;n?噲噑og済?鋭湝滀青?cc'o?c|?;so搇膁`c們g???sr'n躱?鋵湝??#bgo?#靸;so??l?'???{soo躱?鋵溰?c#gn?#|?;{g搇膁`肧DK version:1.5.0-dev(950076a)
mode : sta(68:c6:3a:d6:62:54) + softAP(6a:c6:3a:d6:62:54)
add if0
dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1)
add if1
bcn 100
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 1
cnt 

connected with qqqqq, channel 11                           自動連接路由器
dhcp client start...

    STAMODE_CONNECTED
    Connected to SSID qqqqq, Channel 11
ip:192.168.0.100,mask:255.255.255.0,gw:192.168.0.1

    GOT_IP
    IP:192.168.0.100,Mask:255.255.255.0,GW:192.168.0.1

 

 

好現在,不讓調試信息通過usart0打印

 

 

 

 這個設置以后  printf就不會通過uart0打印了 ,會用uart1(GPIO2) 打印......

 這個不強求哈!!!大家不修改也可以,我只是不希望讓系統一直打印各種信息,我擔心后面和單片機做通信的時候會出問題!

當然大家也可以直接用  USART_SendData(uint8 uart, uint8 TxChar)  發送數據,我只不過是封裝成可以用printf形式

 

還記得咱前面的某一節咱自己寫的printf不,不過呢,咱直接用lua源碼里面寫的,因為我寫的那個太占內存.....

 

 

 

 

 

 

把這部分代碼放到 uart.c 里面

static void kprintn (void (*)(const char), uint32_t, int, int, char);
static void kdoprnt (void (*)(const char), const char *, va_list);

void dbg_printf(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    kdoprnt(uart0_write_char, fmt, ap);
    va_end(ap);
}

void dbg_vprintf(const char *fmt, va_list ap)
{
    kdoprnt(uart0_write_char, fmt, ap);
}

void kdoprnt(void (*put)(const char), const char *fmt, va_list ap)
{
    register char *p;
    register int ch, n;
    unsigned long ul;
    int lflag, set;
    char zwidth;
    char width;

    for (;;)
    {
        while ((ch = *fmt++) != '%')
        {
            if (ch == '\0')
                return;
            put(ch);
        }
        lflag = 0;
        width = 0;
        zwidth = ' ';

        reswitch:
        switch (ch = *fmt++)
        {
            case '\0':
                /* XXX print the last format character? */
                return;
            case 'l':
                lflag = 1;
                goto reswitch;
            case 'c':
                ch = va_arg(ap, int);
                    put(ch & 0x7f);
                break;
            case 's':
                p = va_arg(ap, char *);
                            if (p == 0) {
                              p = "<null>";
                            }
                while ((ch = *p++))
                    put(ch);
                break;
            case 'd':
                ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
                if ((long)ul < 0) {
                    put('-');
                    ul = -(long)ul;
                }
                kprintn(put, ul, 10, width, zwidth);
                break;
            case 'o':
                ul = lflag ?
                    va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
                kprintn(put, ul, 8, width, zwidth);
                break;
            case 'u':
                ul = lflag ?
                    va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
                kprintn(put, ul, 10, width, zwidth);
                break;
            case 'x':
                ul = lflag ?
                    va_arg(ap, uint32_t) : va_arg(ap, uint32_t);
                kprintn(put, ul, 16, width, zwidth);
                break;
            default:
                if (ch >= '0' && ch <= '9')
                {
                   if (ch == '0' && width == 0 && zwidth == ' ')
                   {
                      zwidth = '0';
                   }
                   else
                   {
                      width = width * 10 + ch - '0';
                   }
                   goto reswitch;
                }
                put('%');
                if (lflag)
                    put('l');
                put(ch);
            }
    }
    va_end(ap);
}

static void kprintn(void (*put)(const char), uint32_t ul, int base, int width, char padchar)
{
        /* hold a long in base 8 */
    char *p, buf[(sizeof(long) * 8 / 3) + 2];

    p = buf;
    do {
        *p++ = "0123456789abcdef"[ul % base];
    } while (ul /= base);

        while (p - buf < width--) {
          put(padchar);
        }

    do {
        put(*--p);
    } while (p > buf);
}

需要修改一個地方

 

 

 

 

 

 

 

然后全部替換為

 

 

就可以實現printf的方式了

 

如果大家嫌麻煩也可以不用復制粘貼那部分

直接用  uart0_write_char()  

 

現在只是模塊一開始啟動的時候打印些自身的信息,后期的都是打印的咱自己寫的

 

 

 

如果大家不希望打印信號強度

 

 

 

 

 

 

可以

 

 

 

 

好了,又完成一節

 

 

 https://www.cnblogs.com/yangfengwu/p/11432795.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM