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

STM32-笔记30-串口间的通信

一、前期准备

        本次实现串口间的正常通信,主要是为了后面的编程实现ESP8266的联网功能,在此之前需要检验两个串口之间是否可以正常通信,

串口1:是用来接收串口2中打印的日志-当给ESP8266输入AT指令之后,打印出的结果显示。

串口2:用来接后续的ESP8266-实现单片机通过串口2传递AT代码信息给ESP8266,ESP8266解析AT执行把结果日志通过串口2传递给串口1。

        检验两个串口间是否可以正常通信,使用两个USB转TTL用杜邦线和STM32连接,两个USB连接电脑,电脑上的两个串口助手分别与其相连接。

现在我们先实现一下串口间的通信:串口2模拟输入AT执行,串口1模拟打印对应AT指令的日志。

        在前面我们写过两种代码,一种是串口实现不定长数据的收发(接收中断)和另一种是串口实现不定长数据的收发(空闲中断),空闲中断并不是所有的STM32都有的,所有这里我们使用接收中断的方式,来实现串口间的通信。

二、项目实现

复制19-串口打印功能

重命名为34-ESP8266串口间的通信

的uart1文件夹复制粘贴到

重命名uart为esp8266

打开工程文件

加载文件

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.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(115200);
   // printf("hello word!\r\n");
    

    while(1)
    { 
        //esp8266_receive_data();
        esp8266_test();
        delay_ms(10);
    }
}

esp8266.c

#include "sys.h"
#include "esp8266.h"
#include "string.h"
#include "stdio.h"
#include "delay.h"

uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];//定义一个数组,用来保存接收的数据
uint16_t esp8266_cnt = 0,esp8266_cntPre = 0; //定义一个计数器,和保存计数器原本状态的变量


UART_HandleTypeDef esp8266_handle = {0};

void esp8266_uart_init(uint32_t baudrate)
{
    esp8266_handle.Instance = USART2;
    esp8266_handle.Init.BaudRate = baudrate;  //波特率
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;//收发模式;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;//无校验位
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;  //字长:8个字长
    esp8266_handle.Init.StopBits = UART_STOPBITS_1; //停止位:1个停止位
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
    
    HAL_UART_Init(&esp8266_handle);
}

void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle,UART_FLAG_RXNE) != RESET)//关注RXNE这个标志位的值是不是不为reset(0)
    {
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))//如果接收的字符长度大于字符缓冲区的长度,则把缓冲区长度置0
            esp8266_cnt = 0;
        //如果RXNE的值为1,证明有数据,所以需要接收数据
        HAL_UART_Receive(&esp8266_handle,&receive_data,1,1000);//句柄,接收的数据存放在哪?接收数据的个数,超时时间
        esp8266_rx_buf[esp8266_cnt++] = receive_data;//将接收的数据存放在esp8266rx_buf数组中
        
        //HAL_UART_Transmit(&esp8266_handle,&receive_data,1,1000);//发送数据:句柄,要发送的数据,发送数据的长度,超时
    }
}
//这个函数主要用来判断esp8266cnt有没有动,如果没有动证明接收完成了
uint8_t esp8266_wait_receive(void)
{
    if(esp8266_cnt == 0)//如果cnt为0证明,出现了错误
        return ESP8266_ERROR;//出现错误
    if(esp8266_cnt == esp8266_cntPre)//判断当前cnt和上一个cnt是否一致,如果是一致的证明数据不动了,传输完成
    {
        esp8266_cnt = 0;//cnt清0
        return ESP8266_EOK;//数据接收完成
    }
    esp8266_cntPre = esp8266_cnt;//把当前计数器cnt的值赋给之前计数器
    return ESP8266_ERROR;//
     
}
//把接收寄存器的内容清空
void esp8266_rx_clear(void)
{
    //把接收缓冲器清空
    memset(esp8266_rx_buf,0,sizeof(esp8266_rx_buf));
    //清空长度
    esp8266_cnt = 0;
}
测试函数-这个函数在while循环里,来一直判断当前数据是否接收完
//void esp8266_receive_data(void)
//{
//    if(esp8266_wait_receive() == ESP8266_EOK)//判断数据是否接受完整
//    {
//        printf("esp8266 recv: %s\r\n",esp8266_rx_buf);//接收完整,打印数据
//        esp8266_rx_clear();//清除当前接收
//    }
//}
void esp8266_init(uint32_t baudrate)
{
    //esp8266串口初始化
    esp8266_uart_init(baudrate);
    //esp8266的其他初始化
}
//定义一个发送指令函数,cmd是发送的指令,res是期待的返回值,对应指令接收的日志
uint8_t esp8266_send_command(char *cmd,char *res)
{
    uint8_t time_out = 250;
    esp8266_rx_clear();//把接收缓冲区的内容清空
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);//发送的库函数:句柄,要发生的内容,内容的长度,阻塞的值
    
    //一共等待2.5s的时间,每一次等待10ms
    while(time_out--)
    {
        if(esp8266_wait_receive() == ESP8266_EOK)//表示已经接收到数据
        {
            if(strstr((const char*)esp8266_rx_buf,res) != NULL)//判断接收到的数据里面有没有我们想要的数据
                return ESP8266_EOK;
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
}
//定义一个临时的函数,用来测试,判断发送一个指令回应的函数是否正确
void esp8266_test(void)
{
    if(esp8266_send_command("AT","OK") == ESP8266_EOK)
        printf("esp8266 test:%s\r\n",esp8266_rx_buf);
}












esp8266.h

#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "sys.h"

#define ESP8266_RX_BUF_SIZE 128 //接收的长度
#define ESP8266_TX_BUF_SIZE 64 //发送的长度

#define ESP8266_EOK        0//宏定义错误代码 ok
#define ESP8266_ERROR      1//错误
#define ESP8266_ETIMEOUT   2//超时
#define ESP8266_EINVAL     3//数据非法

void esp8266_init(uint32_t baudrate);
void esp8266_receive_data(void);

#endif


三、学程序一定要会写流程图

初始化函数流程图

在while中调用的函数流程图


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

相关文章:

  • 人工智能的发展领域之GPU加速计算的应用概述、架构介绍与教学过程
  • 《鸿蒙微内核与人工智能算法协同,开启智能系统新时代》
  • Java SpringBoot使用EasyExcel导入导出Excel文件
  • touch详讲
  • 在环境冲突情况下调整优先级以解决ROS Catkin构建中缺少模块的问题【ubuntu20.04】
  • 手机租赁平台开发实用指南与市场趋势分析
  • python常见绘图及代码
  • 技术文档撰写之道:构建清晰准确的知识传递桥梁
  • 【Java设计模式-1】单例模式,Java世界的“独苗”
  • C++中decltype遇到引用类型时的隐藏陷阱
  • 算法解析-经典150(矩阵、哈希表)
  • Redis - 6 ( 9000 字 Redis 入门级教程 )
  • 【快速入门 LVGL】-- 1、STM32 工程移植 LVGL
  • 深入了解SCPI协议:半导体测试与仪器自动化的核心
  • C语言——字符函数和内存函数
  • pikachu靶场--目录遍历和敏感信息泄露
  • 概率基本概念 --- 离散型随机变量实例
  • NLP 中文拼写检测纠正论文-08-Combining ResNet and Transformer
  • React Router 向路由组件传state参数浏览器回退历史页面显示效果问题
  • Vue.js组件开发-在setup函数中使用provide
  • 41.5 nginx拦截prometheus查询请求使用lua脚本做promql的检查替换
  • 少儿编程|基于SSM+vue的少儿编程管理系统的设计与实现(源码+数据库+文档)
  • 云计算中的可用性SLA
  • Flutter 如何编写 Dart CLI应用程序
  • react 封装一个类函数使用方法
  • 【微服务】4、服务保护