STM32之串口(三)

1. wifi模块(esp8266)

1.1 介绍

• ESP8266 是一款高性能的 WIFI 串口 模块,可以实现透明传输,可以利用串口与单片机进行通讯,从而编程实现控制 ESP8266。如图:

1.2 常见AT指令

• 上电后发送AT指令测试通信及模块功能是否正常,如图:

• 通过一下命令配置成9600波特率,如图:

• 设置工作模式,如图:

• 以设备模式接入家中路由器配置,发送指令AT+CWJAP="这是wifi名","这是密码" 如果成功接入wifi返回如下图:

• 连接TCP Server:

• 打开网络助手,设立TCP服务器。

• 在网络助手,设置协议为TCP服务器,写入本地IP和对应端口。

• 连接服务器,发送指令AT+CIPSTART="TCP","服务器IP","端口",成功如下图:

• 发送数据,如图:

• 透传模式,如图:

• 退出透传模式,如图:

2. 实操

2.1 ESP8266连接TCP服务器

• 在esp8266.c

cpp 复制代码
#include "esp8266.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"
UART_HandleTypeDef esp8266_handle = {0};//串口的句柄
uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];//定义接收的数据存放位置
uint16_t esp8266_cnt = 0;//计数器,表示接收了多少个数
uint16_t esp8266_cntPre = 0;//保存接收前一个数是第几个数

uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];

//串口初始化
void esp8266_uart_init(uint32_t baudrate){
    esp8266_handle.Instance = USART2;//选择串口1
    esp8266_handle.Init.BaudRate = baudrate;
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;//不打开检验位
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;//1个停止位
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;//传输字长为8位
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;//硬件流不打开
    HAL_UART_Init(&esp8266_handle);
}

uint8_t esp8266_wait_receive(){
    if(esp8266_cnt == 0)
        return ESP8266_ERROR;
    
    if(esp8266_cnt == esp8266_cntPre){
        esp8266_cnt = 0;
        return ESP8266_EOK;
    }
    esp8266_cntPre = esp8266_cnt;
    return ESP8266_ERROR;
    

}
void esp8266_clear(){
    memset(esp8266_rx_buf,0,sizeof(esp8266_rx_buf));
    esp8266_cnt = 0;
}
void esp8266_reveice_data(){//接收数据
    if(esp8266_wait_receive() == ESP8266_EOK){
        printf("esp8266 recv: %s\r\n",esp8266_rx_buf);
        esp8266_clear();
    }
    
}

void esp8266_send_data(char * fmt,...){//发数据给服务器
    
    va_list ap;
    va_start(ap,fmt);
    vsprintf((char *)esp8266_tx_buf,fmt,ap);
    va_end(ap);
    
    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,strlen((char *)esp8266_tx_buf),100);
}

uint8_t esp8266_send_cmd(char* cmd,char* res){//重点。cmd是发的什么类型的AT指令,res是返回的结果
    esp8266_clear();//发送之前,清空一下接收缓冲区。
    uint8_t timeout = 250;
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);//发给wifi模块。
    while(timeout--){//等待2.5s,等待返回
        if(esp8266_wait_receive() == ESP8266_EOK){
            if(strstr((char *)esp8266_rx_buf,res) != NULL){
                return ESP8266_EOK;
            }
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
    
}

void esp8266_test(){
    esp8266_send_data("this is from esp8266\r\n");
    
    esp8266_reveice_data();//接收数据
}


uint8_t esp8266_set_mode(uint8_t mode){
    switch(mode){
        case ESP8266_STA_MODE:
            return esp8266_send_cmd("AT+CWMODE=1\r\n","OK");
        case ESP8266_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=3\r\n","OK");
        default:
            return ESP8266_EINVET;
    }
}

uint8_t esp8266_join_ap(char* ssid,char* pwd){
    char cmd[64];
    sprintf(cmd,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pwd);
    return esp8266_send_cmd(cmd,"WIFI GOT IP");
}

uint8_t esp8266_single_connect(uint8_t mode){
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);
    return esp8266_send_cmd(cmd,"OK");
}

uint8_t esp8266_at_test(){
    return esp8266_send_cmd("AT\r\n","OK");
}

uint8_t esp8266_connect_tcp_sever(char* sever_id,char* sever_potr){
    char cmd[64];
    sprintf(cmd,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",sever_id,sever_potr);
    return esp8266_send_cmd(cmd,"CONNECT");
}

uint8_t esp8266_send_unvarnished(){
    uint8_t ret ;
    ret = esp8266_send_cmd("AT+CIPMODE=1\r\n","OK");
    ret += esp8266_send_cmd("AT+CIPSEND\r\n",">");
    if(ret == ESP8266_EOK)
        return ESP8266_EOK;
    else 
        return ESP8266_ERROR;   
    
}

void esp8266_init(uint32_t baudrate){
    printf("esp8266初始化开始...\r\n");
    esp8266_uart_init(baudrate);
    //下面还有一些初始化
    
    printf("1. 测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    
    printf("2. 设置工作模式为STA...\r\n");
    while(esp8266_set_mode(ESP8266_STA_MODE))
        delay_ms(500);
    
    printf("3. 设置单路链接模式...\r\n");
    while(esp8266_single_connect(ESP8266_SINGLE_MODE))
        delay_ms(500);
    
    printf("4. 连接wifi,SSID: %s, PWD: %s\r\n", WIFI_SSID, WIFI_PWD);
    while(esp8266_join_ap(WIFI_SSID,WIFI_PWD))
            delay_ms(1500);
    
    printf("5. 连接TCP服务器,server_ip:%s, server_port:%s\r\n", TCP_SERVER_IP, TCP_SERVER_PORT);
    while(esp8266_connect_tcp_sever(TCP_SERVER_IP,TCP_SERVER_PORT))
        delay_ms(500);
    
    printf("6. 进入到透传模式...\r\n");
    while(esp8266_send_unvarnished())
        delay_ms(500);
    
    printf("ESP8266已连接上TCP服务器并进入透传模式\r\n");
    printf("ESP8266初始化完成!\r\n");
}

void USART2_IRQHandler(){
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle,UART_FLAG_RXNE) != RESET){//看是不是被置1了
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))
            esp8266_cnt = 0;//接收前需要判断一下,,esp8266_cnt是否超出总长度esp8266_RX_BUF_SIZE
        HAL_UART_Receive(&esp8266_handle,&receive_data,1,1000);//接收数据
        esp8266_rx_buf[esp8266_cnt++] = receive_data;//把接收到的数据放进数组
        
        //HAL_UART_Transmit(&esp8266_handle,&receive_data,1,1000);
    }
}

• 头文件

cpp 复制代码
#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "stdio.h"
#include "sys.h"

#define ESP8266_RX_BUF_SIZE 128
#define ESP8266_TX_BUF_SIZE 64

#define ESP8266_EOK      0
#define ESP8266_ERROR    1
#define ESP8266_ETIMEOUT 2
#define ESP8266_EINVET   3


#define ESP8266_STA_MODE    1
#define ESP8266_AP_MODE     2
#define ESP8266_STA_AP_MODE 3

#define ESP8266_SINGLE_MODE 0
#define ESP8266_MULTI_MODE  1

#define WIFI_SSID "iphone"
#define WIFI_PWD  "12345678"

#define TCP_SERVER_IP "172.20.10.4"
#define TCP_SERVER_PORT "8080"



void esp8266_init(uint32_t baudrate);

void esp8266_reveice_data();
#endif

• uart1.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "string.h"

UART_HandleTypeDef uart1_handle;                                            /* UART1句柄 */

uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];                                    /* UART1接收缓冲区 */
uint16_t uart1_rx_len = 0;                                                  /* UART1接收字符长度 */

/**
 * @brief       重定义fputc函数
 * @note        printf函数最终会通过调用fputc输出字符串到串口
 */
int fputc(int ch, FILE *f)
{
    while ((USART1->SR & 0X40) == 0);                                       /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch;                                               /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void uart1_init(uint32_t baudrate)
{
    /*UART1 初始化设置*/
    uart1_handle.Instance = USART1;                                         /* USART1 */
    uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart1_handle);                                           /* HAL_UART_Init()会使能UART1 */
}


/**
 * @brief       UART底层初始化函数
 * @param       huart: UART句柄类型指针
 * @note        此函数会被HAL_UART_Init()调用
 *              完成时钟使能,引脚配置,中断配置
 * @retval      无
 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;

    if (huart->Instance == USART1)                                          /* 如果是串口1,进行串口1 MSP初始化 */
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();                                       /* 使能串口TX脚时钟 */
        __HAL_RCC_USART1_CLK_ENABLE();                                      /* 使能串口时钟 */

        gpio_init_struct.Pin = GPIO_PIN_9;                                  /* 串口发送引脚号 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                            /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                                /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;                      /* IO速度设置为高速 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
                
        gpio_init_struct.Pin = GPIO_PIN_10;                                 /* 串口RX脚 模式设置 */
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);                            /* 串口RX脚 必须设置成输入模式 */
        
        HAL_NVIC_EnableIRQ(USART1_IRQn);                                    /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);                            /* 组2,最低优先级:抢占优先级3,子优先级3 */

        __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);                          /* 使能UART1接收中断 */
        __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);                          /* 使能UART1总线空闲中断 */
    }else if(huart->Instance == USART2){
        GPIO_InitTypeDef gpio_init = {0};
        __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIO时钟
        __HAL_RCC_USART2_CLK_ENABLE();
        gpio_init.Mode = GPIO_MODE_AF_PP;//TX线是看GPIO外设配置为复用推挽
        gpio_init.Pin = GPIO_PIN_2;
        gpio_init.Pull = GPIO_PULLUP;//默认上拉
        gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA,&gpio_init);//初始化gpio
        
        gpio_init.Mode = GPIO_MODE_INPUT;//RX线是看GPIO外设配置为上拉输入
        gpio_init.Pin = GPIO_PIN_3;
        HAL_GPIO_Init(GPIOA,&gpio_init);//初始化gpio
        
        HAL_NVIC_SetPriority(USART2_IRQn,3,3);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
        __HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);//使能RXNE中断
        //__HAL_UART_ENABLE_IT(huart,UART_IT_IDLE);//使能空闲中断
    }
}


/**
 * @brief       UART1接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart1_rx_clear(void)
{
    memset(uart1_rx_buf, 0, sizeof(uart1_rx_buf));                          /* 清空接收缓冲区 */
    uart1_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口1中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART1_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart1_rx_len >= sizeof(uart1_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart1_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart1_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart1_rx_buf[uart1_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("recv: %s\r\n", uart1_rx_buf);                               /* 将接收到的数据打印出来 */
        uart1_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart1_handle);                           /* 清除UART总线空闲中断 */
    }
}

• main.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "esp8266.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    esp8266_init(9600);
    printf("hello world\r\n");
    while(1)
    { 
        esp8266_test();
        delay_ms(500);
    }
}

2.2 实战ESP8266作为服务器

• esp8266.c

cpp 复制代码
#include "esp8266.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"
UART_HandleTypeDef esp8266_handle = {0};//串口的句柄
uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];//定义接收的数据存放位置
uint16_t esp8266_cnt = 0;//计数器,表示接收了多少个数
uint16_t esp8266_cntPre = 0;//保存接收前一个数是第几个数

//uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];

//串口初始化
void esp8266_uart_init(uint32_t baudrate){
    esp8266_handle.Instance = USART2;//选择串口1
    esp8266_handle.Init.BaudRate = baudrate;
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;//不打开检验位
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;//1个停止位
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;//传输字长为8位
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;//硬件流不打开
    HAL_UART_Init(&esp8266_handle);
}

uint8_t esp8266_wait_receive(){
    if(esp8266_cnt == 0)
        return ESP8266_ERROR;
    
    if(esp8266_cnt == esp8266_cntPre){
        esp8266_cnt = 0;
        return ESP8266_EOK;
    }
    esp8266_cntPre = esp8266_cnt;
    return ESP8266_ERROR;
    

}

void esp8266_clear(){
    memset(esp8266_rx_buf,0,sizeof(esp8266_rx_buf));
    esp8266_cnt = 0;
}
void esp8266_reveice_data(){
    if(esp8266_wait_receive() == ESP8266_EOK){
        printf("esp8266 recv: %s\r\n",esp8266_rx_buf);//接收客户端发来的数据
        esp8266_clear();
    }
    
}

//void esp8266_send_data(char * fmt,...){
//    
//    va_list ap;
//    va_start(ap,fmt);
//    vsprintf((char *)esp8266_tx_buf,fmt,ap);
//    va_end(ap);
//    
//    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,strlen((char *)esp8266_tx_buf),100);
//}

uint8_t esp8266_send_cmd(char* cmd,char* res){
    esp8266_clear();//发送之前,清空一下接收缓冲区。
    uint8_t timeout = 250;
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);
    while(timeout--){
        if(esp8266_wait_receive() == ESP8266_EOK){
            if(strstr((char *)esp8266_rx_buf,res) != NULL){
                return ESP8266_EOK;
            }
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
    
}

//void esp8266_test(){
//    esp8266_send_cmd("AT+CIPSEND=0,6\r\n",">");
//    esp8266_send_data("abcd\r\n");
//    
//    
//}


uint8_t esp8266_set_mode(uint8_t mode){
    switch(mode){
        case ESP8266_STA_MODE:
            return esp8266_send_cmd("AT+CWM0ODE=1\r\n","OK");
        case ESP8266_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=3\r\n","OK");
        default:
            return ESP8266_EINVET;
    }
}

uint8_t esp8266_multp_connect(uint8_t mode){
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);
    return esp8266_send_cmd(cmd,"OK");
}

uint8_t esp8266_at_test(){
    return esp8266_send_cmd("AT\r\n","OK");
}

uint8_t esp8266_build_tcp_Server(){
    return esp8266_send_cmd("AT+CIPSERVER=1\r\n","OK");
}

void esp8266_init(uint32_t baudrate){
    printf("esp8266初始化开始...\r\n");
    esp8266_uart_init(baudrate);
    //下面还有一些初始化
    
    printf("1. 测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    
    printf("2. 设置工作模式为AP...\r\n");
    while(esp8266_set_mode(ESP8266_AP_MODE))
        delay_ms(500);
    
    printf("3. 使能多链接...\r\n");
    while(esp8266_multp_connect(ESP8266_MULTI_MODE))
        delay_ms(500);
    
    printf("4. 建立TCPServer\r\n");
    while(esp8266_build_tcp_Server())
            delay_ms(1500);
    

    printf("ESP8266初始化完成!\r\n");
}
void USART2_IRQHandler(){
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle,UART_FLAG_RXNE) != RESET){//看是不是被置1了
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))
            esp8266_cnt = 0;//接收前需要判断一下,,esp8266_cnt是否超出总长度esp8266_RX_BUF_SIZE
        HAL_UART_Receive(&esp8266_handle,&receive_data,1,1000);//接收数据
        esp8266_rx_buf[esp8266_cnt++] = receive_data;//把接收到的数据放进数组
        
        //HAL_UART_Transmit(&esp8266_handle,&receive_data,1,1000);
    }
}

• 在esp8266.h

cpp 复制代码
#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "stdio.h"
#include "sys.h"

#define ESP8266_RX_BUF_SIZE 128
#define ESP8266_TX_BUF_SIZE 64

#define ESP8266_EOK      0
#define ESP8266_ERROR    1
#define ESP8266_ETIMEOUT 2
#define ESP8266_EINVET   3


#define ESP8266_STA_MODE    1
#define ESP8266_AP_MODE     2
#define ESP8266_STA_AP_MODE 3

#define ESP8266_SINGLE_MODE 0
#define ESP8266_MULTI_MODE  1

#define WIFI_SSID "iphone"
#define WIFI_PWD  "12345678"

#define TCP_SERVER_IP "172.20.10.4"
#define TCP_SERVER_PORT "8080"



void esp8266_init(uint32_t baudrate);

void esp8266_reveice_data();
#endif

• 在和uart1.c上面第一个实操一样

• main.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "esp8266.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    esp8266_init(9600);
    printf("hello world\r\n");
    while(1)
    { 
        //esp8266_test();
        esp8266_reveice_data();
        
        delay_ms(10);
        
    }
}

3.3 wifi控制风扇

• 在uart1.c和实操1一样的。

• 在esp8266.c

cpp 复制代码
#include "esp8266.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"
#include "fan.h"
UART_HandleTypeDef esp8266_handle = {0};//串口的句柄
uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];//定义接收的数据存放位置
uint16_t esp8266_cnt = 0;//计数器,表示接收了多少个数
uint16_t esp8266_cntPre = 0;//保存接收前一个数是第几个数

uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];

//串口初始化
void esp8266_uart_init(uint32_t baudrate){
    esp8266_handle.Instance = USART2;//选择串口2
    esp8266_handle.Init.BaudRate = baudrate;
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;//不打开检验位
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;//1个停止位
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;//传输字长为8位
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;//硬件流不打开
    HAL_UART_Init(&esp8266_handle);
}

uint8_t esp8266_wait_receive(){
    if(esp8266_cnt == 0)
        return ESP8266_ERROR;
    
    if(esp8266_cnt == esp8266_cntPre){
        esp8266_cnt = 0;
        return ESP8266_EOK;
    }
    esp8266_cntPre = esp8266_cnt;
    return ESP8266_ERROR;
    

}

void esp8266_clear(){
    memset(esp8266_rx_buf,0,sizeof(esp8266_rx_buf));
    esp8266_cnt = 0;
}
uint16_t esp8266_reveice_data(char * recv_data){
    if(esp8266_wait_receive() == ESP8266_EOK){
        printf("esp8266 recv: %s\r\n",esp8266_rx_buf);
        memcpy(recv_data,esp8266_rx_buf,strlen((char *)esp8266_rx_buf));//把接收区的数据拷贝出去
        esp8266_clear();
        return strlen(recv_data);
    }
    return 0;
    
}

//void esp8266_send_data(char * fmt,...){
//    
//    va_list ap;
//    va_start(ap,fmt);
//    vsprintf((char *)esp8266_tx_buf,fmt,ap);
//    va_end(ap);
//    
//    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,strlen((char *)esp8266_tx_buf),100);
//}

uint8_t esp8266_send_cmd(char* cmd,char* res){
    esp8266_clear();//发送之前,清空一下接收缓冲区。
    uint8_t timeout = 250;
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);
    while(timeout--){
        if(esp8266_wait_receive() == ESP8266_EOK){
            if(strstr((char *)esp8266_rx_buf,res) != NULL){
                return ESP8266_EOK;
            }
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
    
}

//void esp8266_test(){
//    esp8266_send_data("this is from esp8266\r\n");
//    
//    esp8266_reveice_data();
//}


uint8_t esp8266_set_mode(uint8_t mode){
    switch(mode){
        case ESP8266_STA_MODE:
            return esp8266_send_cmd("AT+CWMODE=1\r\n","OK");
        case ESP8266_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
            return esp8266_send_cmd("AT+CWMODE=3\r\n","OK");
        default:
            return ESP8266_EINVET;
    }
}

uint8_t esp8266_join_ap(char* ssid,char* pwd){
    char cmd[64];
    sprintf(cmd,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pwd);
    return esp8266_send_cmd(cmd,"WIFI GOT IP");
}

uint8_t esp8266_single_connect(uint8_t mode){
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);
    return esp8266_send_cmd(cmd,"OK");
}

uint8_t esp8266_at_test(){
    return esp8266_send_cmd("AT\r\n","OK");
}

uint8_t esp8266_connect_tcp_sever(char* sever_id,char* sever_potr){
    char cmd[64];
    sprintf(cmd,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",sever_id,sever_potr);
    return esp8266_send_cmd(cmd,"CONNECT");
}

uint8_t esp8266_send_unvarnished(){
    uint8_t ret ;
    ret = esp8266_send_cmd("AT+CIPMODE=1\r\n","OK");
    ret += esp8266_send_cmd("AT+CIPSEND\r\n",">");
    if(ret == ESP8266_EOK)
        return ESP8266_EOK;
    else 
        return ESP8266_ERROR;   
    
}

void esp8266_init(uint32_t baudrate){
    printf("esp8266初始化开始...\r\n");
    esp8266_uart_init(baudrate);
    //下面还有一些初始化
    
    printf("1. 测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    
    printf("2. 设置工作模式为STA...\r\n");
    while(esp8266_set_mode(ESP8266_STA_MODE))
        delay_ms(500);
    
    printf("3. 设置单路链接模式...\r\n");
    while(esp8266_single_connect(ESP8266_SINGLE_MODE))
        delay_ms(500);
    
    printf("4. 连接wifi,SSID: %s, PWD: %s\r\n", WIFI_SSID, WIFI_PWD);
    while(esp8266_join_ap(WIFI_SSID,WIFI_PWD))
            delay_ms(1500);
    
    printf("5. 连接TCP服务器,server_ip:%s, server_port:%s\r\n", TCP_SERVER_IP, TCP_SERVER_PORT);
    while(esp8266_connect_tcp_sever(TCP_SERVER_IP,TCP_SERVER_PORT))
        delay_ms(500);
    
    printf("6. 进入到透传模式...\r\n");
    while(esp8266_send_unvarnished())
        delay_ms(500);
    
    printf("ESP8266已连接上TCP服务器并进入透传模式\r\n");
    printf("ESP8266初始化完成!\r\n");
}
void USART2_IRQHandler(){
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle,UART_FLAG_RXNE) != RESET){//看是不是被置1了
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))
            esp8266_cnt = 0;//接收前需要判断一下,,esp8266_cnt是否超出总长度esp8266_RX_BUF_SIZE
        HAL_UART_Receive(&esp8266_handle,&receive_data,1,1000);//接收数据
        esp8266_rx_buf[esp8266_cnt++] = receive_data;//把接收到的数据放进数组
      
        //esp8266_clear();
        //HAL_UART_Transmit(&esp8266_handle,&receive_data,1,1000);
    }
}

• main.c

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"
#include "esp8266.h"
#include "fan.h"
#include "string.h"
int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    esp8266_init(9600);
    fan_init();
    printf("hello world\r\n");
    char recv_data[ESP8266_RX_BUF_SIZE];
    while(1)
    { 
        esp8266_reveice_data(recv_data);
        if(strstr(recv_data,"ON") != NULL)
            fan_on();
        else if(strstr(recv_data,"OFF") != NULL)
            fan_off();
        delay_ms(10);
    }
}

• 在fan.c

cpp 复制代码
#include "fan.h"


void fan_init(){//继电器可以看作成一个开关,开关连接着负载,这里的负载是个喇叭
    GPIO_InitTypeDef gpio_init = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();//使能GPIO时钟
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init.Pin = GPIO_PIN_6;//推挽输出
    gpio_init.Pull = GPIO_PULLUP;//默认上拉
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB,&gpio_init);//初始化gpio
    fan_off();//关灯

}

void fan_on(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
}

void fan_off(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
}

uint8_t get_fan_staut(){
    return (uint8_t) HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6);
}

相关推荐
兆龙电子单片机设计1 小时前
【STM32项目开源】STM32单片机智能宠物喂养系统
stm32·单片机·开源·毕业设计·电子信息
Y1rong2 小时前
STM32之串口(二)
stm32·单片机·嵌入式硬件
夜月yeyue2 小时前
VFS (虚拟文件系统) 核心架构
linux·c++·单片机·嵌入式硬件·架构
Y1rong2 小时前
STM32之串口(一)
网络·stm32·嵌入式硬件
想睡觉的树2 小时前
解决keil5编译慢的问题-亲测有效-飞一般的感觉
c语言·stm32·嵌入式硬件
__万波__2 小时前
STM32L475串口打印改为阻塞式打印兼DMA, 两种打印方式实时切换
stm32·单片机·嵌入式硬件
猫猫的小茶馆2 小时前
【Linux 驱动开发】二. linux内核模块
linux·汇编·arm开发·驱动开发·stm32·嵌入式硬件·架构
飞睿科技2 小时前
解析ESP-SparkBot开源大模型AI桌面机器人的ESP32-S3核心方案
人工智能·嵌入式硬件·物联网·机器人·esp32·乐鑫科技·ai交互
風清掦2 小时前
【江科大STM32学习笔记-03】GPIO通用输入输出口
笔记·stm32·单片机·学习