zoukankan      html  css  js  c++  java
  • 可穿戴项目总结

    可穿戴项目总结

    项目背景和目的

    • 背景是我的毕业设计, 整个项目的架构是一个IOT的框架, 可穿戴设备采集数据, 手机app做一个数据中转作用, 服务器端做数据存储和处理.
    • 目的: 利用可穿戴设备长时间监测佩戴者的语音、行为、环境和体征的变化,看能不能和心理健康建立一定的联系; 我做的主要是自闭症倾向的研究。

    硬件部分

    • 用Altium Designer, 自己设计了4层板的PCB板, 大小为3.3X3.4厘米
    • 语音传感器部分: 两个MEMS麦克风采集左右声道的信息, 音频编码解码器(wm8978这块语音芯片) --- I2C通信和I2S通信
    • 行为传感器部分: 主要是用的三轴加速度和三轴陀螺仪(mpu6050) --- I2C 通信
    • 环境传感器部分: 主要用了光线传感器(bh1750), 环境温度和环境气压传感器(bmp180) --- I2C通信
    • 体征传感器部分: 主要用了一款皮肤温度和皮肤湿度的传感器(SI7021) --- I2C通信
    • 心率血压传感器模块: 主要测试过松恩电子的几款产品, SON3019A等. 测试效果差强人意, 但不支持二次开发, 就没有集成到我们的设备上.
    • 环境传感器和体征传感器的I2C接在同一I2C总线上, 由于I2C硬件地址不同所以可以正常的读取数据.
    • 主控器是用的STM32F405RG, 64pin的一块芯片
    • 电源管理芯片用的TPS62260(一款稳压到3.3的芯片), 快充管理芯片(BQ24040)
    • 还有一些外设, 按键, OLED显示屏, SD卡存储器
    • 蓝牙部分的话, 之前试过一款北欧(Nordic)的nRF52832蓝牙芯片, 简单实现过基于FreeRTOS的蓝牙透穿数据的功能
    • 但是和我们的可穿戴设备联调的时候, 因为音频数据数据要求太快, 就没有集成在可穿戴设备上.

    STM32F405的硬件资源

    • 有1MB的flash 和192KB的SRAM

    软件部分

    • 利用了一款国内的嵌入式操作系统(RT-Thread), 基于位图的调度器

      • rt-thread的调度算法为基于优先级调度和基于时间片轮转调度共存的策略
      • 支持多个线程具有同样的线程优先级
      • 对不同优先级的线程,采用可抢占的方式:即高优先级的线程会“立刻”抢占低优先级的线程
      • 而对同线程优先级别的多个线程则采用时间片轮转的方式
      • 每一个线程的信息用线程控制块来表示
      • 线程的优先级别用非负整数(即无符号整数)表示,并且优先级越高,对应的数越小
      • 系统的线程优先级的数目固定,最多支持256级(32字节的数据, 每个字节8位)
    • 一共有8个线程一起工作

      • 控制开始和停止记录的按键线程(thread_key)
      • 显示电量、CPU利用率、行为数据变化和温湿度传感器数据的显示线程(thread_oled, SPI协议的OLED屏)
      • 控制电池充电和ADC采样的电池线程(thread_battery)
      • 采集mpu6050的传感器数据的线程(thread_mpu6050)
      • 采集语音信号的线程(thread_wm8978)
      • 采集环境传感器和体征传感器数据的线程(thread_sensors)
      • 保存传感器数据为文本文件(语音保存为.wav, 行为,环境,体征数据保存为.csv文件)于FAT-FS文件系统中(thread_file)
      • 做语音特征计算的线程(thread_dsp), 主要做四个语音特征的计算(短时能量, 谱熵, 亮度, 共振峰)
    • 优先级的设置: 按键线程的优先级最高,

      • 传感器读取数据的线程第2高, 采用的是时间片轮询的方式,
      • 文件写数据到SD卡中的优先级第3高,
      • DSP线程特征计算的线程第4高,
      • 显示数据, 时间, 电量和CPU利用率的线程第5高,
      • 电源管理的线程第6高, 主要是ADC采样, 和监测充电管理芯片的两个I/O;
    • 传感数据传输流:

      • 行为传感器的数据: (三轴陀螺仪和三轴加速度计, IIC控制和传输), 一次读64字节, 缓存设置为5K, 缓存满后再写入SD卡
      • 采集audio的音频采集线程(结合DAM控制器实现, 配置DMA的双buffer机制), 一个buffer设置为5K, 主要实现了一个录音的功能;
      • DMA中断时, 会发一个信号给写文件的线程管理, 把音频数据写入到SD卡中
      • 光线传感器(bh1750)、环境气压和温度传感器(bmp180)和温湿度传感器(si7021)用一个线程进行数据采集, 采集一次马上发事件写入文件中
    • 读写分离的思想和时间同步(保证体征, 环境和体征, 语音的文本同一时刻保存), 利用单独的文件线程来写传感器文件

    • 一些技术细节:

      • 传统的DMA有一个外设地址寄存器(PAR)、一个内存地址寄存器(MAR), 双缓冲DMA有两个内存地址寄存器(M0AR, M1AR)
      • 同时有一个标志位表示当前正在使用哪一个内存地址寄存器MxAR(DMA->SxCR[CT]) //语音利用了DMA双缓冲机制
      • 也可以通过设置该位来主动切换当前的MxAR, 在RAM中定义两个接收缓冲区, DMA配置为双缓冲, 防止数据在处理的时候被DMA改写。
      • WM8979只集成了ADC和DAC的音频编码器, 本身没有音频数据传输功能
      • 将采样到的音频数据输出到SD卡中进行存储, 利用I2S协议进行音频数据传输
      • I2S总线接口有3个主要信号,但只能实现数据半双工传输, 全双工需要扩展数据引脚(一般只用两个引脚sd和ck)
        • SD(serial data): 串行数据线, 用于发送数据
        • WS(word select): 字段选择线, 也称帧时钟(LRC)线, 表明当前传输数据的声道。WS的频率等于采样频率(FS)
        • CK(serial clock): 串行时钟线, 也称位时钟(BCLK), 数字音频的每一位数据都对应有一个CK脉冲,它的频率为:2采样频率量化位数, 2代表左右两个通道数据
        • ext_SD(extern serial data): 扩展串行数据线, 用于全双工的传输的数据接收
        • 传输的一个主时钟(MCK), 256*FS
    • I2C相关知识: (I2C需要两个上拉电阻, 一般是4.7K)

      • I2C的速率: 100Kbits/s(标准模式), 400Kbits(快速模式), 3.4Mbits(高速模式)
      • I2C总线: 一条串行数据线SDA, 一条串行时钟线SCL
      • 每个接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址
      • 主机可以作为主发送器或主机接收器
      • 起始条件: 当SCL线是高电平时, SDA线从高电平向低电平切换, 这种情况表示起始条件, 即下降沿触发
      • 停止条件: 当SCL线是高电平时, SDA线由低电平向高电平切换, 这种情况表示停止条件, 即上升沿触发
      • 总线空闲状态: SDA和SCL两条信号线都处于高电平, 即总线上所有的器件都释放总线, 两条信号线各自的上拉电阻把电平拉高
      • I2C总线端口必须是开漏: 因此需要上拉电阻, 上拉电平驱动能力很弱, 所以决定了它跑不快.
      • I2C的负载能力为400pF, 每个器件的总线接口都有一定的等效电容
      • 数据传输: 发送到SDA线上的每个字节必须为8位, 每次传输发送的字节数不受限制
      • 每个字节后必须跟一个响应位(即应答位)
      • 首先传输数据的最高位(MSB)
      • 如果从机要完成一些其他功能后(如一个中断服务程序)才能接受或发送下一个完整的数据字节, 可以使时钟线保持低电平, 迫使主机进入等待转态
      • 当从机准备好接收下一个数据字节并释放时钟线SCL后, 继续进行数据传输.
      • I2C怎么读写数据: 假设主从机寄存器地址都是8位;
        • 主机先发起一次通信,将读command(0x01)和需要读取的寄存器地址address写入从机;(主机发出写操作);
        • IIC读写讲得很详细
        • 主机先发送从机的7位地址, 在发送一位读写位(R/W, 0代表写, 1代表读), 检查应答, 然后是8位数据, 然后是一个应答位, 然后继续发数据, 直到停止;
    • SPI相关知识:

      • spi是一种高速的, 全双工, 同步的通信总线; 一条时钟线(sck), 一条数据输入线(MOSI), 一条数据输出线(MISO), 一条NSS使能线(传输数据时为低电平)
      • SPI的Master(主设备)会根据将要交换的数据产生相应的时钟脉冲(Clock Pulse), 时钟脉冲组成了时钟信号
      • 时钟信号通过时钟极性(CPOL)和时钟相位(CPHA)控制两个SPI设备间何时数据交换以及何时对接收到的数据进行采样, 来保证数据在两个设备之间是同步传输的
      • SPI四种模式: SPI的四种模式通过时钟线的相位和极性来进行选择:
        • 模式1: CPOL = 0, CPHA = 0; 总线空闲时SCK为低电平, SPI在SCLK第一个边沿开始采样
        • 模式2: CPOL = 0, CPHA = 1; 总线空闲时SCK为低电平, SPI在SCLK第二个边沿开始采样
        • 模式3: CPOL = 1, CPHA = 0; 总线空闲时SCK为高电平, SPI在SCLK第一个边沿开始采样
        • 模式4: CPOL = 1, CPHA = 1; 总线空闲时SCK为高电平, SPI在SCLK第二个边沿开始采样
      • 时钟极性CPOL: 即SPI空闲时, 时钟信号线的电平, CPOL为1时, 空闲时高电平, 0空闲时低电平
      • 时钟相位CPHA: 即SPI在SCLK第几个边沿开始采样, 0表示第一个边沿开始采样, 1表示第二个边沿开始采样
      • OLED显示屏使用的CPOL = 1, CPHA = 1, 即模式4; 总线空闲高电平, 第二个边沿开始采样, 也就是上升沿采样.
      • SPI速率很高, 最高速率大于50Mbps
    • 串口是异步通信(因为没有时钟线), SPI是同步通信, I2C是同步通信

    • 串口是双工通信, SPI双工通信, I2C是半双工通信, 因为只有I2C只有一根数据线

    • SD总线: 最高能到10Mbps

    • USB总线:

      • USB1.1 低速模式: 1.5Mbps, 全速模式: 12Mbps
      • USB2.0 向下兼容, 增加了高速模式, 最大速率为480Mbps, 高速模式25-480Mbps(bits per second, 比特率, 比特/s, 每秒传送位数, 传输速率常用单位)
      • USB3.0 向下兼容, 增加了超高速模式, 理论上可以达到4.8Gbps, 实际中, 也就是高速模式的10倍左右
    • 线程间用到的同步和通信机制:

      • 同步机制: 互斥量(PV原语), 初始化一个数值S为1, P操作(Proberen-测试的意思)就是对这个值减1, 如果S >= 0, 则改线程继续执行, 否则线程进入等待状态, 进入等待队列等待被唤醒
      • V操作(Verhogen)把S的值加1, 如果S > 0, 则该线程继续执行, 否则释放等待队列中第一个等待该信号量的线程.
      • 线程通信: 利用事件来进行通信, 具体实现是利用一个uint32_t(一个无符号整型)来表示一个事件集合, 一种事件表示一个位
      • 该位为1表示事件发生, 该位为0表示事件没有发生, 所以每个事件集合最多容纳32个事件
      • 对一个事件对象发送某种事件, 对该事件对象接收某个事件, 对某个事件进行超时等待(在固定时间内没有等待到某个事件将直接返回)
      • 本质上是利用了事件机制实现了一个状态机编程
    • 异步通信与同步通信

      • 同步通信就是需要发送方和接收方有一个时钟, 在同一个时钟下来进行需要数据的传输
      • 异步通信发送和接收方有着自己的时钟, 通过起始位和停止位来判断是否有数据, 为了保证数据传输的可靠性, 会有一些校验位
      • 用于判断数据是否有效: 如奇偶校验
    • 线程优先级的配置问题

      • 按键的优先级设置为2;
    • 其他功能的实现

      • 计算MCU的利用率
      • 实现U盘的高速传输(USB2.0)

    蓝牙通信方面

    • 通信方面, 用过WIFI透传模块, 主要是发送AT指令, 但功耗太高, 超过了100ma, DC-DC的芯片无法满足, 只有换蓝牙的方案,

    • 后面换了一块蓝牙芯片nRF52832(一个蓝牙4.0的芯片来作数据传输), 试过蓝牙透传的功能, 传输速率比较慢, 10kb/s左右, 115200波特率

      • 如果没有奇偶校验, 就除以10, 如果有奇偶校验就出以11, 波特率115200 = 115200(位/秒) = 11520(字节/秒) 再除以1024等于11.52字节/秒
      • 蓝牙协议栈简介
      • ATT属性协议层
      • 与应用紧密相关的 GAP/GATT 层, GAP 通用访问配置文件层(Generic Access Profile), GATT 通用属性配置文件层(Generic Attribute Profile);
      • 通过 SoftDevice(即协议栈,这种方式使得协议栈和用户应用可以单独编译和链接)的 API 软件接口(以 sd_ 开头)调用来实现;
    • 低功耗蓝牙协议栈包含两部分共8层:主机(Host)和控制器(Controller)。

      1. 控制器部分包括:
        • 物理层(Physical Layer)
        • 链路层(Link Layer)
        • 主机控制接口层(Host Controller Interface)
      2. 主机部分包括:
        • L2CAP 逻辑链路控制及自适应协议层(Logical Link Control and Adaptation Protocol)
        • 安全管理层(Security Manager)
        • ATT 属性协议层(Attribute Protocol)
        • GAP 通用访问配置文件层(Generic Access Profile)
        • GATT 通用属性配置文件层(Generic Attribute Profile)
      3. 低功耗蓝牙有两种频道类型:广播频道 3 个,数据频道 37 个,共 40 个频道;
      4. 最大发射功率为 +10 dBm(10mW),最小发射功率为 -20 dBm(0.01mW);
        • 在低功耗蓝牙中,所有的数据块由一个 Profile 或服务所使用的数据库称为特性(characteristic);
        • ANT协议;

    服务器和手机APP通信

    • 实现了一个http服务器, 主要包括7个步骤:
      • 建立连接: 与客户端建立TCP/IP链接;
      • 接受请求: 从socket链接中读取HTTP请求数据;
      • 解析请求: 根据HTTP请求报文结构解析请求报文;
      • 处理请求: 处理请求, 一般是数据库增、 删、改、查操作;
      • 构建响应: 按照HTTP响应报文格式将处理结果构建成响应报文;
      • 发送响应: 将响应报文通过socket链接发送给客户端;
      • 记录事务: 将上述处理过程作为一个事务记录在日志文件中;
    • 基于muduo库实现了一个简单的HTTP服务器, 利用POST和GET方法进行传输数据;
    • Json文本进行数据传输;
      • JSON解析器和生成器是Github热门开源软件RapidJSON;
      • RapidJSON是一个用C++语言开发的高性能JSON解析/生成器,具有解析速度快、资源占用小等优点;
    • C++版的Mysql Veson3.2.3, 做数据存储;
    • 服务器主要放在阿里云服务器上;
    • App发出HTTP请求, 服务器作HTTP响应;
      • 处理HTTP请求与生成HTTP响应的程序则是基于muduo网络库框架自行开发的;
      • HTTP协议是一个基于请求与响应模式的、无状态、应用层协议,该协议基于TCP传输协议处于七层OSI模型的应用层;
      • HTTP报文分为请求报文和响应报文;
      • 请求报文是客户端发送给服务器的请求动作,响应报文则是服务器处理请求后发送给客户端的响应行动;
    • 解析请求报文时,HTTP服务器会不定期地读取Buffer中的数据;
      • 网络连接可能随时都会出现延迟,每当读取Buffer中的数据时,都需要判断请求的完整性,如果不完整则立即返回,直到请求完整才会解析HTTP请求;
      • 解析完HTTP请求之后,会根据HTTP的方法(GET/POST等)结合首部以及主体来操作服务器的资源,最终对数据进行增加、删除、变改、查询操作;
      • 采用MySQL作为数据库存储App上传的历史数据;
      • 使用C/C++语言连接MySQL数据库的方法主要有两种,一个是使用mysql connector库,另一个是使用mysql++库;

    Muduo库HTTP程序

  • 相关阅读:
    数据库建表的时候报 “1215 Cannot add foreign key constraint”
    Maven项目中提示:Eclipse “cannot be resolved to a type” error
    数据表设计的几个简单原则
    使用brew安装软件
    linux如何设置用户权限
    前端页面——Cookie与Session有什么区别
    Git Push 避免用户名和密码方法
    $GLOBALS['HTTP_RAW_POST_DATA'] 和$_POST的区别
    PHP获取POST的原始数据的方法
    PHP底层的运行机制与原理
  • 原文地址:https://www.cnblogs.com/longjiang-uestc/p/9539465.html
Copyright © 2011-2022 走看看