【STM32移植机智云】超详细教程#2‘代码移植’

  • 准备材料
    1.ESP8266模块

外观:

在这里插入图片描述
引脚图:
在这里插入图片描述

2.单片机及杜邦线等
本文以STM32f013c8t6开发平台为例。

本文接线说明:
esp8266

ESP8266引脚 接口
VCC、EN VCC3.3V
GND GND
UTXD RXD(即USART3_RX PB11)
URXD TXD(即USART3_TX PB10)
IO0及其它引脚 悬空

其他外设接线:

外设 引脚
按键 PA0
LED0 PA8
串口1 PA9,PA10

参考代码工程下载:
方式一:代码工程打包下载
财力雄厚,麻烦支持一下。感谢。
方式二:见评论区置顶的那条。(括号是防止和谐,若失效了,评论或私聊)

欢迎交流讨论,评论提问,我都会回复。

开始移植详细步骤

  1. ESP8266烧录机智云固件
    教程参见:烧录机智云固件详细教程
    烧录程序工具包下载:烧录固件工具包下载
  2. 登录机智云,在开发者中心新建项目。
    在这里插入图片描述
  3. 新建数据点
    在这里插入图片描述

如想控制LED亮灭。
在这里插入图片描述
在这里插入图片描述
4.下载移植代码包。

复制秘钥,因为下载需要填写。
在这里插入图片描述

如下图生成代码包。
在这里插入图片描述
下载代码包:
在这里插入图片描述
下载后解压,将下图俩个复制到自己的工程。
在这里插入图片描述
5.导入代码包到STM32工程。
在这里插入图片描述
记得包含头文件位置。
在这里插入图片描述
在这里插入图片描述
注意:路径地址因人而异。

6.配置单片机基础外设。
(1)串口

  • 串口1(用于printf打印调试信息)
    感谢用户_tony_jia的反馈,让我更加完善博客的分享。
    uart.c的代码如下:
#include "sys.h"
#include "usart.h"	  
// 	 
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif
//	   
//此段代码参考自正点原子@ALIENTEK
// 	  

//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

/*使用microLib的方法*/
 /* 
int fputc(int ch, FILE *f)
{
	USART_SendData(USART1, (uint8_t) ch);

	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}	
   
    return ch;
}
int GetKey (void)  { 

    while (!(USART1->SR & USART_FLAG_RXNE));

    return ((int)(USART1->DR & 0x1FF));
}
*/
 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void uart_init(u32 bound){
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_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
   
  //USART1_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  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级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(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成
			{
			if(USART_RX_STA&0x4000)//接收到了0x0d
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 
#endif	

uart.h代码:

#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 

#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 			1		//使能(1)/禁止(0)串口1接收
	  	
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;         		//接收状态标记	
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif

  • 串口3(用于和esp模块通信)
    本文中,将esp模块连接在串口3,故需要配置串口3。
    初始化串口3参考代码:

//初始化IO 串口3
//与ESP8266模块通信波特率:9600
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率	  
void usart3_init(u32 bound)
{  

	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能

 	USART_DeInit(USART3);  //复位串口3
		 //USART3_TX   PB10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
   
    //USART3_RX	  PB11
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化 PB11
	
	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(USART3, &USART_InitStructure); //初始化串口3
  

	USART_Cmd(USART3, ENABLE);                    //使能串口 
	
	//使能接收中断
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
	
	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
	USART3_RX_STA=0;		//清零

}

(2)定时器
定时器用于和给esp模块提供基准时钟。
本文采用定时3,需要配置1ms的定时。
参考代码:


// 定时器3,定时1ms
void TIMER3_Init()
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
    
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
    
	//初始化
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    // 72MHz
	TIM_TimeBaseInitStruct.TIM_Period=10-1;
	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	TIM_ClearFlag(TIM3, TIM_IT_Update);
	
	TIM_ITConfig(TIM3, TIM_IT_Update,ENABLE);

	
	NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
	NVIC_Init(&NVIC_InitStruct);

	
	TIM_Cmd(TIM3,ENABLE);
}

(3)按键
用户机智云配网,被设计采用外部中断方式实现。
按键PA0,当按下时,接地。故配置上拉、下降沿。
参考代码:

   //外部中断0服务程序
void KEY_EXTIX_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
 	EXTI_InitTypeDef EXTI_InitStructure;
 	NVIC_InitTypeDef NVIC_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能

	//初始化 WK_UP-->GPIOA.0	  上拉输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PA0设置成上拉输入
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0

  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟


   //GPIOA.0	  中断线以及中断初始化配置 下升沿触发 PA0  WK_UP
 	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 

  	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//选择外部中断而不是外部事件
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿产生中断
	
  	EXTI_Init(&EXTI_InitStructure);		//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


  	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//使能按键WK_UP所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;	//抢占优先级0, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级0
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 


  	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
}

7.调用机智云接口。
注:以下步骤,执行一步就编译一下。
若现在找不到XX函数,则包含对应的头文件或者声明函数。
注意要清除所有的警告。
(1)机智云读取串口3数据
接口函数:gizPutData(&value, 1)
参考调用代码:

void USART3_IRQHandler(void)
{
	u8 value = 0;	    
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
	{	 
	
		value = USART_ReceiveData(USART3);	//读取接收到的数据
		gizPutData(&value, 1);
       // USART_SendData(USART3,value);
    }	 											 
}   

(2)机智云发送数据
补充完整接口函数:int32_t uartWrite(uint8_t *buf, uint32_t len)
位置:gizwits_product.c
在这里插入图片描述
让其调用串口3的发送。
补充后参考代码:

int32_t uartWrite(uint8_t *buf, uint32_t len)
{
    uint32_t i = 0;
    
    if(NULL == buf)
    {
        return -1;
    }
    
    #ifdef PROTOCOL_DEBUG
    GIZWITS_LOG("MCU2WiFi[%4d:%4d]: ", gizGetTimerCount(), len);
    for(i=0; i<len; i++)
    {
        GIZWITS_LOG("%02x ", buf[i]);
    }
    GIZWITS_LOG("\n");
    #endif

    for(i=0; i<len; i++)
    {
        //USART_SendData(UART, buf[i]);//STM32 test demo
        //Serial port to achieve the function, the buf[i] sent to the module
        USART_SendData(USART3, buf[i]);
        while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
        if(i >=2 && buf[i] == 0xFF)
        {
          //Serial port to achieve the function, the 0x55 sent to the module
          //USART_SendData(UART, 0x55);//STM32 test demo
             USART_SendData(USART3, 0x55);
            while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
        }
    }

    return len;
}

(3)机智云系统时间。
在前面配置的定时器3(注意是:1ms定时),
中断服务函数中调用接口gizTimerMs()
参考代码:

void TIM3_IRQHandler()
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update))
	{
		
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        
        gizTimerMs();
	}
}

(4)实现系统复位
补充接口:mcuRestart
实现系统复位功能。
位置:如图
在这里插入图片描述

参考代码:

/**
* @brief mcuRestart

* MCU Reset function

* @param none
* @return none
*/
void mcuRestart(void)
{
    __set_FAULTMASK(1);
    NVIC_SystemReset();
}

(5)实现配置入网
支持 SoftAp 和 AirLink 两种方式配置入网,相应接口为 gizwitsSetMode()
AirLink 更方便,本设计采用外部中断按键调用的方式。
参考代码:

//外部中断0服务程序 
void EXTI0_IRQHandler(void)
{
	delay_ms(10);//消抖
    if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==0)	 	 //下降沿触发
    {	   
        gizwitsSetMode(WIFI_AIRLINK_MODE);
        printf("\r\nWIFI_AIRLINK_MODE\r\n") ; // 打印调试信息
    }

	EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE0上的中断标志位  
}
 

至此,stm32已经可以联网了。

8.数据下行
本文以控制LED0点亮、熄灭为例。
在下图位置添加控制代码。
在这里插入图片描述
参考代码:

int8_t gizwitsEventProcess(eventInfo_t *info, uint8_t *gizdata, uint32_t len)
{
  uint8_t i = 0;
  dataPoint_t *dataPointPtr = (dataPoint_t *)gizdata;
  moduleStatusInfo_t *wifiData = (moduleStatusInfo_t *)gizdata;
  protocolTime_t *ptime = (protocolTime_t *)gizdata;
  
#if MODULE_TYPE
  gprsInfo_t *gprsInfoData = (gprsInfo_t *)gizdata;
#else
  moduleInfo_t *ptModuleInfo = (moduleInfo_t *)gizdata;
#endif

  if((NULL == info) || (NULL == gizdata))
  {
    return -1;
  }

  for(i=0; i<info->num; i++)
  {
    switch(info->event[i])
    {
      case EVENT_LED:
        currentDataPoint.valueLED = dataPointPtr->valueLED;
        GIZWITS_LOG("Evt: EVENT_LED %d \n", currentDataPoint.valueLED);
        if(0x01 == currentDataPoint.valueLED)
        {
          //user handle
            LED0 = 0;// 低电平点亮
        }
        else
        {
          //user handle   
          LED0 = 1;  // 高电平熄灭          
        }
        break;




      case WIFI_SOFTAP:
        break;
      case WIFI_AIRLINK:
        break;
      case WIFI_STATION:
        break;
      case WIFI_CON_ROUTER:
 
        break;
      case WIFI_DISCON_ROUTER:
 
        break;
      case WIFI_CON_M2M:
 
        break;
      case WIFI_DISCON_M2M:
        break;
      case WIFI_RSSI:
        GIZWITS_LOG("RSSI %d\n", wifiData->rssi);
        break;
      case TRANSPARENT_DATA:
        GIZWITS_LOG("TRANSPARENT_DATA \n");
        //user handle , Fetch data from [data] , size is [len]
        break;
      case WIFI_NTP:
        GIZWITS_LOG("WIFI_NTP : [%d-%d-%d %02d:%02d:%02d][%d] \n",ptime->year,ptime->month,ptime->day,ptime->hour,ptime->minute,ptime->second,ptime->ntp);
        break;
      case MODULE_INFO:
            GIZWITS_LOG("MODULE INFO ...\n");
      #if MODULE_TYPE
            GIZWITS_LOG("GPRS MODULE ...\n");
            //Format By gprsInfo_t
      #else
            GIZWITS_LOG("WIF MODULE ...\n");
            //Format By moduleInfo_t
            GIZWITS_LOG("moduleType : [%d] \n",ptModuleInfo->moduleType);
      #endif
    break;
      default:
        break;
    }
  }

  return 0;
}

9.数据上行
函数接口:void userHandle(void)
添加方法如图:
在这里插入图片描述

本教程没有建立上行数据点。故没有代码。

10.主函数代码
参考代码:
注意波特率为9600

//机智云初始化
void MyGizwistInit(void)
{
	 
	TIMER3_Init();//1ms
	usart3_init(9600);//gizPutData((uint8_t *)&aRxBuffer,1);
	userInit();//用户信息初始化,目前只是把结构体信息复位
	gizwitsInit();//机智云的初始化
	printf("gizwitsInit智能云初始化\r\n");
	
}
// 主函数
int main(void)
{	

	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//1设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
  
	uart_init(115200);      // 串口1初始化
    LED_Init();             // 初始化LED
    KEY_EXTIX_Init();     // 初始化KEY

    MyGizwistInit();
	while(1) 
	{	
        userHandle();//数据上行
        gizwitsHandle((dataPoint_t *)&currentDataPoint);
	}
	  
}     

结果测试:

烧录程序,连接串口,打开调试助手。
手机端操作:
在这里插入图片描述
单片机按下,按键进入配网。
串口打印调试信息如下。
在这里插入图片描述
手机界面会出现设备。
点击连接"test"。
在这里插入图片描述
在这里插入图片描述
点击开启,即可以点亮LED了。
看到这里,恭喜大家成功联网控制。
谢谢大家的阅读。
有问题欢迎评论交流。

若有帮助,求赞求收藏

常见问题分析

串口错误:
在这里插入图片描述
原因:
1.串口波特率错误,esp通信波特率9600.
2.串口配置引脚错误。rx与tx要反接,引脚、端口不要写错。
其他情况:
3.定时器计算错误,定时器应该为1ms。
4.按键配置出错,配置打印调试,确保按键有效。
5.玄学问题–接触不良,或者接错线,,,,,
6.使用问题,比如gizwitsHandle()要多调用,上面的代码是放在了主循环。注释了这个函数可能直接导致联网失败。。。
7.编译警告。某些警告会导致移植失败,建议规范编程,清除掉所有警告。。。

版权声明:本文为CSDN博主「老子姓李!」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44078824/article/details/116656988

生成海报
点赞 0

老子姓李!

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐