接入米家(通过米家购买的WIFI模组 串口方式)

一、文档资料

添加链接描述

二、整体流程

  1. 引脚
    在这里插入图片描述
  2. 命令列表(注意\r结尾)

其中,restore 用于重新配置模组,类似于出厂了,出厂后,设备进入ap模式

arch                             
ble_config                       
ble_event                        
ble_fastpair                     
ble_linkage                      
call                             
config_router                    
country_code                     
echo                             
error                            
event                            
event_occured                    
factory                          
get_down                         
getwifi                          
help                             
json_ack                         
json_get_down                    
json_send                        
log                              
mac                              
mcu_version                      
model                            
net                              
properties_changed               
props                            
reboot                           
restore                          
result                           
set_mcu_auto_ota                 
setwifi                          
store                            
time                             
update_me                        
version         
  1. 上电先发送model
  2. 周期性发送get_down
    属性格式如下:uid pid 数据
    注意布尔类型,是 true 和 flse,字符串类型,需要加上 “”
    在这里插入图片描述

设置属性:这里一共有2个属性
第一个是 1 1 ,数值是10
第二个是 1 88 ,数值是 字符串数据

对于下发的数据,必须回复 result
格式:result uid pid 返回码(0为成功)

  ↑ get_down  
  ↓ down set_properties 1 1 10 1 88  "str_value"     
  ↑ result 1 1 0 1 88 -4003

获取属性:
第一个是 1 2
第二个是 1 3

必须回复 result
格式:result uid pid 返回码(0为成功) 数值

    ↑ get_down  
    ↓ down get_properties 1 2 1 3                        
    ↑ result 1 2 0 10 1 3 0 "str_value"

上报属性:

  ↑properties_changed 1 1 10
  ↓ok
  1. 周期性通过 net 查询当前网络状态,也可以通过 get_down返回的mii状态判断、

三、整体测试代码(含串口逻辑)

/**
******************************************************************************
* @file     main.c
* @author   AE team
* @version  V1.1.1
* @date     15/05/2019
* @brief
******************************************************************************
* @copy
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, MindMotion SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2019 MindMotion</center></h2>
*/
#include "HAL_device.h"
#include "HAL_conf.h"
#include "stdio.h"
#include "string.h"

#define LED2_ON()  GPIO_SetBits(GPIOA,GPIO_Pin_2)	// PB4
#define LED2_OFF()  GPIO_ResetBits(GPIOA,GPIO_Pin_2)	// PB4
#define LED2_TOGGLE()  (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2))?(GPIO_ResetBits(GPIOA,GPIO_Pin_2)):(GPIO_SetBits(GPIOA,GPIO_Pin_2))	// PB4

#define LED1_ON()  GPIO_SetBits(GPIOA,GPIO_Pin_1)	// PB5
#define LED1_OFF()  GPIO_ResetBits(GPIOA,GPIO_Pin_1)	// PB5
#define LED1_TOGGLE()  (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1))?(GPIO_ResetBits(GPIOA,GPIO_Pin_1)):(GPIO_SetBits(GPIOA,GPIO_Pin_1))	// PB5


#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)


void LED_Init(void);

void Tim1_UPCount_init(u16 Prescaler, u16 Period);

extern u32 SystemCoreClock;

unsigned int uiCnt = 0;
u8 timeflag = 0;
uint16_t time_cont;
char printBuf[100];

uint16_t uart_cont = 0;
uint8_t  uart_timeout_cont = 0;

#define UART_BUFF_LEN            200                                             //定义最大接收字节数 200
uint8_t uart_buf[UART_BUFF_LEN];

//单位1ms
#define WIFI_MODEL_UPLOAD_TIME  100 //电后 100ms后上报
#define WIFI_INQUIRE_PEROID  100//数据查询周期,要一直获取
#define WIFI_DATA_UPLOAD_PEROID  1000//1秒上报一次数据
#define WIFI_CHECK_PEROID  1000//1秒检测一次wifi状态

#define KEY_SHORT_PRESS_TIME  30 //短按30ms
#define KEY_LONG_PRESS_TIME  2000 //长按两秒

#define MI_MODEL "model 这里填模块名字" //对应项目模块名字

uint8_t net_conn_flag = 0;//是否联网成功
uint16_t wifi_inquire_cont = 0,wifi_model_upload_cont = 1,wifi_check_cont = 0,wifi_data_upload_cont;


uint16_t key1_cont;
uint8_t  key1_state = 0;


/********************************************************************************************************
**函数信息 TIM1_BRK_UP_TRG_COM_IRQHandler(void)
**功能描述 :等待定时器溢出,产生中断
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
        time_cont ++ ;
        
        if(uart_timeout_cont)uart_timeout_cont++;//串口超时计数
        
        wifi_inquire_cont++;//wifi心跳
        wifi_check_cont ++; //检测网络状态
        wifi_data_upload_cont++;//数据上报
        key1_cont ++ ;//按键
        
        if(wifi_model_upload_cont)wifi_model_upload_cont++;//上电后多久上报一次model 只使用一次
        
    }
}
void Tim1_Int_Enable(void)
{
    NVIC_InitTypeDef NVIC_StructInit;
    //config Tim1 interrupt
    NVIC_StructInit.NVIC_IRQChannel = TIM1_BRK_UP_TRG_COM_IRQn;
    NVIC_StructInit.NVIC_IRQChannelPriority = 1;
    NVIC_StructInit.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_StructInit);

    TIM_ClearFlag(TIM1, TIM_FLAG_Update);
    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
}

/********************************************************************************************************
**函数信息 :void Tim1_UPCount_init(u16 Period,u16 Prescaler)
**功能描述 :配置定时器1向上计数模式
**输入参数 :Period 16位计数器重载值,Prescaler 时钟预分频值
**输出参数 :无
********************************************************************************************************/
void Tim1_UPCount_init(u16 Prescaler, u16 Period)
{
    TIM_TimeBaseInitTypeDef TIM_StructInit;

    /*使能TIM1时钟,默认时钟源为PCLK2(PCLK2未分频时不倍频,否则由PCLK2倍频输出),可选其它时钟源*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    TIM_TimeBaseStructInit(&TIM_StructInit);
    TIM_StructInit.TIM_Period = Period;                                         //ARR寄存器值
    TIM_StructInit.TIM_Prescaler = Prescaler;                                   //预分频值
    /*数字滤波器采样频率,不影响定时器时钟*/
    TIM_StructInit.TIM_ClockDivision = TIM_CKD_DIV1;                            //采样分频值
    TIM_StructInit.TIM_CounterMode = TIM_CounterMode_Up;                        //计数模式
    TIM_StructInit.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM1, &TIM_StructInit);
    TIM_ARRPreloadConfig(TIM1, ENABLE);
    Tim1_Int_Enable();
    TIM_Cmd(TIM1, ENABLE);
}


/*******************************************************************************
* @name   : GPIO_Clock_Set
* @brief  : RCC clock set
* @param  : Portx , State
* @retval : void
*******************************************************************************/
void GPIO_Clock_Set(GPIO_TypeDef* GPIOx, FunctionalState NewState)
{

    if(GPIOx == GPIOA) {
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, NewState);                         //GPIO clock starts
    }
    if(GPIOx == GPIOB) {
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, NewState);                         //GPIO clock starts
    }
    if(GPIOx == GPIOC) {
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, NewState);                         //GPIO clock starts
    }
    if(GPIOx == GPIOD) {
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, NewState);                         //GPIO clock starts
    }
}
/********************************************************************************************************
**函数信息 :LED_Init(void)
**功能描述 :LED初始化
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
void LED_Init(void)
{

    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_Clock_Set(GPIOA, ENABLE);  //开启GPIOA时钟
  //  GPIO_Clock_Set(GPIOB, ENABLE);  //开启GPIOB时钟
    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_1|GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    LED1_ON();
    LED2_OFF();
}


void KEY_Init(void)
{

    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_Clock_Set(GPIOA, ENABLE);  //开启GPIOA时钟
  //  GPIO_Clock_Set(GPIOB, ENABLE);  //开启GPIOB时钟
    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_4|GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}





/********************************************************************************************************
**函数信息 :void uart_nvic_init(u32 bound)
**功能描述 :UART端口、中断初始化
**输入参数 :bound
**输出参数 :
**    备注 :
********************************************************************************************************/
void uart_nvic_init(u32 bound)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    UART_InitTypeDef UART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);                       //使能UART1
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);                         //开启GPIOA时钟

    //UART1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = UART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority = 3;                             //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                             //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);                                             //根据指定的参数初始化VIC寄存器

    //UART 初始化设置
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);

    UART_InitStructure.UART_BaudRate = bound;                                   //串口波特率
    UART_InitStructure.UART_WordLength = UART_WordLength_8b;                    //字长为8位数据格式
    UART_InitStructure.UART_StopBits = UART_StopBits_1;                         //一个停止位
    UART_InitStructure.UART_Parity = UART_Parity_No;                            //无奇偶校验位
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;//无硬件数据流控制
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;	                //收发模式

    UART_Init(UART1, &UART_InitStructure);                                      //初始化串口1
    UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);                                //开启串口接受中断
    UART_Cmd(UART1, ENABLE);                                                    //使能串口1

    //UART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                                   //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                             //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                      //初始化GPIOA.9

    //UART1_RX	  GPIOA.10初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                                  //PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                       //浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                      //初始化GPIOA.10
    
    
    

}

/********************************************************************************************************
**函数信息 :void UART1_IRQHandler(void)
**功能描述 :串口1中断服务程序
**输入参数 :
**输出参数 :
**    备注 :
********************************************************************************************************/
void UART1_IRQHandler(void)
{
    u8 Res;
    if(UART_GetITStatus(UART1, UART_IT_RXIEN)  != RESET) {                      //接收中断(接收到的数据必须是0x0d 0x0a结尾)
        UART_ClearITPendingBit(UART1, UART_IT_RXIEN);
        Res = UART_ReceiveData(UART1);	                                       //读取接收到的数据
        
        if(uart_cont < UART_BUFF_LEN)
        uart_buf[uart_cont++] = Res;
        
        uart_timeout_cont = 1;
    }
}

/********************************************************************************************************
**函数信息 :void UartSendByte(u8 dat)
**功能描述 :UART发送数据
**输入参数 :dat
**输出参数 :
**    备注 :
********************************************************************************************************/
void UartSendByte(u8 dat)
{
    UART_SendData(UART1, dat);
    while(!UART_GetFlagStatus(UART1, UART_FLAG_TXEPT));
}

/********************************************************************************************************
**函数信息 :void UartSendGroup(u8* buf,u16 len)
**功能描述 :UART发送数据
**输入参数 :buf,len
**输出参数 :
**    备注 :
********************************************************************************************************/
void UartSendGroup(u8* buf, u16 len)
{
    while(len--)
        UartSendByte(*buf++);
}




/*
上报model ,每次上电先传过去
*/
void mi_model_upload()
{
    uint8_t data[50];
    sprintf((char *)data,"model %s\n",MI_MODEL);
    UartSendGroup(data,strlen((char *)data));
}


/*
数据上报
输入为2个ID和数据,注意ID和C都实用ascii码数字 例如 '1' '2',注意总长度别超过256,这里暂时没限制
*/
void mi_data_upload(uint8_t eid,uint8_t pid , uint8_t *value)
{
    uint8_t data[256];
    sprintf((char *)data,"properties_changed %c %c %s\r",eid,pid,value);
    UartSendGroup(data,strlen((char *)data));
}

/* 周期性获取数据,类似于心跳必须发 建议 100ms */
void mi_inquire()
{
    UartSendGroup((uint8_t *)"get_down\r",strlen((char *)"get_down\r"));
}

/* 每1秒查询一次网络状态具体可以自己来*/
void mi_net()
{
    UartSendGroup((uint8_t *)"net\r",strlen((char *)"nte\r"));
}

/* 重置WIFI  */
void mi_restore()
{
    UartSendGroup((uint8_t *)"restore\r",strlen((char *)"restore\r"));
}
/*
解析串口数据
*/
void mi_data_prase(uint8_t *data)
{
    if(strstr((char *)data,"get_properties"))//平台获取数据 注意这个函数只支持 1-9 的eid和 1-9的pid 因为只是简单实用位置去操作
    {
        //down get_properties 1 2
        //p+20 = eid
        //p+22 = pid

        uint8_t eid,pid;//pid
        uint8_t res_data[50],res_value[30];//回复的串口数据
        memset(res_data,0,sizeof(res_data));//回复的属性数据
        
        memset(res_value,0,sizeof(res_value));
        memcpy(res_value,"1",1);//随便先填一个数据上去
        
        eid = data[20];
        pid = data[22];
        
        
        //针对不同的pid 需要发送特定的数据回去 如果是bool类型需要传 true等等
        switch(eid)//先判断eid
        {
            case '2':
            {
                if(pid == '1')
                {
                    //针对不同的pid 需要发送特定的数据回去 如果是bool类型需要传 true等等
                    
                    strcpy((char *)res_value,"1");
                }
                else if(pid == '6')//2 - 6 
                {
                    strcpy((char *)res_value,"55");
                }
            }
            break;
            case '5':
            {
                if(pid == '5')
                {
                    //针对不同的pid 需要发送特定的数据回去 如果是bool类型需要传 true等等
                    
                    strcpy((char *)res_value,"1300");
                }
            }
            break;
            default:
            {
                
            }
            break;
        }
        
        sprintf((char *)res_data,"result %s 0 %s\r",data+20,res_value);
        UartSendGroup(res_data,strlen((char *)res_data));
        
        //回复OK
        //result 5 3 0 
    }
    else if(strstr((char *)data,"set_properties"))//平台设置数据
    {
        uint8_t eid,pid;
        uint8_t res_data[50];//回复的数据
        
        char *p;
        
        
        eid = data[20];
        pid = data[22];
        
        switch(eid)//先判断eid
        {
            case '2':
            {
                if(pid == '1')
                {
                    //数据位于 data[24] 一直到结尾
                }
                else if(pid == '2')
                {
                    
                }
            }
            break;
            default:
            {
                
            }
            break;
        }
        
        p = strchr(data+22,' ');//找到第二个iid后面的空格
        *p = 0;//空格给 0
        
        sprintf((char *)res_data,"result %s 0\r",data+20);
        UartSendGroup(res_data,strlen((char *)res_data));
        //回复OK
    }
    
    
    
    //offline-连接中(或掉线);
    //local-连上路由器但未连上小米云服务器;
    //updating-固件升级中、uap模式等待连接、unprov-关闭wifi(半小时未快连)。

    else if( 0 == strcmp((char *)data,"offline"))//离线状态
    {
        net_conn_flag = 0;
    }
    else if(0 == strcmp((char *)data,"uap"))//配网状态
    {
        net_conn_flag = 1;
    }
    else if(0 == strcmp((char *)data,"local"))//连接wifi成功,正在连平台
    {
        net_conn_flag = 2;
    }
    else if(0 == strcmp((char *)data,"cloud"))//检测WIFI状态
    {
        net_conn_flag = 3;
        
    }
}


/********************************************************************************************************
**函数信息 :main(void)
**功能描述 :
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
int main(void)
{
    uint8_t upload_data[50];
    
    LED_Init();
    uart_nvic_init(115200);//串口115200 带中断    
    Tim1_UPCount_init(SystemCoreClock / 10000 - 1, 10);//1ms
    
    while(1) 
    {
        /* LED处理 判断网络状态 */

        switch(net_conn_flag)
        {
            case 0:
            {
                LED2_OFF();
            }
            break;
            case 1:
            {
                if(time_cont >= 1000) 
                {
                    LED2_TOGGLE();
                    time_cont = 0;
                }
            }
            break;
            case 2:
            {
                if(time_cont >= 200) 
                {
                    LED2_TOGGLE();
                    time_cont = 0;
                }
            }
            break;
            case 3:
            {
               LED2_ON(); 
            }
            break;
            default:
            {
                
            }
            break;
            
        }
        
        /* 按键处理 */
        
        switch(key1_state)
        {
            case 0:
            {
                if(!KEY1)
                {
                    if(key1_cont >= KEY_LONG_PRESS_TIME)
                    {
                        mi_restore();
                        key1_cont = 0;
                        key1_state = 1;
                    }
                }
                else 
                {
                    key1_cont = 0;
                }
            }
            break;
            case 1://等待松手
            {
                if(KEY1) key1_state = 0;
            }
            break;
            default:
                break;
        }

        
        /* 串口处理 */
        if(uart_timeout_cont >= 3)//串口数据30ms超时
        {
            
            uart_buf[uart_cont-1] = 0;//直接将 \r先干掉
          //  uart_buf[uart_cont] = 0;
            
            mi_data_prase(uart_buf);///>处理收到的wifi数据
            
            uart_cont = 0;
            uart_timeout_cont = 0;
        }
        
        /*wifi处理*/
        if(wifi_model_upload_cont > WIFI_MODEL_UPLOAD_TIME)//上报一次的model,上电后只执行一次
        {
            mi_model_upload();
            wifi_model_upload_cont = 0;
        }
        
        if(wifi_inquire_cont >= WIFI_INQUIRE_PEROID)//数据处理周期 
        {
            mi_inquire();
            wifi_inquire_cont = 0;
        }
        
        if(wifi_check_cont >= WIFI_CHECK_PEROID)//检测WIFI状态
        {
            wifi_check_cont = 0;
            mi_net();
            
        }
        
        if(wifi_data_upload_cont >= WIFI_DATA_UPLOAD_PEROID)
        {
            wifi_data_upload_cont = 0;
            
            /* 
            数据上传测试
            uiCnt++;
            memset(upload_data,0,sizeof(upload_data));
            sprintf(upload_data,"%d",uiCnt);
            mi_data_upload('5','7',upload_data);
            */
            
        }
        
        
       
        
            

        
    }
}
int fputc(int ch, FILE* stream)
{
	//USART_SendData(USART1, (unsigned char) ch);
	//while (!(USART1->SR & USART_FLAG_TXE));
    UART_SendData(UART1, ch);
    while(!UART_GetFlagStatus(UART1, UART_FLAG_TXEPT));
	return ch;
}






/**
* @}
*/

/**
* @}
*/

/**
* @}
*/

/*-------------------------(C) COPYRIGHT 2019 MindMotion ----------------------*/



版权声明:本文为xuan530482366原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。