一、准备工作:(1)机智云上下载生成的源码包
(2)一个wifi模块,本例程使用(正点原子的ESP8266模块)
(3)一块STMF103的开发板、核心板(STM32F103C8T6升级板)
(4)一个keil工程,将机智云的源码移植至该工程中
源码包:
二、在源码中主要关注两个文件
1 2 | 1.Gizwits 2.Utils |
三、重点修改两个.c文件
1 | 1.gizwits_product.c 2.gizwits_protocol.c |
四、移植步骤
1.将Gizwits 和Utils两个文件夹复制到自己的工程目录下,下图为我的一级工程目录。
2.在keil中分别导入这两个目录下的.c和.h文件。
3.添加入我们工程之后,编译会出现错误,错误原因是找不到一些.h文件或函数,因此我们直接把这些给删除或替换掉。
在gizwits_product.h中#include <stm32f1xx.h>替换成我们单片机的头文件,我使用#include "stm32f103x.h"
4.在gizwits_product.c文件中有一些删除一些程序
到此,我们也就基本完成移植的删减工作。下面要实现一个1ms定时器和一个与WIFI模块通讯的串口。
5.定时器实现(完整程序)
(1)定时器初始化
/*timer2.c*/
/*定时器TIM2*//* TIM2中断优先级配置 */
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*中断周期为1ms*/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period=1000; //自动重装载寄存器周期的值(计数值)
/* 累计 TIM_Period个频率后产生一个更新或者中断 */
TIM_TimeBaseStructure.TIM_Prescaler= (72 - 1); //时钟预分频数 72M/72
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update); // 清除溢出中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE); // 开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE); //先关闭等待使用
}
void TIM2_Init(void)
{
TIM2_NVIC_Configuration(); /* TIM2 定时配置 */
TIM2_Configuration();
START_TIME; /* TIM2 开始计时 */
}
(2)实现定时器开关(个人)
/*timer2.h*/
#include "stm32f10x.h"
#define START_TIME RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);TIM_Cmd(TIM2, ENABLE)
#define STOP_TIME TIM_Cmd(TIM2, DISABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE)
void TIM2_NVIC_Configuration(void);
void TIM2_Configuration(void);
void TIM2_Init(void);
(3)中断处理,gizTimerMs();在#include "gizwits_product.h"文件中,实现WIFI系统的计时。
void TIM2_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
gizTimerMs();
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
}
}
6.串口实现
(1)串口初始化(USART3)
/*usart3.c*/
void USART3_Config(u32 BaudRate)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
/*打开USART3时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
/*打开CPIOB时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //Tx
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11; //Rx
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
/*设置波特率*/
USART_InitStruct.USART_BaudRate = BaudRate;
/*不使用硬件流*/
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/*RX TX都使能*/
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
/*不使用校验*/
USART_InitStruct.USART_Parity = USART_Parity_No;
/*1位停止位*/
USART_InitStruct.USART_StopBits = USART_StopBits_1;
/*8位数据位*/
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
/*初始化USART*/
USART_Init(USART3, &USART_InitStruct);
/*清除USARTx的挂起标志*/
USART_ClearFlag(USART3, USART_IT_RXNE);
/*打开中断事件,接收不为空时,打开中断*/
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
/*指定中断源,也可认为是中断号*/
NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
/*中断使能*/
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
/*设置中断优先级类型*/
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
/*设置中断优先级*/
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
/*初始化中断向量*/
NVIC_Init(&NVIC_InitStruct);
/*使能USART3*/
USART_Cmd(USART3,ENABLE);
}
(2)发送函数
/*usart3.c*/
/*发送数据*/
void USART3_Send(u8 *buf,uint16_t len)
{
u16 t;
for(t = 0;t < len;t++) //循环发送
{
/*检测当前串口为空闲*/
while(USART_GetFlagStatus(USART3,USART_FLAG_TC) == RESET);
USART_SendData(USART3,buf[t]);//发送USARTx的数据
}
/*等待发送完成*/
while(USART_GetFlagStatus(USART3,USART_FLAG_TC) == RESET);
}
(3)中断接收函数
#include "gizwits_protocol.h"
extern uint8_t aRxBuffer; //该参数在gizwits_product.c中定义
//串口中断函数
void USART3_IRQHandler()
{
/*等待发送完成*/
while(USART_GetFlagStatus(USART3,USART_FLAG_TC));
/*接收数据*/
aRxBuffer = USART_ReceiveData(USART3);
/*等待接收完成*/
gizPutData((uint8_t *)&aRxBuffer,1);
/*清空中断位*/
USART_ClearITPendingBit(USART3,USART_IT_RXNE); //清除USARTx的中断挂起位
}
(4)usart3.h
#ifndef __USART3_H__
#define __USART3_H__
#include "stm32f10x.h"
void USART3_Config(u32 BaudRate);
void USART3_Send(u8 *buf,uint16_t len);
#endif
6.一键配网设置,就是实现一个按键功能,调用配网函数即可。配网函数为#include "gizwits_product.h"中的int32_t gizwitsSetMode(uint8_t mode)。
(1)key.c
#include "key.h"
#include "led.h"
#include "SysTick.h"
#include "usart1.h"
#include "E2prom.h"
#include "EPS8266.h"
#include "gizwits_product.h"
void Key_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = KEY_PIN; //选择对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(KEY_IOA, &GPIO_InitStructure); //初始化PC端口
}
/*******************************************************************************
* 函 数 名 : KEY_Scan
* 函数功能 : 按键扫描检测
* 输 入 : mode=0:单次按下按键
mode=1:连续按下按键
* 输 出 : 0:未有按键按下
KEY_UP_PRESS:KEY_UP键按下
KEY0_PRESS:KEY0键按下
KEY1_PRESS:KEY1键按下
*******************************************************************************/
unsigned char Key_Scan(u8 mode)
{
static unsigned char KeyUp_En = 1;
if(mode == 1)KeyUp_En = 1;
if((KeyUp_En==1) && (KEY_UP == 0))
{
delay_ms(20);
KeyUp_En = 0;
if(KEY_UP == 0)
{
LED2(0);
gizwitsSetMode(WIFI_AIRLINK_MODE); //一键配网
return KEY_UP_PRESS;
}
}
else if((KeyUp_En==0) &&(KEY_UP == 1))KeyUp_En = 1;
return 0;
}
(2)Key.h
#ifndef __KEY_H__
#define __KEY_H__
#include "system.h"
#define KEY_PIN GPIO_Pin_0
#define KEY_IOA GPIOA
#define KEY_UP PAin(0)
#define KEY_UP_PRESS 1
extern void Key_GPIO_Config(void);
extern unsigned char Key_Scan(u8 mode);
#endif
配网时将LED打开,如果配网成功,关闭LED。在gizwits_product.c中的gizwitsEventProcess()函数中。该函数时整个系统的核心,完成数据的下传处理和数据的上报工作,以及系统状态的检测。
五、gizwits_product.c文件函数的完善。
(1)上报信息采集函数,这里我只有一个数据上报点(温度值),因此只有一个参数。
/*采集要上报的数据,如温度,湿度等等*/
void userHandle(void)
{
currentDataPoint.valueTEMP = MyTemp;//Add Sensor Data Collection
}
(2)在userInit(void)中调用该文件的串口初始化和定时器初始化函数。
void userInit(void)
{
memset((uint8_t*)¤tDataPoint, 0, sizeof(dataPoint_t));
timerInit();
uartInit();
}
(3)timerInit();
void timerInit(void) //定时器初始化
{
TIM2_Init();
}
(4)uartInit();
/**
* @brief USART init function
* Serial communication between WiFi modules and device MCU
* @param none
* @return none
*/
void uartInit(void) //串口初始化
{
USART3_Config(9600);
}
(5)发送函数
/** * @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) { uint32_t i = 0; uint8_t crc = 0x55; if(NULL == buf) { return -1; } for(i = 0; i < len; i++) { USART3_Send(buf+i,1); if(i >= 2 && buf[i] == 0xFF) { USART3_Send(&crc,1); } } return len; }
六、main.c文件
#include "stm32f10x.h" #include "led.h" #include "SysTick.h" #include "key.h" #include "E2prom.h" #include "usart1.h" #include "usart3.h" #include "Timer1.h" #include "gizwits_product.h" #include "common.h" int main(void) { SystemInit(); // 配置系统时钟为72M userInit(); gizwitsInit(); while(1) { userHandle(); //在该函数中实现数据的上报和下行处理 gizwitsHandle((dataPoint_t *)¤tDataPoint); //将数据上报 } }
至此,移植到STM32F103完成。有兴趣的同学想了解WIFI如何配网的,可自己参考对用资料和源程序。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?