【STM32单片机_(HAL库)】6-6-1【串口通信UART、USART】【蓝牙遥控插座项目】HC-08蓝牙模块实验

news2024/10/24 7:23:42

通信示意图
在这里插入图片描述

1.硬件

  • STM32单片机最小系统
  • HC-08蓝牙模块

2.软件

  • bluetooth驱动文件添加
  • main.c程序
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "bluetooth.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* 初始化LED灯 */
    uart1_init(115200);                 /*串口1初始化*/
    bt_init(115200);                    /*蓝牙模块初始化,波特率根据自己设置的*/
    printf("hello world!\r\n");

    uint8_t i = 0;
    while(1)
    { 
        bt_send("hello, bt%d\r\n", i++);//类似于printf效果
        delay_ms(500);
//        led1_on();
//        led2_off();
//        delay_ms(500);
//        led1_off();
//        led2_on();
//        delay_ms(500);
    }
}


  • uart1.c程序
#include "sys.h"
#include "uart1.h"
#include "string.h"

UART_HandleTypeDef uart1_handle;                                            /* UART1句柄 */

uint8_t uart1_rx_buf[UART1_RX_BUF_SIZE];                                    /* UART1接收缓冲区 */
uint16_t uart1_rx_len = 0;                                                  /* UART1接收字符长度 */

/**
 * @brief       重定义fputc函数
 * @note        printf函数最终会通过调用fputc输出字符串到串口
 */
int fputc(int ch, FILE *f)
{
    while ((USART1->SR & 0X40) == 0);                                       /* 等待上一个字符发送完成 */

    USART1->DR = (uint8_t)ch;                                               /* 将要发送的字符 ch 写入到DR寄存器 */
    return ch;
}

/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void uart1_init(uint32_t baudrate)
{
    /*UART1 初始化设置*/
    uart1_handle.Instance = USART1;                                         /* USART1 */
    uart1_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart1_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart1_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart1_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart1_handle);                                           /* HAL_UART_Init()会使能UART1 */
}

/**
 * @brief       UART底层初始化函数
 * @param       huart: UART句柄类型指针
 * @note        此函数会被HAL_UART_Init()调用
 *              完成时钟使能,引脚配置,中断配置
 * @retval      无
 */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;

    if (huart->Instance == USART1)                                          /* 如果是串口1,进行串口1 MSP初始化 */
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();                                       /* 使能串口TX脚时钟 */
        __HAL_RCC_USART1_CLK_ENABLE();                                      /* 使能串口时钟 */

        gpio_init_struct.Pin = GPIO_PIN_9;                                  /* 串口发送引脚号TX(PA9) */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                            /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                                /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;                      /* IO速度设置为高速 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
                
        gpio_init_struct.Pin = GPIO_PIN_10;                                 /* 串口RX脚 模式设置 RX(PA10)*/
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);                            /* 串口RX脚 必须设置成输入模式 */
        
        HAL_NVIC_EnableIRQ(USART1_IRQn);                                    /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);                            /* 组2,最低优先级:抢占优先级3,子优先级3 */

        __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);                          /* 使能UART1接收中断 */
        __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);                          /* 使能UART1总线空闲中断 */
    }
    else if (huart->Instance == USART2)                                          /* 如果是串口2,进行串口2 MSP初始化 */
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();                                       /* 使能串口TX脚时钟 */
        __HAL_RCC_USART2_CLK_ENABLE();                                      /* 使能串口时钟 */

        gpio_init_struct.Pin = GPIO_PIN_2;                                  /* 串口发送引脚号TX(PA2) */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                            /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                                /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;                      /* IO速度设置为高速 */
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
                
        gpio_init_struct.Pin = GPIO_PIN_3;                                 /* 串口RX脚 模式设置 RX(PA3)*/
        gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;    
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);                            /* 串口RX脚 必须设置成输入模式 */
        
        HAL_NVIC_EnableIRQ(USART2_IRQn);                                    /* 使能USART2中断通道 */
        HAL_NVIC_SetPriority(USART2_IRQn, 3, 3);                            /* 组2,最低优先级:抢占优先级3,子优先级3 */

        __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);                          /* 使能UART2接收中断 */
        __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);                          /* 使能UART2总线空闲中断 */
    }
}

/**
 * @brief       UART1接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart1_rx_clear(void)
{
    memset(uart1_rx_buf, 0, sizeof(uart1_rx_buf));                          /* 清空接收缓冲区 */
    uart1_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口1中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART1_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart1_rx_len >= sizeof(uart1_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart1_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart1_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart1_rx_buf[uart1_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart1_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("recv: %s\r\n", uart1_rx_buf);                               /* 将接收到的数据打印出来 */
        uart1_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart1_handle);                           /* 清除UART总线空闲中断 */
    }
}

  • uart1.h程序
#ifndef __USART_H__
#define __USART_H__

#include "stdio.h"
#include "sys.h"

/* 错误代码 */
#define UART_EOK                     0      /* 没有错误 */
#define UART_ERROR                   1      /* 通用错误 */
#define UART_ETIMEOUT                2      /* 超时错误 */
#define UART_EINVAL                  3      /* 参数错误 */

/* UART收发缓冲大小 */
#define UART1_RX_BUF_SIZE            128
#define UART1_TX_BUF_SIZE            64


void uart1_init(uint32_t bound);            /* 串口初始化函数 */

#endif

  • bluetooth.c程序
#include "sys.h"
#include "bluetooth.h"
#include "string.h"
#include "stdarg.h"//包含va_list的头文件

UART_HandleTypeDef uart2_handle;                                            /* uart2句柄 */

uint8_t uart2_rx_buf[UART2_RX_BUF_SIZE];                                    /* uart2接收缓冲区 */
uint16_t uart2_rx_len = 0;                                                  /* uart2接收字符长度 */

/**
 * @brief       串口1初始化函数
 * @param       baudrate: 波特率, 根据自己需要设置波特率值
 * @retval      无
 */
void bt_init(uint32_t baudrate)
{
    /*uart2 初始化设置*/
    uart2_handle.Instance = USART2;                                         /* USART2 */
    uart2_handle.Init.BaudRate = baudrate;                                  /* 波特率 */
    uart2_handle.Init.WordLength = UART_WORDLENGTH_8B;                      /* 字长为8位数据格式 */
    uart2_handle.Init.StopBits = UART_STOPBITS_1;                           /* 一个停止位 */
    uart2_handle.Init.Parity = UART_PARITY_NONE;                            /* 无奇偶校验位 */
    uart2_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;                      /* 无硬件流控 */
    uart2_handle.Init.Mode = UART_MODE_TX_RX;                               /* 收发模式 */
    HAL_UART_Init(&uart2_handle);                                           /* HAL_UART_Init()会使能uart2 */
}

/**
 * @brief       uart2接收缓冲区清除
 * @param       无
 * @retval      无
 */
void uart2_rx_clear(void)
{
    memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf));                          /* 清空接收缓冲区 */
    uart2_rx_len = 0;                                                       /* 接收计数器清零 */
}

/**
 * @brief       串口2中断服务函数
 * @note        在此使用接收中断及空闲中断,实现不定长数据收发
 * @param       无
 * @retval      无
 */
void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;   
    if(__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_RXNE) != RESET){        /* 获取接收RXNE标志位是否被置位 */
        if(uart2_rx_len >= sizeof(uart2_rx_buf))                            /* 如果接收的字符数大于接收缓冲区大小, */
            uart2_rx_len = 0;                                               /* 则将接收计数器清零 */
        HAL_UART_Receive(&uart2_handle, &receive_data, 1, 1000);            /* 接收一个字符 */
        uart2_rx_buf[uart2_rx_len++] = receive_data;                        /* 将接收到的字符保存在接收缓冲区 */
    }

    if (__HAL_UART_GET_FLAG(&uart2_handle, UART_FLAG_IDLE) != RESET)        /* 获取接收空闲中断标志位是否被置位 */
    {
        printf("bt recv: %s\r\n", uart2_rx_buf);                               /* 将接收到的数据打印出来 */
        uart2_rx_clear();
        __HAL_UART_CLEAR_IDLEFLAG(&uart2_handle);                           /* 清除UART总线空闲中断 */
    }
}

//void bt_send(char *send_buf, uint8_t size)
//{
//    HAL_UART_Transmit(&uart2_handle, (uint8_t *)send_buf, size, 100);
//}

void bt_send(char * format, ...)//不定长传入参数
{
    uint8_t send_buf[128] ={0};
    va_list arg;
    va_start(arg, format);
    vsprintf((char *)send_buf, format, arg);
    va_end(arg);
    HAL_UART_Transmit(&uart2_handle, send_buf, sizeof(send_buf), 100);//串口发送函数
}

  • bluetooth.h程序
#ifndef __BLUETOOTH_H__
#define __BLUETOOTH_H__

#include "stdio.h"
#include "sys.h"

/* UART收发缓冲大小 */    //蓝牙用串口2
#define UART2_RX_BUF_SIZE            128
#define UART2_TX_BUF_SIZE            64


void bt_init(uint32_t bound);            /* 串口初始化函数 */
//void bt_send(char *send_buf, uint8_t size);
void bt_send(char * format, ...);

#endif

3.实物效果

  • 硬件模块接线
STM32USB转TTLHC-08蓝牙模块
串口1—PA9(TX)RX
串口1—PA10(RX)TX
串口2—PA2(TX)RX
串口2—PA3(RX)TX
5V5V5V
GNDGNDGND

ST-Link下载方式

  • 实验现象
    将STM32单片机与蓝牙连接,打开蓝牙串口助手连接蓝牙,蓝牙模块上蓝灯长亮时,代表已连接。此时点击蓝牙串口助手HC-08界面,可以看到蓝牙模块发送来的数据。

HC-08蓝牙模块实验keil源文件

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

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

相关文章

日本IT|事务与IT营业岗位分别是什么?

在日本IT行业中,“事务”与“IT营业”是两个不同的岗位,它们各自承担着不同的职责。以下是对这两个岗位的详细解释: 一、事务岗位 定义与工作内容: 事务岗位通常指的是处理公司日常事务的职位,这些事务可能涉及IT派遣…

零基础搭建QQ机器人(Ⅱ)

基于 PythonSDK 和 三方协议 开发搭建QQ机器人 [交流QQ群]:QQ官方机器人交流群csdn 文章目录 基于 PythonSDK 和 三方协议 开发搭建QQ机器人接受消息并发送内容接受消息hello后发送语音接受消息hello后发送文件接受消息hello后发送视频接受消息hello后发送骰子/猜拳…

操作系统——位示图

这里写目录标题 前言基础说明相关计算题目一题目二题目三 前言 基础说明 位示图是一种用来表示文件和目录在磁盘上存储位置的图形化表示方法。它通过使用一系列的位来表示文件或目录所占用的磁盘块,从而显示出磁盘上的存储情况。 位示图通常是一个位向量&#xf…

FileInputStream类

目录 1.案例代码: 2.注意细节 3.FileInputStream循环读取 1.案例代码: 准备的txt文件 结果: 如果需要输出原本的字母,强制转换为char即可: 结果: 2.注意细节 (1)如果文件不存在…

RandLA-Net 基于 Tensorflow , 训练自定义数据集

搭建 RandLA-Net 训练环境, 生成自定义训练数据集, 训练自定义数据集. Code: https://github.com/QingyongHu/RandLA-Net 搭建训练环境 Clone the repositorygit clone --depth=1 https://github.com/QingyongHu

Transformer学会有手就行?这本 Transformer自然语言处理实战 书无敌了

在人工智能领域,Transformer架构、大模型是当下最激动人心的话题之一。它们不仅推动了技术的极限,还重新定义了我们与机器交互的方式。Transformer模型最初由Google的研究人员在2017年提出,它是一种基于自注意力机制的深度学习模型&#xff0…

4K变倍镜头特点

1、高分辨率成像: ① 能够呈现清晰、细腻的图像,可清晰快速地识别出被测物体的微小细节、特征以及潜在的缺陷等。例如在芯片外观瑕疵检测中,能清晰地分辨出芯片上的刮痕、污渍、破损、引脚缺失等问题。 ② 相比传统的变倍镜头,在…

【华为】配置NAT访问互联网

1.AR1: int g0/0/0 ip ad 64.1.1.2 255.255.255.0 int g0/0/1 ip ad 110.242.68.1 255.255.255.02.AR2: (1)配置端口ip: int g0/0/1 ip ad 10.3.1.2 255.255.255.0 int g0/0/0 ip ad 64.1.1.1 255.255.255.0(2)配置默认路由: ip route-static 0.0.0.0 0.…

JavaWeb之监听器

在JavaWeb开发中,常见的监听器(Listener)用于监听Web应用程序、会话(Session)、请求(Request)的生命周期或属性的变化。 应用域监听器: 应用域监听器(也称为ServletCon…

2023年中国环境统计年鉴(EXCEL)

2023年中国环境统计年鉴(EXCEL) 1、时间:2023年 2、《Z国环境统计年鉴》是一本重要的年度参考资料,全面反映了Z国的环境状况与发展趋势。本年鉴收集整理了大量来自各级环境保护部门、科研机构以及相关领域的数据和统计信息,内容涵盖了大气、…

APB接口协议

APB 简介信号传输时序WriteWrite stobesReadError responseWrite transferRead transferMapping of PSLVERRProtection unit support 状态机 简介 APB(Advanced Peripheral Bus)是AMBA总线的一部分,从1998年第一版至今共有3个版本。 AMBA2 …

【专题】计算机网络概述

1. 计算机网络的作用及其发展史 1.1. 计算机网络的作用 二十一世纪的一些重要特征就是数字化、网络化和信息化,它是一个以网络为核心的信息时代。 网络现在已经成为信息社会的命脉和发展知识经济的重要基础。 信息时代以网络为核心。 (1) 网络 “网络”是一个统称…

UE4 材质学习笔记10(程序化噪波/覆雪树干着色器/岩层着色器)

一.程序化噪波 柏林噪波是一种能生成很好的随机图案的算法,它是一个无限的、不重复的图案,可以采用这种基础图案并以多种方式对其进行修改, 将它缩放并进行多次组合,就可以创建一个分形图案。这些组合的缩放等级称为一个Octave 这…

ArrayList和顺序表(下)

1. Java本身提供的ArrayList 在ArrayList和顺序表(上)那一节里面,我们自己实现了ArrayList的底层大部分代码,在这个基础上,我们就可以开始来了解Java本身提供的ArrayList. 1.1 ArrayList的三种构造方法 方法解释ArrayList()无参构造ArrayList(Collection<? extends E > …

‌ComfyUI 高级实战:实现华为手机的AI消除功能

大家好&#xff0c;我是每天分享AI应用的萤火君&#xff01; 不知道大家是否还记得华为 Pura 70的「AI消除」事件&#xff0c;当时使用 华为Pura 70 系列手机的智能消除功能时&#xff0c;该功能可以被用来消除照片中女性胸口处的衣物&#xff0c;这一功能曾引发广泛的关注和伦…

OpenAI Canvas最新发布,编程和写作迎来全新史诗级加强!

文章目录 零、前言一、GPT-40 with canvas操作指导写作领域加强建议编辑调整长度阅读水平添加最后的润色添加表情 编程领域加强选中代码问问题添加评论&#xff08;添加注释&#xff09;添加日志转换语言代码审查 二、感受 零、前言 最新消息&#xff0c;国庆期间OpenAI有大动…

使用管理员删除垃圾文件

1、先设置为管理员权限 2、执行删除文件命令 使用&#xff1a;del /f /s /q “文件夹位置”例如&#xff1a;del /f /s /q "C:\Program Files (x86)\my_code\.git"

2024深圳秋季糖酒会参会攻略!建议收藏

10月29日-31日&#xff0c;第111届全国糖酒商品交易会将在深圳国际会展中心&#xff08;宝安&#xff09;举办。本届糖酒会将邀请来自超四十个国家和地区的超4200家行业厂商和20万国内外专业观众到会交易交流&#xff0c;为食品酒类行业搭建一个集展示、交易、交流、合作于一体…

IP- guard产品版本升级指引详解

一、IP-guard服务器升级步骤 1、下载升级包(IPgUpgrade版本号.zip) 到IP-guard服务器 2、解压升级包,右键以管理员身份运行 (1)“升级包”解压 (2)右键以管理员身份运行“升级包” ࿰

报表工具如何助力企业报表开发?如何选择最适合的报表工具?一篇文章统统解答!

在当今瞬息万变的商业格局中&#xff0c;企业信息化建设已成为驱动业务飞跃与增强核心竞争力的核心引擎。然而&#xff0c;伴随业务数据的井喷式增长&#xff0c;企业在数据治理与价值挖掘方面遭遇了前所未有的挑战。数据孤岛、处理流程冗长、对业务动态调整反应迟缓&#xff0…