第一部分:模块原始数据
拿到模块,在网上查了一圈,发现基本没什么有用的资料,很多都是一些相关但是没有实际价值的东西。许多论文都是再谈怎么去做,而没有实实在在的去完成这么一个过程。
废话不多说,直接步入正题。
昨天在网上才发现这个软件,据评论说是这款串口软件很好用。
RealTerm的下载地址https://realterm.sourceforge.io/
这是通过单片机的232通信例程直接接收得到的原始数据,也就是参考手册中的数据流。其中小包数据,是每秒512个大概,大包数据是每秒1个。
小包的格式是AA AA 04 80 02 xxHigh xxLow xxCheckSum前面的AA AA 04 80 02 是不变的,后三个字节是一只变化的,xxHigh和xxLow组成了原始数据rawdata,xxCheckSum就是校验和。所以一个小包里面只包含了一个对开发者来说有用的数据,那就是rawdata,可以说一个小包就是一个原始数据,大约每秒钟会有512个原始数据。
从小包中解析出原始数据:
rawdata = (xxHigh << 8) | xxLow;
if(rawdata > 32768){ rawdata =65536; }
根据手册,在计算原始数据之前,要先检查检验和:
sum = ((0x80 + 0x02 + xxHigh + xxLow)^ 0xFFFFFFFF) & 0xFF。
就是把头文件AA AA 04后面的四个数据加起来,取反,在取低八位。当检验码不对时,直接丢弃该包。
在大包数据里面可以解析Signal,Attention,Meditation和8个EEG的信号值,大包的格式是固定的:
AA 同步
AA 同步
20 是十进制的32,即有32个字节的payload,除掉20本身+两个AA同步+最后校验和
02 代表信号值Signal
C8 信号的值
83 代表EEG Power开始了
18 是十进制的24,说明EEG Power是由24个字节组成的,以下每三个字节为一组
18 Delta 1/3
D4 Delta 2/3
8B Delta 3/3
13 Theta 1/3
D1 Theta 2/3
69 Theta 3/3
02 LowAlpha 1/3
58 LowAlpha 2/3
C1 LowAlpha 3/3
17 HighAlpha 1/3
3B HighAlpha 2/3
DC HighAlpha 3/3
02 LowBeta 1/3
50 LowBeta 2/3
00 LowBeta 3/3
03 HighBeta 1/3
CB HighBeta 2/3
9D HighBeta 3/3
03 LowGamma 1/3
6D LowGamma 2/3
3B LowGamma 3/3
03 MiddleGamma 1/3
7E MiddleGamma 2/3
89 MiddleGamma 3/3
04 代表专注度Attention
00 Attention的值(0到100之间)
05 代表放松度Meditation
00 Meditation的值(0到100之间)
D5 校验和
想要获得某个EEG信号值,只需将相应信号的1/3值左移16位,2/3值左移8位,3/3值不变,然后将他们或运算:
delta=(payload[i]<<16) | (payload[(i+1)]<<8) | (payload[(i+2)])。
第二部分:串口接收处理
将数据处理移植到STM32上,采用串口的DMA接收模式,注意的是DMA_MODE采用Circular,DMA_BufferSize>(8*512+36=4132)(小包8个字节,每秒512个,完整的大包36个字节)。
代码如下:
void usart_init()
{
//声明结构体//
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//时钟打开//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA1时钟
//GPIO配置//
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX
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;//RX
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//USART配置//
USART_InitStructure.USART_BaudRate=57600;
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;//硬件流DMA
USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//接受发送
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
//DMA接收//
void USART1_DMA_Recv(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(USART1->DR);//外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&buffer;//内存基地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//SRC作为数据传送的来源
DMA_InitStructure.DMA_BufferSize=5000;//数据传输长度!!!!!!
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_PeripheralDataSize_Byte;//内出数据单位
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//传输模式!!!!!
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先级
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//禁止内存到内存传输
DMA_Init(DMA1_Channel5,&DMA_InitStructure);
DMA_ClearFlag(DMA1_FLAG_TC5);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);//DMA1传送完成产生中断
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA_Cmd(DMA1_Channel5,ENABLE);
}
void DMA1_Channel5_IRQHandler(void)//中断函数
{
if (DMA_GetITStatus(DMA1_IT_TC5)==1)
{
DMA_ClearITPendingBit(DMA1_IT_TC5);
DMA_Cmd(DMA1_Channel5, DISABLE);
flag = 1; //将下面的程序放到main的while中,不然运行容易丢包
// for(i=0;i<5000;i++)
// {
// parseByte( buffer[i]);
// }
// DMA_Cmd(DMA1_Channel5,ENABLE);
}
}
这部分代码还需要进一步修改……我们是依靠蓝牙传输信号,在下面会解决如何通信的问题。
下一部分将会讲述当STM3原2接收到始数据后,怎样将它处理后得到signal,attention,meditation和eeg信号的值
第三部分:数据解析
待续……通信协议部分还是比较关键的
第四部分:数据通信
这一部分在我另一篇文章里有示例性的图文介绍
https://blog.csdn.net/seek97/article/details/81333701
我使用的是HC05和BT06俩个蓝牙模块
1、【AT模式】HC05蓝牙模块的PIO11接VCC,上电后即进入HC05AT指令模式,对于BT06蓝牙直接上电进入AT模式,用USBT06转TTL模块连接到电脑的USBT06接口。
2、【打开串口调试助手】开启2个串口调试窗口,一个打开HC05的COM口,一个打开BT06的COM口。【HC05默认波特率一般为38400,BT06默认是9600】.
3、【恢复HC05默认设置】串口调试助手HC05,将HC05恢复默认设置:AT+ORGL【即回车、换行,在串口调试助手上输入一个回车即可】
4、【设置HC05配对码】串口调试助手HC05,配置蓝牙HC05的配对码:AT+PSWD=1234【蓝牙HC05与蓝牙BT06的配对码相同,这样才能成功配对,配对码随意】
5、【设置HC05主模式】串口调试助手HC05,将蓝牙HC05配置为主机模式:AT+ROLE=1
6、【恢复BT06默认设置】串口调试助手BT06,将蓝牙BT06恢复默认设置:AT+ DEFAULT
7、【设置BT06配对码】串口调试助手BT06,配置蓝牙BT06的配对码与蓝牙HC05一致:AT+PIN 1234
8、【设置BT06从模式】串口调试助手BT06,将蓝牙BT06配置为从机模式:AT+ ROLE
9、【 查询BT06地址 】串口调试助手BT06,查询蓝牙BT06的地址:AT+LADDR 【如20:15:02:12:07:58】
10、【蓝牙HC05绑定蓝牙BT06】串口调试助手HC05,蓝牙HC05绑定蓝牙BT06地址:AT+BIND=0101,01,010101
【注意把地址的冒号换成逗号,同时注意这个格式,实验多次,只有这样写,HC05才可以绑定该地址】
11、【设置波特率】根据各自的命令符号修改各自的波特率 HC05:AT+UART=57600,0,0。BT06:AT+BAUD7.
12、【常规工作模式】2个模块断电,重新上电后进入常规工作模式,自动完成配对。之后, HC05就能接收到BT06的数据了。
【注意事项】:确保2个蓝牙模块的配对码(PSWD)相同,都上电后两个模块会自动相连。
【设置蓝牙的连接模式】:默认是:0—指定蓝牙地址连接模式,这样HC05才能自动连接绑定的地址,如果不是模式0,设置为模式0:AT+CMODE=0
第五部分:数据处理
待续……这部分会涉及一些算法,比如BP神经网络模型提速特征值
第六部分:系统控制
待续……这部分比较简单,把小四轴的代码理解完成,也就可以实现控制了。
第七部分:论文写作
待续....这部分应该贯穿于整个项目研究过程,注重将学习成果记录
来源:https://blog.csdn.net/seek97/article/details/81328542