完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
零. 概述
主要介绍下用正点原子的战舰(STM32F103ZET6)外接我们的蓝牙扩展版跑蓝牙协议栈的初始化以及搜索演示 一. 声明 二. STM32蓝牙协议栈封装使用AT command实现搜索 使用步骤操作如下:(正点原子开发板外接蓝牙扩展点击链接)!!!!!!!!!!!!!!!!!!!! 步骤 1)准备好代码,从github下载下来最新的代码(在上面有介绍Github连接) 步骤 2)连接好硬件 分为以下几个小的步骤: ① UART2 TX/RX的接线 首先我们把原子的战舰开发板的P7的两个跳帽拔掉,分别把模组的丝印的TX接到P7的3pin上,然后把模组的RX接到P7的4 pin上 另外由于我们蓝牙协议栈跑的是Transport h4,所以需要流控功能,所以需要接CTS/RTS,所以我们还需要把模组的CTS接到原子战舰的PA0,模组的RTS接到原子战舰的PA1 ② 电源,GND接线 原子有单独的VOUT,因为我们的模组是5V供电,所以我们把模组的5V接到VOUT2的5V上,把GND接到战舰的VOUT2的GND上 整个正点原子接线位置如下 步骤 3)打开Keil工程文件夹下的projectstm32f10x_bb_csr8x11_btstm32f10x_bb_csr8x11.uvprojx,然后编译下载 注意几点: ① 设备类型修改为F103ZET6 ② 下载的时候要勾选Use micro lib 步骤4)打开串口工具(我用的是XCOM),然后做初始化动作,在发送串口敲BT_START,点击发送,出来以下log就证明初始化通过了,我们就可以来进行搜索动作了,注意一点:不能勾选发送新行,否则会解析错误 步骤5)然后敲BT_INQUIRY就能搜索到设备了 三.使用我们自己写的上位机来实现搜索 步骤跟AT的1)2)3)一样,我们从第四步开始讲解 打开我们工程源码1-BLUETOOTHmcu_bt_toolmcu_bt_toolmcu_bt_toolbinDebug中的mcu_bt_tool.exe,当然你也可以直接用VS2010打开工程 步骤 4)打开串口 步骤 5)点击蓝牙开启按钮(此步骤跟AT 命令BT_START一样的效果,就是实现蓝牙初始化) 步骤 6) 等待初始化完成点击搜索按钮,你就发现可以搜索到蓝牙了 另外:使用上位机的时候注意几点: ① mcu_bt_tool.exe你如果想把可执行文件拿到别的路径单独执行,那么必须要把Newtonsoft.Json.dll跟exe放在同一个路径下,因为上位机是跟STM32用json沟通的 ② 因为目前搜索是开启的EIR,带RSSI的,所以他会重复性上来同一个设备,我没做根据同一个蓝牙地址做显示过滤,如果有兴趣的人可以加上这一块 四. 串口工具AT command以及上位机实现搜索的原理 步骤 1)Type C uart debug口的tx,rx初始化 /****************************************************************************** * func name : hw_uart_debug_init * para : baud_rate(IN) --> Baud rate of uart1 * return : hw_uart_debug_init result * description : Initialization of USART1.PA9->TX PA10->RX ******************************************************************************/ uint8_t hw_uart_debug_init(uint32_t baud_rate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; DMA_InitTypeDef DMA_InitStructure; /* Enable RCC clock for USART1,GPIOA,DMA1 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Initialization GPIOA9 GPIOA10 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 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_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Data format :1:8:1, no parity check, no hardware flow control */ USART_InitStructure.USART_BaudRate = baud_rate; 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_Tx | USART_Mode_Rx; /* Enable USART interrupts, mainly for idle interrupts */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=DEBUG_PREE_PRIO; NVIC_InitStructure.NVIC_IRQChannelSubPriority = DEBUG_SUB_PRIO; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Initializes USART1 to enable USART, USART idle interrupts and USART RX DMA */ USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); USART_Cmd(USART1, ENABLE); /* Initializes DMA and enables it */ DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)uart1_rev_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = UART1_MAX_REV; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel5, &DMA_InitStructure); DMA_Cmd(DMA1_Channel5, ENABLE); return HW_ERR_OK; } 可以看到TX我们就是普通的实现发送,RX我们用串口空闲中断+DMA的方式来实现接受串口工具以及上位机的发送指令,然后串口中断的实现原理是这样: /****************************************************************************** * func name : USART1_IRQHandler * para : NULL * return : NULL * description : Interrupt handler for usart1 ******************************************************************************/ void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { /* Without this, the interrupt cannot be cleared and continues into the interrupt */ USART_ReceiveData(USART1); uart1_rev_len =UART1_MAX_REV-DMA_GetCurrDataCounter(DMA1_Channel5); if(uart1_rev_len != 0) { /* Call the parse function */ shell_parse(uart1_rev_buffer); hw_memset(uart1_rev_buffer,0,sizeof(uart1_rev_buffer)); } /* Clear the interrupt and reset DMA */ USART_ClearITPendingBit(USART1,USART_IT_IDLE); uart1_dma_enable(DMA1_Channel5); } } 步骤2)收到串口工具或者上位机的解析函数如下: uint8_t shell_parse(uint8_t *shell_string) { uint8_t result = HW_ERR_OK; cJSON* parse_json = cJSON_Parse((const char *)shell_string); uint8_t* func_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"FUNC"))->valuestring; uint8_t* operate_value = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"OPERATE"))->valuestring; uint8_t* para1 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM1"))->valuestring; uint8_t* para2 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM2"))->valuestring; uint8_t* para3 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM3"))->valuestring; uint8_t* para4 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM4"))->valuestring; uint8_t* para5 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM5"))->valuestring; uint8_t* para6 = (uint8_t*)((cJSON *)cJSON_GetObjectItem(parse_json,"PARAM6"))->valuestring; if(hw_strcmp((const char *)func_value,"BT") == 0) { result = shell_json_parse(operate_value,para1,para2,para3,para4,para5,para6); } else { result = shell_at_cmd_parse(shell_string); } cJSON_Delete(parse_json); return result; } 在这里我们分两种方式来解析:①AT command(串口工具采用这种方式) ②Json(上位机采用这种方式),如果解析不是我们定义的json格式,那么就自动转变为AT指令的解析 步骤3)AT command解析执行BT_START,以及BT_INQUIRY uint8_t shell_at_cmd_parse(uint8_t *shell_string) { if(hw_strcmp("BT_START",(const char*)shell_string) == 0) { HW_DEBUG("SHELL:operate bt startn"); bt_start(&bt_app_cb); return HW_ERR_OK; } ........ if(hw_strcmp("BT_INQUIRY",(const char*)shell_string) == 0) { HW_DEBUG("SHELL:operate bt inquiryn"); bt_start_inquiry(0x30,HCI_INQUIRY_MAX_DEV); return HW_ERR_OK; } } 步骤4)接受上位机json指令解析 uint8_t shell_json_parse(uint8_t *operate_value, uint8_t *para1,uint8_t *para2,uint8_t *para3, uint8_t *para4,uint8_t *para5,uint8_t *para6) { if(hw_strcmp((const char *)operate_value,"BT_START") == 0) { HW_DEBUG("UART PARSE DEBUG:operate BT_STARTn"); bt_start(&bt_app_cb); operate_stauts_oled_show("BT",operate_value,"SUCCESS",0,0,0,0,0,0); return HW_ERR_OK; } ..... if(hw_strcmp((const char *)operate_value,"BT_START_INQUIRY") == 0) { HW_DEBUG("UART PARSE DEBUG:operate BT_INQUIRYn"); bt_start_inquiry(0x30,HCI_INQUIRY_MAX_DEV); return HW_ERR_OK; } } 以上步骤3)4)其中bt_start以及bt_start_inquiry就是协议栈函数了,这样就实现了AT command或者json上位机跟蓝牙协议栈的对接。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1907 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1678 浏览 1 评论
1171 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
770 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1730 浏览 2 评论
1970浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
806浏览 4评论
stm32f4下spi+dma读取数据不对是什么原因导致的?
254浏览 3评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
623浏览 3评论
634浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-23 08:40 , Processed in 0.769041 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号