概述:

本章节主要实现esp8266通过usart3与stm32通信。首先,使用串口工具在电脑端测试模块AT指令,模拟测试模块通信是否正常,设置查询模块的参数;确认模块通信正常后,再着手软件配置串口,通过软件发送AT测试指令检测usart3收发是否正常。

开篇:STM32F767igt6 + RT-Thread + ESP8266

完结篇:STM32F767igt6 + RT-Thread + ESP8266

本章节代码请移步到github处下载:

github代码下载地址

1.esp8266的AT指令测试

USB转TTL工具连接好esp8266模块,使用串口调试助手测试,配置好参数,默认为波特率115200,数据位8位,停止位1位;我把波特率配置为4800bps。

2.软件配置usart3

2.1 串口初始化配置:

模块AT指令测试通过后,开始软件上usart3的初始化参数配置:

void usart3_init(uint32_t bound)
{   UART3_Handler.Instance=USART3;                    UART3_Handler.Init.BaudRate=bound;                  UART3_Handler.Init.WordLength=UART_WORDLENGTH_8B;  UART3_Handler.Init.StopBits=UART_STOPBITS_1;      UART3_Handler.Init.Parity=UART_PARITY_NONE;        UART3_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;  UART3_Handler.Init.Mode=UART_MODE_TX_RX;           HAL_UART_Init(&UART3_Handler);}void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{if(huart==(&UART3_Handler)){ __HAL_RCC_GPIOB_CLK_ENABLE();           __HAL_RCC_USART3_CLK_ENABLE();      GPIO_Initure.Pin=GPIO_PIN_10;          GPIO_Initure.Mode=GPIO_MODE_AF_PP;     GPIO_Initure.Pull=GPIO_PULLUP;         GPIO_Initure.Speed=GPIO_SPEED_FAST;        GPIO_Initure.Alternate=GPIO_AF7_USART3;    HAL_GPIO_Init(GPIOB,&GPIO_Initure);     GPIO_Initure.Pin=GPIO_PIN_11;          HAL_GPIO_Init(GPIOB,&GPIO_Initure);     TIM7_Int_Init(1000-1,10800-1);      TIM7->CR1&=~(1<<0);        //关闭定时器7   __HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);       //开启接收中断HAL_NVIC_EnableIRQ(USART3_IRQn);                //使能USART3中断HAL_NVIC_SetPriority(USART3_IRQn,2,3);          //抢占优先级2,子优先级3USART3_RX_STA=0;}
}

2.2 串口收发逻辑:

2.2.1 串口发送:

f7的串口有各自的发送、接收寄存器,va_start、va_end使用方法及作用自行去了解;

while((USART3->ISR&0X40)==0)等待发送完成,再发送下一字节数据。

void USART3_Send(char* fmt, ...)
{uint16_t i,j; va_list ap; va_start(ap,fmt);vsprintf((char*)USART3_TX_BUF,fmt,ap);va_end(ap);i=strlen((const char*)USART3_TX_BUF);for(j=0;j<i;j++){while((USART3->ISR&0X40)==0);            USART3->TDR=USART3_TX_BUF[j];  } printf("uart3 tx data:%s\r\n",USART3_TX_BUF);
}

2.2.2 串口接收:

基本实现原理:在uart1中接收处理函数是通过判断是否接收到 "\r\n" 来确定接收是否完成的,接收完成相应标志位置1。usart3中则是通过添加一个定时器来处理,接收数据时产生中断,中断处理函数中打开定时器,在定时时间未到达之前接收到数据时会重置定时数,重新计时,直到定时到达产生中断,才结束数据的接收,接收完成标志位置1。

在usart3的中断处理函数中,__HAL_UART_GET_FLAG(&UART3_Handler,UART_IT_ERR) == RESET判断是否发生溢出错误,在测试的前期,由于这个溢出中断,程序不做处理的话会一直卡在这个处理函数里,所以我把波特率降低为4800bps,大大降低这个错误,使接收数据更加稳定;

__HAL_UART_GET_FLAG(&UART3_Handler,UART_FLAG_RXNE) != RESET判断接收寄存器是否为空,然后读取寄存器数据;接收第一个字节的时候打开定时器,之后接收数据均做计数器清空处理。

void USART3_IRQHandler(void)
{uint8_t res;if(__HAL_UART_GET_FLAG(&UART3_Handler,UART_IT_ERR) == RESET){__HAL_UART_CLEAR_OREFLAG(&UART3_Handler);printf("UART_FLAG_ORE\r\n");}    if(__HAL_UART_GET_FLAG(&UART3_Handler,UART_FLAG_RXNE) != RESET){     res=USART3->RDR;  if((USART3_RX_STA&(1<<15))==0){ if(USART3_RX_STA<USART3_MAX_RECV_LEN){TIM7->CNT=0;                       //计数器清空if(USART3_RX_STA==0){TIM7->CR1|=1<<0;                //使能定时器7memset(USART3_RX_BUF, 0 , USART3_MAX_RECV_LEN);//printf("timer7 open!\r\n");}USART3_RX_BUF[USART3_RX_STA++]=res;        }else {USART3_RX_STA|=1<<15;printf("uart3 rx error!\r\n");} }}    }   

定时器中断处理函数:串口接收标志位置1,并关闭定时器。

void TIM7_IRQHandler(void)
{                   if(USART3_RX_STA !=0){USART3_RX_STA|=1<<15; //标记接收完成printf("uart3 rx data:%s\r\n",USART3_RX_BUF);esp8266_data_check();}__HAL_TIM_CLEAR_FLAG(&TIM7_Handler,TIM_EventSource_Update );       //清除TIM7更新中断标志  TIM7->CR1&=~(1<<0);               //关闭定时器7                    printf("timer7 close!\r\n");
}  

3. esp8266模块:

3.1 esp8266模块了解:

模块支持 STA/AP/STA+AP 三种工作模式。
STA模式:通过路由器连接上网,可以理解为手机连接WiFi热点;
AP模式  :模块作为热点;
STA+AP:以上两种模式共存,即可通过路由器连接到互联网,也可以作为WiFi热点。
在三个模式下,又有TCP服务端、客户端和UDP。

3.2 esp8266软件实现:

cmd_send发送函数中配置好指令、应答和等待时间即可,指令后需要加“\r\n”结束,在等待时间内收到正确应答,则跳出等待。


/************************  接收应答检测  *******************************/
uint8_t esp8266_ack_check(char *Cmd ,char *Str)
{char *str = NULL;USART3_RX_BUF[USART3_RX_STA & 0x7fff] = 0 ;     //添加结束符str = strstr((const char*)USART3_RX_BUF,(const char*)Str);if(str != NULL){printf("AT_CMD : %s\t ACK : %s\r\n",Cmd,str);return 0;     }else{printf("ack error!\r\n");}return 1;
}/************************  发送指令  *******************************/
uint8_t esp8266_at_cmd_send(char *CMD ,char *ACK , uint16_t timeout)
{uint8_t res = 0 ;USART3_RX_STA = 0 ;USART3_Send("%s\r\n",CMD);if(ACK && timeout){while (--timeout){rt_thread_mdelay(10);if(USART3_RX_STA & 0x8000){if(esp8266_ack_check(CMD,ACK)==0){USART3_RX_STA = 0 ;break;}              USART3_RX_STA = 0 ;}}if(timeout == 0)res = 1 ;}return res;
}
esp8266_data_send函数中,有些固件发送完数据后,会接收到“OK”应答,有些无应答,根据8266模块烧录的固件版本而定,自行修改。
/************************  发送数据  *******************************/
void esp8266_data_send(char *DATA)
{uint16_t timeout = 100;USART3_RX_STA = 0 ;USART3_Send("%s",DATA);  while (--timeout){rt_thread_mdelay(10);if(USART3_RX_STA & 0x8000){if(esp8266_ack_check("NONE","OK")==0){USART3_RX_STA = 0 ;break;}                USART3_RX_STA = 0 ;}}
}
        在透传状态下发送“+++”,即可退出透传模式, 进入 AT 模式。
/************************  退出透传  *******************************/
uint8_t esp8266_quit_trans(void)
{while((USART3->ISR&0X40)==0);USART3->TDR='+';      rt_thread_mdelay(15);while((USART3->ISR&0X40)==0); USART3->TDR='+';      rt_thread_mdelay(15);              while((USART3->ISR&0X40)==0);USART3->TDR='+';      rt_thread_mdelay(500);return esp8266_at_cmd_send("AT","OK",20);
}

另外对STA、AP模式的配置进行了简单的封装,代码就不一一贴出来了。

/************************  AP-TCP-SERVER配置  *******************************/
void esp8266_ap_tcp_server(char *SSID , char *PWD , uint8_t CH , uint8_t ECN , char *portnum)
{char *pt = (char *)rt_malloc(50);esp8266_at_cmd_send("AT+CWMODE=2","OK",50);esp8266_at_cmd_send("AT+RST","OK",50);rt_thread_mdelay(2000);sprintf(pt,"AT+CWSAP=\"%s\",\"%s\",%d,%d",SSID, PWD, CH, ECN);printf("AP-TCP_SERVER: %s\r\n",pt);esp8266_at_cmd_send(pt,"OK",200); esp8266_at_cmd_send("AT+CIPMUX=1","OK",50);sprintf(pt,"AT+CIPSERVER=1,%s", portnum);printf("AP-TCP_SERVER: %s\r\n",pt);esp8266_at_cmd_send(pt,"OK",100);if(pt != RT_NULL){rt_free((void *)pt);}
}/************************  AP-TCP-CLIENT配置  *******************************/
void esp8266_ap_tcp_client(char *SSID , char *PWD , uint8_t CH , uint8_t ECN , char * tcp_ip , char *portnum)
{char *pt = (char *)rt_malloc(50);esp8266_quit_trans();esp8266_at_cmd_send("AT+CWMODE=2","OK",50);esp8266_at_cmd_send("AT+RST","OK",200);rt_thread_mdelay(2000);sprintf(pt,"AT+CWSAP=\"%s\",\"%s\",%d,%d",SSID, PWD, CH, ECN);printf("AP-TCP_CLIENT: %s\r\n",pt);esp8266_at_cmd_send(pt,"OK",200);esp8266_at_cmd_send("AT+CIPMUX=0","OK",100);sprintf(pt,"AT+CIPSTART=\"TCP\",\"%s\",%s",tcp_ip, portnum);printf("AP-TCP_CLIENT: %s\r\n",pt);esp8266_at_cmd_send(pt,"CONNECTED",300);esp8266_at_cmd_send("AT+CIPMODE=1","OK",50);esp8266_at_cmd_send("AT+CIPSEND","OK",100);if(pt != RT_NULL){rt_free((void *)pt);}
}/************************  AP-UDP配置  *******************************/
void esp8266_ap_udp(char *SSID , char *PWD , uint8_t CH , uint8_t ECN , char * tcp_ip , char *portnum)
{char *pt = (char *)rt_malloc(50);esp8266_at_cmd_send("AT+CWMODE=2","OK",50);esp8266_at_cmd_send("AT+RST","OK",200);rt_thread_mdelay(2000);sprintf(pt,"AT+CWSAP=\"%s\",\"%s\",%d,%d",SSID, PWD, CH, ECN);printf("AP-UDP: %s\r\n",pt);esp8266_at_cmd_send(pt,"OK",200);esp8266_at_cmd_send("AT+CIPMUX=0","OK",100);sprintf(pt,"AT+CIPSTART=\"UDP\",\"%s\",%s",tcp_ip, portnum);printf("AP-UDP: %s\r\n",pt);esp8266_at_cmd_send(pt,"CONNECTED",300);    if(pt != RT_NULL){rt_free((void *)pt);}
}

4.通信测试:

创建一个esp8266测试线程和一个按键线程,按键用于发送数据。

4.1 esp8266测试线程:

对各模式进一步封装,方便调用,通过设置Esp_mode值切换模式。

enum ESP_Mode Esp_mode = AP_TCP_CLIENT_MODE;   //更改枚举值切换WIFI传输模式void esp8266_mode_select(uint8_t mode)
{switch (mode){case AP_TCP_SERVER_MODE:esp8266_ap_tcp_server("ATK8266","43218765", 1 , 4 ,"8086");break;case AP_TCP_CLIENT_MODE:esp8266_ap_tcp_client("ATK8266","43218765", 1 , 4 ,"192.168.4.2" ,"8086");break;case AP_UDP_MODE:esp8266_ap_udp("ATK8266","43218765", 1 , 4 ,"192.168.4.2" ,"8086");break;case STA_TCP_SERVER_MODE:esp8266_sta_tcp_server("OnePlus9R","13582467","8082");break;case STA_TCP_CLIENT_MODE:esp8266_sta_tcp_client("OnePlus9R","13582467","192.168.0.107","8082");break;case STA_UDP_MODE:esp8266_sta_udp("OnePlus9R","13582467","192.168.0.107","8082");break;default:break;}
}static void esp8266_test_thread(void *p)
{uart1_init(115200);usart3_init(4800);rt_thread_mdelay(500);esp8266_mode_select(Esp_mode);while(1){printf("hello\r\n");rt_thread_mdelay(2000);}}

4.2 按键线程:

void key_handler()
{if(key_pin == KEY_UP){esp8266_at_cmd_send("AT+CIPSEND","OK",20);LED_0(0);}else if(key_pin == KEY_0){if((Esp_mode == 0)||(Esp_mode == 3))esp8266_server_data_send("1.stm32f7-esp8266");else if((Esp_mode == 1)||(Esp_mode == 4))esp8266_client_data_send("2.stm32f7-esp8266");elseesp8266_UDP_data_send("3.stm32f7-esp8266");}else if(key_pin == KEY_1){esp8266_quit_trans();LED_0(1);}key_pin = 0 ;
}static void key_thread(void *p)
{LED_Init(); KEY_Init();#ifdef KEY_SEM  key_sem = rt_sem_create("keysem", 0, RT_IPC_FLAG_PRIO);if(key_sem == RT_NULL)printf("key_sem creat failed!\r\n");elseprintf("key_sem creat ok!\r\n");
#endifwhile(1){while(rt_sem_trytake(key_sem) != RT_EOK){rt_thread_mdelay(10);}printf("key_thread : key_sem take.\r\n");key_handler();}}

4.3 测试结果:

软件配置模块模式为AP-TCP客户端;手机连接模块热点,APP网络调试助手配置成TCP服务端,设置好端口号;然后进行数据收发测试,开发板上按KEY0键发送数据,结果如下:

第二篇:STM32F7 + RT-Thread + ESP8266相关推荐

  1. 第二篇 在Arduino IED环境下测试ESP8266模块与外网通信

    这是通过使用ESP8266模块实现Android客户端控制Arduino板载LED闪烁的第二篇 如果你还没搭建起来编译环境请阅读第一篇相关操作 因为最近工作忙到要死,拖了一周才有空来继续写完,还请见谅 ...

  2. Python之路【第二篇】:Python基础(一)

    Python之路[第二篇]:Python基础(一) 入门知识拾遗 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 1 2 3 if 1==1:     name ...

  3. Android 进阶第二篇——性能优化

    Android 进阶第二篇--性能优化 一些Android书籍喜欢把性能优化放在最后的章节,简单提一提作为内容全面的点缀.在这里我将工具使用和性能优化的一些个人经验放在进阶系列博客的开始,因为我认为防 ...

  4. Java并发编程|第二篇:线程生命周期

    文章目录 系列文章 1.线程的状态 2.线程生命周期 3.状态测试代码 4.线程终止 4.1 线程执行完成 4.2 interrupt 5.线程复位 5.1interrupted 5.2抛出异常 6. ...

  5. Tessent专栏第二篇:Tessent Shell ETChecker介绍(1续)

    系列文章目录 前言 1. Tessent Shell ETChecker与传统ETChecker的对比 1.1 工具比较 1.1.1 TS-ETChecker支持的功能 1.1.2 TS-ETChec ...

  6. 看山聊并发:如果非要在多线程中使用 ArrayList 会发生什么?(第二篇)

    你好,我是看山. 前面写过一篇文章 <如果非要在多线程中使用 ArrayList 会发生什么?>,有读者反馈,Java 11 代码已经修复,还会出现 null 元素. 为了便于理解,当时只 ...

  7. Django框架之第二篇

    Django框架之第二篇 一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中). view ...

  8. java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...

    23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...

  9. 深入理解javascript函数系列第二篇——函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...

  10. Spotify敏捷模式详解三部曲第二篇:研发过程

    本文转自:Scrum 中文网 引言 在本系列文章的第一篇,我们介绍了Spotify的敏捷研发团队,以及它独特的组织架构.Spotify的研发团队采用的是一种非常独特的组织架构,如下图所示: 整个研发组 ...

最新文章

  1. PostgreSQL在何处处理 sql查询之五十二
  2. 【Linux】时间戳与正常日期
  3. sklearn自学指南(part56)--朴素贝叶斯
  4. MEGA | 多序列比对及系统发育树的构建
  5. 语义分割论文阅读:FCN、PSPNet、DDRNet、BiseNet、BiseNetV2、deeplabv3
  6. mysql5.7 设置远程访问
  7. 秋意来袭,这些清新促销海报不容错过!
  8. CFS完全公平调度类
  9. 《Java练习题》Java编程题合集(转载)
  10. 下载网页中的html5视频之手动方法
  11. IT服务及相关概念界定
  12. boost入门(三):Asio简单示例
  13. 液晶12864显示图片
  14. adb命令——adb命令大全
  15. 基于java+SpringBoot+HTML+MySQL精准扶贫网站的设计与实现
  16. Python游戏开发,Python实现贪吃蛇小游戏与吃豆豆 附带源码
  17. foc学习笔记1——准备工作
  18. LENOVO ERAZER Z51 安装固态指南
  19. iOS开发-Umeng第三方登录-个人整理
  20. linux opencv 人脸识别,iOS下 基于OpenCV实现的人脸识别匹配

热门文章

  1. exe制作成安装包,Inno Setup软件使用教程
  2. cout与printf区别
  3. qq消息定时自动发送的简单实现策略
  4. BUUCTF WEB PIAPIAPIA1
  5. BUU刷题记录-[0CTF 2016]piapiapia
  6. 梦幻西游网页版服务器,服务器荣辱战,《梦幻西游网页版》梦幻攻防战“挖矿人”经验来啦...
  7. 七夕表白攻略:程序员的代码情书
  8. 计算机基础知识整理--概述
  9. [大学物理实验-0]修约规则和常见的实验数据的处理
  10. PS非主流照片文字合成表现手法