【WCH蓝牙系列芯片】-基于CH582开发板—串口自定义MAC地址和广播名称
-------------------------------------------------------------------------------------------------------------------------------------
在WCH沁恒官方提供的CH583的EVT资源包中,找到BLE文件中找到Broadcaster这个工程文件,在这个程序中是一个广播者角色例程,处于广播态一直广播,不能建立连接,因此,通过BLE调试助手来观察蓝牙的广播名称和MAC地址值。
将这个工程文件,重复复制一份,并修改文件名字,需要建立一个独立的工程文件。具体的修改过程可以参考这篇文章:https://blog.csdn.net/mx1117/article/details/122209600?spm=1001.2014.3001.5506
在程序中先添加一个串口接收数据的函数,其中MAC地址是用十六进制数据进行传入和修改,广播名称利用字符串形式进行传入和修改;在串口中利用中断服务函数接收串口发送的数据。
在中断服务函数中写一个状态机函数,将MAC地址接收数据和接收广播名称数据分开处理。
//中断服务函数 __INTERRUPT //用于指定中断服务函数并设置中断的类型或属性。 __HIGH_CODE // 将代码或数据分配到指定的内存段 void UART3_IRQHandler(void) { volatile uint8_t i; static uint16_t Rxstate = 0; //状态机变量,静态变量类似于全局变量,函数进入后只会初始化一次0,函数退出后数据仍然有效 switch(UART3_GetITFlag()) //获取UART3的中断标志位 { case UART_II_LINE_STAT: // 线路状态错误中断 { UART3_GetLinSTA(); //获取线路状态错误的具体信息 break; } case UART_II_RECV_RDY: // 数据达到设置触发点中断 for(i = 0; i != NUM-1; i++) //NUM-1保证每次接收都能进超时 { // RX_Data = UART3_RecvByte(); //每次读取一个字节并存储到RX_Data // UART3_SendByte(RX_Data); //将接收到的字符串通过UART1发送出去; len = UART3_RecvString(RX_buff); // UART3_SendString(RX_buff,RX_Data); // for (uint8_t j = 0; j < len; ++j) { RX_Data = RX_buff[j]; if (Rxstate == 0) //判断包头 { if (RX_Data == '[') //判断广播名字 { Rxstate = 1; pRxpacket_1 = 0; //数据包清零 // UART3_SendByte('O'); // UART3_SendByte('K'); } else if (RX_Data == 0xFF) //判断MAC地址 { Rxstate = 2; pRxpacket_2 = 0; //数据包清零 } } else if (Rxstate == 1) //判断数据包 { Rx_NAMEPacket[pRxpacket_2] = RX_Data; //存放发送的广播名字字符 pRxpacket_2 ++; if (pRxpacket_2 >= 6) { Rxstate = 11; UART3_SendString(Rx_NAMEPacket, pRxpacket_2); } } else if (Rxstate == 2) //判断数据包 { Rx_MACPacket[pRxpacket_1] = RX_Data; //存放发送的MAC地址数据 pRxpacket_1 ++; if (pRxpacket_1 >= 6) { Rxstate = 22; UART3_SendString(Rx_MACPacket, pRxpacket_1); } } else if (Rxstate == 22) //判断MAC地址包尾 { if (RX_Data == 0xFE) { Rxstate = 0; RX_Flag_mac = 1; //数据接收到,标志位为1 } } else if (Rxstate == 11) //判断广播包名字包尾 { if (RX_Data == ']') { Rxstate = 0; RX_Flag_name = 1; } } } } break; case UART_II_RECV_TOUT: // 接收超时中断,暂时一帧数据接收完成 // i = UART3_RecvString(RX_buff); //接收一帧完整的字符串,返回字符串长度 // UART3_SendString(RX_buff, i); //将接收到的字符串通过UART1发送出去 break; case UART_II_THR_EMPTY: // 发送缓存区空中断,可继续发送 break; case UART_II_MODEM_CHG: // 模式变化中断,只支持串口0,可继续发送 break; default: break; } }
<第一步>修改广播名称
在主函数中,根据中断标志位处理数据,广播名称的接收标志位,利用EEPROM存储广播名称数据。
1 if(Serial_GetRXFlag_NAME() == 1) //广播名字的接收标志位 2 { 3 OLED_ShowString(4, 1, Rx_NAMEPacket); 4 EEPROM_ERASE(512, 6); 5 EEPROM_WRITE(512,Rx_NAMEPacket,6); 6 7 SYS_ResetExecute(); //软件复位 8 }
1、先利用EEPROM_ERASE(512, 6),用于擦除 EEPROM 存储器中指定地址范围的数据。当调用 EEPROM_ERASE 函数时,它会将起始地址为 512 的连续 6 个字节的数据擦除为初始值。
EEPROM_WRITE(512, Rx_NAMEPacket, 6)这个函数将数据写入 EEPROM 存储器中指定地址处。当调用 EEPROM_WRITE 函数时,将串口接收到的 Rx_NAMEPacket 数组中的 6 个字节的数据写入 EEPROM 存储器从起始地址为 512 的位置开始的连续地址中。
2、然后进行一次软件复位的操作。
在用于处理 Broadcaster 任务的事件中,新建一个动态修改广播包的任务事件,先关闭广播状态,将广播包数据前31个字节清零,
使用 EEPROM_READ 函数从 EEPROM 存储器的地址 512 处读取 6 个字节的数据,存储到 name 数组中。
重新定义一个广播数组,将name 数组填入,更新广播数据和扫描应答包数据。更新使能广播状态,
然后在使用 tmos_start_task 函数,在一定时间后触发这个事件。
//动态修改广播包内容 if ( events & NAME_CHANGE_ADV_EVT) { uint8_t addnum; uint8_t name[6]; // Updata the advertising data uint8 initial_advertising_enable = FALSE; //关闭广播 GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable ); //关闭广播状态 //将广播包数据前31个字节清零 tmos_memset(advertData, 0, 31); EEPROM_READ(512, name, 6); //使用 EEPROM_READ 函数从 EEPROM 存储器的地址 512 处读取 6 个字节的数据,存储到 name 数组中。 //定义一个新的广播包数组 uint8_t newAdvertData[] = { 0x08, GAP_ADTYPE_LOCAL_NAME_SHORT, name[0],name[1],name[2],name[3], name[4], name[5],name[6],name[7] }; printf("Start Dynamic advertData.....\r\n"); GAP_UpdateAdvertisingData(Broadcaster_TaskID, TRUE, sizeof(newAdvertData), newAdvertData); //更新广播数据 GAP_UpdateAdvertisingData(Broadcaster_TaskID, FALSE, sizeof(scanRspData), scanRspData); //更新扫描应答数据 initial_advertising_enable = TRUE; //开启广播 GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8 ), &initial_advertising_enable ); //更新使能广播状态 tmos_start_task( Broadcaster_TaskID, NAME_CHANGE_ADV_EVT ,1600); //单位是0.625mS,1600*0.625mS为一秒执行一次(需要在初始化调用) , return ( events ^ NAME_CHANGE_ADV_EVT ); }
需要将tmos_start_task函数,在Broadcaster_Init中进行初始化处理。
此时,就可以将串口发送的字符串格式为[xxxxxx],广播名称修改为设置的xxxxxx。
<第二步>修改MAC地址
else if (Serial_GetRXFlag_MAC() == 1) { OLED_ShowHexNum(1, 1, Rx_MACPacket[0], 2); OLED_ShowHexNum(1, 5, Rx_MACPacket[1], 2); OLED_ShowHexNum(1, 9, Rx_MACPacket[2], 2); OLED_ShowHexNum(2, 1, Rx_MACPacket[3], 2); OLED_ShowHexNum(2, 5, Rx_MACPacket[4], 2); OLED_ShowHexNum(2, 9, Rx_MACPacket[5], 2); EEPROM_ERASE(256, EEPROM_PAGE_SIZE); // unsigned char Rx_NAMEPacket[6] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; // 将串口接收到的数据复制到MAC数组中 memcpy(MAC, Rx_MACPacket, 6); // 假设数据长度为6 EEPROM_WRITE(256,MAC,6); SYS_ResetExecute(); //软件复位 }
在根据中断标志位处理数据中MAC地址的接收标志位,利用EEPROM存储MAC地址的数据。
1、EEPROM_ERASE(256, EEPROM_PAGE_SIZE)对 EEPROM 进行擦除。该函数的目的是擦除指定地址处的 EEPROM 存储空间,其中 256 是起始地址,EEPROM_PAGE_SIZE 表示要擦除的页大小。
2、使用 memcpy 函数将串口接收到的数据(存储在 Rx_MACPacket 数组中)复制到名为 MAC 的数组中。这里使用了 memcpy 函数是为了将数据从一个内存位置复制到另一个内存位置,数据的长度为 6 字节。
3、EEPROM_WRITE(256, MAC, 6) 操作,将数组 MAC 的数据写入到 EEPROM 存储器的地址 256 处。将数据写入 EEPROM 存储空间,其中 256 是写入的起始地址,MAC 是要写入的数据,6 是要写入的数据长度。
4、最后进行一次软件复位。
在蓝牙初始化前,将EEPROM_READ(256, ReadMacAddr, 6) 操作,从 EEPROM 存储器的地址 256 处读取长度为 6 字节的数据,并将数据存储到名为 ReadMacAddr 的数组中。
使用 memcpy 函数将 ReadMacAddr 数组中的数据复制到 MacAddr 数组中。数据长度为 6。
此时,就可以将串口发送的MAC地址十六进制格式为FF ** ** ** ** ** ** FE,去掉帧头和帧尾,MAC地址修改为设置的** ** ** ** ** **。
在MacAddr 数组中原先的数值定义为
const uint8_t MacAddr[6] ={0x84, 0xC2, 0xE4, 0x03, 0x23, 0x11};
其中const 限定符,这意味着在程序的执行过程中,不能通过对数组元素的直接赋值来修改数组的内容。const 限定符表示该数组是只读的。
因此需要改为:uint8_t MacAddr[6] ={0x84, 0xC2, 0xE4, 0x03, 0x23, 0x11};
在公共文件中,Config.h中需要重新定义一个数据变量。但是更改这里的公共文件,会导致其他工程文件也会更改,所以需要像文章开头讲的那样,建立独立工程,将公共文件包含在内,这样就能随意更改Config.h中的代码程序。
<第三步>串口测试验证
由串口发送十六进制的MAC地址,FF 11 22 33 44 55 66 FE。通过串口打印出修改后的MAC地址是11:22:33:44:55:66
由串口发送字符串的蓝牙广播名字,[BLE-77]。这样去掉帧头和帧尾,此时蓝牙广播名称为BLE-77。
通过手机BLE调试助手可以看出,此时,蓝牙已修改好,蓝牙广播名称为BLE-77,MAC地址为11:22:33:44:55:66。
程序如下:
链接:https://pan.baidu.com/s/1MAX0qbAfSzQwrzzoNPuejA
提取码:7pdj