本帖最后由 donatello1996 于 2020-11-23 00:34 编辑
大联大友尚ST MEMS sensor 开发板上有多组传感器,有用于测量模块在三维空间姿态的三轴陀螺仪,有用于测量模块在三维空间运动趋势的加速度传感器,有测量模块相对于地磁方向的地磁传感器,还有测量环境温湿度和大气压的环境传感器,将这些数据通过总线传到电脑上位机上,就可以实现各种各样的商用或工业用途,比如分析模块姿态得出模块当前情况,或者是当作一个手柄(输入设备)去控制电脑上位机,总之用途多种多样。
由于ST MEMS sensor开发板只有最纯粹的传感器采集功能,所以不需要对ST官方给出的SDK代码进行过多的修改,只需要选取其中的DataLogTerminal工程,将数据采集的代码简化一下即可,并通过USART1即串口1发送特定格式的串口报文:
- void MX_MEMS_Process(void)
- {
- int i;
- int32_t accx1,accx2,accy1,accy2,accz1,accz2;
- int32_t gyrox1,gyroy1,gyroz1;
- int32_t magx1,magy1,magz1;
- float temp1,temp2,temp3,humi,pres;
- char buf[20] = {0x01,0xfe,0x02,0xfd};
- uint8_t flag_acc = 0;
- uint8_t flag_gyro = 0;
- uint8_t flag_mag = 0;
- uint8_t flag_temp = 0;
- uint8_t flag_humi = 0;
- uint8_t flag_pres = 0;
-
- IKS01A3_MOtiON_SENSOR_Axes_t acceleration;
- if(!IKS01A3_MOTION_SENSOR_GetAxes(0,MOTION_ACCELERO,&acceleration))
- {
- flag_acc = 1;
- accx1 = acceleration.x/10;
- accy1 = acceleration.y/10;
- accz1 = acceleration.z/10;
- if(accx1 < -100) accx1 = -100;
- if(accx1 > 100) accx1 = 100;
- if(accy1 < -100) accy1 = -100;
- if(accy1 > 100) accy1 = 100;
- if(accz1 < -100) accz1 = -100;
- if(accz1 > 100) accz1 = 100;
-
- buf[4] = accx1,buf[5] = accy1;
- }
-
- // if(!IKS01A3_MOTION_SENSOR_GetAxes(1,MOTION_ACCELERO,&acceleration))
- // {
- // accx2 = acceleration.x;
- // accy2 = acceleration.y;
- // accz2 = acceleration.z;
- // printf("----- accx2=%d accy2=%d accz2=%d -----n",
- // accx2,accy2,accz2
- // );
- // }
-
- IKS01A3_MOTION_SENSOR_Axes_t angular_velocity;
- if(!IKS01A3_MOTION_SENSOR_GetAxes(0, MOTION_GYRO, &angular_velocity))
- {
- flag_gyro = 1;
- gyrox1 = angular_velocity.x/10000;
- gyroy1 = angular_velocity.y/10000;
- gyroz1 = angular_velocity.z/10000;
-
- if(gyrox1 < -100) gyrox1 = -100;
- if(gyrox1 > 100) gyrox1 = 100;
- if(gyroy1 < -100) gyroy1 = -100;
- if(gyroy1 > 100) gyroy1 = 100;
- if(gyroz1 < -100) gyroz1 = -100;
- if(gyroz1 > 100) gyroz1 = 100;
-
- buf[6] = gyrox1,buf[7] = gyroy1,buf[8] = gyroz1;
- }
-
- IKS01A3_MOTION_SENSOR_Axes_t magnetic_field;
- if(!IKS01A3_MOTION_SENSOR_GetAxes(2, MOTION_MAGNETO, &magnetic_field))
- {
- flag_mag = 1;
- magx1 = magnetic_field.x/13;
- magx1 = abs(magx1);
- magy1 = magnetic_field.y;
- magz1 = magnetic_field.z;
- // printf("----- magx1 = %d magy1 = %d magz1 = %d -----n",
- // magx1,magy1,magz1
- // );
- buf[9] = magx1;
-
- }
-
- if (!IKS01A3_ENV_SENSOR_GetValue(0, ENV_TEMPERATURE, &temp1))
- if (!IKS01A3_ENV_SENSOR_GetValue(1, ENV_TEMPERATURE, &temp2))
- if (!IKS01A3_ENV_SENSOR_GetValue(2, ENV_TEMPERATURE, &temp3))
- {
- flag_temp = 1;
- temp1 += temp2 + temp3;
- temp1 /= 3.0;
- buf[10] = (int)temp1;
- }
-
- if(!IKS01A3_ENV_SENSOR_GetValue(0 , ENV_HUMIDITY , &humi))
- {
- flag_humi = 1;
- buf[11] = (int)humi;
- }
-
- if (!IKS01A3_ENV_SENSOR_GetValue(1, ENV_PRESSURE , &pres))
- {
- flag_pres = 1;
- buf[12] = ((int)pres >> 8) & 0xff;
- buf[13] = (int)pres & 0xff;
- buf[14] = ((int)(pres * 1000)%1000 >> 8) & 0xff;
- buf[15] = (int)(pres * 1000)%1000 & 0xff;
-
- }
-
- if(flag_acc == 1 && flag_gyro == 1 && flag_mag == 1 &&
- flag_temp == 1 && flag_humi == 1 && flag_pres == 1)
- {
- flag_acc = 0;
- flag_gyro = 0;
- flag_mag = 0;
- flag_temp = 0;
- flag_humi = 0;
- flag_pres = 0;
- USART1_Send(0x01);
- USART1_Send(0xfe);
- USART1_Send(0x02);
- USART1_Send(0xfd);
- USART1_Send(buf[4]);
- USART1_Send(buf[5]);
- USART1_Send(buf[6]);
- USART1_Send(buf[7]);
- USART1_Send(buf[8]);
- USART1_Send(buf[9]);
- USART1_Send(buf[10]);
- USART1_Send(buf[11]);
- USART1_Send(buf[12]);
- USART1_Send(buf[13]);
- USART1_Send(buf[14]);
- USART1_Send(buf[15]);
- }
- }
复制代码
串口1初始化函数,只有串口发送功能:
- void UART1_Init(int baud)
- {
- __HAL_RCC_GPIOA_CLK_ENABLE();
- __HAL_RCC_USART1_CLK_ENABLE();
- __HAL_RCC_DMA2_CLK_ENABLE();
-
- GPIO_InitTypeDef GPIO_Initure;
-
- GPIO_Initure.Pin=GPIO_PIN_9;
- GPIO_Initure.Mode=GPIO_MODE_AF_PP;
- GPIO_Initure.Pull=GPIO_PULLUP;
- GPIO_Initure.Speed=GPIO_SPEED_FAST;
- GPIO_Initure.Alternate=GPIO_AF7_USART1;
- HAL_GPIO_Init(GPIOA,&GPIO_Initure);
- GPIO_Initure.Pin=GPIO_PIN_10;
- HAL_GPIO_Init(GPIOA,&GPIO_Initure);
-
- UART1_Handler.Instance=USART1;
- UART1_Handler.Init.BaudRate=baud;
- UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;
- UART1_Handler.Init.StopBits=UART_STOPBITS_1;
- UART1_Handler.Init.Parity=UART_PARITY_NONE;
- UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;
- UART1_Handler.Init.Mode=UART_MODE_TX_RX;
- HAL_UART_Init(&UART1_Handler);
-
- // hdma_usart1_rx.Instance = DMA2_Stream2;
- // hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
- // hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
- // hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
- // hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
- // hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
- // hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
- // hdma_usart1_rx.Init.Mode = DMA_NORMAL;
- // hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
- // hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
- // HAL_DMA_Init(&hdma_usart1_rx);
- // __HAL_LINKDMA(&UART1_Handler,hdmarx,hdma_usart1_rx);
- // __HAL_UART_ENABLE_IT(&UART1_Handler,UART_IT_IDLE);
- //
- // HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
- // HAL_NVIC_EnableIRQ(USART1_IRQn);
- }
复制代码
系统的重点在上位机上,我写了个带陀螺仪/加速度显示/地磁传感器/温湿度/气压的监控上位机,并在后端写了个基本的TCP网页服务器,使用HTTP协议,上位机开启之后, 手机或者别的设备可以通过内网直接访问或内网穿透的方式访问上位机的TCP网页服务器,首先是陀螺仪和加速度显示界面:
这里对于倾角仪的设计我偷懒了一下用了之前写过的代码直接套用,不造轮子,新增了一个加速度显示,根据牛顿第二定律F=ma可知,套件受到的加速度跟所受的力呈线性关系,而根据牛二退出的简单公式Δa = ΔF/m,这里加速度变化的快慢跟套件所受的力的变化的快慢有关系,也就是说,如果用力转动套件,力度由小至大再由大至小,就能直观地反映到上位机的加速度变化槽上面,槽量会突变,而如果是以恒定/柔和的力度转动套件,那么槽量就会恒为一个固定值直到套件运动结束(运动结束时力度逐渐变小,加速度槽的反方向也会有显示),上位机图示中,倾角仪左侧为X轴加速度变化,X轴是套件的左右轴,即前后摆动;倾角仪下侧为Y轴加速度变化,Y轴是套件的前后轴,即左右摆动;倾角仪右侧是套件的竖向轴,即顺/逆时针转动:
然后是根据地磁传感器写的一个罗盘代码,上位机实现罗盘的代码算是非常简单,但无奈那个MAG地磁传感器的代码涉及的算法我实在是看不懂,做出来的效果跟鬼一样,这个功能实用价值不大,远没有上面的陀螺仪有用,因此不打算深究了,之后再看看网上大佬是怎么解读地磁传感器算法的:
这几个运动传感器弄完之后,剩下的就是非常简单的环境传感器了,这个套件非常走心,同时使用了三个检测温度的传感器,符合人们约定俗成的多温度结合探测习惯,这样我就更放心偷懒了,直接把三个温度读数做个平均值完事,然后气压传感器也是非常牛逼,实际测试中如果忽略尾数噪点可能性的情况下,精度能去到0.1KPa,而100KPa和10KPa的变化则是非常准确且灵敏,绝对不是尾数噪点(不排除1KPa以下是噪点),上位机上做一些优化,美化以下以前做的温湿度仪表盘的刻度显示问题,在下方添加一个黄色的大气压显示刻度:
红色指针为三温度平均值,蓝色指针为湿度,黄色指针为大气压,温湿度的范围不变(0~100),大气压范围刻度我用了常用的990KPa~1090KPa,一般情况下,亚热带季风气候的强降雨发生前(即人们俗称的大雨前的狂风),气压完全可以跌落到995KPa以下,此时人们体感会非常舒适,但中老年人容易在这种低气压下发生气喘;而亚热带地带处于艳阳高照的天气下(一般是夏天的中午)或者是暴风雨来临前的半天,万里无风,气压可升至1025KPa以上,人们干活就会感觉很闷,这些数据能直观地反映到套件的气压传感器上,甚至可以用手指按压的方式直接大幅改变气压传感器读数。
上位机运行之后,通过浏览器访问服务器IP:6660端口,可以进入搭建好的HTTP网页:
上传套件MDK代码文件:
上传QT上位机程序:
0
|
|
|
|
|
|