BG22蓝牙——第四弹 联调单片机,蓝牙点灯Demo

联调单片机,蓝牙点灯Demo

前面都是对基础的工程创建,本次实验结合外接单片机(stm32F4)和蓝牙(BG22)通过串口通讯传输信息,实现手机app发送信息个蓝牙,蓝牙芯片接收到信息以后把数据处理后通过串口转发给单片机。单片机解读蓝牙芯片BG22通过串口发送过来的信息,解读成为控制LED的信号。从而实现手机通过蓝牙控制单片机控制LED的亮灭。

同样新建工程,本次使用的芯片的型号为:

EFR32BG22C224F512GM32

需要在工程中重新配置:

在这里插入图片描述

本次使用的协议栈的版本为:

在这里插入图片描述

选择此空的工程:

在这里插入图片描述

配置GATT如下:

点击Generate 生成工程,打开后编译,下载测试一下。

在这里插入图片描述

如果编译出错,错误提示如下:

在这里插入图片描述

不要怕,这就是协议栈的毛病!

在init_mcu.c文件添加如下图的宏定义:

#define BSP_DCDC_INIT     EMU_DCDCINIT_DEFAULT

在这里插入图片描述

再次点击编译,编译后没有错误。

点开app.c文件

在前面添加头文件和函数:

添加头文件内容如下:

/****************add here********************/
/*
 * 增加如下改动
 * */
#include "stdio.h"
#include "em_usart.h"
#include "em_device.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_core.h"
#define printLog printf
/**************/

添加串口服务函数如下:

/*增加如下代码段*/

/**************************************************************************//**
 * @brief
 *    GPIO initialization
 *****************************************************************************/
void initGpio(void)
{
  // Configure PA5 as an output (TX)
  GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 0);

  // Configure PA6 as an input (RX)
  GPIO_PinModeSet(gpioPortA, 6, gpioModeInput, 0);

  // Configure PB4 as output and set high (VCOM_ENABLE)
  // comment out next line to disable VCOM
  GPIO_PinModeSet(gpioPortB, 4, gpioModePushPull, 1);
}

/**************************************************************************//**
 * @brief
 *    CMU initialization
 *****************************************************************************/
void initCmu(void)
{
  // Enable clock to GPIO and USART1
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_USART1, true);
}

/**************************************************************************//**
 * @brief
 *    USART1 initialization
 *****************************************************************************/
void initUsart1(void)
{
  // Default asynchronous initializer (115.2 Kbps, 8N1, no flow control)
  USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

  // Route USART1 TX and RX to PA5 and PA6 pins, respectively
//  GPIO->USARTROUTE[1].TXROUTE = (gpioPortA << _GPIO_USART_TXROUTE_PORT_SHIFT)
//      | (5 << _GPIO_USART_TXROUTE_PIN_SHIFT);
  GPIO->USARTROUTE[1].RXROUTE = (gpioPortA << _GPIO_USART_RXROUTE_PORT_SHIFT)
      | (6 << _GPIO_USART_RXROUTE_PIN_SHIFT);

  // Enable RX and TX signals now that they have been routed
  GPIO->USARTROUTE[1].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | GPIO_USART_ROUTEEN_TXPEN;

  // Configure and enable USART1
  USART_InitAsync(USART1, &init);

  // Enable NVIC USART sources
  NVIC_ClearPendingIRQ(USART1_RX_IRQn);
  NVIC_EnableIRQ(USART1_RX_IRQn);
  NVIC_ClearPendingIRQ(USART1_TX_IRQn);
  NVIC_EnableIRQ(USART1_TX_IRQn);
}


uint8_t Buffer5[5] =	{0x00,0x67,0x63,0x00,0xfd};
uint8_t buffer[80]; //串口接收到是数据
uint8_t USART1_RX_buffer[128] = {0};
uint32_t 	USART1_RX_NUM= 0;
bool 	receive_flag = true;
/**************************************************************************//**
 * @brief
 *    The USART1 receive interrupt saves incoming characters.
 *****************************************************************************/
void USART1_RX_IRQHandler(void)
{
  uint32_t i;
  // Get the character just received
  buffer[USART1_RX_NUM] = USART1->RXDATA;

  // Exit loop on new line or buffer full
  if ((buffer[USART1_RX_NUM] != '\n') && (USART1_RX_NUM < 128))
	  USART1_RX_NUM++;
  else
  {
	  receive_flag = false;   // Stop receiving on CR
	  // Enable receive data valid interrupt
	  USART_IntEnable(USART1, USART_IEN_RXDATAV);
	  USART1_RX_NUM = 0;
	  for(i=0;i<128;i++)
	  {
		  USART1_RX_buffer[i] =	buffer[i];
		  buffer[i] = 0;
	  }
  }
}
void Receive_serial_data(void)
{
	uint32_t i;

	/*根据接收到的指令进行行为判断*/
	if (!receive_flag) //如果接收到了串口数据
	{
		if(USART1_RX_buffer[0] == 'A' && USART1_RX_buffer[1] == 'T' && USART1_RX_buffer[2] == '+' && USART1_RX_buffer[3] == '\r')
		{
			printf("ok\r\n");

			printf("rev=");

			printf("%s\r\n",USART1_RX_buffer);

			Buffer5[2]++;

		}
		else if(USART1_RX_buffer[0] == 'A' && USART1_RX_buffer[1] == 'T' && USART1_RX_buffer[2] == '+' && USART1_RX_buffer[3] != '\r')
		{
			printf("ok\r\n");
			printf("%s\r\n",USART1_RX_buffer);
		}
		else
		{
			printf("error=%s \r\n",USART1_RX_buffer);
		}
		for (i = 0; i < 128; i++) //清空接收数组
		{
			USART1_RX_buffer[i] = 0;
		}
		receive_flag = true;
	}
}

void init_fun(void)
{
	// Chip errata
	CHIP_Init();
	// Initialize GPIO and USART1
	initCmu();

	initGpio();

	initUsart1();

	// Enable receive data valid interrupt
	USART_IntEnable(USART1, USART_IEN_RXDATAV);

	printf("begin\r\n");
}
/********************************************************************************************************************************/

在appMain函数内添加定义:

long unsigned int x;
unsigned char i =0;

在appMain函数内的while循环之前添加串口的初始化函数:

init_fun(); //串口中断初始化

printLog("begin\r\n"); //打印信息

在appMain函数的while(1)循环内添加串口中断检测函数:

Receive_serial_data(); //接收串口中断的数据

注释掉等待函数,同时把协议栈的事件获取的运行方式从阻塞式改为非阻塞式:

evt = gecko_peek_event();//改变阻塞方式为非阻塞方式

改动后的appMain函数如下:
在这里插入图片描述

最后在后面增加case执行,对事件检测:

      /* Add additional event handlers as your application requires */
      case gecko_evt_gatt_server_characteristic_status_id:
      {
		  if ((evt->data.evt_gatt_server_characteristic_status.characteristic == gattdb_temperature_measurement)&& (evt->data.evt_gatt_server_characteristic_status.status_flags == 0x01))
		  {
			if (evt->data.evt_gatt_server_characteristic_status.client_config_flags == 0x02)
			{
				/* Indications have been turned ON - start the repeating timer. The 1st parameter '32768'
				* tells the timer to run for 1 second (32.768 kHz oscillator), the 2nd parameter is
				* the timer handle and the 3rd parameter '0' tells the timer to repeat continuously until
				* stopped manually.*/
				gecko_cmd_hardware_set_soft_timer(32768, 0, 0);

				//printf("启动重复计时器\r\n");
			}
			else if (evt->data.evt_gatt_server_characteristic_status.client_config_flags == 0x00)
			{
				/* Indications have been turned OFF - stop the timer. */
				gecko_cmd_hardware_set_soft_timer(0, 0, 0);

				//printf("指示已关闭-停止计时器\r\n");
			}
		  }
		  printLog("order = set set soft timer\r\n");
		}
		break;

      case gecko_evt_hardware_soft_timer_id:
		  /* Measure the temperature as defined in the function temperatureMeasure() */

		  printf("order = sand indicate\r\n");

		  gecko_cmd_gatt_server_send_characteristic_notification(0xFF, gattdb_temperature_measurement, 5, Buffer5);

		  break;

		/*检测在app内变量被更改*/
      case 0xa00a0:
      {
		  /*更改值*/
		  if (evt->data.evt_gatt_server_user_write_request.characteristic == gattdb_test)
		  {
			// Write user supplied value to LEDs.
			//printf("BG22 receive command is %c\n",evt->data.evt_gatt_server_attribute_value.value.data[0]);

			//set_leds(evt->data.evt_gatt_server_attribute_value.value.data[0]);
			gecko_cmd_gatt_server_send_user_write_response(evt->data.evt_gatt_server_user_write_request.connection, gattdb_test, bg_err_success);

			//printf("BG22 send response to client.\n");

			//判断电灯操作
			if(evt->data.evt_gatt_server_attribute_value.value.data[0] == '1')
			{
				printf("LED=N\r\n");
			}
			else if(evt->data.evt_gatt_server_attribute_value.value.data[0] == '2')
			{
				printf("LED=F\r\n");
			}
			else
			{
				printf("get data = ");

				for(i=0;i<8;i++)
				{
					if(evt->data.evt_gatt_server_attribute_value.value.data[i] != 0x00)
						printf("%c",evt->data.evt_gatt_server_attribute_value.value.data[i]);
					else
						break;
				}
				printf("\r\n");
			}
		 }
      }
      break;

手动分割线:——————————————————————————————————

下面是单片机上面的工程配置:

在单片机上我使用的两个串口,一个串口用来和PC链接显示打印信息,另一个串口和蓝牙BG22芯片连接进行数据通讯。同时还配置了一个LED。
在这里插入图片描述

这里配置的过程我也是直接参考了胡工的教程,感谢他❤

STM32CubeMx开发之路—4采用DMA方式收发数据

打开KEIL后,在while循环内添加代码:

if(Rx_Flag) // Receive flag
{
Rx_Flag=0; // clean flag
HAL_UART_Transmit_DMA(&huart6, Rx_Buf, Rx_Len);

		if(Rx_Buf[0] == 'L' &&  Rx_Buf[1] == 'E' &&  Rx_Buf[2] == 'D'  &&  Rx_Buf[3] == '=')//判断接收到的数据是不是正确
		{
				printf("usart0 sand data is LED\r\n");
				if(Rx_Buf[4] == 'N')
				{
						HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET); //打开灯
				}
				if(Rx_Buf[4] == 'F')
				{
						HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET); //关闭灯
				}
		}
	} 
	/*蓝牙部分接收到了数据,一方面将数据转发到串口,另一方面对数据进行判断,执行开关灯操作*/
	if(Rx6_Flag)    	// Receive flag 
	{  
			Rx6_Flag=0;	// clean flag
			HAL_UART_Transmit_DMA(&huart2, Rx6_Buf, Rx6_Len);//把接收到的串口6的数据转发到串口2 
			
			if(Rx6_Buf[0] == 'L' &&  Rx6_Buf[1] == 'E' &&  Rx6_Buf[2] == 'D'  &&  Rx6_Buf[3] == '=')//判断接收到的数据是不是正确
			{
					printf("usart0 sand data is LED\r\n");
					if(Rx6_Buf[4] == 'N')
					{
							HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET); //打开灯
					}
					if(Rx6_Buf[4] == 'F')
					{
							HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET); //关闭灯
					}
			}
	} 

在这里插入图片描述

串口6会把接收到的信息转发给串口2打印到电脑上,同时还会检测是不是需要电灯。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值