STM32F103C8T6第4天:串口实验(非中断和中断)、hc01蓝牙、esp8266WIFI、4g

news2024/10/6 20:31:27

1. 串口基本介绍(332.36)

常用函数介绍

串口发送/接收函数:

  • HAL_UART_Transmit(); 串口发送数据,使用超时管理机制
  • HAL_UART_Receive(); 串口接收数据,使用超时管理机制
  • HAL_UART_Transmit_IT(); 串口中断模式发送
  • HAL_UART_Receive_IT(); 串口中断模式接收
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,
      uint8_t *pData, uint16_t Size, uint32_t Timeout)

作用:以阻塞的方式发送指定字节的数据

  • 形参 1 :UART_HandleTypeDef 结构体类型指针变量
  • 形参 2:指向要发送的数据地址
  • 形参 3:要发送的数据大小,以字节为单位
  • 形参 4:设置的超时时间,以ms单位
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
      uint8_t *pData, uint16_t Size)

作用:以中断的方式接收指定字节的数据

  • 形参 1 是 UART_HandleTypeDef 结构体类型指针变量
  • 形参 2 是指向接收数据缓冲区
  • 形参 3 是要接收的数据大小,以字节为单位

此函数执行完后将清除中断,需要再次调用以重新开启中断。

串口中断回调函数:

  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart); //串口中断处理函数
  • HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); //发送中断回调函数
  • HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); //接收中断回调函数

状态标记变量:

  • USART_RX_STA(符合变量的命名规则下 可重新命名):
    • 从 0 开始,串口中断接收到一个数据(一个字节)就自增 1。当数据读取全部 OK 时候(回车和换行符号来的时
      候),那么 USART_RX_STA 的最高位置 1,表示串口数据接收全部完毕了,然后 main 函数里面可以处理数据
      了。
      在这里插入图片描述

串口接收中断流程

在这里插入图片描述

2. 串口实验 (非中断)(333.37)

  • 需求: 接受串口工具发送的字符串,并将其发送回串口工具。
  • 硬件接线:
    • TX – A10
    • RX – A9
    • gnd – gnd (5v 实测可以不接)
      一定要记得交叉接线!!
  • 串口配置:
  1. 选定串口
    在这里插入图片描述
  2. 选择模式(异步通讯)
    在这里插入图片描述
  3. 串口配置
    在这里插入图片描述
  4. 使用MicroLIB库
    从魔术棒打开,这个勾勾一定要打上,否则 printf 无法重映射!
    在这里插入图片描述
  • STM32CubeMx工程配置
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 串口调试助手的一些设置
    在这里插入图片描述
    在这里插入图片描述
  • 代码(11.uart1_test/MDK-ARM)
#include <stdio.h>
#include <string.h>
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}
int main(void)
{
	unsigned char ch[20] = {0};//char(acter)
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();//串口初始化
	HAL_UART_Transmit(&huart1, (uint8_t *) "hello world\n", strlen("hello world\n"), 100);//超时100
  while (1)
  {
		HAL_UART_Receive(&huart1, ch, 19, 100);//有\0所以要20-1
		//HAL_UART_Transmit(&huart1, ch, strlen((const char *)ch), 100);
		printf("%s", ch);//printf重定向(串口输出)
		memset(ch, 0, strlen((const char *)ch));//清空
  }
}

3. 串口实验 (中断)(334.38)

  • 需求: 通过中断的方法接受串口工具发送的字符串,并将其发送回串口工具。
  • 硬件接线:(同上)
    • TX – A10
    • RX – A9
    • gnd – gnd (5v 实测可以不接)
      一定要记得交叉接线!!
  • 串口配置:
    前4步同上
  1. 打开中断
    在这里插入图片描述
  • 代码(12.uart2_test/MDK-ARM)
#include <stdio.h>
//串口接收缓存(1字节)
uint8_t buf=0;
//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200
// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];
// 接收状态
// bit15,   接收完成标志
// bit14,   接收到0x0d
// bit13~0,  接收到的有效字节数目
uint16_t UART1_RX_STA = 0;
// 接收完成(一个字节)回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  // 判断中断是由哪个串口触发的
  if(huart->Instance == USART1)
 {
    // 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
    if((UART1_RX_STA & 0x8000) == 0)//如果不是1即没有接收完成
   {
      // 如果已经收到了 0x0d (回车),
      if(UART1_RX_STA & 0x4000)
     {
        // 则接着判断是否收到 0x0a (换行)
        if(buf == 0x0a)
          // 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
          UART1_RX_STA |= 0x8000;
        else
          // 否则认为接收错误,重新开始
          UART1_RX_STA = 0;
     }
      else   // 如果没有收到了 0x0d (回车)
     {
        //则先判断收到的这个字符是否是 0x0d (回车)
        if(buf == 0x0d)
       {
          // 是的话则将 bit14 位置为1
          UART1_RX_STA |= 0x4000;
       }
        else
       {
          // 否则将接收到的数据保存在缓存数组里
          UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
          UART1_RX_STA++;
          // 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
          if(UART1_RX_STA > UART1_REC_LEN - 1)
            UART1_RX_STA = 0;
       }
     }
   }
    // 重新开启中断
    HAL_UART_Receive_IT(&huart1, &buf, 1);
 }
}
int fputc(int ch, FILE *f)//printf重定向(串口输出)
{   
  unsigned char temp[1]={ch};
  HAL_UART_Transmit(&huart1,temp,1,0xffff); 
  return ch;
}
int main()
{
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
    MX_USART1_UART_Init();

	HAL_UART_Receive_IT(&huart1, &buf, 1);
	while (1)
	{
	/* USER CODE END WHILE */
	/* USER CODE BEGIN 3 */
	  //判断判断串口是否接收完成
	  if(UART1_RX_STA & 0x8000)
	 {
	    printf("收到数据:");
	    // 将收到的数据发送到串口
	    HAL_UART_Transmit(&huart1, UART1_RX_Buffer, UART1_RX_STA & 0x3fff, 0xffff);
	    // 等待发送完成
	    while(huart1.gState != HAL_UART_STATE_READY);
	    printf("\r\n");
	    // 重新开始下一次接收
	    UART1_RX_STA = 0;
	 }
	 printf("Hello Jessie!\r\n");
	 HAL_Delay(2000);//每两秒检测一次
	}
}

4. 蓝牙插座_风扇_灯(非中断)(335.39)

项目需求

  • 通过蓝牙模块,实现手机控制蓝牙插座/风扇/灯。
  • 本质:
  1. 采用蓝牙的透传功能;
  2. 控制 IO 口的输出。

项目框图

在这里插入图片描述

硬件清单

  • HC01 蓝牙模块
  • CH340 USB串口工具
  • 杜邦线

项目设计

  • HC01_TX – RX1(A10)
  • HC01_RX – TX1(A9)
  • gnd – gnd (5v 实测可以不接)

项目实现(串口非中断法)

  • STM32CubeMx工程配置(串口非中断法)
    • 第2节基础之上 设置gpio口
      在这里插入图片描述
  • 代码(13.bluetooth_led_project1/MDK-ARM)
while (1)
  {
		HAL_UART_Receive(&huart1, ch, 19, 100);//有\0所以要20-1
		//HAL_UART_Transmit(&huart1, ch, strlen((const char *)ch), 100);
		printf("%s", ch);//printf重定向(串口输出)
		if(!strcmp((char *)ch, "open"))//字符串比较 相等返回0
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//点亮
			if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET)//进一步判断
				printf("LED1已打开\r\n");
		}
		else if (!strcmp((char *)ch, "close"))
		{
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭
			if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET)
				printf("LED1已关闭\r\n");
		}
		else
		{//如果不是以上指令
			if(ch[0] != '\0')
				printf("指令发送错误:%s\r\n", ch);
		}
		memset(ch, 0, strlen((char *)ch));//清空
  }

在这里插入图片描述

5. 蓝牙插座_风扇_灯(中断)(334.40)

  • 蓝牙的波特率是9600
    在这里插入图片描述
  • 代码(14.bluetooth_led_project2/MDK-ARM)
while (1)
  {
		//判断判断串口是否接收完成
		if(UART1_RX_STA & 0x8000)
		{
			printf("收到数据:");
			// 将收到的数据发送到串口
			HAL_UART_Transmit(&huart1, UART1_RX_Buffer, UART1_RX_STA & 0x3fff, 0xffff);
			// 等待发送完成
			while(huart1.gState != HAL_UART_STATE_READY);
			printf("\r\n");
			if(!strcmp((char *)UART1_RX_Buffer, "open"))//字符串比较 相等返回0
			{
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//点亮
				if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET)//进一步判断
					printf("LED1已打开\r\n");
			}
			else if (!strcmp((char *)UART1_RX_Buffer, "close"))
			{
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//熄灭
				if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET)
					printf("LED1已关闭\r\n");
			}
			else
			{//如果不是以上指令
				if(UART1_RX_Buffer[0] != '\0')
					printf("指令发送错误:%s\r\n", UART1_RX_Buffer);
			}
			memset(UART1_RX_Buffer, 0, strlen((char *)UART1_RX_Buffer));//清空
			// 重新开始下一次接收
			UART1_RX_STA = 0;
		}
		//printf("Hello Jessie!\r\n");
		HAL_Delay(40);
  }
}

在这里插入图片描述
在这里插入图片描述

6. WiFi插座_风扇_灯(项目概述)(337.41)

项目需求

  • 通过ESP8266模块,实现手机控制wifi插座/风扇/灯。

项目框图

在这里插入图片描述

硬件清单

  • ESP8266 WIFI模块
  • CH340 USB串口工具
  • 杜邦线

项目设计

在这里插入图片描述

  • 串口1用于与ESP8266通讯,串口2连接PC,用于打印log,查看系统状态。

项目实现

  • 注意:
  1. 工作中一般不直接在中断服务函数里处理数据,而是在收到数据后直接丢给队列,再处理数据;
  2. 在中断服务函数里尽量减少使用延时函数及打印函数。

7. ESP工作为AP路由模式并当成服务器(338.42)

  • 基于uart2_test:
    在这里插入图片描述
    在这里插入图片描述
  • 代码(15.wifi_led_project1/MDK-ARM)(AP模式)

8. 上官二号当路由和服务器模式控制(339.43)

  • STA模式
    在这里插入图片描述
    在这里插入图片描述
  • 代码(16.wifi_led_project2/MDK-ARM)(STA模式)

9. 上官二号通过4g模块控制LED(340.44)

项目需求

  • 通过4G模块,实现电脑控制插座/风扇/灯。

项目框图

在这里插入图片描述

  • 注意: 由于硬件的限制,上官二号无法直接带动 4G 模块,可以将 4G 模块的 VCC 和 GND 插到 CH340 的 5V 和GND 里。

硬件清单

  • 4G模块
  • CH340
  • 杜邦线

项目设计

  1. 服务器搭建:参照C51课程;
  2. 代码修改:直接复用上节课的代码,把不相关的代码删除即可

4g – USB.ttl:配置4g模块的波特率、心跳包、内网穿透ip连接

  1. 先建立一个服务器
    在这里插入图片描述
  2. 利用花生壳软件 内网穿透
    在这里插入图片描述
  3. 设置波特率(cubemx中的串口都是设置的115200 要保持一致)、设置心跳包内容和时间、让4g连接socket服务器(公网ip地址)
    在这里插入图片描述
  4. 观察到 一直在接收心跳包
    在这里插入图片描述

回到正题

  • 先测试 open、close 指令是否成功(结果:成功点亮和熄灭)
  • 注意:指令要换新行(shift+enter)
    在这里插入图片描述
  • 删除多余的代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 再次测试指令(结果:成功点亮和熄灭)
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214128.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

栈的三道oj【C++】

栈和队列的相关oj 最小栈思路解决代码 栈的压入弹出序列思路解决代码 逆波兰表达式思路&#xff1a;解决代码 这里就挑了三道题用来熟悉栈 最小栈 力扣链接 咱们已经是高贵的C使用者了&#xff0c;不用像C语言一样从头开始造轮子了 这里我们调用了stack后&#xff0c;就会发…

SMART PLC滑动平均值滤波(指针+FOR循环应用浮点数滤波)

SMART PLC滑动平均值滤波应用于单整型数据请查看下面文章链接: 【精选】S7-200 SMART PLC信号处理系列之滑动平均值滤波FB_smart200 滤波函数_RXXW_Dor的博客-CSDN博客文章浏览阅读1.5k次。PLC相关滤波算法,专栏有很多详细讲解这里不再赘述。滑动平均值滤波和算术平均值滤波…

halcon识别验证码,先训练后识别

识别验证码图片&#xff0c;使用halcon 21.05 下面代码识别准确率100% 目录 训练&#xff0c;图片打标签使用代码创建分类器&#xff1b;识别验证码&#xff0c;检验识别效果使用“助手”加载训练文件&#xff0c;加载训练分类器&#xff0c;察看收集的字符&#xff0c;训练识别…

创建数据透视表:根据表中一列作为分类的依据统计每个类别下不同子项数量cross_tab()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 创建数据透视表&#xff1a; 根据表中一列作为分类的依据 统计每个类别下不同子项数量 cross_tab() [太阳]选择题 关于以下代码的说法中正确的是? import pandas as pd data{A:[a1,a2,a1,a2,a…

StyleGAN:彻底改变生成对抗网络的艺术

一、介绍 多年来&#xff0c;人工智能领域取得了显着的进步&#xff0c;其中最令人兴奋的领域之一是生成模型的发展。这些模型旨在生成与人类创作没有区别的内容&#xff0c;例如图像和文本。其中&#xff0c;StyleGAN&#xff08;即风格生成对抗网络&#xff09;因其创建高度逼…

数据库概率 期末复习

第一章 绪论 概述 数据 定义&#xff1a;描述事物的符号记录 地位&#xff1a;数据库中存储的基本对象 数据的语义&#xff1a;数据的含义&#xff0c;数据与其语义是不可分的 数据库 定义&#xff1a;长期储存在计算机内、有组织的、可共享的大量数据的集合 特点&…

JSP 购物商城系统eclipse定制开发mysql数据库BS模式java编程servlet

一、源码特点 java 购物商城系统是一套完善的web设计系统 系统采用serlvetdaobean 模式开发&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模 式开发。开发环境为TOMCAT7.0,eclipse开发&#xff0c;数…

从0开始学习JavaScript--JavaScript 异步编程

在现代的Web开发中&#xff0c;异步编程变得愈发重要。随着用户期望的提高和网络应用的复杂性增加&#xff0c;有效地处理异步操作成为构建高性能、交互丰富的应用的关键。JavaScript作为一门单线程的语言&#xff0c;采用异步机制来处理并发任务&#xff0c;确保用户体验不受阻…

计算机网络五层协议的体系结构

计算机网络中两个端系统之间的通信太复杂&#xff0c;因此把需要问题分而治之&#xff0c;通过把一次通信过程中涉及的所有问题分层归类来进行研究和处理 体系结构是抽象的&#xff0c;实现是真正在运行的软件和硬件 1.实体、协议、服务和服务访问点 协议必须把所有不利条件和…

php实现选择排序法

选择排序法是一种简单的排序算法&#xff0c;其基本思想是每次从未排序的部分中选择最小&#xff08;或最大&#xff09;的元素&#xff0c;然后放到已排序部分的末尾。 以下是用PHP实现选择排序法的代码示例&#xff1a; <?php function selectionSort($arr) {$n count…

LeetCode - 26. 删除有序数组中的重复项 (C语言,快慢指针,配图)

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 ​​​​​​​ 思路一&#xff1a;快慢指针 在数组中&#xff0c;快慢指针就是两个整数下标&#xff0c;定义 fast 和 slow 这里我们从下标1开始&#xff08;下标0的数据就1个&#xff0c;没有重复项&…

RabbitMQ之延迟队列(万字总结,手把手教你学习延迟队列)

文章目录 一、延迟队列概念二、延迟队列使用场景三、RabbitMQ 中的 TTL1、队列设置 TTL2、消息设置 TTL3、两者的区别 四、整合 springboot1、添加依赖2、修改配置文件3、添加 Swagger 配置类 五、队列 TTL1、代码架构图2、配置文件类代码3、消息生产者代码4、消息消费者代码 六…

RT-Thread STM32F407 ADC

ADC(Analog-to-Digital Converter) 指模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号&#xff0c;例如温度、压力、声音或者图像等&#xff0c;需要转换成更容易储存、处理和发射的数字形式。模数转换器可以实现这个功能&#xff0c;在各…

如何解决网页中的pdf文件无法下载?pdf打印显示空白怎么办?

问题描述 偶然间&#xff0c;遇到这样一个问题&#xff0c;一个网页上的附件pdf想要下载打印下来&#xff0c;奈何尝试多种办法都不能将其下载下载&#xff0c;点击打印出现的也是一片空白 百度搜索了一些解决方案都不太行&#xff0c;主要解决方案如&#xff1a;https://zh…

计算机网络——物理层-编码与调制(数字基带信号、模拟基带信号、码元、常用编码、基本调制方法、混合调制)

目录 编码与调制 数字基带信号 模拟基带信号 码元 常用编码 不归零编码 归零编码 曼彻斯特编码 差分曼彻斯特编码 编码习题 基本调制方法 调幅 调频 调相 混合调制 QAM-16 编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频…

JavaScript学习_01——JavaScript简介

JavaScript简介 JavaScript介绍 JavaScript是一种轻量级的脚本语言。所谓“脚本语言”&#xff0c;指的是它不具备开发操作系统的能力&#xff0c;而是只用来编写控制其他大型应用程序的“脚本”。 JavaScript 是一种嵌入式&#xff08;embedded&#xff09;语言。它本身提供…

ubuntu中cuda12.1配置(之前存在11.1版本的cuda)(同时配置两个版本)

ubuntu中cuda12.1配置 由于YOLOv8项目中Pytorch版本需要cuda12.1版本 在官网下载12.1版本的deb包 官网地址 sudo dpkg -i cuda-keyring_1.0-1_all.deb sudo apt-get update sudo apt-get -y install cuda然后需要修改bashrc文件&#xff08;隐藏文件&#xff09; 添加 exp…

C#,数值计算——插值和外推,BaryRat_interp的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 重心有理插值对象 /// Barycentric rational interpolation object. /// After constructing the object, /// call interp for interpolated values. /// Note t…

供应商选择和评估:如何寻找合适的供应商并与其合作

如果供应商不能按时交货或产品质量低劣&#xff0c;制造商的生产计划就会延误&#xff1b;客户交货将被延迟&#xff0c;商品可能被退回&#xff0c;你的公司声誉也将受损。 要在当今竞争激烈的市场中取得成功&#xff0c;你需要一流的、价格合理且来源可靠的原材料和服务&…

Leetcode刷题详解——岛屿数量

1. 题目链接&#xff1a;200. 岛屿数量 2. 题目描述&#xff1a; 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上…