基于stm32f103c8t6的串口中断蓝牙通讯

news2024/11/18 16:38:31

这一篇文章与 上一篇文章相基于 stm32f103c8t6的串口非中断蓝牙通讯上一篇文章相http://t.csdnimg.cn/7j0Ec 

相比,硬件部分是相同的。在原有的旧初上,要在stm32cube加入中断,同时代码中也要引入中断函数以及中断回调函数。到后面我谁说说我遇到的坑。

一、硬件部分

名称作用图片
stm32f103c8t6板子————
HC08蓝牙模块连接单片机通讯TX接单片机RX1,RX接单片机TX1。
usb转ttl模块模拟调试蓝牙通讯,同时在串口助手里修改蓝牙的波特率,让蓝牙的波特率和单片机相同

二、stm32cube新增加的部分

把USART1的中断打开,其余的不变

三、代码部分(黑色软件生成,蓝色自己书写)

#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#define UART1_REC_LEN 200
uint8_t buf=0;
uint8_t UART1_RX_Buffer[UART1_REC_LEN];
uint16_t UART1_RX_STA=0;

void SystemClock_Config(void);

/* USER CODE BEGIN 0 */

unsigned char ch[20] = {0};
int fputc(int ch, FILE *f)//重映射使用
{
unsigned char temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,0xffff);
return ch;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//中断接收回调函数
{
// 判断中断是由哪个串口触发的
if(huart->Instance == USART1)
{
// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
   if((UART1_RX_STA & 0x8000) == 0)
  {
// 如果已经收到了 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);

}
}

/* USER CODE END 0 */

int main(void)
{
 
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, &buf, 1);
  /* USER CODE END 2 */

while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        //判断判断串口是否接收完成
  if(UART1_RX_STA & 0x8000)
        {
            printf("收到数据:");
            if (!strcmp((const char *)UART1_RX_Buffer, "open"))
        {
             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");
          
 memset(UART1_RX_Buffer, 0, strlen((const char *)UART1_RX_Buffer));
        }
        else if(!strcmp((const 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");
          
 memset(UART1_RX_Buffer, 0, strlen((const char *)UART1_RX_Buffer));
        } 
        else 
        {
            if(UART1_RX_Buffer[0] != '\0')
            printf("指令发送错误:%s", UART1_RX_Buffer);
            
memset(UART1_RX_Buffer, 0, strlen((const char *)UART1_RX_Buffer));
        }
             printf("\r\n");
            // 重新开始下一次接收
             UART1_RX_STA = 0;
        }
            
            HAL_Delay(40);
    }
                
/* USER CODE END 3 */
}

四、其它补充

我不知道大家看完中断回调函数有没有啥疑问?

我来提两个问题

1.为什么在中断回调函数里还要在此调用中断接收函数?

我们打开HAL_UART_Receive_IT(&huart1, &buf, 1)的解释,可以看到下图所示

        从图中我们可以看到,当我们开启中断的时候,串口就已经READY了,第一个if满足;接着因为我们的输入非空或者大小不为0U,所以第二个if跳过。接着就来到了一个结构体指针的赋值语句,这程序的意思就是表示UART串口的接收模式为标准模式。在标准模式下,UART串口以字节为单位接收数据,当接收到一个字节后,将触发接收完成事件,并将数据保存在接收缓冲区中。所以这句话过后,就相当于中断关闭了,所以我们每次接受一个字节之后,都需要重新调用中断函数。

    还有就是要注意这里的逻辑,回调函数里是来一个字节触发一次中断,而不是把识别一个字符串触发中断,回调函数没有写循环,却可以循环。从第一个字符开始,到标志位(UART1_RX_STA=1结束,好好想想这个循。

2.我不知道有没有人关心程序中出现的变量buf,再回回调函数中,buf并没有任何人给他赋值,buf仅仅是出现在HAL_UART_Receive_IT(&huart1, &buf, 1),那么问题来了。既然没有给buf赋值,那程序中有关buf值的判断是怎么进行的呢?

比如if(buf == 0x0a)之类的语句,后来我跳转了HAL_UART_Receive_IT(&huart1, &buf, 1)解释,

我们看到串口接收变为标准模式之后,紧接着return另一个都函数里面。我们进入这个函数,大家看到了吗,这里是 huart->pRxBuffPtr一个结构体指针,而且pRxBuffPtr与pData都是指针,把指针赋值给指针,它们指向的是同一个内存位置。这意味着它们可以用来访问相同的数据,这不就意味着uart1的接收传输缓冲区与buf共享数据了嘛,所以看似buf没有赋值,但是HAL库已经帮我们赋值了。

3.memset(UART1_RX_Buffer, 0, strlen((const char *)UART1_RX_Buffer))

关于这句话,我建议你加上,我在手机蓝牙上试过,如果不加的话,当你输入的不是open或者close而是别的字符串,比如asdajd,它会报错,没问题。但是当你再次输入正确的指令的open或者close的时候,他还是会报错。

这是回调函数里的一个bug

    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;
                }

printf("指令发送错误:%s\r\n", UART1_RX_Buffer);

个人觉得可能是printf的存在,导致只要不超过200个字节,他会一直给你累加字节

想要解决这个问题,要么你重启单片机,要么你加上memset(UART1_RX_Buffer, 0, strlen((const char *)UART1_RX_Buffer)),位置我已经用红色标记了。

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

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

相关文章

免费的国产数据集成平台推荐

在如今的数字化时代下&#xff0c;企业内部的数据无疑是重要资产之一。随着数据源的多样性和数量剧增&#xff0c;如何有效地收集、整合、存储、管理和分析数据变得至关重要。为了解决这些常见痛点&#xff0c;数据集成平台成为了现代企业不可或缺的一部分。 数据集成是现代数…

腾讯云双11服务器优惠活动价格表预热!

2023腾讯云双十一优惠活动服务器特价多配置报价2核2G3M、2核2G4M、2核4G5M、2核4G5M、4核8G12M、8核16G18M和16核32G28M&#xff0c;目前腾讯云双11价格还没出来&#xff0c;阿腾云根据目前2核2G3M配置95元一年预测双11价格可能是88元一年&#xff0c;整理大概有个10%的优惠幅度…

原型设计工具:Balsamiq Wireframes 4.7.4 Crack

原型设计工具:Balsamiq Wireframes是一种快速的低保真UI 线框图工具&#xff0c;可重现在记事本或白板上绘制草图但使用计算机的体验。 它确实迫使您专注于结构和内容&#xff0c;避免在此过程后期对颜色和细节进行冗长的讨论。 线框速度很快&#xff1a;您将产生更多想法&am…

Android笔记(七)Android JetPack Compose组件搭建Scaffold脚手架

在去年2022年曾发布一篇关于脚手架的文章&#xff1a;“Android JetPack Compose组件中Scaffold的应用” 。但是Android的版本从12变更到13及以上版本&#xff0c;导致一些细节的实现存在不同。在本文中&#xff0c;将从头开始介绍整个脚手架的搭建过程。 一、新建项目模块 在…

uniGUI文件操作

一.文件上传TUniFileUploadButton TUniFileUploadButton主要属性&#xff1a; Filter: 文件类型过滤&#xff0c;有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸&#xff1b; Message&#xff1a;标题以及消息文本&#xff0c;可翻译成中文…

手写call(),apply(),bind()方法

目录 知识储备&#xff1a; 一&#xff1a;手写call方法 1、思路 2、实现 3、Symbol调优 二&#xff1a;手写apply方法 1、思路 2、实现 三&#xff1a;手写bind方法 1、思路 2、实现 四&#xff1a;总结 知识储备&#xff1a; 所有的方法都可以调用我们手写的方法&…

npm ERR! node-sass@6.0.1 postinstall: `node scripts/build.js`

1.遇到的问题 vue npm install提示以下错误 2.首次尝试方法 尝试用下面的方式重新安装弄得-saas&#xff0c;结果不起作用 。 npm config set sass_binary_sitehttps://npm.taobao.org/mirrors/node-sass npm install node-sass 这时考虑降级node版本&#xff0c;node.js从…

上海亚商投顾:沪指再创年内新低 贵州茅台等权重股集体调整

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日全线调整&#xff0c;沪指逼近3000点大关&#xff0c;深成指、创业板指续创年内新低。芯片板块逆…

推荐系统(RS)

主流推荐算法 协同过滤算法 协同过滤算法的原理 根据用户群体对产品偏好的数据&#xff0c;发现用户之间的相似性或者物品之间的相似性&#xff0c;并基于这些相似性为用户作推荐。 基于用户的协同过滤算法&#xff08;User-based Collaborative Filtering&#xff09; 其本…

Leetcode刷题详解——四数之和

1. 题目链接&#xff1a;四数之和 2. 题目描述&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0…

『力扣刷题本』:相交链表

咳咳&#xff0c;实在抱歉&#xff0c;刚开始心气太高了&#xff0c;叫『每日一题』&#xff0c;我是真的坚持不下了。 经过这次打击&#xff0c;我算是摸明白自己在写博客这件事情上几斤几两了&#xff0c;现在预计一周两更&#xff0c;再慢慢把更新频率提上来。 正在努力补…

python写的自动按键和鼠标连点

自己用python写的自动按键和鼠标自动点击。 分享一下源码&#xff0c;比较干净的&#xff0c;缺点就是是python打包有点大50多M from PyQt5 import QtWidgets, uic, QtCore from pynput import keyboard, mouse import pygetwindow as gw from PyQt5.QtGui import QPainter, Q…

YOLOv7改进实战 | 更换轻量化主干网络Backbone(一)之Ghostnet

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

Netty常用类与接口

netty架构图 ServerBootstrap 、 Bootstrap ServerBootstrap &#xff1a;服务器的引导类&#xff0c;可以绑定服务器和端口&#xff0c;配置 Channel、ChannelHandler等。 Bootstrap&#xff1a;客户端的引导类。可以开启客户端&#xff0c;连接服务端的端口&#xff0c;配置…

矩阵系统功能介绍

数据大屏&#xff1a;监测读取后台数据 AI素材库&#xff1a;一键去水印功能 将视频做出自己的 AI智能文案&#xff1a;一键生成各种文案&#xff0c;解决文案编写困难的问题 视频剪辑&#xff1a;一键剪辑多个视频

vue3引入全局js

main.js中引入js&#xff0c;设置全局属性 m a p : a p p . c o n f i g . g l o b a l P r o p e r t i e s . map:app.config.globalProperties. map:app.config.globalProperties.map引入js对象 vue页面中使用。引入vue实例&#xff1a; import {getCurrentInstance} from “…

VS2022更换背景壁纸逐步图示教程

&#x1f984;个人主页:修修修也 ⚙️操作环境:Visual Studio 2022 目录 一.下载壁纸插件 二.更改自定义壁纸 三.调整壁纸布局 一.下载壁纸插件 因为更改自定义壁纸需要一个插件的辅助,所以我们要先下载一个小插件 首先,打开VS2022,点击"扩展"->"管理扩…

无人机电力巡检:国网安徽实际案例解析

在科技快速发展的今天&#xff0c;传统行业正在经历前所未有的转型。电力巡检&#xff0c;这一看似传统且乏味的任务&#xff0c;却因为无人机技术的介入而焕发新生。今天&#xff0c;让我们深入了解一个具体的案例&#xff0c;探索无人机如何革新电力巡检。 案例背景&#xff…

Postman —— postman的介绍和安装

Postman的介绍 Postman 是一款谷歌开发的接口测试工具,使API的调试与测试更加便捷。 它提供功能强大的 Web API & HTTP 请求调试。它能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..)&#xff0c;附带任何数量的参数 headers postman是一款支持http协议的接口调试与…

【试题020】C语言自减运算符例题

1.题目&#xff1a;设int a1&#xff0c;b6;&#xff0c;执行表达式--all(b8)后&#xff0c;a和b的值分别是 &#xff1f; 2.代码分析&#xff1a; #include <stdio.h> int main() {//设int a1&#xff0c;b6;执行表达式--all(b8)后&#xff0c;a和b的值分别是?int a …