使用esp8266实现STM32联网(最简单USART方法)

上一篇

esp8266怎么配置
    esp8266和USB转TTL连接
esp8266简单介绍
esp8266连接路由器
esp8266通过路由器连接在同一局域网中的电脑,建立TCP连接
esp8266使用串口发送数据到电脑上的网络调试助手
esp8266使用串口通过局域网发送到电脑上自己写的Java程序
esp8266的透传模式
esp8266使用透传模式连接到电脑的网络调试助手
esp8266使用透传模式连接到电脑上的java程序

这一篇

esp8266与STM32连接,电脑通过STM32配置esp8266实现联网发送数据
具体流程如下图
2=

esp8266怎么和STM32连接(引脚连接)?

STM32CubeMx配置的usart2使用的PA2和PA3要与esp8266的TX和RX对应,但是得反过来接,要么根本发不出去,看来esp8266又印反了
3V3和EN得接到同一个3V上才可以,要不收到的老是error

STM32使用USART和电脑相互传输数据?

将STM32产生的数据发送到电脑的串口调试助手
    第一种方式:
        使用UASRT传输只需要重新定义fputc()函数,直接使用Printf函数就可以将字符串打印到电脑(即通过串口输出到电脑)
    第二种方式:
        使用HAL库中封装好的UASART函数  HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)也可以实现串口输出
电脑要发送字符串给STM32,那么STM32怎么收到数据,而且知道这个数据什么意思呢?
    第一种方式(只能接收定长字符串):
        HAL库依旧有封装好的函数HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),但是使用这个函数有一个问题,这个函数的额第三个参数是收到的字符串的大小,可是我都没有发送,怎么提前把这个字符串的大小写入单片机呢?
            其实问题是STM32如何接收不定长的字符串?
        【STM32内部产生的数据或者从传感器中获取的数据,STM32如果要发送该数据可以直接使用sizeof获得数据长度作为第三个参数,但是当人为的发送给串口时,由于提前烧入的程序如果要使用HAL库的USART接收函数的话,需要确定一个字符串长度,那么这个程序就只能接收指定长度的字符串了,那要如何实现不定长也能接收呢?】
    第二种方式:
        DMA+接收结束判断。这接收结束判断可以是字节的timeout,也可以是USART_IT_IDLE线路空闲的标志等。这种方式对于需要整帧接收,且通信速度较快或需要占用cpu较少的情况
        【详细的处理方式可见串口USART 收发数据处理方式总结--DMA+USART+USART_Idle_Interrupt】

那么如何配置呢?

        既然是DMA和空闲接收中断就需要设置DMA和UASRT的中断(即在中断处理函数中需要有DMA1 channel5 global interrupt和USART1 global interrupt)
        
        如果要使用printf输出到串口的话,就需要重定义fputc函数(定义在usart.c中)
        
        如果要用线路空闲来触发中断来结束接收的话,需要有判断线路是否空闲的函数,这个函数最好还需要在结束接收时将收到的数据保存到自己定义的变量中

那么如何实现不定长接收呢,不还是得知道接受的字符串的长度吗?

    是需要知道,这里使用一个结构体来保存字符串和字符串的长度以及一个标记(用来表示一次接收完成,如果不放在结构体里面,使用全局变量的话会比较麻烦)
    具体的方法是这样的:在一开始接收的时候,将收到的字符串保存在结构体中的字符串数组中,而函数要求的大小这个参数设置为比较大的数字(可以是一次接收数据长度的最大值,这里是1024),在判断线路是否空闲的函数中,当线路空闲时(即一次接收完成时),将收到的字符串的长度保存到这个结构体中的字符串长度变量中,这样,当需要将收到的字符串再次发出时,就可以使用已知的长度进行发送了,由此实现了不定长接收。
    【其原理其实是用一个大空间去接收(看来接收空间够大就行,不需要定长接收),在接收完成时计算收到的数据长度保存起来(和收到的数据要一一对应,这也是使用结构体的好处),当需要再次发送出去时,就知道这个字符串的长度了,就可以定长发送了】
    
    结构体
        #define RX_LEN 1024  
             
        typedef struct  
        {  
        uint8_t  RX_flag:1;        //IDLE receive flag
        uint16_t RX_Size;          //receive length
        uint8_t  RX_pData[RX_LEN]; //DMA receive buffer
        }USART_RECEIVETYPE; 
        
        extern USART_RECEIVETYPE UsartType;
        
下面是程序的流程
    
    首先在main函数中使用HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN); 开始接收,接收的数据放到结构体中,长度为最大值
    然后打开中断,__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);这个函数进行中断使能,
    
    具体介绍:
    /** @brief  Enable the specified UART interrupt.
    * @param  __HANDLE__: specifies the UART Handle.
    *         UART Handle selects the USARTx or UARTy peripheral 
    *         (USART,UART availability and x,y values depending on device).
    * @param  __INTERRUPT__: specifies the UART interrupt source to enable.
    *          This parameter can be one of the following values:
    *            @arg UART_IT_CTS:  CTS change interrupt
    *            @arg UART_IT_LBD:  LIN Break detection interrupt
    *            @arg UART_IT_TXE:  Transmit Data Register empty interrupt
    *            @arg UART_IT_TC:   Transmission complete interrupt
    *            @arg UART_IT_RXNE: Receive Data register not empty interrupt
    *            @arg UART_IT_IDLE: Idle line detection interrupt
    *            @arg UART_IT_PE:   Parity Error interrupt
    *            @arg UART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)
        * @retval None
        * */
            #define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)
    之后是否需要延时防止接收不到或者防止其他错误的发生不是很清楚。
    
    在stm32f1xx_it.c的DMA和USART的中断函数中并没有需要重写的回调函数
    
    在usart.c中实现处理空闲的函数添加到USART的中断函数中,那么当线路产生空闲时,就会触发一个中断,这个空闲处理的函数,就会开始工作,先清空空闲标志以允许继续接收,然后使用HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)停止此次接收,接着获得此次接收到的字符串的长度(这里比较深入,有寄存器的问题,不大理解),然后又调用了HAL_UART_Receive_DMA,这个应该和取得的长度是同一个结构体,那么之前的HAL_UART_Receive_DMA又是再干什么呢?(或许是为了解决第一次的传输问题,学的不够深入,还需要学的再深入)
    最后就可以使用获得的长度和字符串将收到的字符串发送出去了,这样就实现了不定长接收。
    
【问题】在结构体中定义的是一个uint8_t类型的数组,那么可以按字符串输出吗?

        可以,
        HAL_UART_Transmit(&huart1, UsartType.RX_pData, UsartType.RX_Size, 0xFFFF);
        printf("\n%s\n",UsartType.RX_pData);
        上面两句一样的效果
    具体代码:
        在usart.c中添加
            /* USER CODE BEGIN 1 */
            /**
              * @brief  Retargets the C library printf function to the USART.
              */
            int fputc(int ch,FILE *f)
            {
                HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
                return ch;
            }
            
            /**
              * @brief  This function handles USART1 IDLE interrupt.
              */
            void UsartReceive_IDLE(UART_HandleTypeDef *huart)  
            {  
                uint32_t temp;  
              
                if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))  
                {   
                    __HAL_UART_CLEAR_IDLEFLAG(&huart1);  
                    HAL_UART_DMAStop(&huart1);  
                    temp = huart1.hdmarx->Instance->CNDTR;  
                    UsartType.RX_Size =  RX_LEN - temp;   
                    UsartType.RX_flag=1;  
                    HAL_UART_Receive_DMA(&huart1,UsartType.RX_pData,RX_LEN);  
                }  
            }  
            /* USER CODE END 1 */
    在usart.c中实例化结构体
            /* USER CODE BEGIN 0 */
            USART_RECEIVETYPE UsartType; 
            /* USER CODE END 0 */
            
    在usart.h中定义结构体
            /* USER CODE BEGIN Private defines */
            #define RX_LEN 1024  
                 
            typedef struct  
            {  
            uint8_t  RX_flag:1;        //IDLE receive flag
            uint16_t RX_Size;          //receive length
            uint8_t  RX_pData[RX_LEN]; //DMA receive buffer
            }USART_RECEIVETYPE;  
               
            extern USART_RECEIVETYPE UsartType; 
            /* USER CODE END Private defines */
    在stm32f1xx_it.c的中断函数中添加
            void USART1_IRQHandler(void)
            {
              /* USER CODE BEGIN USART1_IRQn 0 */
                UsartReceive_IDLE(&huart1);  
              /* USER CODE END USART1_IRQn 0 */
              HAL_UART_IRQHandler(&huart1);
              /* USER CODE BEGIN USART1_IRQn 1 */
            
              /* USER CODE END USART1_IRQn 1 */
            }
    在main.c中main函数中基本的初始化函数后添加
              /* USER CODE BEGIN 2 */
                HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN);  
                __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 
                HAL_Delay(1000);
              /* USER CODE END 2 */

STM32如何给esp8266发送AT指令?

途径就为通过串口
那么怎么使用串口,
    是直接使用HAL库封装的相关函数
    还是需要一些驱动代码
电脑通过串口与STM32交流,STM32通过串口与esp8266交流
    既然上面实现了电脑与STM32使用USART相互传输数据,即STM32可以接收电脑发来的不定长数据,那么STM32也能接收esp8266返回的不定长数据(向esp8266发送不同的指令,返回消息不一样,长度也不一样)

对于接收esp8266返回的信息也使用DMA加空闲中断的方式,那么向esp8266发送数据要怎么做呢?

        上面的代码已经可以接收来自电脑的不定长消息,然后再发给电脑,那么将这个消息直接发送给esp8266就可以了,两个不同的串口有不同的实例,只需要指定好串口就可以向这个串口发送数据了。【突然觉得自己写的好乱,没有条理,得改】
    其实具体的代码就是在什么那个处理STM2与电脑使用USART通信的代码上再增加一个STM与esp8266的USART交流流程就可以了,需要注意区分不同的串口,两个流程的交汇点在main函数中,当STM32收到电脑发来的不定长信息后,通过空闲中断处理函数获得长度,将该消息直接使用串口发送到连接esp8266的串口即可,如果STM32收到来自esp8266串口的消息,一样使用DMA加空闲中断的方式获得来自esp8266的不定长返回信息,在这里也是一样通过这个串口的空闲中断处理函数获得返回信息的长度,将这个返回信息发送给与电脑相连的串口就可以了,这样就完成了通过STM32配置esp8266的整个流程。

其意义是什么呢?

    这样STM32本身就可以使用串口将获取的传感器信息通过esp8266发送到指定服务器,实现了STM32的联网,一样也实现了通过网络向STM32发送指令控制传感器的功能。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容