蓝牙和51单片机

2018-08-28 18:51:06 u010898329 阅读数 14080

系列博文:

(1)安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯 

(2)安卓手机与蓝牙模块联合调试(二)—— 单片机蓝牙控制LED灯亮灭(上)

(3)安卓手机与蓝牙模块联合调试(三)—— 单片机蓝牙控制LED灯亮灭(下)

本教程的项目地址:1989Jiangtao/BluetoothSCM: 安卓手机通过蓝牙与单片机通信-发送指令/接收数据​​​​​​​


忙里偷闲,承接上一篇文章继续

安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯 - CSDN博客

本篇将实现两个实例,手头正好有8位的单片机,索性就用来练手了。将会提供两个例子,一个是基于STM8的库函数实例,一个是基于STC89C52的实例。

1.首先了解下单片机串口通讯线的接法。这个比较重要,建议参考文章。

(1)HC-05初探 - 骑着蜗牛逛世界 - 博客园      https://www.cnblogs.com/LittleHann/p/5621937.html

(2)HC-05 蓝牙模块的调试与使用 - CSDN博客      https://blog.csdn.net/txf1984/article/details/46553715

 

2. 准备工作和单片机原理图。

       首先看下我用到的硬件支持,一块STM8S103F2P6最小系统板,一个ST-Link下载器,一个HC-05的模块(暂时先调试HC-5的模块,CC2541单片机端的代码是一样的)

最小系统的原理图如下,大家按照上面两个博文中的接线方法接好单片机,特别注意蓝牙模块的TX/RX与单片机的TX/RX要交叉相接

3. 单片机的代码,使用STM8库函数编写。

首先看下目录结构,本项目使用的是IAR编译器

下面贴出来main函数,注释在代码中已经描述的很清楚了,大家可以自行参考。

/*************
** Author   : 江涛
** Date     :  2018/08/28
** Describe : 蓝牙控制单片机开关灯
**************/
/* Includes -----------*/
#include "stm8s.h"
#include <string.h>

/********************************************
**  TestLed        PB5  测试LED
**********************************************/

/**串口1接收数据标志位**/
unsigned char Usart1_bufStart_or_bufSotp = 0 ;
/**串口1数据,这里10个字节够放命令了,大家可以根据实际需要调整数组长度**/
char Usart1BufData[10];
/**串口数据数目自增量,用来统计数目是否达到数组最大长度**/
char Usart1BufConst;

/****以下是定义的命令*****/
char LED_ON[10] = "ON\n";  
char LED_OFF[10] = "OFF\n";

void Delay(uint16_t nCount)
{
  /* Decrement nCount value */
  while (nCount != 0)
  {   
    nCount--;
  }
}

/*************
* 初始化串口UART1
**************/
void initUart1()
{
  // 串口设置
  UART1_DeInit();
  // 9600波特率,8位数据位,一位停止位,
  UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);//UART1_MODE_TX_ENABLE);
  // 使能串口接收中断
  UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
}

/*********
* 端口配置
**************/
void initGPIO(){
  // LED灯的GPIO口初始化
  GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST);
  GPIO_WriteHigh(GPIOB , GPIO_PIN_5); // 关测试灯
  
}

/*****************
*  程序入口
*******************/
void main(void)
{

  // 初始化系统时钟,
  CLK_HSICmd(ENABLE);
  CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);
  //内部时钟16M,8分频
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);    
  
  initGPIO();
   
  initUart1();
  
  enableInterrupts(); // 使能中断
       
  while (1)
  {    
    if(Usart1_bufStart_or_bufSotp)
    {
       Usart1_bufStart_or_bufSotp = 0 ; 
              
       if(strcmp(Usart1BufData,LED_ON)==0)
       {
          GPIO_WriteLow(GPIOB , GPIO_PIN_5);         
       }
       else if(strcmp(Usart1BufData,LED_OFF)==0)
       {
          GPIO_WriteHigh(GPIOB , GPIO_PIN_5);
       }
              
       Usart1BufConst = 0 ;
       memset(Usart1BufData,0,10);//清0数组   
    }    
  }
}


#ifdef USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *   where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval : None
  */
void assert_failed(u8* file, u32 line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

 项目中还有个it.c文件,内容如下:

/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"

/* Private typedef -----------------------------------------------------------*/

extern unsigned char Usart1_bufStart_or_bufSotp;
extern char Usart1BufData[10];
extern char Usart1BufConst;

/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/


#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S103) || \
    defined(STM8S003) ||  defined (STM8AF62Ax) || defined (STM8AF52Ax) || defined (STM8S903)
/**
  * @brief UART1 TX Interrupt routine.
  * @param  None
  * @retval None
  */
 INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17)
 {
    /* In order to detect unexpected events during development,
       it is recommended to set a breakpoint on the following instruction.
    */
 }


/**
  * @brief UART1 RX Interrupt routine.
  * @param  None
  * @retval None
  */
 INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
 {
    /* In order to detect unexpected events during development,
       it is recommended to set a breakpoint on the following instruction.
    */  
     
     Usart1BufData[Usart1BufConst]=UART1_ReceiveData8();
     UART1_SendData8(UART1_ReceiveData8()); 
     // 收到了结束符号
     if(Usart1BufData[Usart1BufConst]==0x0A)
     {
       Usart1_bufStart_or_bufSotp=1;    
     }
     else
       Usart1BufConst++;
   
      UART1_ClearITPendingBit(UART1_IT_RXNE); // 清除标志位
      
 }
#endif /*STM8S208 or STM8S207 or STM8S103 or STM8S903 or STM8AF62Ax or STM8AF52Ax */

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

主要代码就是这些了,注释中已经写的很清楚了。

4.接好线看下运行的效果 。

过后放上一个视频连接,实在因为gif的效果不明显。 

 

好了,STM8蓝牙控制LED亮灭的功能基本实现了,下一遍将实现蓝牙和STC89单片机的联调。

当这个系列结束之后我会将代码一并上传到Git。博文更新的话,可能因为工作原因会断断续续,希望大家见谅。如果觉得有帮助或者有设么其他好的建议可以在博文下留言,赞赏码没有别的意思,这是个知识付费的时代,可能付费了才会更珍惜学习的不易,当然也是作者创作的动力所在,哈哈。


 

 

 

 

2018-10-02 22:34:20 qimi923511491 阅读数 21053

需要的工具:

usb转ttl模块*1


模块如下:

        要想使用HC-05蓝牙模块进行单片机之间通讯或者单片机和蓝牙设备之间通讯,首先要配置好HC-05蓝牙模块的参数。设置好蓝牙的名称、密码、波特率等待。

step1:

        连接usb转ttl模块蓝牙模块,把两个模块的VCC口相连,GND口相连,TX和RX交叉相连(既TX连RX,RX连TX)。

然后下载蓝牙串口配置软件进行配置:提取码:6d32

软件界面如下:

step2:

        连接好两个模块之后,按住蓝牙模块上的小按钮(按住上电是配置模式,直接上电是正常使用模式),然后把usb转ttl模块插上电脑。

选择好端口设置上的COM口,其它配置默认不需要改,点击打开串口。如果硬件连接和端口设置没问题的话这时候就可以连接成功了。

之后点击AT按钮,如果左边界面出现OK字样就证明已经连接成功了,然后就开始根据需求进行配置


手机连接51单片机+蓝牙

  1. 点击设置从机。
  2. 点击设置模式,在右上角改1为0然后点击手动发送。
  3. 点击设置波特率,PS:这里设置的波特率和刚刚端口设置中的波特率是不一样的,这个是正常模式下蓝牙和单片机通讯的波特率,端口设置中的波特率是配置模式下的波特率,修改这里的波特率不是改变配置模式的波特率,下次配置蓝牙模块的端口设置中的波特率还是保持默认。波特率要和单片机的波特率设置为一样,通常51单片机的程序都是用9600,这里默认9600。
  4. 设置密码,看个人喜好。
  5. 设置名称,看个人喜好。

如果以上设置中出现什么问题的话,点击恢复出厂设置重新设置一边。如果没问题的话就可以开始把蓝牙换到单片机上进行使用了。

 

step3:

        吧蓝牙和单片机串口进行连接,蓝牙和单片机的连接和上面的一样,注意TX和RX之间要交叉连接。

        只要连接好蓝牙,烧录好单片机程序,蓝牙就会把单片机串口发送来的数据向已经连接上的蓝牙设备进行发送。

51单片机的demo:

/*串口初始化配置*/
void UartConfiguration()  
{
    TMOD=0x20;      //设置计数器1的工作方式2
    TH1=0xfd;	    //设置计数器1的初值,决定波特率
    TL1=0xfd;		//设置计数器1的初值,决定波特率
    PCON=0x00;      // 波特率倍增0x00不加倍	 0x80加倍
    SCON=0x50;		//设置工作方式1 开启接受允许
    EA=1;		    //开启总中断
    ES=1;			//开启串口接受中断
    TR1=1;			//计数器1开始运行
}
/*发送数据*/
void sendDate(char date)
{
    SBUF=date;		  //接收到的数据放入发送缓存器发送
    while(!TI);       //等待发送数据完成
    TI=0;			  //清除发送完成标志位
}

/*主函数*/
void main()
{
    UartConfiguration();

    sendDate('1');  //发送字符1

    while(1);
}

/*中断函数*/
void Uart() interrupt 4
{
    uchar date;
    date=SBUF;        //取出接受到的数据
    RI=0;			  //清除接受中断标志位

    //收到的数据是date
	
}

这是51单片机向串口发送数据的例程,其中while(!TI)是等待消息发送成功,如果发送不成功的话会一直等待阻塞程序。

        而且51单片机的串口中断是一个字节一个字节地接收数据的,比如手机向单片机发送了数据“123”,单片机中的中断函数Uart()会进入三次,把数据“123”分三次接收完,一次接收一个字符,所以要在其中添加自己的逻辑把单个字符组合成一个字符串来进行处理。

                                           

2019-11-24 23:10:34 itszok 阅读数 1137

51单片机蓝牙小车(精要版)

实现:通过手机与小车的蓝牙通信,实现手机控制小车前后左右的移动。

这是博主学了51单片机第一次做的单片机项目,选择了许多人喜欢的蓝牙小车作为第一个项目。

准备材料:

1.小车亚克力底盘
2.减速电机4个(网上搜索有很多)
3.蓝牙 HC-06
4.L298N
5.7.2V电源(记得配好接口,我买的是大田宫的接口)
6.杜邦线若干(公对公,母对母,公对母)
8.89C52RC单片机最小系统板
7.必要的话要用电焊铁

在这里插入图片描述

在这里插入图片描述

第一:

首先说蓝牙模块,蓝牙模块是比较重要的模块,通过接收手机的信号,把数据传送给单片机,单片机控制电平,使L298N步进电机驱动小车轮子。蓝牙买了HC-06型号,配置非常简单,教程在汇承官网(官网)
具体步骤就不列举了,官网非常详细。单片机程序后面再列举出来。

第二:

说一下连线,连线的话呢单片机的TX,RX,5V,GND分别接蓝牙的 RX,TX,5V,GND
7.2V电源接口连接L298N步进电机的12V,电源GND连接L298N步进电机GND,然后关键的地方来了L298N的一个5V输出口连接单片机给单片机供电,步进电机的GND连接单片机的GND.
(之前用电源连接单片机,单片机再输出供电给L298N,减速电机很难动起来,一直以为是程序错误或者是杜邦线连接错误,搞了很久,后来知道是单片机输出的电流是不够大的,所以正确的连接是 : 电源供电L298N,L298N供电给单片机,L298N供电给四个减速电机
步进电机的左右两边分别有两个口,分别为output1,output2,output3,output4.
output1,output2分别连接减速电机的正负(一共连接两个减速电机)
output3,output4分别连接减速电机的正负(一共连接两个减速电机)

第三:

手机控制端就下载SPP蓝牙串口,然后选择按钮。定义按钮输入要发送的字符就OK了。
在这里插入图片描述
在这里插入图片描述

第四:

代码部分

#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char
#define uint  unsigned int


sbit LF=P0^0;//左上
sbit LB=P0^1;//左下
sbit RF=P0^2;//右上
sbit RB=P0^3;//右下

/前进/
void forward()
{
	LF=0;
	LB=1;
	RF=0;
	RB=1;
}

/后退/
void back()
{
	LF=1;
	LB=0;
	RF=1;
	RB=0;	
}

/左/ 
void left()
{
	LF=0;
	LB=0;
	RF=0;
	RB=1;
}

/右/
void right()
{
	LF=0;
	LB=1;
	RF=0;
	RB=0;
	
}

void UsartConfiguration();
void Delay_1ms(uint i);



void Com_Int(void) interrupt 4
{

  uchar receive_data;
	
  EA = 0;
	
  if(RI == 1) 
	{ 		
		RI = 0;
		
		    LF=0;
				RF=0;
				LB=0;
				RB=0;
		receive_data = SBUF;
			
		if(receive_data == '1')	 
		{
				forward();
		}
		
		else if(receive_data == '2')
		{
				back();
		}
		
		
			else if(receive_data == '3')
		{
			left();
		}
		
		
			else if(receive_data == '4')
		{
				right(); 
		}
		
		
		else if(receive_data == '0')
		{
				LF=0;
				RF=0;
				LB=0;
				RB=0;
		}
		
		
}
		
		
		EA = 1;
}


void main()
{

	UsartConfiguration();
	
	while(1);	
}
	

void UsartConfiguration()
{	
	SCON=0X50;			
	TMOD=0X20;			
	PCON=0X00;		
	TH1=0XFd;		    
	TL1=0XFd;
	TR1=1;					
	ES = 1;        
  EA = 1;         
}



void Delay_1ms(uint i)
{
  uchar x,j;
  
  for(j=0;j<i;j++)
    for(x=0;x<=148;x++);
}

第五:

这次的单片机蓝牙小车项目让我知道了许多东西都是要不断试错不断踩坑才能完成,多查查互联网,多问问朋友,有助于解决问题。下一个项目想要用STM32F407和openmv做一个跟着人运动的小车,朋友说用树莓派会更快,但是我STM32还没学好,就不跳跃这么快,先来STM32。学习时间大概为3个月(STM32&& openmv && python)。做好了会继续写博客。希望这个能对你有一点点帮助。感谢~

2018-02-22 12:17:38 qq_40277973 阅读数 71303

不久前开始学习使用蓝牙模块,在模块与51单片机连接的过程中出现了非常多的问题,我想应该也是很多新手和我一样会遇到这样的问题,因此特地写这篇文章,想分享下在学习过程中遇到的问题以及解决方法。


此次学习用到模块是HC-06蓝牙模块,如下图:

该模块某宝有售,价格约为20RMB。某宝上的HC-06有两种,分别是带引脚不带引脚的,建议新手购买带引脚的。我从试验开始到成功,一共使用了四块蓝牙模块。第一次买的是带引脚的,但是模块本身是坏的;第二次买的是不带引脚的,但是由于自身的焊功有限,导致模块损坏,无法使用;第三次是朋友送的蓝牙4.0,由于某些原因无法使用,在此也特别感谢朋友送我蓝牙;第四次购买,就是上图所示的蓝牙,才最终完成了试验。

总结:在某宝购买时,最好货比三家,虽然模块不值钱,但是在购买过程遇到问题会耽误时间,影响开发,非常麻烦。

单片机用了两个,分别是新手常用的开发板还有一个单片机最小模块,两者有什么区别我稍后会说明。

开发板:


单片机最小模块:


我特别标注了两者的晶振,分别为12MHZ11.0594MHZ,就是晶振的不同导致我在学习中问题的发生。以下是学习试验过程。


蓝牙模块的调试:

接线,蓝牙模块的RX接转换模块的TX蓝牙模块的TX接转换模块的RX,如下图所示:


接入电脑,在PC端下载好串口调试助手,软件自搜,此处不再赘述。

附可能会用到的驱动:链接:https://pan.baidu.com/s/1bpYLfCr 密码:yabv

进入到调试助手,其实基本不怎么用调参数了,蓝牙模块基本都默认设置好波特率为9600,因此直接启动软件调试即可。具体调参数的方法可以自行百度其他文章,都有很详细的介绍。

启动串口,成功后左下角显示成功:


发送AT指令,返回OK:


表明串口正常,此时用手机连接蓝牙模块。手机端也是用到调试助手,请自行下载。

搜索蓝牙模块:

备注:我的蓝牙模块此前已经被我改名为Ezio,未改名前默认为HC06。


连接成功:


尝试发送消息hello:


此时在PC端的串口助手上,可以收到来自手机端发送的消息:


在此说明一点,在蓝牙模块上电以后,模块上的LED灯为闪烁状态,此时处于从机模式,与手机成功连接后,LED灯会变为常亮。自此,蓝牙模块调试成功,可以与单片机连接进行试验


蓝牙模块与51单片机接线:

和连接转换模块一样,蓝牙模块的RX连接单片机的TX,蓝牙模块的TX连接单片机的RX,此处说明单片机的RX和TX引脚分别为P3.0和P3.1,如图(图片来自网络):


正确接线后,向单片机中写入程序,程序如下:

#include <reg52.h>

sbit P1_0 = P1^0;	//测试口,可用可不用
sbit P1_3 = P1^3;	//输出口

unsigned char tempbuf;	//存储接收到的信息

/*初始化串口*/
void BlueteethInit()
{
	SCON = 0x50;	//串口模式1,允许接收
	TMOD = 0x20;	//T1工作模式为2,自动重装
	PCON = 0x00;	//波特率不倍增

	REN = 1;

	TH1 = 0xfd;		//设置波特率为9600
	TL1 = 0xfd;

	RI = 0;

	EA = 1;
	ES = 1;

	TR1 = 1;
}

void main()
{
	BlueteethInit();
	P1_0 = 0;
	P1_3 = 0;
	TI = 0;
	while(1)
	{
		if(tempbuf == 0x31)	//可以使用
			P1_3 = 1;
		if(tempbuf == 0)	//不可以使用
			P1_3 = 0;
		if(tempbuf == 'A')	//可以使用
			P1_3 = 1;
		if(tempbuf == 'B')	//可以使用
			P1_3 = 0;
	}
}

void Serial(void) interrupt 4
{
	tempbuf = SBUF;
	RI = 0;	//读标志清零
	SBUF = tempbuf;	//将内容返回到手机端,可在手机查看发送的内容
	while(!TI);
	TI = 0;	//写标志清零
}

该程序为最简单的测试程序,利用蓝牙接收手机发来的信息,控制P1.3口输出高或者低电平,以测试是否正确接收到信息。


第一步,用蓝牙模块与开发板接线,并成功用手机与蓝牙模块连接,尝试发送信息,过程如图所示:


无论是发送数字或者是其他字符,都可以看见返回的是乱码,因此可以知道,单片机接收的也是乱码,故程序中的判断:

while(1)
	{
		if(tempbuf == 0x31)	//可以使用
			P1_3 = 1;
		if(tempbuf == 0)	//不可以使用
			P1_3 = 0;
		if(tempbuf == 'A')	//可以使用
			P1_3 = 1;
		if(tempbuf == 'B')	//可以使用
			P1_3 = 0;
	}

无法正确执行,P1.3口自然也无法根据需要来输出高或者低电平。

第二步,用蓝牙模块与单片机最小模块接线,成功用手机连接收尝试发送信息,如下图所示:


可见,此时返回的内容与发出的内容相同,经测试此时程序也可以正确执行,使用万用表可以检查出P1.3口输出电平的变化,表明此时蓝牙模块可以正常使用。

特别说明:

if(tempbuf == 0x31)	//可以使用
	P1_3 = 1;
if(tempbuf == 0)	//不可以使用
	P1_3 = 0;

当发送数字消息时,应为十六进制,因此在判断时,如接收到1,应判断是否等于0x31,而不是判断是否等于1。此处经过测试,发送1时,判断tempbuf == 0x31,该判断有效;当发送0时,判断tempbuf == 0,判断无效。判断字符加单引号即可。

第三步,为什么使用两个相同的单片机会导致结果不同?这也是困扰了我很久的问题,后来经过检查,才知道原来就是晶振的问题。此处PO一下大神关于晶振的说明,暂时未看懂:https://www.zhihu.com/question/30930577

但可以得出的结论就是,如果使用串口通信,应使用的晶振为11.0594MHZ,否则可能出现乱码的情况。

另附:开发板上的晶振如图:


是可以更换的,某宝也有售,可以根据需要的晶振购买。


2017-09-07 20:35:21 yangzigege 阅读数 9885

 最近用89c51单片机和HC05蓝牙模块进行了匹配和数据对接。

总体上匹配成功,数据也可以发送接收成功,但是发现一个奇怪的问题,有时候发送一个一字节的数据,低四位正常接收,高四位接受异常。

比如发送0x10 接受为0x30;

后来发现是晶振的问题,之前一直用卖方指定的12M晶振,后来发现用11.0592M晶振可以正常接受。

---》波特率的问题,51单片机12M晶振9600的波特率误差高达%7传送结果很不准确,11.0592晶振刚刚好没误差