#采用stm32f103c8t6芯片

我又回来了!这一次我要学习的是蓝牙芯片的使用!连上蓝牙,小车可以做很多事情,我们可以控制小车前进后退,左转右转,甚至还可以在整体调试时运用蓝牙进行debug!当然,如果你不去实现的话,几乎等于在梦里,嘿嘿,所以让我们开始吧!
感觉好难啊…首先要搞清楚蓝牙使用方法,可能还要用app inventor来进行app开发…
来吧来吧。
首先是蓝牙使用方法,我查阅了csdn的一些文章,其中有一些讲得比较清楚,就这些文章得链接放在下面。 读者可以参考,这些文章基本上详细记述了蓝牙模块的使用方法,当然,对于不同的模块型号,操作方法可能略有不同,这个就需要读者去自己细细琢磨了,哈哈。
阅读完这些文章后,我发现,其实蓝牙通讯并没有想象的这么难嘛,其实就是串口通信套上一个壳子,作为串口通信的延伸而已。这样子,我就又有更大的信心了,毕竟我以前写过串口通信的代码嘛。说不定可以改改直接拿来用了,哈哈哈。
试了试,改了改,结果真的能用!代码如下:

#bluetooth.h

#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H

#define BLUETOOTH_GPIO GPIOA
#define BLUETOOTH_TX_Pin GPIO_Pin_2
#define BLUETOOTH_RX_Pin GPIO_Pin_3
#define BLUETOOTH_Usart USART2
#define BLUETOOTH_IRQ USART2_IRQn

extern volatile uint16_t data_in;
extern volatile uint16_t data_out;

void BluetoothUsartInit(void);


#define BLUETOOTH_baud_rate 115200

#endif
#bluetooth.c

#include "stm32f10x.h"
#include "bluetooth.h"

volatile uint16_t data_in;
volatile uint16_t data_out;

void BluetoothUsartInit(void)
{
	GPIO_InitTypeDef GPIO_init_set;
	USART_InitTypeDef USART_init_set;
	NVIC_InitTypeDef NVIC_init_set;
	
	// 使能GPIOA与usart时钟
	// 由于io复用,需要使能GPIOA时钟
    if (BLUETOOTH_IRQ == USART1_IRQn)
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    else if (BLUETOOTH_IRQ == USART2_IRQn)
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    else if (BLUETOOTH_IRQ == USART3_IRQn)
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    
	if (BLUETOOTH_GPIO == GPIOA)
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	else if (BLUETOOTH_GPIO == GPIOB)
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	else if (BLUETOOTH_GPIO == GPIOC)
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

	else if (BLUETOOTH_GPIO == GPIOD)
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

	// 串口复位
	USART_DeInit(BLUETOOTH_Usart);
    
	// GPIO端口模式设置
	GPIO_init_set.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_init_set.GPIO_Pin = BLUETOOTH_TX_Pin;
	GPIO_init_set.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(BLUETOOTH_GPIO, &GPIO_init_set);

	GPIO_init_set.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_init_set.GPIO_Pin = BLUETOOTH_RX_Pin;
	GPIO_Init(BLUETOOTH_GPIO, &GPIO_init_set);


	// USART Rx|Tx init
	USART_init_set.USART_BaudRate = BLUETOOTH_baud_rate;
	USART_init_set.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_init_set.USART_Parity = USART_Parity_No;
	USART_init_set.USART_StopBits = USART_StopBits_1;
	USART_init_set.USART_WordLength = USART_WordLength_8b;
	USART_init_set.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(BLUETOOTH_Usart, &USART_init_set);


	// 串口使能
	USART_Cmd(BLUETOOTH_Usart, ENABLE);
	
	// USART1中断设置
	USART_ITConfig(BLUETOOTH_Usart, USART_IT_RXNE, ENABLE);


	// 中断设置
	NVIC_init_set.NVIC_IRQChannel = BLUETOOTH_IRQ;
	NVIC_init_set.NVIC_IRQChannelCmd = ENABLE;
	NVIC_init_set.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_init_set.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_init_set);

	USART_SendData(BLUETOOTH_Usart, 123);
}

void USART2_IRQHandler(void)
{
	if (USART_GetITStatus(BLUETOOTH_Usart, USART_IT_RXNE))
	{
		data_in = USART_ReceiveData(BLUETOOTH_Usart);
		USART_SendData(BLUETOOTH_Usart, data_in);
	}
}

不过,这里要提到一点,由于usart2与usart3是挂载在apb1时钟上的,与usart1不同,导致我查了好久的bug,也算是一个教训吧[无奈]。
因此,接下来,开始写服务函数了!在我的构想中,我需要蓝牙模块传送速度,红外传感器是否接收到等参数,还需要接收前进,停止,巡线信号,在后续扩展中,我还需要调整pid的参数,所以服务函数一定要写好!
由于我并不是特别清楚蓝牙模块的具体原理,所以我打算用传送两次数据来实现我的目的。一次传输的是标志,一次传输的是数值。当蓝牙第一次接收到标志时,将参数传入一个变量data_in_flag保存,第二次读取时读取这个变量来确定相应的命令。输出也是同样的原理。
在头文件进行一些宏定义,用于确定标志位,

// 运动与巡线
#define move_forward '2'
#define move_back '3'
#define move_right '4'
#define move_left '5'
#define move_stop '6'
#define xunxian '7'

// pid控制
#define change_p '8'
#define change_I '9'
#define change_d '!'

// 红外
#define infrared1 '@'
#define infrared2 '#'
#define infrared3 '$'
#define infrared4 '%'

// 速度
#define BL_speed_test1 '^'
#define BL_speed_test2 '&'
#define BL_speed_test3 '*'
#define BL_speed_test4 '('

#define start_transmit '`'
#define stop_transmit '~'

由于每一次发送只能有一个字符,所以我采取了单字符标志位。由于单字符其实有许多,所以对于我来说,已经够用了。
接下来,开始写最简单的接收处理函数,“前后左右”。在这里我同样使用了data_in_flag来储存接收到的数据,然后采用if……else来确定进入哪一个分支。这个函数是包含在串口中断函数中的。

void USART2_IRQHandler(void)
{
	if (USART_GetITStatus(BLUETOOTH_Usart, USART_IT_RXNE))
	{
		data_in_flag = USART_ReceiveData(BLUETOOTH_Usart);
		if (data_in_flag == move_forward)
		{
			CarControl(MOTORA, 3000);
			CarControl(MOTORB, 3000);
		}
		else if (data_in_flag == move_left)
		{
			CarControl(MOTORA, 0);
			CarControl(MOTORB, 3000);
		}
		else if (data_in_flag == move_right)
		{
			CarControl(MOTORA, 3000);
			CarControl(MOTORB, 0);
		}
		else if (data_in_flag == move_back)
		{
			CarControl(MOTORA, -1500);
			CarControl(MOTORB, -1500);
		}
		else if (data_in_flag == move_stop)
		{
			CarControl(MOTORA, 0);
			CarControl(MOTORB, 0);
		}
	}
}

USART_ReceiveData固件库中提供的串口数据接收函数,经过测试,似乎每次仅能接收一个位数。
以上这些函数写好后,我试着和电机一起调试,发现可以实现控制小车的移动,所以这个测试是成功的。
基础的服务函数大概就写到这里了,至于app的开发以及接收速度传感器和红外传感器的数据,我计划在下一篇整合篇中写下。
由于目前仅仅是测试蓝牙,所以就不放完整代码了。
我们下一篇见吧!