zoukankan      html  css  js  c++  java
  • 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!
    ");
    }
    
    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 
    ",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 
    ",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("
    
    ");
            for (i=0; i<lan_buf_len; i++)
                os_printf("%c",lan_buf[i]);
            os_printf("
    
    ");
    
            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
    ",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
    ");
                break;
            case SC_STATUS_FIND_CHANNEL:
                printf("SC_STATUS_FIND_CHANNEL
    ");
                break;
            case SC_STATUS_GETTING_SSID_PSWD:
                printf("SC_STATUS_GETTING_SSID_PSWD
    ");
                sc_type *type = pdata;
                if (*type == SC_TYPE_ESPTOUCH) {
                    printf("SC_TYPE:SC_TYPE_ESPTOUCH
    ");
                } else {
                    printf("SC_TYPE:SC_TYPE_AIRKISS
    ");
                }
                break;
            case SC_STATUS_LINK:
                printf("SC_STATUS_LINK
    ");
                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
    ");
                if (pdata != NULL) {
                    //SC_TYPE_ESPTOUCH
                    uint8 phone_ip[4] = {0};
    
                    memcpy(phone_ip, (uint8*)pdata, 4);
                    printf("Phone ip: %d.%d.%d.%d
    ",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("
    	STAMODE_CONNECTED
    ");
    
            printf("	Connected to SSID %s, Channel %d
    ",
              evt->event_info.connected.ssid,
              evt->event_info.connected.channel);
          break;
    
        case EVENT_STAMODE_DISCONNECTED://和路由器断开
            printf("
    	STAMODE_DISCONNECTED
    ");
    
            printf("	Disconnect from SSID %s, reason %d
    ",
              evt->event_info.disconnected.ssid,
              evt->event_info.disconnected.reason);
          break;
    
        case EVENT_STAMODE_AUTHMODE_CHANGE://这个是 啥..
            printf("
    	STAMODE_AUTHMODE_CHANGE
    ");
    
            printf("	Authmode: %u -> %u
    ",
              evt->event_info.auth_change.old_mode,
              evt->event_info.auth_change.new_mode);
          break;
    
        case EVENT_STAMODE_GOT_IP://连接上路由器,并获取了IP
            printf("
    	GOT_IP
    ");
    
            printf("	IP:" IPSTR ",Mask:" IPSTR ",GW:" IPSTR "
    ",
              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("
    	STAMODE_DHCP_TIMEOUT
    ");
          break;
    
        case EVENT_SOFTAPMODE_STACONNECTED://AP模式下,有设备连接WIFI模块的无线
            printf("
    	SOFTAPMODE_STACONNECTED
    ");
    
            printf("	Station: " MACSTR "join, AID = %d
    ",
              MAC2STR(evt->event_info.sta_connected.mac),
              evt->event_info.sta_connected.aid);
          break;
    
        case EVENT_SOFTAPMODE_STADISCONNECTED://AP模式下,有设备断开和WIFI模块的无线连接
            printf("
    	SOFTAPMODE_STADISCONNECTED
    ");
    
            printf("	station: " MACSTR "leave, AID = %d
    ",
              MAC2STR(evt->event_info.sta_disconnected.mac),
              evt->event_info.sta_disconnected.aid);
          break;
    
        case EVENT_SOFTAPMODE_PROBEREQRECVED://这是啥??,,,信号强度改变了
            printf("
    	SOFTAPMODE_PROBEREQRECVED
    ");
    
            printf("Station PROBEREQ: " MACSTR " RSSI = %d
    ",
              MAC2STR(evt->event_info.ap_probereqrecved.mac),
              evt->event_info.ap_probereqrecved.rssi);
          break;
    
        default://其它错误
            printf("
    	switch/case default
    ");
          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("
    startsmart
    ");
                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("
    system_restart
    ");
                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("
    smartconfig_timeout
    ");
                    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
    ", 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 == '')
                    return;
                put(ch);
            }
            lflag = 0;
            width = 0;
            zwidth = ' ';
    
            reswitch:
            switch (ch = *fmt++)
            {
                case '':
                    /* 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

  • 相关阅读:
    程序员书单
    36条极简人生建议
    Nacos
    jvm详解
    22种世界500强都在用的高效工作方法,你了解几种?
    道德经39经典
    积累的力量
    JUC之线程间定制化通信
    JVM调优参考
    docker开机启动和dockercompose开机启动执行相应的各个docker容器
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/11429007.html
Copyright © 2011-2022 走看看