【前言】
现在对健康的监护人们越来越需要高,国庆假期鼓捣一个健康监护仪,目前可以实现测心率、血氧、血压健康监护仪,现在分享如下:
【硬件】
1、NUCLEO-H755开发板。
2、ST7789LCD屏
3、健康监测模块 心率血氧检测模块反射式检测传感器
【程序框图】
CM4开启usart2,开启中断接收,当从CM7内核接收到OpenAMP的信号后,解析命,通过向传感器发送开始监测/停止监测的命。当开始监测后,传感器会周期的将数据回传给CM4。CM4接收到数据后,通过OpenAMP发送给CM7内核。
CM7开启了TouchGFX用户交互界面,当GUI点击开启转换后,通过OpenAMP向CM4内核发送开始/停止信号;同时如果OpenAMP接收到数据后,置位接收标志,在touchGFX的handleTickEvent周期函数,判断是否有数据更新,如何有更新,就将数据列新到的用户界面。
【GUI界面设计】
打开touchGFX Designer,制作界面如下:
界面中bntRun,添加一个虚拟函数,当按下后,判断其标签来实现按键按下事件,来通知CM4是否开启或者停止采集。
void screenView::funRun() { // 获取bntRun的标签文本 touchgfx::TypedText btnRunText = bntRun.getLabelText(); // 判断按钮文本是否为"START" if (touchgfx::Unicode::strncmp(btnRunText.getText(), TypedText(T_START).getText(), 5) == 0) { // 改变按钮文本为"STOP" MKS_RUN(0x8a); bntRun.setLabelText(touchgfx::TypedText(T_STOP)); bntRun.invalidate(); } else if (touchgfx::Unicode::strncmp(btnRunText.getText(), TypedText(T_STOP).getText(), 4) == 0) { // 改变按钮文本为"START" MKS_RUN(0x88); bntRun.setLabelText(touchgfx::TypedText(T_START)); bntRun.invalidate(); } // Override and implement this function in screen }
在handleTickEvent事件中周期判断是否接到数据,如果有更新数据
void screenView::handleTickEvent() { // 调用基类的处理函数 // screenViewBase::handleTickEvent(); // // 检查是否有新数据需要处理 if (message_received == 1) { // 处理接收到的数据 handleReceivedData(); // 重置标志 message_received = 0; } } void screenView::handleReceivedData() { Unicode::snprintf(valHartBuffer,10,"%d",default_mks_params.heart); valHart.invalidate(); Unicode::snprintf(valSpo2Buffer,10,"%d",default_mks_params.spo2); valSpo2.invalidate(); Unicode::snprintf(valbpBuffer1, VALBPBUFFER1_SIZE, "%d", default_mks_params.diastolic_pressure); Unicode::snprintf(valbpBuffer2, VALBPBUFFER2_SIZE, "%d", default_mks_params.systolic_pressure); valbp.invalidate(); }
【CM7事件处理】
1、事件发送
void MKS_RUN(uint8_t state) { if(state == 0x88) { default_mks_params.cmd = 0x88; OPENAMP_send(&rp_endpoint, &default_mks_params, sizeof(default_mks_params)); } else if(state == 0x8A) { default_mks_params.cmd = 0x8A; OPENAMP_send(&rp_endpoint, &default_mks_params, sizeof(default_mks_params)); } }
当接收到touchGFX的命令,通OPENAMP_sen将事件发送给CM4。
2、事件接收
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { default_mks_params = *((mks_control_params_t *) data); message_received=1; return 0; }
当有从CM4的事件接收时,在此回函数,解析数据,并置位message_receivied置,touchGFX事件会即接收并完成数据的更新。
【CM4事件处理】
1、OpenAmp接收事件:
static int rpmsg_recv_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { default_mks_params = *((mks_control_params_t *) data); uint8_t txData; if(default_mks_params.cmd == 0x8A) { txData = 0x8A; HAL_UART_Transmit(&huart2,&txData,1,0xffff); } else if(default_mks_params.cmd == 0x88) { txData = 0x88; HAL_UART_Transmit(&huart2,&txData,1,0xffff); } return 0; }
当有从CM7事件接收到时,向usart2即传感器转输命令,开始或停止数据采集。
2、中断回调
RT_PACK *rt_pack = (RT_PACK *)usart2_rx_buffer; // ӳ�仺�������ṹ�� void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { UART_Start_Receive_IT(&huart2, usart2_buf, 1); } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART2) { if(usart2_buf[0] == PACKET_HEADER) { usart2_rx_in_progress = 1; usart2_rx_count = 0; usart2_rx_complete = 0; usart2_rx_buffer[usart2_rx_count++] = usart2_buf[0]; } else if(usart2_rx_in_progress) { if(usart2_rx_count < RECEIVE_LENGTH) { usart2_rx_buffer[usart2_rx_count++] = usart2_buf[0]; if(usart2_rx_count >= RECEIVE_LENGTH) { usart2_rx_complete = 1; usart2_rx_in_progress = 0; } } } } UART_Start_Receive_IT(&huart2, usart2_buf, 1); } void process_rt_packet(void) { if (usart2_rx_complete) { if (rt_pack->head == 0xFF) { int8_t* ecg_wave = rt_pack->acdata; uint32_t heart_rate = rt_pack->heartrate; uint32_t spo2_val = rt_pack->spo2; uint8_t micro_circ = rt_pack->bk; uint8_t fatigue_index = rt_pack->rsv[0]; uint32_t systolic_pressure = rt_pack->rsv[3]; uint32_t diastolic_pressure = rt_pack->rsv[4]; uint8_t sdann_val = rt_pack->sdann; uint8_t rmssd_val = rt_pack->rmssd; uint8_t* rr_interval = rt_pack->rra; send_hart(heart_rate, spo2_val, systolic_pressure, diastolic_pressure); } usart2_rx_complete = 0; } }
在这里按照程序框图,当判断接收到完整的一个数据包时,通过send_hart函数将参数传输出OpenAmp发送函数:
void send_hart(uint32_t heart,uint32_t spo2,uint8_t systolic_pressure,uint8_t diastolic_pressure) { default_mks_params.heart = heart; default_mks_params.spo2 = spo2; default_mks_params.systolic_pressure = systolic_pressure; default_mks_params.diastolic_pressure = diastolic_pressure; OPENAMP_send(&rp_endpoint, &default_mks_params, sizeof(default_mks_params)); }
【实现效果】