本帖最后由 eew_TKwwQ7 于 2023-11-7 23:31 编辑
一、蓝牙串口背景相关知识:
蓝牙技术:
谈到蓝牙技术,大家一下子可以想到智能手机的蓝牙功能,通过蓝牙可以与其它智能设备进行通讯,可以将智能家居设备实时进行监控数据和控制设备工作状态,随着智能手机的使用,目前蓝牙和智能设备已经息息相关,该技术在生活中非常普及。蓝牙Bluetooth具有短距离,解决有线通讯的不利之处;低功耗,对人体辐射小;低成本,电路应用简单,容易推广应用等特点。工作在2.4GHz频段的无线通信技术,现已经广泛应用于我们日常生活的各个方面,其工作有四种状态分别是:激活Active、呼吸Sniff、保持Hold、休眠Park、其中激活是正常工作状态,其它三种是节能规定的低功耗状态模式。蓝牙技术中规定,进行蓝牙通信的设备需要一个为主模式Master mode另一个为从模式Slave mode,才能进行正常通信。
目前市面上很多蓝牙模组,其中低功耗非常具有优势,其中常见的模组有HC-04、HC-05、HC-06、ESP32、BLE、BT等,该实验采用大夏龙雀科技的BT04-E蓝牙模块(淘宝很便宜,资料很全)
该蓝牙模块的系统框架图
蓝牙模块采用串口通讯,通过串口即可实现数据发送与接收,故需要讲述一下串口通讯相关知识。
串口通讯:
在微控制器MCU中串口作为一种常见通讯协议可以说是必备项,作为一种标准化协议,通过两个I/O引脚即可实现MCU和MCU通讯,MCU和外部传感器、执行设备、上位机等进行通讯。串口通讯 (Serial Communication) 是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试
信息。对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流。
串口协议关键参数
1)波特率
在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率(Baud rate)。波特率是指数据信号对载波的调制速率,它用单位时间内载波调制状态改变的次数来表示(也就是每秒调制的符号数),其单位是波特(Baud:Symbol/s)。
MCU的USART接口采用数字信号,它的波特率就是每秒钟传输的bit数。典型的波特率有:9600、115200(115200 / 8 / 1024 = 14.06KB的速度)等。UART对波特率没有上限,需要考虑到实际通信双方的参数要求。
2)停止位
每个字发送后,紧跟停止位,停止位可以选择“1、2、0.5、1.5”bit(0.5实际代表停止位高电平持续半个周期的时间)。
3)校验位
UART传送的每个字节都可以选择是否增加1bit的奇偶校验位,而且奇校验或偶校验都可以选择。
4)字长度
传送一个字的位数,一般情况下都会选择8bit字节,这也和国际标准单位的字节宽度相对应。
5)起始位
起始位是必须的,由硬件产生,无需软件配置。起始位就是在发送每个字的第一个有效位之前,先发送1周期的低电平,表示发送开始。嵌入式应用中,最常见的配置是:8位字节,1个停止位,无校验,波特率115200。
电平转换:
电平转换主要涉及到不同电平电压的硬件转换,转换硬件方式有多种多样,可以是集成芯片,或者三极管场效应管构成的都转换电路,例如5V电平的通讯电平需要和3.3VMCU进行串口通讯,这个时候就需要电平转换电路,如图是3.3V信号转5V电压信号,该项目使用蓝牙通讯电平是3.3V和RA6E2开发板串口电压一致,故不需要电平转换电路。
二、实战演示使用蓝牙进行通讯控制
1、串口选择
从这张图可以看出该开发板有两个物理串口可用,通过查询芯片规格书,也证实该RA6E2芯片确实只有两个串口
2、硬件引脚配置
那就直接使用RXD0和TXD0,作为蓝牙模块的通讯接口,RXD0和TXD0分别对应P410和P411
连接实物图
3、软件搭建
实现发送不同指令控制LED的亮灭
指令 |
作用 |
“1” |
LED1亮 |
“2” |
LED2亮 |
“3” |
LED1灭 |
“4” |
LED2灭 |
1)软件工程添加UART功能模块,在FSP进行设置添加,设置相应参数后进行跟新(Genrate Project Content)
2)使用print函数需要进行设置
使用 printf 函数时,需要使用到堆,默认情况下堆的大小为 0,因此我们需要修改堆的大小。可以在 FSP 配置界面中的“BSP”属性栏的“RA Common”中通过修改“Heap size”来设置堆区大小。
3)添加uart函数
bsp_uart.c文件如下
#include "bsp_uart.h"
#include "led/bsp_led.h"
/* 调试串口 UART4 初始化 */
void UART0_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_UART_Open (&g_uart0_ctrl, &g_uart0_cfg);
assert(FSP_SUCCESS == err);
}
/* 发送完成标志 */
volatile bool uart_send_complete_flag = false;
/* 串口中断回调 */
void debug_uart0_callback (uart_callback_args_t * p_args)
{
switch (p_args->event)
{
case UART_EVENT_RX_CHAR:
{
/* 根据字符指令控制RGB彩灯颜色 */
switch (p_args->data)
{
case '1':
LED1_ON;
break;
case '2':
LED2_ON;
break;
case '3':
LED1_OFF;
break;
case '4':
LED2_OFF;
break;
default:
break;
}
break;
}
case UART_EVENT_TX_COMPLETE:
{
uart_send_complete_flag = true;
break;
}
default:
break;
}
}
/* 重定向 printf 输出 */
#if defined __GNUC__ && !defined __clang__
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
(void)fd;
R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return size;
}
#else
int fputc(int ch, FILE *f)
{
(void)f;
R_SCI_UART_Write(&g_uart4_ctrl, (uint8_t *)&ch, 1);
while(uart_send_complete_flag == false);
uart_send_complete_flag = false;
return ch;
}
#endif
bsp_uart.h文件如下
#ifndef __BSP_DEBUG_UART_H
#define __BSP_DEBUG_UART_H
#include "hal_data.h"
#include "stdio.h"
void UART0_Init(void);
#endif
调试函数hal_entr.c添加#include "uart/bsp_uart.h"和printf ("\t hello \r\n ");
#include "hal_data.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/* 用户头文件包含 */
#include "led/bsp_led.h"
#include "uart/bsp_uart.h"
/*******************************************************************************************************************//**
* main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
UART0_Init();
while(1)
{
printf ("\t hello \r\n ");
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS); //延时 1 秒
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
/*******************************************************************************************************************//**
* This function is called at various points during the startup process. This implementation uses the event that is
* called right before main() to set up the pins.
*
* @param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
/* Enable reading from data flash. */
R_FACI_LP->DFLCTL = 1U;
/* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
* C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
}
if (BSP_WARM_START_POST_C == event)
{
/* C runtime environment and system clocks are setup. */
/* Configure pins. */
R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
}
}
#if BSP_TZ_SECURE_BUILD
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
#endif
以上功能实现通过蓝牙发送指令控制LED的亮灭
演示视频:
225746
参考文献:
正点原子:STM32F4 开发指南
野火电子:[野火] 瑞萨 RA 系列 FSP 库开发实战指南—基于野火启明开发板