嵌入式实训
先前已经实现了串口通信,如今使用蓝牙通信的原理和串口基本一样,只不过是把原本的串口收发数据改成通过蓝牙收发数据。
但很多时候有可能蓝牙还没初始化,比如说设置蓝牙的名字、密码等等。
所以先通过串口与蓝牙间收发数据实现蓝牙的初始化,然后再通过蓝牙收发数据即可。
蓝牙初始化
执行步骤
-
首先是让UART1的1、3和2、4通过跳线帽跳起来,实现通过串口让电脑和开发板通信(day5_1便是如此实现串口通信)
-
然后让UART3的3、5和4、6通过跳线帽跳起来(此时蓝牙模块接在P6,注意,RX和TX要反接)
-
通过电脑的串口调试软件工具实现对蓝牙的初始化(通过AT指令,注意,要加回车换行)
BLE-CC41-A蓝牙模块AT指令集操作如下:
发送AT,接收ATOK说明蓝牙响应成功
设置名字
设置密码
代码
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_usart.h"
#include "stdio.h"
static GPIO_InitTypeDef GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static uint8_t g_usart1_recv_buf[128]={0};
static uint8_t g_usart1_recv_cnt = 0;
//重定义fputc函数
int fputc(int ch, FILE *f)
{
USART_SendData(USART1,ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
void delay_us(int nus) //微秒
{
//SystemCoreClock
SysTick->LOAD = (SystemCoreClock/8/1000000) * nus; //定时时间
SysTick->CTRL |= 1; //开启定时器,开始计数
while((SysTick->CTRL & (1<<16)) == 0); //等待定时时间到
SysTick->CTRL &=~1; //关闭定时器
}
void delay_ms(int nms) //毫秒
{
uint32_t m,n;
m = nms/500;
n = nms%500;
while(m--)
{
SysTick->LOAD = (SystemCoreClock/8/1000) * 500; //定时时间
SysTick->CTRL |= 1; //开启定时器,开始计数
while((SysTick->CTRL & (1<<16)) == 0); //等待定时时间到
SysTick->CTRL &=~1; //关闭定时器
}
if(n)
{
SysTick->LOAD = (SystemCoreClock/8/1000) * n; //定时时间
SysTick->CTRL |= 1; //开启定时器,开始计数
while((SysTick->CTRL & (1<<16)) == 0); //等待定时时间到
SysTick->CTRL &=~1; //关闭定时器
}
}
void LED_Init(void)
{
//使能GPIOE,GPIOF时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF, ENABLE);
//GPIOF9,F10初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //LED0和LED1对应IO口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式,
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,驱动LED需要电流驱动
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOF, &GPIO_InitStructure); //初始化GPIOF,把配置的数据写入寄存器
//GPIOE13,PE14初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14; //LED2和LED3对应IO口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOE, &GPIO_InitStructure); //初始化GPIOE,把配置的数据写入寄存器
GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10); //GPIOF9,PF10设置高,灯灭
GPIO_SetBits(GPIOE,GPIO_Pin_13 | GPIO_Pin_14);
}
void USART1_Init(uint32_t baud)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能USART1时钟
//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
//USART1端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = baud; //波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
void USART3_Init(uint32_t baud)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* GPIOB Configuration: PB10 PB11 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect USART3_TX pins to PB10 */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
/* Connect USART3_RX pins to PB11 */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
/* Enable USART3 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStructure);
/* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable USART3 */
USART_Cmd(USART3, ENABLE);
/* Enable the Rx buffer empty interrupt */
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
}
void USART1_SendBytes(uint8_t *pbuf,uint32_t len)
{
while(len--)
{
USART_SendData(USART1,*pbuf++);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
}
void USART1_SendString(uint8_t *pstr)
{
while(pstr && *pstr)
{
USART_SendData(USART1,*pstr++);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
}
void USART3_SendBytes(uint8_t *pbuf,uint32_t len)
{
while(len--)
{
USART_SendData(USART3,*pbuf++);
while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);
}
}
void USART3_SendString(uint8_t *pstr)
{
while(pstr && *pstr)
{
USART_SendData(USART3,*pstr++);
while(USART_GetFlagStatus(USART3,USART_FLAG_TXE)==RESET);
}
}
int main(void)
{
LED_Init();
//系统定时器初始化,时钟源来自HCLK,且进行8分频,
//系统定时器时钟频率=168MHz/8=21MHz
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//设置中断优先级分组2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//串口1,波特率115200bps,开启接收中断
USART1_Init(9600);
//串口3,波特率9600bps,开启接收中断
USART3_Init(9600);
while(1)
{
}
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
//从串口1接收数据
g_usart1_recv_buf[g_usart1_recv_cnt]=USART_ReceiveData(USART1);
USART_SendData(USART1, g_usart1_recv_buf[g_usart1_recv_cnt]);
//记录多少个数据
g_usart1_recv_cnt++;
//检测到换行符或接收的数据满的时候则发送数据
if(g_usart1_recv_buf[g_usart1_recv_cnt-1]=='\n' || g_usart1_recv_cnt>=(sizeof g_usart1_recv_buf)-1)
{
USART3_SendBytes(g_usart1_recv_buf,g_usart1_recv_cnt);
USART1_SendBytes(g_usart1_recv_buf,g_usart1_recv_cnt);
g_usart1_recv_cnt = 0;
}
}
}
void USART3_IRQHandler(void)
{
uint8_t d;
/* USART in Receiver mode */
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
d=USART_ReceiveData(USART3);
USART1_SendBytes(&d,1);
}
}
蓝牙连接
在初始化蓝牙完成之后,把UART1改成3、5和4、6跳起来,然后把蓝牙模块接到P4(原本串口通信实现UART1是1、3和2、4跳起来,连接着串口,现在是连接蓝牙所以要改动,当然蓝牙也要由原本接着的P6改接成P4,因为P6是连接到UART3的),注意,蓝牙的TX连接P4的RX,蓝牙的RX连接P4的TX,要交替相接
挪用day5_1里串口通信的代码,连接蓝牙,然后就可以实现了。
- 手机端下载蓝牙调试器app
- 打开app连接上对应的蓝牙
- 实现通过蓝牙输入1打开蜂鸣器,输入0关闭蜂鸣器(可以直接在数据发送界面实现,也可以设置按钮实现)