当前位置: 首页 > article >正文

使用stm32控制esp01s


title: 使用stm32控制esp01s
date: 2025年2月9日 18:41:20
tags:

  • 单片机
  • 模块使用
    categories: stm32
    description: 使用stm32控制esp01s连接WiFi查看内容等操作

前言

使用stm32f103控制esp01s是步入物联网的第一步,接下来的文章会详细讲解如何使用stm32控制esp01s。

一、电路图设计

对于这个模块的使用我是用我制作的项目来进行使用的,本质的内容很简单,因为esp01s它要进行通讯其实本质上就是用串口来进行通讯的,所以我们只需要使用串口来进行通讯就可以了。电路图如下:

这个电路图很简单,只需要将单片机的串口和esp01s的串口进行连接就可以了,然后再连接电源线,这样就可以了,剩下的就是对于串口通讯的编写了,实现串口收发数据的功能,控制esp01s的操作就是比较简单的了。

二、程序编写

这里主要针对于串口的编写和功能的实现,测试使用的TFT显示屏的代码编写就不说明了,因为不是这一节的内容。

1.串口的编写

1.1 串口的时钟的开启

这里在教程中我没有书写,这里简单介绍一下,实现是开启串口的时钟,这里要开启两个时钟,因为串口是借助GPIO口的,所以需要开启GPIO的时钟后再开启串口的时钟。代码如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

1.2 串口的配置

这里的串口的配置其实就是配置串口的一些参数,比如波特率、数据位、停止位、校验位等,首先先创建一个配置的变量,这里创建的变量类型为USART_InitTypeDef,然后配置变量的相关参数后使用的USART_Init()函数来进行配置的,配置的时候先需要配置一下GPIO。

对于GPIO来说,首先要确定使用的是USART1还是USART2,如果是一些高性能的,可能还要其它的,这个需要参考手册,对于我们这个基础型来说,只有USART1USART2,所以这里我们使用的是USART1,然后配置的是GPIOA,然后配置的是GPIOA9GPIOA10,这里需要注意的是,GPIOA9GPIOA10一个是TX输入,一个是RX输出,所以这里需要将GPIOA9配置成复用推挽输出的模式,GPIOA10配置为浮空输入。

代码如下:

GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStruct = {0};

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);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);

1.3 配置串口中断

因为我们没办法知道串口多久才接收数据,所以这里使用的是中断来进行接收数据的,这里使用的是串口的中断接收,所以需要配置一下串口的中断,这里需要先配置串口开启中断后再配置的是串口的中断优先级,然后配置中断。

首先配置串口中断的开启:

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

这里的USART_IT_RXNE是串口的中断接收,然后配置串口的中断优先级:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

这里的NVIC_PriorityGroup_2是中断优先级分组为2,然后配置中断:

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);

这样就写好了中断配置,然后在中断服务函数中进行接收数据的处理,这里的中断服务函数我使用状态机来进行实现,因为我们不知道串口什么时候会接收数据,所以这里使用状态机来进行实现,代码如下:

typedef enum
{
    RECEIVE_IDLE,  // 空闲状态
    RECEIVE_DATA,  // 接收数据状态
    RECEIVE_FINISH  // 接收完成状态
}USART_STATE;

USART_STATE usart_state = RECEIVE_IDLE;
static uint8_t usart_recv_buf[100] = {0};
static uint8_t usart_recv_index = 0;

void USART1_IRQHandler(void)
{
    uint8_t res = 0;
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        // USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        res = USART_ReceiveData(USART1);
        switch(usart_state)
        {
            case RECEIVE_IDLE:
            if (res != '\r' && res != '\n')
                {
                    usart_recv_buf[usart_recv_index++] = res;
                    usart_state = RECEIVE_DATA;
                }
                else if (res == '\n')
                {
                    usart_recv_buf[usart_recv_index++] = '\n';
                }
                break;
            case RECEIVE_DATA:
                if (res == '\r')
                {
                    // 跳过\r
                }
                else
                {
                    usart_state = RECEIVE_IDLE;
                    usart_recv_buf[usart_recv_index++] = res;
                    if (usart_recv_index >= 100)
                    {
                        usart_recv_index = 0;
                        usart_state = RECEIVE_FINISH;
                    }
                }
                break;
            case RECEIVE_FINISH:
                usart_state = RECEIVE_IDLE;
                usart_recv_index = 0;
                break;
        }
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

这里的状态机还是比较简单的,就是一开始是未接收状态,如果接收到的不是\r或者\n就开始接收数据,然后如果都不是那就开始接收数据,当接收到\r或者\n就开始接收完成状态,然后将接收的数据进行处理。

但是我感觉这个状态机有点问题,但暂时没有更好的方案,大家如果有更好的方案可以和我交流一下。

1.4 发送数据

发送数据的代码很简单,就是先判断发送标志位是否置位,然后发送数据,然后等待发送完成,代码如下:

void Usart_Send(uint8_t* str)
{
    while(*str != '\0')
    {
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);    // 等待发送寄存器为空
        USART_SendData(USART1, *str++);
    }
}

这里的USART_FLAG_TXE是发送寄存器为空的标志位,然后发送数据,然后等待发送完成。

这样对于串口的代码就写好了,然后就是对于esp01s的控制了。

2.esp01s的控制

对于esp01s的控制其实就是串口的发送数据,然后等待接收数据,然后将接收的数据进行处理,这里的处理就是判断接收的数据是否正确,然后进行相应的操作,这里的操作就是连接WiFi,然后将连接的数据显示在TFT显示屏上,因为只是简单的介绍,对于更多的操作我还没有加,因为只要把这些最基础的问题解决了后,剩下的只是在这个基础上增加东西。

这里的操作其实就是发送AT指令,当esp01s接收到AT指令后就会进行相应的操作,然后将操作的结果返回给esp01s,然后esp01s将结果返回给单片机,单片机就可以进行相应的操作了。

这里的AT指令我就不一一介绍了,因为我也不是很清楚,大家可以去百度一下,然后就可以了。

这里就简单的把我写的代码贴出来,大家可以去百度一下,然后就可以了。

#include "esp01s.h"
#include "system_config.h"
#include "stdio.h"

// 这个是去除空格
void Clear_String_Lj(uint8_t* buf)
{
    uint8_t recv_buf[100];
    uint8_t i = 0;
    uint8_t j = 0;
    Usart_Get_Recv_Buf(recv_buf);
    do
    {
        if (recv_buf[i]=='\n' && recv_buf[i+1]=='\n')
        {
            buf[j++] = '\n';
            i += 2;
        }
        else {
            buf[j++] = recv_buf[i++];
        }
    }while(recv_buf[i] != '\0');
    buf[j] = '\0';
}

void ESP01S_Init(uint8_t* buf)
{
    // 初始化串口
    Usart_Init();
}

void ESP01S_Test(uint8_t* buf)
{
    Usart_Send("AT+CWSTATE?\r\n");
    delay_ms(1000);
    Clear_String_Lj(buf);
}

void ESP01S_Rst(uint8_t* buf)
{
    Usart_Send("AT+RST\r\n");
    delay_ms(1000);
    Clear_String_Lj(buf);
}

void ESP01S_Look_GMR(uint8_t* buf)
{
    Usart_Send("AT+GMR\r\n");
    delay_ms(1000);
    Usart_Get_Recv_Buf(buf);
}

void ESP01S_Wifi_Mode_Show(uint8_t* buf)
{
    Usart_Send("AT+CWMODE?\r\n");
    delay_ms(1000);
    Clear_String_Lj(buf);
}

void ESP01S_Wifi_Mode_Set(uint8_t* buf, ESP01S_WIFI_MODE mode)
{
    uint8_t str[16];
    sprintf((char*)str, "AT+CWMODE=%d\r\n", mode);
    Usart_Send(str);
    delay_ms(1000);
    Clear_String_Lj(buf);
}

void ESP01S_Wifi_Join(uint8_t* buf)
{
    uint8_t str[32];
    sprintf((char*)str, "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_NAME, WIFI_PASSWORD);
    Usart_Send(str);
    delay_ms(1000);
    Usart_Get_Recv_Buf(buf);
}

void ESP01S_Wifi_Join_Show(uint8_t* buf)
{
    Usart_Send("AT+CIPSTATE?\r\n");
    delay_ms(1000);
    Usart_Get_Recv_Buf(buf);
}

然后我们可以让esp01s连接WiFi,后面就可以通过网络来进行其它的操作了,这里只是简单的介绍一下,后面的文章我会详细介绍一下。

#include "stm32f10x.h"                  // Device header
#include "TFT144.h"
#include "systick.h"
#include "image.h"
#include "button.h"
#include "buzz.h"
#include "DS3231.h"
#include "stdio.h"          // HACK 测试
#include "esp01s.h"

void menu2(void)
{
    uint8_t buf[100];
    TFT_Clear(TFT_Color(255, 255, 255));
    ESP01S_Wifi_Join(buf);
    while(1)
    {
        TFT_Show_String(0, 0, TFT_Color(0, 0, 0), TFT_Color(255, 255, 255), buf);
        if (Read_Button_B())
        {
            TFT_Clear(TFT_Color(255, 255, 255));
            void ESP01S_Wifi_Join_Show(uint8_t* buf);
            TFT_Show_String(0, 0, TFT_Color(0, 0, 0), TFT_Color(255, 255, 255), buf);
            break;
        }
    }
}

int main(){
    uint8_t buf[100];

    TFT_Init();
    Button_Init();
    Buzz_Init();
    DS3231_Init();
    TFT_Clear(TFT_Color(255, 255, 255));
    delay_ms(1000);
    ESP01S_Init(buf);
    ESP01S_Wifi_Mode_Set(buf, ESP01S_WIFI_STATION);
    TFT_Show_String(0, 0, TFT_Color(0, 0, 0), TFT_Color(255, 255, 255), buf);
	while(1)
    {
        if (Read_Button_B())
        {
            menu2();
        }
	}
}

效果如下:

这样就连接到WiFi了,因为是连接的电脑热点,所有可以在电脑上看到设备连接情况:

总结

其实对于esp01s的控制还是比较简单的,因为它本质上就是串口的通讯,所以我们只需要使用串口来进行通讯就可以了,然后就可以了,后面的文章我会详细介绍一下。


http://www.kler.cn/a/543361.html

相关文章:

  • Java知识速记:ArrayList 和 Array
  • 算法学习笔记之贪心算法
  • 【Obsidian】当笔记接入AI,Copilot插件推荐
  • 【SVN基础】
  • elasticsearch实战应用从入门到高效使用java集成es快速上手
  • ASP.NET Core 如何使用 C# 向端点发出 POST 请求
  • Hive的数据库操作和表操作
  • 未来替代手机的产品,而非手机的本身
  • SpringBoot服务器的采购上,服务器的数量和性能配置如何取舍【无标题】
  • 【vue3】入门基础知识点
  • PHP 中的除以零错误
  • 深度学习实战基础案例——卷积神经网络(CNN)基于DenseNet的眼疾检测|第4例
  • 基于Python flask-sqlalchemy的SQLServer数据库管理平台
  • WinForm 防破解、反编译设计文档
  • 2025年3月一区SCI-真菌生长优化算法Fungal growth optimizer-附Matlab免费代码
  • Citus的TPCC、TPCH性能测试
  • 时间敏感和非时间敏感流量的性能保证配置
  • 3dgs 2025 学习笔记
  • 【算法】【双指针】acwing算法基础 2816. 判断子序列
  • 懒人精灵内存插件(手游x86x64内存插件)
  • 芯盾时代数据安全产品体系,筑牢数据安全防线
  • Flowable:现代业务流程管理的解决方案
  • 深度学习新宠:卷积神经网络如何重塑人工智能版图?
  • Django 初学小案例:用户登录
  • ffmpeg -pix_fmts
  • 介绍几款免费的显示器辅助工具!