stm32蓝牙模块通过手机和电脑双向通信
只需将蓝牙连到单片机上,使用usart3(PB10、PB11)作为蓝牙和单片机的数据传输,而电脑的收发数据要是用usart1(PA9、PA10),将数据存入数组中,从而在串口助手中打印值
1.下面是usart.c文件,将io口和串口初始化,并且加入中断(其中电脑发送时,所用的中断需要回车换行,正常情况下,直接数据存入寄存器,将数据存放在数组中(参考下面usart3的中断))
#include "sys.h"
#include "usart.h"
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //如果使能了接收
u8 USART_RX_BUF[USART_REC_LEN];
u8 USART3_RX_BUF[USART_REC_LEN];
//接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0;
u16 USART3_RX_STA=0;
//接收状态标记
/*1、使能对应串口使用的时钟
2、对应GPIO配置
3、中断配置(中断通道 优先级)
4、串口相关参数配置(波特率 数据位 停止位 等)
5、设置使用的中断
6、使能串口函数
*/
void uart1_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开GPIOA时钟和串口1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
//配置PA.10复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//配置PA.9浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//中断参数配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;在这里存在两个优先级,要区分不能一样
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//串口参数配置
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//收发模式
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
USART_Cmd(USART1,ENABLE);
}
usart1的中断服务函数过程,当接收到从电脑发过来的数据,把接收到的数据保存在 USART_RX_BUF 中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待0X0A 的到来,而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。如果顺利接收到 0X0A,则标记 USART_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到 0X0D,那么在接收数据超过 USART_REC_LEN 的时候,则会丢弃前面的数据,重新接收。
当接收到从电脑发过来的数据,把接收到的数据保存在 USART_RX_BUF 中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车的表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待0X0A 的到来,而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。如果顺利接收到 0X0A,则标记 USART_RX_STA 的第 15 位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到 0X0D,那么在接收数据超过 USART_REC_LEN 的时候,则会丢弃前面的数据,重新接收。
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET) //接收标志位是否为1
{
Res = USART1->DR;//Res = USART_ReceiveData(USART1)
if((USART_RX_STA&0x8000) != 1) //未接收完成
{
if(USART_RX_STA & 0x4000) //接收0x0D完成 等待0x0A到来
{
if(Res == 0x0A) //如果接收到0x0A 接收完成标志位置1
{
USART_RX_STA |= 0x8000;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
else //接收失败 重新接收
USART_RX_STA = 0;
}
else
{
if(Res == 0x0D) //接收到的数据是否为0x0D
USART_RX_STA |= 0x4000; //位14置1
else //非0x0D 0x0A这两个字符
{
USART_RX_BUF[USART_RX_STA&0x3FFF] = Res; //把数据给数组
USART_RX_STA++; //数组下标增加
if(USART_RX_STA>USART_REC_LEN-1)
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
void uart3_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//打开GPIOA时钟和串口1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//配置PB11复用推挽输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//配置PB10浮空输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//中断参数配置
NVIC_InitStructure.NVIC_IRQChannel=USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init (&NVIC_InitStructure);
//串口参数配置
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//收发模式
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
USART_Init(USART3,&USART_InitStructure);
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
USART_Cmd(USART3,ENABLE);
}
u8 Flag = 0; 这里的flag作为一个标志位,用于打印在串口助手
void USART3_IRQHandler(void) //串口3中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART3,USART_IT_RXNE) == SET) //接收标志位是否为1
{
USART_ClearITPendingBit(USART3,USART_IT_RXNE);
Res = USART3->DR;//Res = USART_ReceiveData(USART3)
USART3_RX_BUF[USART_RX_STA&0x3FFF] = Res; //把数据给数组
USART3_RX_STA++;
Flag = 1;
}
}
#endif
2.其次在.h文件中声明
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
extern u8 USART3_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART3_RX_STA;
extern u8 Flag;
void uart3_init(u32 bound);
void uart1_init(u32 bound);
#endif
3.主函数程序,运行
int main()
{
u8 i = 0,len;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart3_init(9600);
uart1_init(9600);
while(1)
{
if(Flag == 1)
{
printf("%s",USART3_RX_BUF);
//USART3_RX_STA=0;
//memset(USART3_RX_BUF,0,sizeof(USART3_RX_BUF));
Flag = 0;
}
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3FFF;
for(i = 0;i<len;i++)
{
USART_SendData(USART3,USART_RX_BUF[i]);将存入数组的数据,发送到串口3
while((USART3->SR&0x40) == 0);//等待发送结束 读取USART1 SR寄存器状态为0表示发送未完成 1为发送完成 (判断发送是否成功)
}
printf("%s",USART_RX_BUF);
memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));
USART_RX_STA = 0;
}
}
}