蓝牙与单片机连接程序

2018-05-02 22:11:29 dok12 阅读数 15348

打算利用蓝牙芯片HC06实现手机和单片机之间的简单通信。工具包括淘宝上淘的stc单片机实验板一块,hc-06蓝牙模块一个,杜邦线,win7电脑一部,安卓手机一部,相关软件:单片机小精灵,串口通讯助手,keil以及单片机烧录软件,蓝牙通讯软件APP。软件基本上都是免安装直接运行的。

工作流程简单总结下为以下3步:
1.利用单片机小精灵软件,做好烧录程序,确定波特率应该设置为2400
2.hc-06蓝牙模块进入AT模式,串口通讯助手成功将蓝牙模块波特率设置为2400
3.将烧录程序通过keil编译成功后烧录至单片机实验板上,手机上安装好APP,设置完成后运行,确定成功。

步骤(2)见


https://blog.csdn.net/dok12/article/details/80152239
步骤(3)见
https://blog.csdn.net/dok12/article/details/801730

本篇先介绍步骤1。工具,单片机小精灵软件,免安装,直接运行。

打开单片机小精灵软件,选择串口波特率选项。必须选择好晶振和波特率。其他选项,c语言还是汇编,是否串口中断,波特率加倍,允许接收都自己决定。
因为淘宝买到的单片机实验板是12M晶振,蓝牙模块的默认波特率是9600。所以一开始输入这两项数据。
结果发现误差太大,必须修改。晶振改不了,只好改波特率了。
修改波特率为2400后误差控制在千分之一点六,效果不错,得到了一个C语言的串口通信基本框架了。

根据这个框架做了个C语言程序,目标是对单片机实现蓝牙通讯,实现不同的单片机流水灯效果,并且得到回复数字8。
#include <reg51.h>
unsigned char k;
void InitUART(void)
{
    TMOD = 0x20;
    SCON = 0x50;
    TH1 = 0xF3;
    TL1 = 0xF3;
    PCON = 0x00;
    EA = 1;
    ES = 1;
    TR1 = 1;
}
/*******延时函数*************/
void delay(unsigned int i)
{
    unsigned char j;
    for(i; i > 0; i--)   
        for(j = 255; j > 0; j--);
}
void main(void)
{	k=0;
    InitUART();
	while  (1){
	if(k==1)
	{P1=0xff;delay(500);P1=0x00;delay(500);}
	else if (k==2)
	{P1=0x01;delay(500);P1=0xfe;delay(500);}
	else 
	{P1=0x02;delay(500);P1=0xfd;delay(500);}
	}
}
void SendOneByte(unsigned char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

void UARTInterrupt(void) interrupt 4
{
    if(RI)
    {
        RI = 0;
        //add your code here!
		k++;
		if(k>2)k=0;
		SendOneByte(8);
    }
    else
        TI = 0;
}






2016-12-26 09:57:29 c_ycy 阅读数 6260
蓝牙(Bluetooth):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。蓝牙技术最初由电信巨头爱立信公司于1994年创制,当时是作为RS232数据线的替代方案。蓝牙可连接手机、平板、电脑等设备,与单片机连接搭建无线系统的分端在各领域都得到了广泛应用。
1、端口连接
与单片机串口连接时,两者之间相互可以读写。例如51给蓝牙传递数据,即51向蓝牙写数据,蓝牙从51读取数据,那么51单片机串口写端P3.1引脚(TXD)就与蓝牙读端(RXD)相连,同样蓝牙向51传递数据时,蓝牙写端(TXD)T与51串口的读端P3.0引脚(RXD)相连,这样51单片机就可以与蓝牙相互通信。
通常用以下连接方式即可实现数据传送(两者使用同一电源)。

实现蓝牙HC-05、06与单片机的连接及与手机通信注意:只有正确连接读写端才能正常通信。
2、电平选择
一般情况下,蓝牙不能正常工作的原因出在电源这的可能比较小,大多数蓝牙模块电压范围比较大,像HC-05蓝牙模块一般在3.3~6V,单片机电源都在这个范围内。不过不排除部分3.3V蓝牙,所以在连接电源前一定按照技术手册,连接正确电源,并保证正负极不能接反。
3、蓝牙配置
设置决定了蓝牙模块自动连接工作后的角色,主角色(Master)会自动搜索配对连接。从角色(Slave)只被动接受连接,不会主动搜索。回环角色(Loopback),属于被动连接,接收远程蓝牙主设备数据并将数据原样返回给远程蓝牙主设备。如果两个HC05模块要建立连接,其中一个必须设置为主角色,另外一个可以设置为从角色,如果一个HC05模块和电脑蓝牙或者手机蓝牙通信,一般电脑或手机可以主动建立连接,所以HC05使用从角色,出厂默认也是设置为从角色的。
4、AT指令
在控制电平信号下,可以对蓝牙的一些特性参数进行查询课更改。
AT+XXX?                   //查询参数XXX
AT+XXX=mmm        //设置参数XXX为mmm
例如: 命令: AT+NAME?\r\n                //查询蓝牙名称
         返回:+NAME:ChunyuY19           //蓝牙名称为:ChunyuY19
          命令:AT+NAME=Xidian\r\n      //设置蓝牙名称为:Xidian
          返回: OK                                //返回提示符:OK
          命令:AT+PSWD?\r\n               //查询蓝牙配对密码
         返回:+PSWD:1234                   //配对密码为:1234
          命令: AT+ROLE?\r\n               //查询蓝牙模式
          返回:+ROLE:0                        //0:从角色,1:主角色,2:回环角色
注意:每行命令必须以更多AT命令\r\n结尾,更多的AT指令一般技术手册都会给出,或在网上查询。
             一般作为从角色时,不用配置
5、实现基于STC51单片机的蓝牙与手机通信
首先,给单片机载入串口通信程序,注意!!一般下载程序时单片机与蓝牙断开,避免因蓝牙占用单片机串口导致程序无法烧写。载入程序后,按照上图给出的读写连接方式连接,并给给单片机及HC-05连接合适电源,一般都用单片机开发板上电源。手机端需先在浏览器上搜索并下载“蓝牙串口调试助手”。
上电后,蓝牙指示灯一般进入快闪状态,即等待蓝牙连接(从模式),用手机搜索并连接单片机上的蓝牙,配对密码默认为1234。配对成功就可以发送数据给蓝牙,如下图,至此基于STC51单片机的蓝牙与手机通信成功。
单片机端代码连接: STC51单片机端蓝牙串口程序

2016-05-22 13:38:22 wuermohuang 阅读数 45237

蓝牙(Bluetooth):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。蓝牙技术最初由电信巨头爱立信公司于1994年创制,当时是作为RS232数据线的替代方案, 蓝牙可连接多个设备,在与单片机连接使用也得到了广泛应用。

1、端口连接
与单片机串口连接时,两者之间 相互可以读写。例如51给HC-05传递数据,即51向HC-05写数据,HC-05从51读取数据,那么串口连接处51的写端P3.1引脚(TXD)就与HC-05读端(RXD)相连,反之蓝牙向51传递数据时,HC-05写端(TXD)T与51的读端P3.0引脚(RXD)相连,所以通常为以下连接方式即可实现数据传送。
注意:只有正确连接读写端才能正常通信。
端口连接
2、电平选择
一般情况下,蓝牙不能正常工作的原因出在电源这得可能比较小,大多数蓝牙模块电压范围比较大,像HC-05蓝牙模块一般在3.3~6V,单片机电源都在这个范围内。不过不排除部分3.3V蓝牙,所以在连接电源前一定按照技术手册,连接正确电源,并保证正负极不能接反。
3、蓝牙配置
设置决定了蓝牙模块自动连接工作后的角色,主角色(Master)会自动搜索配对连接,从角色(Slave)只被动接受连接,不会主动搜索,回环角色(Loopback),属于被动连接,接收远程蓝牙主设备数据并将数据原样返回给远程蓝牙主设备。如果两个HC05模块要建立连接,其中一个必须设置为主角色,另外一个可以设置为从角色或回环角色,如果一个HC05模块和电脑蓝牙或者手机蓝牙通信,一般电脑或手机可以主动建立连接,所以HC05可以使用从角色,出厂默认也是设置为从角色的。
4、AT指令
在控制电平信号下,可以对蓝牙的一些特性参数进行查询课更改。
AT+XXX? //查询参数XXX
AT+XXX=mmm //设置参数XXX为mmm
例如: 命令: AT+NAME?\r\n //查询蓝牙名称
返回:+NAME:ChunyuY19 //蓝牙名称为:ChunyuY19
命令: AT+NAME=Xidian\r\n //设置蓝牙名称为:Xidian
返回: OK //返回提示符:OK
命令: AT+PSWD?\r\n //查询蓝牙配对密码
返回:+PSWD:1234 //配对密码为:1234
命令: AT+ROLE?\r\n //查询蓝牙模式
返回:+ROLE:0 //0:从角色,1:主角色,2:回环角色
注意!!每行命令必须以更多AT命令\r\n结尾,更多的AT指令一般技术手册都会给出,活在网上查询。
5、实现基于STC51单片机的蓝牙与手机通信
首先,给单片机载入串口通信程序,注意!!一般下载程序时单片机与蓝牙断开,避免因蓝牙占用单片机串口导致程序无法烧写。载入程序后,按照上图给出的读写连接方式连接,并给给单片机及HC-05连接合适电源,一般都用单片机板子上电源。手机端需先在浏览器上搜索并下载“蓝牙串口调试助手”。
上电后,蓝牙指示灯一般进入快闪状态,即等待蓝牙连接(从模式),用手机搜索并连接单片机上的蓝牙,配对密码默认为1234。配对成功就可以发送数据给蓝牙,如下图,至此基于STC51单片机的蓝牙与手机通信成功。

因为毕业设计需要用到无线传输,第一次接触蓝牙串口通信,芯片用的HC-05。调试了一天,复制了不少例程,一直无解认为是程序问题。直到看到这篇文章才发现自己引脚就接错了……
一定记住单片机TX接蓝牙RX,单片机RX接蓝牙TX。一定记住单片机TX接蓝牙RX,单片机RX接蓝牙TX。一定记住单片机TX接蓝牙RX,单片机RX接蓝牙TX。重要的事说三次。

附基于STM32的HC-05串口通信框架代码

#include "stm32f10x.h"    
#include "stm32f10x_rcc.h"    
#include "stm32f10x_gpio.h"    
#include "stm32f10x_usart.h"   
#include "stm32f10x_crc.h"  
#include "system_stm32f10x.h"   
#include "stdio.h"   
  
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)  
  
void RCC_Configuration(void);    
void GPIO_Configuration(void);   
void USART_Configuration(void);   
void delay_ms(u16 time);  
void UART_PutChar(USART_TypeDef* USARTx, uint8_t Data);  
void UART_PutStr (USART_TypeDef* USARTx, uint8_t *str);
int Putchar(int c);
  
int main()  
{  
    SystemInit();  
    RCC_Configuration();    
    GPIO_Configuration();     
    USART_Configuration();
		GPIO_SetBits(GPIOB,GPIO_Pin_5);		
    while(1)  
    {  
      UART_PutStr(USART1, "hello world!"); 
			delay_ms(1000);			
    }   
      
}  
void RCC_Configuration(void)      
{       
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB,ENABLE);       
}     
    
void GPIO_Configuration(void)      
{      
  GPIO_InitTypeDef GPIO_InitStructure;      
      
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;           
  GPIO_Init(GPIOA, &GPIO_InitStructure);                
      
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;        
  GPIO_Init(GPIOA, &GPIO_InitStructure);                 
       
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    
  GPIO_Init(GPIOB, &GPIO_InitStructure);     
}  
void USART_Configuration(void)
{    
       
    USART_InitTypeDef USART_InitStructure;                   
  
    USART_InitStructure.USART_BaudRate = 9600;                    
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;   
    USART_InitStructure.USART_StopBits = USART_StopBits_1;       
    USART_InitStructure.USART_Parity = USART_Parity_No;        
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   
    USART_Init(USART1,&USART_InitStructure);                    
    USART_Cmd(USART1,ENABLE);    
}  
void delay_ms(u16 time)       
{      
  u16 i=0;      
  while(time--)       
  {      
    i=12000;      
    while(i--);      
  }      
}   
int Putchar(int c)                                             
{    
    if (c == '\n'){putchar('\r');}                                
    USART_SendData(USART1,c);                                  
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET){};
    return c;                                                       
}   
void UART_PutChar(USART_TypeDef* USARTx, uint8_t Data)  
{  
    USART_SendData(USARTx, Data);  
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET){}  
}  
void UART_PutStr (USART_TypeDef* USARTx, uint8_t *str)    
{    
    while (0 != *str)    
    {    
        UART_PutChar(USARTx, *str);    
        str++; 		
    }    
}  

程序员开源交流QQ群 792272915

2014-01-05 12:04:42 jason0539 阅读数 38752

之前两篇都是在说与手机的连接,连接方法,和主动配对连接,都是手机与手机的操作,做起来还是没问题的,但是最终的目的是与单片机的蓝牙模块的通信。

 

下面是到目前为止尝试的与单片机的通信方法,没有成功,但是从思路上来说没有问题,最大的问题是与单片机配对的时候,单片机的蓝牙模块的PIN配对码是写死的,固定为1234,

而手机这边连接配对都是自动生成的PIN配对码,这种方式在手机与手机配对的时候是极为方便的,但是在这里与单片机连接却成了最大的问题,因为手机自动生成而且每次都不一样,所以没法与单片机蓝牙模块的1234相同也就没法陪对了。下面只是介绍的到目前为止我们的大题思路,具体代码很多,而且涉及到项目也就没有贴。

如果关于上面的问题哪位同学有思路或者做过类似的项目还请指点。

 

首先,如何开启蓝牙设备和设置可见时间:

private void search() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (!adapter.isEnabled()) {
            adapter.enable();
        }
        Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); //3600为蓝牙设备可见时间
         startActivity(enable);
        Intent searchIntent = new Intent(this, ComminuteActivity.class);
        startActivity(searchIntent);
    }


正式开始与蓝牙模块进行通信

public class ComminuteActivity extends Activity {
    private BluetoothReceiver receiver;
    private BluetoothAdapter bluetoothAdapter;
    private List<String> devices;
    private List<BluetoothDevice> deviceList;
    private Bluetooth client;
    private final String lockName = "YESYOU";
    private String message = "000001";
    private ListView listView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search_layout);

        listView = (ListView) this.findViewById(R.id.list);
        deviceList = new ArrayList<BluetoothDevice>();
        devices = new ArrayList<String>();
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        bluetoothAdapter.startDiscovery();
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        receiver = new BluetoothReceiver();
        registerReceiver(receiver, filter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                setContentView(R.layout.connect_layout);
                BluetoothDevice device = deviceList.get(position);
                client = new Bluetooth(device, handler);
                try {
                    client.connect(message);
                } catch (Exception e) {
                    Log.e("TAG", e.toString());
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case Bluetooth.CONNECT_FAILED:
                    Toast.makeText(ComminuteActivity.this, "连接失败", Toast.LENGTH_LONG).show();
                    try {
                        client.connect(message);
                    } catch (Exception e) {
                        Log.e("TAG", e.toString());
                    }
                    break;
                case Bluetooth.CONNECT_SUCCESS:
                    Toast.makeText(ComminuteActivity.this, "连接成功", Toast.LENGTH_LONG).show();
                    break;
                case Bluetooth.READ_FAILED:
                    Toast.makeText(ComminuteActivity.this, "读取失败", Toast.LENGTH_LONG).show();
                    break;
                case Bluetooth.WRITE_FAILED:
                    Toast.makeText(ComminuteActivity.this, "写入失败", Toast.LENGTH_LONG).show();
                    break;
                case Bluetooth.DATA:
                    Toast.makeText(ComminuteActivity.this, msg.arg1 + "", Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };

    private class BluetoothReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (isLock(device)) {
                    devices.add(device.getName());
                }
                deviceList.add(device);
            }
            showDevices();
        }
    }

    private boolean isLock(BluetoothDevice device) {
        boolean isLockName = (device.getName()).equals(lockName);
        boolean isSingleDevice = devices.indexOf(device.getName()) == -1;
        return isLockName && isSingleDevice;
    }

    private void showDevices() {
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                devices);
        listView.setAdapter(adapter);
    }
}

这里需要提一下的是,startDiscovery()这个方法和它的返回值,它是一个异步方法,会对其他蓝牙设备进行搜索,持续时间为12秒。

搜索过程其实是在System Service中进行,我们可以通过cancelDiscovery()方法来停止这个搜索。在系统搜索蓝牙设备的过程中,系统可能会发送以下三个广播:ACTION_DISCOVERY_START(开始搜索),

ACTION_DISCOVERY_FINISHED(搜索结束)

和ACTION_FOUND(找到设备)。

ACTION_FOUND这个才是我们想要的,这个Intent中包含两个extra fields:    EXTRA_DEVICE和EXTRA_CLASS,

包含的分别是BluetoothDevice和BluetoothClass

EXTRA_DEVICE中的BluetoothDevice就是我们搜索到的设备对象,从中获得设备的名称和地址。

EXTRA_CLASS中的BluetoothClass是搜索到的设备的类型,比如搜索到的是手机还是耳机或者其他,之后我会写一篇关于它的介绍

在这个上面我现在在想,是否通过判断搜索到的设备类型来识别单片机蓝牙模块与手机蓝牙的不同,采取不一样的配对方式,从而不自动生成配对码。不知是否可行,一会尝试。

 

 搜索到该设备后,我们就要对该设备进行连接和通信。

public void connect(final String message) {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                BluetoothSocket tmp = null;
                Method method;
                try {
                    method = device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                    tmp = (BluetoothSocket) method.invoke(device, 1);
                } catch (Exception e) {
                    setState(CONNECT_FAILED);
                    Log.e("TAG", e.toString());
                }
                socket = tmp;
                try {
                    socket.connect();
                    isConnect = true;
                } catch (Exception e) {
                    setState(CONNECT_FAILED);
                    Log.e("TAG", e.toString());
                }
	       if (isConnect) {
                    try {
                        OutputStream outStream = socket.getOutputStream();
                        outStream.write(getHexBytes(message));
                    } catch (IOException e) {
                        setState(WRITE_FAILED);
                        Log.e("TAG", e.toString());
                    }
                    try {
                        InputStream inputStream = socket.getInputStream();
                        int data;
                        while (true) {
                            try {
                                data = inputStream.read();
                                Message msg = handler.obtainMessage();
                                msg.what = DATA;
                                msg.arg1 = data;
                                handler.sendMessage(msg);
                            } catch (IOException e) {
                                setState(READ_FAILED);
                                Log.e("TAG", e.toString());
                                break;
                            }
                        }
                    } catch (IOException e) {
                        setState(WRITE_FAILED);
                        Log.e("TAG", e.toString());
                    }
                }

                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        Log.e("TAG", e.toString());
                    }
               }
       }
}

 这里包括写入和读取,用法和基本的Socket是一样的,但是写入的时候,需要将字符串转化为16进制:

private byte[] getHexBytes(String message) {
        int len = message.length() / 2;
        char[] chars = message.toCharArray();
        String[] hexStr = new String[len];
        byte[] bytes = new byte[len];
        for (int i = 0, j = 0; j < len; i += 2, j++) {
            hexStr[j] = "" + chars[i] + chars[i + 1];
            bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
        }
        return bytes;
    }


 

连接设备之前需要UUID,所谓的UUID,就是用来进行配对的,全称是Universally Unique Identifier,是一个128位的字符串ID,用于进行唯一标识。网上的例子,包括谷歌的例子提供的uuid,通用的"00001101-0000-1000-8000-00805F9B34FB"也试过了,在配对的时候都是自动生成了配对码,也无法正常与单片机的蓝牙模块连接,所以,我就利用反射的原理,让设备自己提供UUID尝试。到这里其实我有点怀疑自己对于UUID的理解是否正确了。

            在谷歌提供的例子中,我们可以看到谷歌的程序员的程序水平很高,一些好的编码习惯我们可以学习一下,像是在try..catch中才定义的变量,我们应该在try...catch之前声明一个临时变量,然后再在try...catch后赋值给我们真正要使用的变量。这种做法的好处就是:如果我们直接就是使用真正的变量,当出现异常的时候,该变量的使用就会出现问题,而且很难进行排查,如果是临时变量,我么可以通过检查变量的值来确定是否是赋值时出错。

   

作者:jason0539

微博:http://weibo.com/2553717707

博客:http://blog.csdn.net/jason0539(转载请说明出处)

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

不久前开始学习使用蓝牙模块,在模块与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,否则可能出现乱码的情况。

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


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