YFROBOT创客社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 19683|回复: 5
打印 上一主题 下一主题

BC04蓝牙串口模块与STM32通信,STM32串口2

[复制链接]

签到天数: 63 天

[LV.6]常住居民II

跳转到指定楼层
楼主
发表于 2014-6-10 10:53:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
蓝牙通信测试-利用适配器/手机/电脑自带蓝牙
http://www.yfrobot.com/forum.php?mod=viewthread&tid=599
(出处: arduino 单片机机器人爱好者之家)
BC-04蓝牙模块使用教程-AT指令的使用
http://www.yfrobot.com/forum.php?mod=viewthread&tid=4
(出处: arduino 单片机机器人爱好者之家)
通过对上两个帖子的学习,了解蓝牙的基本知识,实现手机串口与电脑串口之间的通信。
蓝牙的使用十分简单,不用把它想的多么复杂,当蓝牙通电后,手机蓝牙就可以连接到BC04,连接完成后蓝牙模块中的灯常亮,此时它就是一根线,一段接着STM32的串口2,另一端接着手机,这时,手机就可以向STM32发送指令了。
1、实验目的:利用STM32的串口2与BC04相连,实现与手机的通信,并通过手机串口助手发送“ON”与“OFF”,控制“STATE”灯的“亮灭”。
2、硬件连接方式:STM32核心板-->YFROBOT_BC04
                                         PA2   --   RXD
                                         PA3   --   TXD
                                         GND  --   GND
                                         3.3V  --   3V3
3、新建工程
首先,我们初始化STM32的串口2(USART2),这样才能够保证与蓝牙的正常通信。
新建文件usart2.c
  1. #include "delay.h"
  2. #include "usart2.h"
  3. #include "stdarg.h"                  
  4. #include "stdio.h"                  
  5. #include "string.h"          //这3个文件为标准库的头文件,具体用途请百度
  6. /***************************************************************
  7. Copyright (C), 2013-2023, YFRobot.
  8. www.yfrobot.com
  9. File:串口2驱动代码(PA2/U2_TX;PA3/U2_RX)
  10. Author:aosini    Version:1.0     Data:2014/05/28
  11. Description:此函数对原子的串口驱动代码进行了修改,在此感谢正点原子@ALIENTEK开源
  12.             硬件与BC04的接线方式;PA2接蓝牙RXD;PA3接TXD。
  13. ***************************************************************/  

  14. //串口发送缓存区         
  15. __align(8) u8 USART2_TX_BUF[USART2_MAX_SEND_LEN];         //发送缓冲,最大USART2_MAX_SEND_LEN字节
  16. #ifdef USART2_RX_EN                                                                   //如果使能了接收            
  17. //串口接收缓存区         
  18. u8 USART2_RX_BUF[USART2_MAX_RECV_LEN];                                 //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
  19. //通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
  20. //如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
  21. //任何数据,则表示此次接收完毕.
  22. //接收到的数据状态
  23. //[15]:0,没有接收到数据;1,接收到了一批数据.
  24. //[14:0]:接收到的数据长度
  25. u16 USART2_RX_STA=0;            
  26. void USART2_IRQHandler(void)
  27. {
  28.         u8 res;            
  29.         if(USART2->SR&(1<<5))//接收到数据
  30.         {         
  31.                 res=USART2->DR;                          
  32.                 if(USART2_RX_STA<USART2_MAX_RECV_LEN)                //还可以接收数据
  33.                 {
  34.                         TIM1->CNT=0;                                                 //计数器清空
  35.                         if(USART2_RX_STA==0)TIM1_Set(1);                 //使能定时器4的中断
  36.                         USART2_RX_BUF[USART2_RX_STA++]=res;                //记录接收到的值         
  37.                 }else
  38.                 {
  39.                         USART2_RX_STA|=1<<15;                                        //强制标记接收完成
  40.                 }
  41.         }                                                                                          
  42. }   
  43. //初始化IO 串口2
  44. //pclk1:PCLK1时钟频率(Mhz)
  45. //bound:波特率         
  46. void USART2_Init(u32 pclk1,u32 bound)
  47. {                           
  48.         RCC->APB2ENR|=1<<8;           //使能PORTG口时钟  
  49.          GPIOG->CRH&=0XFFFFFF0F;        //IO状态设置
  50.         GPIOG->CRH|=0X00000030;        //IO状态设置
  51.         RCC->APB2ENR|=1<<2;           //使能PORTA口时钟  
  52.         GPIOA->CRL&=0XFFFF00FF;        //IO状态设置
  53.         GPIOA->CRL|=0X00008B00;        //IO状态设置         
  54.         RCC->APB1ENR|=1<<17;          //使能串口时钟         
  55.         RCC->APB1RSTR|=1<<17;   //复位串口2
  56.         RCC->APB1RSTR&=~(1<<17);//停止复位                     
  57.         //波特率设置
  58.          USART2->BRR=(pclk1*1000000)/(bound);// 波特率设置         
  59.         USART2->CR1|=0X200C;          //1位停止,无校验位.
  60.         USART2->CR3=1<<7;           //使能串口2的DMA发送
  61.         UART_DMA_Config(DMA1_Channel7,(u32)&USART2->DR,(u32)USART2_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF
  62. #ifdef USART2_RX_EN                          //如果使能了接收
  63.         //使能接收中断
  64.         USART2->CR1|=1<<8;            //PE中断使能
  65.         USART2->CR1|=1<<5;            //接收缓冲区非空中断使能                    
  66.         MY_NVIC_Init(2,3,USART2_IRQChannel,2);//组2,最低优先级
  67.         TIM1_Init(99,7199);                //10ms中断
  68.         USART2_RX_STA=0;                //清零
  69.         TIM1_Set(0);                        //关闭定时器4
  70. #endif                                                                                          
  71. }
  72. //串口2,printf 函数
  73. //确保一次发送数据不超过USART2_MAX_SEND_LEN字节
  74. void u2_printf(char* fmt,...)  
  75. {  
  76.         va_list ap;
  77.         va_start(ap,fmt);
  78.         vsprintf((char*)USART2_TX_BUF,fmt,ap);
  79.         va_end(ap);
  80.         while(DMA1_Channel7->CNDTR!=0);        //等待通道7传输完成   
  81.         UART_DMA_Enable(DMA1_Channel7,strlen((const char*)USART2_TX_BUF));         //通过dma发送出去
  82. }
  83. //定时器1中断服务程序                    
  84. void TIM1_UP_IRQHandler(void)
  85. {         
  86.         if(TIM1->SR&0X01)//是更新中断
  87.         {                                    
  88.                 USART2_RX_STA|=1<<15;        //标记接收完成
  89.                 TIM1->SR&=~(1<<0);                //清除中断标志位                  
  90.                 TIM1_Set(0);                        //关闭TIM1
  91.         }            
  92. }
  93. //设置TIM1的开关
  94. //sta:0,关闭;1,开启;
  95. void TIM1_Set(u8 sta)
  96. {
  97.         if(sta)
  98.         {
  99.             TIM1->CNT=0;         //计数器清空
  100.                 TIM1->CR1|=1<<0;     //使能定时器1
  101.         }else TIM1->CR1&=~(1<<0);//关闭定时器1           
  102. }
  103. //通用定时器中断初始化
  104. //这里始终选择为APB1的2倍,而APB1为36M
  105. //arr:自动重装值。
  106. //psc:时钟预分频数                 
  107. void TIM1_Init(u16 arr,u16 psc)
  108. {
  109.         RCC->APB2ENR|=1<<11;        //TIM1时钟使能   
  110.          TIM1->ARR=arr;          //设定计数器自动重装值   
  111.         TIM1->PSC=psc;          //预分频器
  112.          TIM1->DIER|=1<<0;   //允许更新中断                                
  113.          TIM1->CR1|=0x01;          //使能定时器1                     
  114.            MY_NVIC_Init(1,3,TIM1_UP_IRQChannel,2);//抢占2,子优先级3,组2        在2中优先级最低                                                                 
  115. }
  116. #endif                 
  117. ///////////////////////////////////////USART2 DMA发送配置部分//////////////////////////////////                              
  118. //DMA1的各通道配置
  119. //这里的传输形式是固定的,这点要根据不同的情况来修改
  120. //从存储器->外设模式/8位数据宽度/存储器增量模式
  121. //DMA_CHx:DMA通道CHx
  122. //cpar:外设地址
  123. //cmar:存储器地址   
  124. void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
  125. {
  126.          RCC->AHBENR|=1<<0;                        //开启DMA1时钟
  127.         delay_us(5);
  128.         DMA_CHx->CPAR=cpar;                 //DMA1 外设地址
  129.         DMA_CHx->CMAR=cmar;                 //DMA1,存储器地址         
  130.         DMA_CHx->CCR=0X00000000;        //复位
  131.         DMA_CHx->CCR|=1<<4;                  //从存储器读
  132.         DMA_CHx->CCR|=0<<5;                  //普通模式
  133.         DMA_CHx->CCR|=0<<6;                  //外设地址非增量模式
  134.         DMA_CHx->CCR|=1<<7;                  //存储器增量模式
  135.         DMA_CHx->CCR|=0<<8;                  //外设数据宽度为8位
  136.         DMA_CHx->CCR|=0<<10;                 //存储器数据宽度8位
  137.         DMA_CHx->CCR|=1<<12;                 //中等优先级
  138.         DMA_CHx->CCR|=0<<14;                 //非存储器到存储器模式                          
  139. }
  140. //开启一次DMA传输
  141. void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
  142. {
  143.         DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输
  144.         DMA_CHx->CNDTR=len;          //DMA1,传输数据量
  145.         DMA_CHx->CCR|=1<<0;          //开启DMA传输
  146. }           
复制代码
这部分代码,主要实现了1:串口 2 的初始化;2:实现了串口 2 的 printf 函数:u2_printf;3:串口 2 的接收处理。
串口 2 这里我们发送数据采用 DMA 发送,以提高系统实时性。串口2 的数据接收,采用了定时判断的方法,对于一次连续接收的数据,如果出现连续 10ms 没有接收到任何数据,则表示这次连续接收数据已经结束。
新建usart2.h
  1. #ifndef __USART2_H
  2. #define __USART2_H         
  3. #include "sys.h"
  4. /***************************************************************
  5. Copyright (C), 2013-2023, YFRobot.
  6. www.yfrobot.com
  7. File:串口2驱动代码(PA2/U2_TX;PA3/U2_RX)
  8. Author:aosini    Version:1.0     Data:2014/05/28
  9. Description:此函数对原子的串口驱动代码进行了修改,在此感谢正点原子@ALIENTEK分享
  10.             硬件与BC04的接线方式;PA2接蓝牙RXD;PA3接TXD。
  11. ***************************************************************/        

  12. #define USART2_MAX_RECV_LEN                200                                        //最大接收缓存字节数
  13. #define USART2_MAX_SEND_LEN                200                                        //最大发送缓存字节数
  14. #define USART2_RX_EN                         1                                        //0,不接收;1,接收.
  15. #define true                  1
  16. #define false                 0

  17. extern u8  USART2_RX_BUF[USART2_MAX_RECV_LEN];                 //接收缓冲,最大USART2_MAX_RECV_LEN字节
  18. extern u8  USART2_TX_BUF[USART2_MAX_SEND_LEN];                 //发送缓冲,最大USART2_MAX_SEND_LEN字节
  19. extern u16 USART2_RX_STA;                                                   //接收数据状态

  20. void USART2_Init(u32 pclk2,u32 bound);                                //串口2初始化
  21. void TIM1_Set(u8 sta);
  22. void TIM1_Init(u16 arr,u16 psc);
  23. void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar);
  24. void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len);
  25. void u2_printf(char* fmt, ...);
  26. float myatof(const char *sptr);
  27. #endif
复制代码
初始化“STATE”,新建led.c
  1. #include <stm32f10x_lib.h>           
  2. #include "led.h"
  3. //初始化PD2为输出口.并使能这个口的时钟                    
  4. //LED IO初始化
  5. void LED_Init(void)
  6. {                    
  7.         RCC->APB2ENR|=1<<5;    //使能PORTD时钟         
  8.         GPIOD->CRL&=0XFFFFF0FF;
  9.         GPIOD->CRL|=0X00000300;//PD.2推挽输出
  10.         GPIOD->ODR|=1<<2;      //PD.2输出高
  11. }
复制代码
新建led.h
  1. #ifndef __LED_H
  2. #define __LED_H         
  3. #include "sys.h"
  4. //LED端口定义
  5. #define LED1 PDout(2)// PD2        
  6. void LED_Init(void);//初始化                                                     
  7. #endif
复制代码
这部分代码,主要实现LED1的初始话。
最后在main.c文件中编写如下代码
  1. #include<stm32f10x_lib.h>
  2. #include "sys.h"
  3. #include "usart.h"               
  4. #include "delay.h"
  5. #include "led.h"
  6. #include "usart2.h"
  7. #include "string.h"
  8. /*********************************************************
  9. Copyright (C), 2013-2023, YFRobot.
  10. www.yfrobot.com
  11. File:BC04蓝牙串口模式实验(STM32/TIM1)
  12. Author:aosini    Version:1.0     Data:2014/06/09
  13. Description:通过手机端Android串口,向蓝牙发送“ON”或“OFF”,
  14.         控制指示灯的“亮”与“灭”。
  15. **********************************************************/
  16. int main(void)
  17. {
  18.     u8 reclen=0; //数据长度
  19.         Stm32_Clock_Init(9); //系统时钟设置
  20.         delay_init(72);             //延时初始化
  21.         uart_init(72,9600);  //串口1初始化
  22.         USART2_Init(36,9600);//串口2初始化
  23.         LED_Init();
  24.         while(1)
  25.         {
  26.             if(USART2_RX_STA&0X8000)                        //接收到一次数据了
  27.                 {
  28.                          reclen=USART2_RX_STA&0X7FFF;        //得到数据长度
  29.                           USART2_RX_BUF[reclen]=0;                 //结尾加入结束符  这句很重要,可以保证这次收到的信息不受上次的影响,
  30.                                                         //没有这语句的时候,当上一条信息长于当前信息时,收到的信息是不正确的
  31.                                                                                         //可以将这条语句注释,发不同长度的信息,观察手机串口收到的信息。
  32.                         if(reclen==2||reclen==3)                 //控制DS1检测
  33.                         {
  34.                                 if(strcmp((const char*)USART2_RX_BUF,"ON")==0) LED1=0;        //打开LED1
  35.                                 if(strcmp((const char*)USART2_RX_BUF,"OFF")==0)LED1=1;  //关闭LED1
  36.                         }
  37.                          u2_printf("Receive:%s\r\n",USART2_RX_BUF); //通过串口2,发生蓝牙接收到的数据
  38.                          USART2_RX_STA=0;         
  39.                 }
  40.         }
  41. }
复制代码
这样整个工程就完成了,具体内容,程序中有详细说明。
4、下载验证
编译成功后,下载到stm32核心板上,此时灯“STATE”是灭的。将STM32与蓝牙正确连接,打开手机端串口助手,连接蓝牙,连接成功后,蓝牙模块上的灯常亮。
通过蓝牙串口发送“ON”,“STATE”灯亮,蓝牙串口收到“Receive:ON”;发送“OFF”,“STATE”灯灭,蓝牙串口收到“Receive:OFF”,发送其它数据,不影响“STATE”灯状态。
BC04蓝牙串口模块实验(STM32核心板).rar (594.54 KB, 下载次数: 242)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 支持支持3 反对反对

该用户从未签到

沙发
发表于 2015-10-3 08:56:19 | 只看该作者
请教一下,stm32通过蓝牙接收到的数据存在哪里呢?

是AT24c02中么?
回复 支持 反对

使用道具 举报

该用户从未签到

板凳
发表于 2015-10-3 08:57:53 | 只看该作者
请问stm32通过蓝牙接收到的数据存在哪里呢?
是AT24C02中么?
回复 支持 反对

使用道具 举报

该用户从未签到

地板
发表于 2015-10-3 08:58:19 | 只看该作者
请问stm32通过蓝牙接收到的数据存在哪里呢?
是AT24C02中么?
回复 支持 反对

使用道具 举报

签到天数: 63 天

[LV.6]常住居民II

5#
 楼主| 发表于 2015-12-12 14:51:44 | 只看该作者
zero 发表于 2015-10-3 08:56
请教一下,stm32通过蓝牙接收到的数据存在哪里呢?

是AT24c02中么?

//串口接收缓存区         
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN];
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|联系我们|YFROBOT ( 苏ICP备20009901号-2  

GMT+8, 2024-11-22 00:49 , Processed in 0.088133 second(s), 32 queries .

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表