YFROBOT创客社区
标题:
BC04蓝牙串口模块与STM32通信,STM32串口2
[打印本页]
作者:
aosini
时间:
2014-6-10 10:53
标题:
BC04蓝牙串口模块与STM32通信,STM32串口2
蓝牙通信测试-利用适配器/手机/电脑自带蓝牙
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
#include "delay.h"
#include "usart2.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h" //这3个文件为标准库的头文件,具体用途请百度
/***************************************************************
Copyright (C), 2013-2023, YFRobot.
www.yfrobot.com
File:串口2驱动代码(PA2/U2_TX;PA3/U2_RX)
Author:aosini Version:1.0 Data:2014/05/28
Description:此函数对原子的串口驱动代码进行了修改,在此感谢正点原子@ALIENTEK开源
硬件与BC04的接线方式;PA2接蓝牙RXD;PA3接TXD。
***************************************************************/
//串口发送缓存区
__align(8) u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
#ifdef USART2_RX_EN //如果使能了接收
//串口接收缓存区
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
u16 USART2_RX_STA=0;
void USART2_IRQHandler(void)
{
u8 res;
if(USART2->SR&(1<<5))//接收到数据
{
res=USART2->DR;
if(USART2_RX_STA<USART2_MAX_RECV_LEN) //还可以接收数据
{
TIM1->CNT=0; //计数器清空
if(USART2_RX_STA==0)TIM1_Set(1); //使能定时器4的中断
USART2_RX_BUF[USART2_RX_STA++]=res; //记录接收到的值
}else
{
USART2_RX_STA|=1<<15; //强制标记接收完成
}
}
}
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率
void USART2_Init(u32 pclk1,u32 bound)
{
RCC->APB2ENR|=1<<8; //使能PORTG口时钟
GPIOG->CRH&=0XFFFFFF0F; //IO状态设置
GPIOG->CRH|=0X00000030; //IO状态设置
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
GPIOA->CRL&=0XFFFF00FF; //IO状态设置
GPIOA->CRL|=0X00008B00; //IO状态设置
RCC->APB1ENR|=1<<17; //使能串口时钟
RCC->APB1RSTR|=1<<17; //复位串口2
RCC->APB1RSTR&=~(1<<17);//停止复位
//波特率设置
USART2->BRR=(pclk1*1000000)/(bound);// 波特率设置
USART2->CR1|=0X200C; //1位停止,无校验位.
USART2->CR3=1<<7; //使能串口2的DMA发送
UART_DMA_Config(DMA1_Channel7,(u32)&USART2->DR,(u32)USART2_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF
#ifdef USART2_RX_EN //如果使能了接收
//使能接收中断
USART2->CR1|=1<<8; //PE中断使能
USART2->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(2,3,USART2_IRQChannel,2);//组2,最低优先级
TIM1_Init(99,7199); //10ms中断
USART2_RX_STA=0; //清零
TIM1_Set(0); //关闭定时器4
#endif
}
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u2_printf(char* fmt,...)
{
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART2_TX_BUF,fmt,ap);
va_end(ap);
while(DMA1_Channel7->CNDTR!=0); //等待通道7传输完成
UART_DMA_Enable(DMA1_Channel7,strlen((const char*)USART2_TX_BUF)); //通过dma发送出去
}
//定时器1中断服务程序
void TIM1_UP_IRQHandler(void)
{
if(TIM1->SR&0X01)//是更新中断
{
USART2_RX_STA|=1<<15; //标记接收完成
TIM1->SR&=~(1<<0); //清除中断标志位
TIM1_Set(0); //关闭TIM1
}
}
//设置TIM1的开关
//sta:0,关闭;1,开启;
void TIM1_Set(u8 sta)
{
if(sta)
{
TIM1->CNT=0; //计数器清空
TIM1->CR1|=1<<0; //使能定时器1
}else TIM1->CR1&=~(1<<0);//关闭定时器1
}
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
void TIM1_Init(u16 arr,u16 psc)
{
RCC->APB2ENR|=1<<11; //TIM1时钟使能
TIM1->ARR=arr; //设定计数器自动重装值
TIM1->PSC=psc; //预分频器
TIM1->DIER|=1<<0; //允许更新中断
TIM1->CR1|=0x01; //使能定时器1
MY_NVIC_Init(1,3,TIM1_UP_IRQChannel,2);//抢占2,子优先级3,组2 在2中优先级最低
}
#endif
///////////////////////////////////////USART2 DMA发送配置部分//////////////////////////////////
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
{
RCC->AHBENR|=1<<0; //开启DMA1时钟
delay_us(5);
DMA_CHx->CPAR=cpar; //DMA1 外设地址
DMA_CHx->CMAR=cmar; //DMA1,存储器地址
DMA_CHx->CCR=0X00000000; //复位
DMA_CHx->CCR|=1<<4; //从存储器读
DMA_CHx->CCR|=0<<5; //普通模式
DMA_CHx->CCR|=0<<6; //外设地址非增量模式
DMA_CHx->CCR|=1<<7; //存储器增量模式
DMA_CHx->CCR|=0<<8; //外设数据宽度为8位
DMA_CHx->CCR|=0<<10; //存储器数据宽度8位
DMA_CHx->CCR|=1<<12; //中等优先级
DMA_CHx->CCR|=0<<14; //非存储器到存储器模式
}
//开启一次DMA传输
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
{
DMA_CHx->CCR&=~(1<<0); //关闭DMA传输
DMA_CHx->CNDTR=len; //DMA1,传输数据量
DMA_CHx->CCR|=1<<0; //开启DMA传输
}
复制代码
这部分代码,主要实现了1:串口 2 的初始化;2:实现了串口 2 的 printf 函数:u2_printf;3:串口 2 的接收处理。
串口 2 这里我们发送数据采用 DMA 发送,以提高系统实时性。串口2 的数据接收,采用了定时判断的方法,对于一次连续接收的数据,如果出现连续 10ms 没有接收到任何数据,则表示这次连续接收数据已经结束。
新建usart2.h
#ifndef __USART2_H
#define __USART2_H
#include "sys.h"
/***************************************************************
Copyright (C), 2013-2023, YFRobot.
www.yfrobot.com
File:串口2驱动代码(PA2/U2_TX;PA3/U2_RX)
Author:aosini Version:1.0 Data:2014/05/28
Description:此函数对原子的串口驱动代码进行了修改,在此感谢正点原子@ALIENTEK分享
硬件与BC04的接线方式;PA2接蓝牙RXD;PA3接TXD。
***************************************************************/
#define USART2_MAX_RECV_LEN 200 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN 200 //最大发送缓存字节数
#define USART2_RX_EN 1 //0,不接收;1,接收.
#define true 1
#define false 0
extern u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern u16 USART2_RX_STA; //接收数据状态
void USART2_Init(u32 pclk2,u32 bound); //串口2初始化
void TIM1_Set(u8 sta);
void TIM1_Init(u16 arr,u16 psc);
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar);
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len);
void u2_printf(char* fmt, ...);
float myatof(const char *sptr);
#endif
复制代码
初始化“STATE”,新建led.c
#include <stm32f10x_lib.h>
#include "led.h"
//初始化PD2为输出口.并使能这个口的时钟
//LED IO初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOD->CRL&=0XFFFFF0FF;
GPIOD->CRL|=0X00000300;//PD.2推挽输出
GPIOD->ODR|=1<<2; //PD.2输出高
}
复制代码
新建led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED端口定义
#define LED1 PDout(2)// PD2
void LED_Init(void);//初始化
#endif
复制代码
这部分代码,主要实现LED1的初始话。
最后在main.c文件中编写如下代码
#include<stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "usart2.h"
#include "string.h"
/*********************************************************
Copyright (C), 2013-2023, YFRobot.
www.yfrobot.com
File:BC04蓝牙串口模式实验(STM32/TIM1)
Author:aosini Version:1.0 Data:2014/06/09
Description:通过手机端Android串口,向蓝牙发送“ON”或“OFF”,
控制指示灯的“亮”与“灭”。
**********************************************************/
int main(void)
{
u8 reclen=0; //数据长度
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口1初始化
USART2_Init(36,9600);//串口2初始化
LED_Init();
while(1)
{
if(USART2_RX_STA&0X8000) //接收到一次数据了
{
reclen=USART2_RX_STA&0X7FFF; //得到数据长度
USART2_RX_BUF[reclen]=0; //结尾加入结束符 这句很重要,可以保证这次收到的信息不受上次的影响,
//没有这语句的时候,当上一条信息长于当前信息时,收到的信息是不正确的
//可以将这条语句注释,发不同长度的信息,观察手机串口收到的信息。
if(reclen==2||reclen==3) //控制DS1检测
{
if(strcmp((const char*)USART2_RX_BUF,"ON")==0) LED1=0; //打开LED1
if(strcmp((const char*)USART2_RX_BUF,"OFF")==0)LED1=1; //关闭LED1
}
u2_printf("Receive:%s\r\n",USART2_RX_BUF); //通过串口2,发生蓝牙接收到的数据
USART2_RX_STA=0;
}
}
}
复制代码
这样整个工程就完成了,具体内容,程序中有详细说明。
4、下载验证
编译成功后,下载到stm32核心板上,此时灯“STATE”是灭的。将STM32与蓝牙正确连接,打开手机端串口助手,连接蓝牙,连接成功后,蓝牙模块上的灯常亮。
通过蓝牙串口发送“ON”,“STATE”灯亮,蓝牙串口收到“Receive:ON”;发送“OFF”,“STATE”灯灭,蓝牙串口收到“Receive:OFF”,发送其它数据,不影响“STATE”灯状态。
[attach]869[/attach]
作者:
zero
时间:
2015-10-3 08:56
请教一下,stm32通过蓝牙接收到的数据存在哪里呢?
是AT24c02中么?
作者:
zero
时间:
2015-10-3 08:57
请问stm32通过蓝牙接收到的数据存在哪里呢?
是AT24C02中么?
作者:
zero
时间:
2015-10-3 08:58
请问stm32通过蓝牙接收到的数据存在哪里呢?
是AT24C02中么?
作者:
aosini
时间:
2015-12-12 14:51
zero 发表于 2015-10-3 08:56
请教一下,stm32通过蓝牙接收到的数据存在哪里呢?
是AT24c02中么?
//串口接收缓存区
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN];
欢迎光临 YFROBOT创客社区 (http://yfrobot.com.cn/)
Powered by Discuz! X3.1