【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

 

posted on 2023-09-15 14:10  凡仕  阅读(805)  评论(7编辑  收藏  举报