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

物联沃分享整理
物联沃-IOTWORD物联网 » stm32蓝牙模块通过手机和电脑双向通信

发表评论