第一部分:模塊原始數據
拿到模塊,在網上查了一圈,發現基本沒什麼有用的資料,很多都是一些相關但是沒有實際價值的東西。許多論文都是再談怎麼去做,而沒有實實在在的去完成這麼一個過程。
廢話不多說,直接步入正題。
昨天在網上才發現這個軟件,據評論說是這款串口軟件很好用。
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神經網絡模型提速特徵值
第六部分:系統控制
待續……這部分比較簡單,把小四軸的代碼理解完成,也就可以實現控制了。
第七部分:論文寫作
待續....這部分應該貫穿於整個項目研究過程,注重將學習成果記錄