ESP8266模块
ESP8266模块简介
-
ESP8266是一款超低功耗的UART-WiFi 透传模块,拥有业内极富竞争力的封装尺寸和超低能耗技术,专为移动设备和物联网应用设计,可将用户的物理设备连接到Wi-Fi 无线网络上,进行互联网或局域网通信,实现联网功能。
-
支持无线802.11 b/g/n 标准
-
支持STA/AP/STA+AP三种工作模式
-
内置TCP/IP协议栈,支持多路TCP Client连接
-
支持丰富的Socket AT指令
-
支持UART/GPIO数据通信接口
-
支持Smart Link 智能联网功能
-
支持远程固件升级(OTA)
-
内置32位MCU, 可兼作应用处理器
-
超低能耗,适合电池供电应用
-
3.3V 单电源供电
引脚介绍
ESP8266硬件接口丰富,可支持UART,IIC,PWM,GPIO,ADC等,适用于各种物联网应用场合
主要功能和工作模式
主要功能
-
ESP8266可以实现的主要功能包括:串口透传,PWM 调控,GPIO控制。
-
串口透传:数据传输,传输的可靠性好,最大的传输速率为:460800bps。
-
PWM 调控:灯光调节,三色LED 调节,电机调速等。
-
GPIO控制:控制开关,继电器等。
工作模式
- ESP8266模块支持STA/AP/STA+AP 三种工作模式。
- STA 模式:ESP8266模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制。
- AP 模式:ESP8266模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。
- STA+AP 模式:两种模式的共存模式,即可以通过互联网控制可实现无缝切换,方便操作。
调试模块
硬件接线
ESP8266WIFI模块 | USB转TTL模块 | 面包板 |
---|---|---|
TX | RX | None |
RX | TX | None |
GND | GND | GND |
EN | None | VCC |
3V3 | None | VCC |
IO0 | None | VCC |
IO2 | None | VCC |
RST | None | VCC |
注意: 面板板处于通电状态
发送AT+RST指令
接好线后,将USB转TTL模块接入电脑打开串口助手,发送AT+RST指令
- 串口接收到模块返回的信息,调试完成
参考资料
本小节参考:
ESP8266新手入门调试指导(ESP-01).pdf
ESP8266-01 WiFi模块用户手册V1.0
机智云平台
简介
文档中心
开发的一些教程和资料
开发者中心
创建产品、APP和自动生成代码服务
基于机智云平台的物联网开发
开发流程:
- 在平台开发者界面创建产品和小程序
- 将GAgent固件烧入WIFI模组中
- 平台自动生成MCU方案代码
- 将自动生成的代码移植到ST标准库(主要完成硬件功能设计、WIFI模块与MCU的通信)
- 下面是开发时比较重要的一些概念
GAgent
-
官方提供的固件,可将其烧录进ESP8266WIFI模组;烧录后,模组原来的AT指令集失去作用,模组能够接入机智云平台,并自动完成模组与平台间的数据交换
-
GAgent配网方式
- airlink
- softap
MCU与WIFI模块的通信
ESP8266用UART通信,并有应答机制;MCU与WIFI模块的通讯可以用MCU自带的USART(支持UART)资源
参考资料
本小节参考:
平台概述 - Gizwits
机智云名词定义解释 - Gizwits
【机智云带你一节课入门物联网APP开发】
实操01: GAgent固件的烧写(ESP8266)
烧录的方法有两种,一是用烧录器烧录,而是用USB转TTL模块烧录,由于我没有烧录器,就只介绍用USB转TTL烧录的方式
1.下载GAgent固件包
下载好的固件包的内容,根据参数选择烧录的固件包
- 下载安可信ESP8266资料
安信可ESP8266系列接入机智云方案及问题排查指引 - Gizwits
- 硬件接线(ESP-01s为例)(因为我买的是这款)
接线:
ESP-01s | USB转TTL | 面包板 |
---|---|---|
RX | TX | None |
TX | RX | None |
3V3 | VCC | None |
IO0 | None | GND |
GND | GND | GND |
- 打开 第2步 ESP8266资料中的烧录软件
一直点进去直到找到.exe文件
打开后是这样的
查看芯片参数(之前调试的时候有)
参数配置
点击start
完成
参考资料
本小节参考资料:
(1条消息) 个人项目——STM32接入机智云教程_at指令能连机智云吗_唯恋殊雨的博客-CSDN博客
【ESP8266固件烧录详解】
安信可ESP8266系列接入机智云方案及问题排查指引 - Gizwits
说明: 若问题无法解决 ESP01或ESP01-s系列接线可参考B站大佬的视频,烧录的步骤可参考官网文档和另一个大佬写的博客
注意: 烧写失败有可能是线接触不良(Combine包比较大),有时候需重试几次才能烧录成功!!!
实操02: 检查GAgent固件是否烧录成功
- 进入机智云平台随便新建一个产品
随便加个数据点(不然调试助手会检测不到产品)
- 可以看到左上角有PK和PS
- 下载机智云的串口调试助手
- 打开串口调试助手
- 将EPS8266模块与usb-TTL连接
ESP-01s | USB转TTL | 面包板 |
---|---|---|
RX | TX | None |
TX | RX | None |
3V3 | VCC | None |
IO0 | None | VCC |
GND | GND | GND |
ESP其他引脚都接VCC(手册上说悬空也行,但有的芯片必须得全接好才能正常工作!!!)
- 进入模拟MCU、选择串口、SoftAP
- 点击SoftAp后,串口向模块发送进入SoftAP模式的信息,模块收到后会进行应答
- 若能接收到模块的信息则说明GAgent烧录成功
- 打开手机WIFI界面可以看到XPG-GAgent开头的WIFI
实操03: 创建产品
参考资料
本小节参考:
【机智云带你一节课入门物联网APP开发】
更多细节参考官方视频
实操04: 虚拟设备
- 下载中心下载机智云APP
- 开发者中心->虚拟设备->打开APP扫码绑定设备
- APP上改变舵机角度,云端数据发生相应变化
机智云虚拟设备
参考资料
本小节参考:
【机智云带你一节课入门物联网APP开发】
更多细节参考官方视频
实操05: MCU自动代码生成+代码移植到标准库(*)
1. 自动生成代码服务
下载代码即可
2. 自动生成代码说明
-
两个重要的包
自动生成代码中,Gizwits和Utils是我们需要的(一个建立起与机智云的通讯,一个是工具包)
-
打开MDK-ARM文件夹,打开keil工程文件
-
可以看到,自动生成的代码是基于Hal库的,我们需要实现自己的功能,并将其移植到标准库中
-
打开Gizwits中的gizwits_product.c
-
机智云服务用到的三个外设
可以看到,需要用一个定时器(Timer)和两个串口(USART)
说明:
-
定时器也可以用TIM1、TIM3,同理串口也不一定要用USART1和USART2
-
USART1用于打印调试信息,这一部分功能可以删去,但相应要修改一些代码
关于USART1:
在gizwits_product.c大概两百多行的位置,重写了fputc函数
然后再utils/common.h文件中可以看到GIZWITS_LOG(日志函数)就是printf
在自动生成的代码中,很多调试信息的打印都调用了GIZWITS_LOG
当完成USART1的初始化并重写fputc函数后, 将USART1的端口与usb转TTL模块连接后接入电脑,借助串口助手可以打印调试信息到串口助手
重写的方式如上(本质上就是用USART1发送数据)
6. 主要文件和接口
文件 | 说明 |
---|---|
Gizwits_product.c | 该文件为产品相关处理函数,如gizEventProcess()平台相关硬件初始化,如串口、定时器等。 |
Gizwits_product.h | 该文件为gizwits_product.c的头文件,存放产品相关宏定义如:HARDWARE_VERSION、SOFTWARE_VERSION |
Gizwits_protocol.c | 该文件为SDK API接口函数定义文件 |
Gizwits_protocol.h | 该文件为gizwits_protocol.c对应头文件,相关API的接口声明均在此文件中。 |
API名称 | API功能 |
---|---|
Void gizwitsInit(void) | gizwits 协议初始化接口。用户调用该接口可以完成 Gizwits 协议相关初始化(包括协议相关定时器、串口的初始化)。 |
Void gizwitsSetMode(unit8_t mode) | 参数mode[in]:仅支持0,1和2,其他数据无效。参数为 0,恢复模组出厂配置接口,调用会清空所有配置参数,恢复到出厂默认配置; 参数为 1 时配置模组进入 SoftAp 模式; 参数为 2 配置模组进入 AirLink 模式。 |
Void gizwitsHandle(dataPoint_t *dataPoint) | 参数 dataPoint[in]:用户设备数据点。该函数中完成了相应协议数据的处理即数据上报的等相关操作。 |
Int8_t gizwitsEventProcess(eventInfo_t *info,uint8_t *data,uint32_t len) | 参数 info[in]:事件队列参数 ; data[in]:数据; 参数 len [in]:数据长度。用户数据处理函数,包括 wifi 状态更新事件和控制事件。a) Wifi 状态更新事件WIFI_开头的事件为 wifi 状态更新事件,data 参数仅在WIFI_RSSI 有效,data 值为 RSSI 值,数据类型为 uint8_t,取值范围 0~7。 b) 控制事件与数据点相关,本版本代码会打印相关事件信息,相关数值也一并打印输出,用户只需要做命令的具体执行即可。 |
可参考官方文档: 独立MCU方案接入机智云 - Gizwits
3. 代码移植 (需要根据需求进行修改)
串口通信(Serial.c)
#include "stm32f10x.h"
#include "Server.h"
#include "gizwits_protocol.h"
/*
* WIFI模块通信初始化 USART2
*/
void Serial_WIFI_Init(uint32_t BoundRate)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIO
// Tx
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Rx
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate=BoundRate;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_InitStructure.USART_Parity=USART_Parity_No; // 无奇偶校验
USART_InitStructure.USART_StopBits=USART_StopBits_1; // 一位停止位
USART_InitStructure.USART_WordLength=USART_WordLength_8b; // 传输字长
USART_Init(USART2, &USART_InitStructure);
// 打开USART中断
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 打开接收寄存器非空中断
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; // 响应优先级
NVIC_Init(&NVIC_InitStructure);
// 启动USART
USART_Cmd(USART2, ENABLE);
}
void USART2_IRQHandler(void)
{
uint8_t Data=0;
if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET)
{
Data = USART_ReceiveData(USART2);
gizPutData(&Data, 1); // 解析数据
}
}
/*
* 调试端口USART1
*/
void Serial_DebugInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//TX PA9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//RX PA10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//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);
//USART 初始化设置
USART_InitStructure.USART_BaudRate = 9600;//串口波特率
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);
}
void USART1_IRQHandler(void)
{
}
Timer.c
#include "stm32f10x.h"
#include "Serial.h"
#include "gizwits_product.h"
// TIM3
void Timer_TIM3Init(uint16_t PSC, uint16_t CNT)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_InternalClockConfig(TIM3);
// TimeBase
TIM_TimeBaseInitTypeDef TimerBaseInitStructure;
TimerBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TimerBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TimerBaseInitStructure.TIM_Period=CNT;
TimerBaseInitStructure.TIM_Prescaler=PSC;
TimerBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1, &TimerBaseInitStructure);
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
// 使能更新中断
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3; // 响应优先级
NVIC_Init(&NVIC_InitStructure);
// 开启TIM
TIM_Cmd(TIM1, ENABLE);
}
/*
* TIM3 中断函数
*/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update))
{
gizTimerMs(); // 机智云计数
// 清除标志位
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
Key.c (用于配置模式)
#include "stm32f10x.h"
#include "delay.h"
#include "Server.h"
#include "gizwits_protocol.h"
// PA1作为按键输入
// 2023年4月18日16:32:06
/*
* 按键初始化函数 下降沿触发 配置为上拉输入
*/
void Key_Init(void)
{
// RCC 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); // PA1
// 配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; // 下降沿触发
EXTI_Init(&EXTI_InitStructure);
// 配置NVIC分组 只需配置一次
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; // 响应优先级
NVIC_Init(&NVIC_InitStructure);
}
/*
* EXTI 中断函数
*/
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1))
{
// 消抖
Delay_ms(40);
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)==0)
{
Serve_Angle += 30;
}
while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)==0);
if(Serve_Angle>180)
{
Serve_Angle = 0;
}
Server_SetAngle((float)Serve_Angle);
// 清除标志位
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
// 机智云模式配置按钮 AirLink SoftAP Reset 三种模式
void Key_WIFIModeInit(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
// PB10 按下低电平 配置成上拉输入
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// PB12 PB13 按下高电平 配置成下拉输入
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_14;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource10);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
// EXTI
// PB1 下降沿触发
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line10;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
// PB12 PB14 上升沿触发
EXTI_InitStructure.EXTI_Line=EXTI_Line12|EXTI_Line14;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
// NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; // 响应优先级
NVIC_Init(&NVIC_InitStructure);
}
/*
* EXTI通道10-15中断函数 PB10 PB12 PB14 分别对应WIFI模块工作的三种模式
*/
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line10))
{
// 消抖
Delay_ms(40);
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)==0)
{
gizwitsSetMode(WIFI_AIRLINK_MODE);
GIZWITS_LOG("AirLink mode\r\n");
}
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)==0);
// clear
EXTI_ClearITPendingBit(EXTI_Line10);
}
else if(EXTI_GetITStatus(EXTI_Line12))
{
// 消抖
Delay_ms(40);
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)==1)
{
gizwitsSetMode(WIFI_SOFTAP_MODE);
GIZWITS_LOG("Soft AP mode\r\n");
}
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)==1);
// clear
EXTI_ClearITPendingBit(EXTI_Line12);
}
else if(EXTI_GetITStatus(EXTI_Line14))
{
// 消抖
Delay_ms(40);
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14)==1)
{
gizwitsSetMode(WIFI_RESET_MODE);
GIZWITS_LOG("Reset mode\r\n");
}
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14)==1);
// clear
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
gizwits_product.c (注释掉Hal库的内容, 替换成ST库,完成User Handle部分内容)
/**
************************************************************
* @file gizwits_product.c
* @brief Gizwits control protocol processing, and platform-related hardware initialization
* @author Gizwits
* @date 2017-07-19
* @version V03030000
* @copyright Gizwits
*
* @note 机智云.只为智能硬件而生
* Gizwits Smart Cloud for Smart Products
* 链接|增值ֵ|开放|中立|安全|自有|自由|生态
* www.gizwits.com
*
***********************************************************/
#include <stdio.h>
#include <string.h>
// #include "hal_key.h"
#include "gizwits_product.h"
#include "common.h"
#include "LED.h"
#include "Server.h"
#include "AD.h"
static uint32_t timerMsCount;
//static uint32_t timerMsCount;
uint8_t aRxBuffer;
/** User area the current device state structure*/
dataPoint_t currentDataPoint;
//extern TIM_HandleTypeDef htim2;
//extern UART_HandleTypeDef huart1;
//extern UART_HandleTypeDef huart2;
/**@} */
/**@name Gizwits User Interface
* @{
*/
/**
* @brief Event handling interface
* Description:
* 1. Users can customize the changes in WiFi module status
* 2. Users can add data points in the function of event processing logic, such as calling the relevant hardware peripherals operating interface
* @param [in] info: event queue
* @param [in] data: protocol data
* @param [in] len: protocol data length
* @return NULL
* @ref gizwits_protocol.h
*/
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_Angle:
currentDataPoint.valueAngle = dataPointPtr->valueAngle;
GIZWITS_LOG("Evt:EVENT_Angle %4f\n",currentDataPoint.valueAngle);
//user handle
Serve_Angle=currentDataPoint.valueAngle;
Server_SetAngle(currentDataPoint.valueAngle); // 设置电机角度
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
GIZWITS_LOG("moduleType : [%d] \n",gprsInfoData->Type);
#else
GIZWITS_LOG("WIF MODULE ...\n");
//Format By moduleInfo_t
GIZWITS_LOG("moduleType : [%d] \n",ptModuleInfo->moduleType);
#endif
break;
default:
break;
}
}
return 0;
}
/**
* User data acquisition
* Here users need to achieve in addition to data points other than the collection of data collection, can be self-defined acquisition frequency and design data filtering algorithm
* @param none
* @return none
*/
void userHandle(void)
{
currentDataPoint.valueLED = LED_Info();//Add Sensor Data Collection
currentDataPoint.valueAD_Voltage = AD_Voltage;//Add Sensor Data Collection
}
/**
* Data point initialization function
* In the function to complete the initial user-related data
* @param none
* @return none
* @note The developer can add a data point state initialization value within this function
*/
void userInit(void)
{
memset((uint8_t*)¤tDataPoint, 0, sizeof(dataPoint_t));
/** Warning !!! DataPoint Variables Init , Must Within The Data Range **/
/*
currentDataPoint.valueLED = ;
currentDataPoint.valueAD_Voltage = ;
currentDataPoint.valueAngle = ;
*/
}
/**
* @brief Millisecond timing maintenance function, milliseconds increment, overflow to zero
* @param none
* @return none
*/
void gizTimerMs(void)
{
timerMsCount++;
}
/**
* @brief Read millisecond count
* @param none
* @return millisecond count
*/
uint32_t gizGetTimerCount(void)
{
return timerMsCount;
}
/**
* @brief MCU reset function
* @param none
* @return none
*/
void mcuRestart(void)
{
__set_FAULTMASK(1);
NVIC_SystemReset();
}
/**@} */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART1 and Loop until the end of transmission */
// HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);
return ch;
}
///**
// * @brief Period elapsed callback in non blocking mode
// * @param htim : TIM handle
// * @retval None
// */
//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
//{
// if(htim==&htim2)
// {
// keyHandle();
// gizTimerMs();
// }
//}
///**
//* @brief Timer TIM3 init function
//* @param none
//* @return none
//*/
//void timerInit(void)
//{
// HAL_TIM_Base_Start_IT(&htim2);
//}
///**
// * @brief This function handles USART IDLE interrupt.
// */
//void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
//{
// if(UartHandle->Instance == USART2)
// {
// gizPutData((uint8_t *)&aRxBuffer, 1);
// HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);//开启下一次接收中断
// }
//}
///**
//* @brief USART init function
//* Serial communication between WiFi modules and device MCU
//* @param none
//* @return none
//*/
//void uartInit(void)
//{
// HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);//开启下一次接收中断
//}
/**
* @brief Serial port write operation, send data to WiFi module
*
* @param buf : buf address
* @param len : buf length
*
* @return : Return effective data length;-1,return failure
*/
int32_t uartWrite(uint8_t *buf, uint32_t len)
{
uint8_t crc[1] = {0x55};
uint32_t i = 0;
if(NULL == buf)
{
return -1;
}
for(i=0; i<len; i++)
{
// HAL_UART_Transmit_IT(&huart2, (uint8_t *)&buf[i], 1);
// while (huart2.gState != HAL_UART_STATE_READY);//Loop until the end of transmission
// if(i >=2 && buf[i] == 0xFF)
// {
// HAL_UART_Transmit_IT(&huart2, (uint8_t *)&crc, 1);
// while (huart2.gState != HAL_UART_STATE_READY);//Loop until the end of transmission
// }
USART_SendData(USART2, (uint8_t)buf[i]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE)==RESET);
if(i>=2 && buf[i] == 0xFF)
{
USART_SendData(USART2, crc[0]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE)==RESET);
}
}
#ifdef PROTOCOL_DEBUG
GIZWITS_LOG("MCU2WiFi[%4d:%4d]: ", gizGetTimerCount(), len);
for(i=0; i<len; i++)
{
GIZWITS_LOG("%02x ", buf[i]);
if(i >=2 && buf[i] == 0xFF)
{
GIZWITS_LOG("%02x ", 0x55);
}
}
GIZWITS_LOG("\n");
#endif
return len;
}
gizwits_protocol.c (注释掉Hal库的代码)
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "OLED.h"
#include "key.h"
#include "Server.h"
#include "Timer.h"
#include "Serial.h"
#include "AD.h"
#include "LED.h"
#include "gizwits_protocol.h"
#include "gizwits_product.h"
/*
* 单片机课设
* 2023年4月18日16:06:37
* 需求: 1. 上位机控制舵机旋转的角度(0-180°)
* 2. 每5秒返回一次信息(传给上位机和OLED屏幕)
* 3. 按下按键使舵机角度增加30°(若超过180°则回到0°)
* 4. LED灯闪烁作为系统指示灯
* 5. 光敏传感器 控制蜂鸣器报警
* 6. 加入机智云物联网方案
* 程序设计:
* 1. 硬件: STM32F103c8t6、面包板、舵机、OLED屏幕
* 2. 上位机与单片机的通信用USART1和DMA1(PA9 Tx, PA10 Rx)
* 3. TIM1用来计时
* 4. TIM2_CH1 用来输出PWM信号控制舵机旋转角度 PA0
* 5. B6、B7、B8、B9接OLED屏幕
* 6. PA1作为按键输入
*/
void Gitwits_Init(void)
{
Timer_TIM3Init(10-1, 7200-1); // 1ms
Serial_WIFI_Init(9600); // 波特率9600
Serial_DebugInit(); // 串口初始化
userInit(); // 数据初始化
gizwitsInit(); // 机智云初始化
Key_WIFIModeInit(); // 模式选择按键初始化
}
int main(void)
{
OLED_Init();
Gitwits_Init();
Key_Init();
Server_Init();
AD_Init();
LED_Init();
OLED_ShowString(1, 1, "Angle:");
OLED_ShowString(2, 1, "AD_Value:");
OLED_ShowString(3, 1, "Voltage:0.00V");
while(1)
{
gizwitsHandle((dataPoint_t *)¤tDataPoint); // 机智云协议处理 必须
OLED_ShowNum(1, 7, Serve_Angle, 3);
OLED_ShowNum(2, 10, AD_Value, 4);
AD_Voltage = (float)AD_Value*3.3/4096;
OLED_ShowNum(3, 9, AD_Voltage, 1);
OLED_ShowNum(3, 11, (uint16_t)(AD_Voltage * 100)% 100, 2);
LED_Off();
userHandle(); //数据上行 必须 上行的数据可在gizwits_product.c中修改
}
}
4. 其他代码 (MCU实现的功能)
LED.c
#include "stm32f10x.h"
#include "delay.h"
/*
* 初始化LED PB10 低电平驱动
*/
void LED_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_10);
}
/*
* LED灭
*/
void LED_Off(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_10);
}
/*
* LED亮
*/
void LED_On(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_10);
}
uint8_t LED_Info(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10);
}
#include "stm32f10x.h"
#include "delay.h"
/*
* 初始化LED PB10 低电平驱动
*/
void LED_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_10);
}
/*
* LED灭
*/
void LED_Off(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_10);
}
/*
* LED亮
*/
void LED_On(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_10);
}
uint8_t LED_Info(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10);
}
Server.c (舵机驱动)
#include "stm32f10x.h"
float Serve_Angle;
// TIM2_CH1 用来输出PWM信号控制舵机旋转角度 PA0
// 频率50Hz
void Server_Init(void)
{
// RCC使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 选择内部时钟作为TIM2的时钟
TIM_InternalClockConfig(TIM2);
// 配置时基单元
TIM_TimeBaseInitTypeDef TimeBase_InitStructure;
TimeBase_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TimeBase_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TimeBase_InitStructure.TIM_Period=20000-1; // ARR
TimeBase_InitStructure.TIM_Prescaler=72-1;
TimeBase_InitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TimeBase_InitStructure);
// 配置OC单元(输出比较单元 OutPut Compare) OC1
TIM_OCInitTypeDef OC_InitStructure;
TIM_OCStructInit(&OC_InitStructure);
OC_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;
OC_InitStructure.TIM_Pulse=0; // CCR寄存器
OC_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High; // 设置有效电平
OC_InitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM2, &OC_InitStructure);
// 开启TIM
TIM_Cmd(TIM2, ENABLE);
}
/*
* 设置OC1 CCR寄存器的值
*/
void Server_Set_Compare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
/*
设置舵机角度
因为舵机需要20ms的波长来驱动 可知频率为50Hz 若ARR设置为 20000-1 则PSC设置为72-1
又0.5ms~2.5ms对应舵机角度的0~180°
0.5ms 对应ARR为500 2.5ms 对应ARR为2500
对应角度的CCR应该设置为(Angle / 180 * 2000 + 500)
*/
void Server_SetAngle(float Angle)
{
Server_Set_Compare1(Angle / 180 * 2000 + 500);
}
AD.c
#include "stm32f10x.h"
#include "MyDMA.h"
#include "LED.h"
uint16_t AD_Value;
float AD_Voltage;
/*
* 初始化ADC
*/
void AD_Init(void)
{
// 初始化DMA通道1运输ADC1的数据
AD_MyDMA_Init();
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz mm
// 配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 选择规则通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_55Cycles5);
// 配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 单次转换或者连续转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC模式, 单独还是交叉
ADC_InitStructure.ADC_NbrOfChannel = 1; // 扫描的通道数
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式或者非扫描模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发控制
ADC_Init(ADC1, &ADC_InitStructure);
// 开启DMA转运
ADC_DMACmd(ADC1, ENABLE);
// 开启模拟看门狗
ADC_AnalogWatchdogThresholdsConfig(ADC1, 0xFFF, 0x5DC); // 设置看门狗阈值
ADC_AnalogWatchdogSingleChannelConfig(ADC1, ADC_Channel_7); // 对通道7设置看门狗
ADC_AnalogWatchdogCmd(ADC1, ADC_AnalogWatchdog_SingleRegEnable); // 使能单通道模拟看门狗
ADC_ITConfig(ADC1, ADC_IT_AWD, ENABLE); // 开启模拟看门狗中断
// 配置NVCI
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);
// 开启ADC功能
ADC_Cmd(ADC1, ENABLE);
// ADC校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 已初始化为零
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
/*
* ADC中断函数
*/
void ADC1_2_IRQHandler(void)
{
if(ADC_GetITStatus(ADC1, ADC_IT_AWD)==SET)
{
// 开启警报灯
LED_On();
// 清除中断标志
ADC_ClearITPendingBit(ADC1, ADC_IT_AWD);
}
}
MyDMA.c
#include "stm32f10x.h"
#include "Serial.h"
#include "AD.h"
#define TXBUFFERSIZE 11
#define RXBUFFERSIZE 15
/*
* ADC DMA初始化
*/
void AD_MyDMA_Init(void)
{
// RCC使能时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// 配置DMA
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // ADC的数据寄存器
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
// 地址非自增, ADC可以理解为上菜的桌子只有一个
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value; // 保存的地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 这里要自增
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 转运方向
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 自动重装
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 硬件触发
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// 开启DMA
DMA_Cmd(DMA1_Channel1, ENABLE); // 通道1
}
将移植后的代码下载进单片机中,连接好硬件电路后,即可进入下一步
接线示范 (仅供参考,根据自己的实际需求接)
说明:
- A2、A3为USART的端口,分别接WIFI模块的TX、RX
- WIFI模块出了TX、RX和GND,其余引脚工作时接高电平(手册解释有些引脚浮空也行,但我这块实测都得接高电平)
- B10、B12、B14为选择WIFI模块工作模式的三个按键分别对应(RESET、SoftAP、AirLink)
- A7为光敏传感器模拟信号输入口
- A0为控制舵机PWM信号输出口
- A1接按键,控制角度加30°
- 这里USART1的A9、A10未接线,可接USB转TTL模块将调试信息打印到电脑的串口助手
5. 设备连网
-
准备工作
需要: 机智云APP,两台移动设备(手机,一台用来开热点,热点频率为2.4G)
-
机智云APP下载
- 用另外一台设备开启热点 (注意频段为2.4G)
- 进入机智云连接设备,然后…
输入热点密码,下一步
选择乐鑫 (选择模块对应的模组) 继续点直到进入,这时候先别点,先按下B10的按键(SoftAP模式的按键)让模组进入SoftAP工作模式,然后点几蓝色字体
点击XPG-GAgent-7067(漏了一步,在点击XPG前,手机要先连上热点)
若找不到: XPG开头的,则可将MCU与WIFI模组通信的串口的发送口,通过USB转TTL接到电脑上,用串口助手查看发送的信息是否正确(与实操02中的协议一致),若不一致则需进一步进行检查
还有一种情况,需接受调试串口的信息,看程序是否运行正常,见参考资料【STM32移植机智云】超详细教程#2ESP8266移植机智云教程‘代码移植的最后
这是大佬文章的最后:
回到机智云调试APP,等待设备连接
若连接失败: 则检查热点质量,检查输入的热点密码是否正确
可以看到设备在线,点进去后
可以通过手机控制舵机的角度
参考资料
本小节参考以下资料
参考文档:
独立MCU方案接入机智云 - Gizwits
GAgent详解 - Gizwits
安信可ESP8266系列接入机智云方案及问题排查指引 - Gizwits
参考视频:
【机智云带你一节课入门物联网APP开发】
【机智云移植到stm32F103C8T6基于标准库】
参考博客:
【STM32移植机智云】超详细教程#2ESP8266移植机智云教程‘代码移植
实操06: APP生成
-
创建 → \rightarrow →移动应用 → \rightarrow →应用名称、应用包名随便填(应用包名最好英文) → \rightarrow →关联应用,不关联
在这里插入图片描述 -
关联应用 → \rightarrow →选择产品 (图标壁纸可以根据喜好,自己上传资源)
- 构建应用 → \rightarrow →应用构建 → \rightarrow →构建测试版
- 构建成功后可以用手机下载
-
添加设备 (过程与在调试APP添加设备类似)
-
展示一下文章来源:https://www.toymoban.com/news/detail-751437.html
文章来源地址https://www.toymoban.com/news/detail-751437.html
到了这里,关于机智云案例(ESP8266模块接入机智云平台实现APP控制舵机旋转)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!