RISC-V MCU+病房系统
RISC-V MCU+病房系统报告书
团队名称: 一模一样
团队成员:李玉锋、李树燊、欧平源
目录
摘要
一、设计概述
1.1设计目的
1.2应用领域
1.3主要技术特点
1.4主要创新点
二、系统组成及设计方法
2.1整体介绍
2.2硬件及其各模块的介绍
2.2.1 CH32V307VCT6主控板
2.2.2 MAX30102心率传感器模块
2.2.3 LMT170体温传感器模块
三、完成情况及实验结果
四、总结
五、参考文献
六、附录
6.1主函数main.c程序
6.2 LED.c
6.3 AHT-10.c
6.4 IIC.c
6.2程序流程框图
摘要
随着可穿戴医疗设备被越来越多地应用于生命体征监测,医疗机构也迅速注意到了便携医疗设备和可穿戴医疗设备在预防疾病、助诊、术后恢复、膳食调理等方面展现出的重大价值,因此智慧病房项目逐步在医院、康复中心迅速展开……
一、设计概述
1.1设计目的
为满足现代医疗需求,为医院设计一个快便携的智慧病房终端,能测量病人体温的同时,可以检测病人的心率,同时采集该病房的实时温湿度并显示处理,方便医护人员巡查病房时更快的完成数据采集减少工作负担,更及时的上报。
1.2应用领域
在医院、诊所、急救中心,让医护人员能快速诊察发热症状病人的体征状态及温度,以及住院病房日常巡查的数据测量采集。
1.3主要技术特点
主控采用了CH32V307VCT6国产高速微处理器,心率采集使用MAX30102,体温测量使用了医用级LMT70体温测量芯片,以及环境传感器采用AHT-10进行采集环境实时温度,这类模块具有尺寸小,测量时间段,体积小。
1.4主要创新点
与传统病房的一些监护测量仪器,该系统拥有便携性,可携带外出使用,也能在病房使用,具有快速诊察病人生命基础的体征,如测量体温,不再需要夹着水银体温针等待,只需要夹在病人腋窝里即可实时测得当前病人的体温,心率测量只需将脉搏压在传感器几秒即可显示心率,无需安装繁重的仪器即可快速采集测量。让医生护士在不接触患者和操作设备的情况下,精准监测患者身体状态,帮助医护人员第一时间发现患者的病情变化,实现生命体征异常风险预警,也为医生诊治患者提供科学的数据支撑,极大地减轻了医护工作者的工作强度,提高了工作效率。
二、系统组成及设计方法
2.1整体介绍
本系统主要由CH32V307VCT6核心板、AHT-10温湿度传感器模块、MAX30102心率传感器模块、LMT70体温传感器模块构成。通过CH32V307VCT6芯片驱动AHT-10温湿度传感器模块、MAX30102心率传感器模块、LMT70体温传感器模块,由AHT-10温湿度传感器模块、MAX30102心率传感器模块、LMT70体温传感器模块这三个模块回传各自所测得的数据到CH32V307VCT6芯片,再通过LCD屏实时显示各个模块所回传的数据。系统框图如2-1图所示。
2-1系统整体框图
2.2硬件及其各模块的介绍
2.2.1 CH32V307VCT6主控板
CH32V307VCT6的引脚原理图
2.2.2 MAX30102心率传感器模块
Maxim MAX30102传感器是一款集成脉搏血氧仪和心率监测器模块。MAX30102是一个集成的脉搏血氧仪和心率检测仪生物传感器模块。它集成了一个红光LED和一个红外光LED,光电检测器,以及带环境光抑制的低噪声电子电路。
MAX30102采用PPG光电容积脉搏波描记法(PhotoPlethysmoGraphy)测量数据,微控制器对这些数据进行处理运算过后得到心率血氧数值,再通过I2C或UART接口输出,大大降低了传感器的使用难度和对主控的资源占用。同时该传感器还配备有对应的上位机,可通过电脑直接读取数据。可应用穿戴设备、辅助医疗设备。MAX30102心率传感器如2-3图所示。
特性:搭载集成算法的微控制器、可通过电脑上位机直接读取数据。
参数:
● 供电电压:3.3-5V
● 工作电流:<15mA
● 通讯方式:I2C/UART
● I2C地址:0x57
● 串口波特率:9600
● 工作温度范围:-40℃~85℃
● 产品尺寸:25.5*32mm
图2-3 MAX30102心率传感器
2.2.3 LMT170体温传感器模块
LMT70 模块是采用德州仪器(TI)的 LMT70 芯片设计的,其模拟输出温度传感器,LMT70 是一款带有输出使能引脚的超小型、高精度、低功耗互补金属氧化物半导体 (CMOS) 模拟温度传感器。LMT70几乎适用于所有高精度、低功耗的经济高效型温度感测应用,例如物联网 (IoT) 传感器节点、医疗温度计、高精度仪器仪表和电池供电设备。 LMT70 也是RTD 和高精度 NTC/PTC 热敏电阻的理想替代产品。LMT70具有出色的温度匹配性能,同一卷带中取出的相邻两个 LMT70 的温度最多相差 0.1°C。因此,对于需要计算热量传递的能量计量应用而言,LMT70是一套理想的解决方案。可以用来测试人体表面体温,例如手被,额头等,实施监测人体体温。LMT70体温传感器如2-4图所示。
特性:功耗低,测量的温度精度高。
参数:
● 电压:2.0V~5.5V (推荐 3.3V)
● 通信方式:采用模拟量输出
图2-4 LMT70体温传感器
三、完成情况及实验结果
本系统经过实际测试,可以正常运行,并能通过核心板上的按键发送指令到MAX30102心率模块测量出当前的人体心率和血氧浓度,显示屏显示返回所测的数据,实时显示出当前的人体心率和血氧浓度,还可以实时测量显示房间温湿度和按键控制房间灯等功能。实验结果如3-1图所示。
图3-1 实验结果图
四、总结
经过多天的团队奋斗,最终成功完成本系统的主要功能,并且使系统正常运转。在制作过程中,遇到了许多问题,困扰我们团队许久,但最后还是通过查阅资料,团队共同讨论,把这些问题都给一一攻破。列举遇到的几个问题,第一个,就是串口数据收发问题,我们预想是通过一个串口发送指令到传感器模块,然后传感器模块接收到指令后采集数据,并把采集到的数据返回到芯片并通过LCD显示出来。但发现单独的一个串口不能实现我们想要的功能,最后,采用两个串口,指令通过串口3发到传感器,传感器采集数据,并返回数据,然后把数据透传给串口1返回到芯片。第二个,按键中断,我们发现用了按键中断函数,LCD显示屏就卡死,因为是通过按键发送指令到传感器,指令发送都是采用while循环的方式发送,判断没有接收到数据就会一直循环等待。后面我们换了一种方式,采用DMA,就能正常,LCD和按键之间就不冲突。
五、参考文献
[1]CH32V307EVT 应用例程
[2]MK_LMT70模块使用说明书.pdf
[3]MAX30102芯片资料.pdf
[4]CH32F20xDS0.PDF
[5]CH32FV2x_V3xRM.PDF
[6]SCH_openCH_CH32V307_Board.pdf
六、附录
6.1主函数main.c程序
/**@Note*/#include "debug.h"
#include "AHT_10.h"
#include "lcd.h"
#include "LED.h"u16 TxBuf[1024];
s16 Calibrattion_Val = 0;/* Global define */
#define RXBUF_SIZE 1024 // DMA buffer size
#define size(a) (sizeof(a) / sizeof(*(a)))#define up 1
#define down 2
#define left 3
#define right 4
#define sel 5
#define sw1 6
#define sw2 7/* Global Variable */
u8 TxBuffer[] = " ";
u8 RxBuffer[RXBUF_SIZE]={0};
/* Global Variable *///初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3
void Adc_Init(void)
{ADC_InitTypeDef ADC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M//PA1 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1ADC_ResetCalibration(ADC1); //使能复位校准while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束ADC_StartCalibration(ADC1); //开启AD校准while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{//设置指定ADC的规则组通道,一个序列,采样时间ADC_RegularChannelConfig(ADC1,ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}u16 Get_Adc_Average(u8 ch,u8 times)
{u32 temp_val=0;u8 t;for(t=0;t<times;t++){temp_val+=Get_Adc(ch);delay_ms(5);}return temp_val/times;
}void GPIO_INIT(){GPIO_InitTypeDef GPIO_InitTypdefStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE,ENABLE);GPIO_InitTypdefStruct.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;GPIO_InitTypdefStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitTypdefStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE, &GPIO_InitTypdefStruct);GPIO_InitTypdefStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitTypdefStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitTypdefStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitTypdefStruct);GPIO_InitTypdefStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_13;GPIO_InitTypdefStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitTypdefStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOD, &GPIO_InitTypdefStruct);
}
/*******************************************************************************
* Function Name : Basic_Key_Handle
* Description : Basic Key Handle
* Input : None
* Return : 0 = no key press
* 1 = key press down
*******************************************************************************/
uint8_t Basic_Key_Handle( void ) //按键函数
{uint8_t keyval = 0;if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_4 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_4 ) ){keyval = sw1;}}else {if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_5 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_5 ) ){keyval = sw2;}}else {if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_1 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_1 ) ){keyval = up;}}else {if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_2 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_2 ) ){keyval = down;}}else {if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_3 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOE, GPIO_Pin_3 ) ){keyval = right;}}else {if( ! GPIO_ReadInputDataBit( GPIOD, GPIO_Pin_6 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOD, GPIO_Pin_6 ) ){keyval = left;}}else {if( ! GPIO_ReadInputDataBit( GPIOD, GPIO_Pin_13 ) ){Delay_Ms(20);if( ! GPIO_ReadInputDataBit( GPIOD, GPIO_Pin_13 ) ){keyval = sel;}}}}}}}}return keyval;
}void USARTx_CFG(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO,ENABLE);//重映射串口3RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_USART3,ENABLE);/* USART2 TX-->A.2 RX-->A.3 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //设置PD8为复用推挽输出GPIO_Init(GPIOD, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置PD9为浮空输入GPIO_Init(GPIOD, &GPIO_InitStructure);USART_InitStructure.USART_BaudRate = 9600; // 波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 数据位 8USART_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位 1USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //使能 RX 和 TXUSART_Init(USART3, &USART_InitStructure);DMA_Cmd(DMA1_Channel3, ENABLE); //开启接收 DMAUSART_Cmd(USART3, ENABLE); //开启USART
}/*******************************************************************************
* Function Name : DMA_INIT
* Description : Configures the DMA.
* 描述 : DMA 初始化
* Input : None
* Return : None
*******************************************************************************/
void DMA_INIT(void)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// TX DMA 初始化DMA_DeInit(DMA1_Channel2);DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DATAR); // DMA 外设基址,需指向对应的外设DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer; // DMA 内存基址,指向发送缓冲区的首地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 方向 : 外设 作为 终点,即 内存 -> 外设DMA_InitStructure.DMA_BufferSize = 0; // 缓冲区大小,即要DMA发送的数据长度,目前没有数据可发DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址自增,禁用DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自增,启用DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据位宽,8位(Byte)DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据位宽,8位(Byte)DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 普通模式,发完结束,不循环发送DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // 优先级最高DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // M2P,禁用M2MDMA_Init(DMA1_Channel2, &DMA_InitStructure);// RX DMA 初始化,环形缓冲区自动接收DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RxBuffer; // 接收缓冲区DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 方向 : 外设 作为 源,即 内存 <- 外设DMA_InitStructure.DMA_BufferSize = RXBUF_SIZE; // 缓冲区长度为 RXBUF_SIZEDMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式,构成环形缓冲区DMA_Init(DMA1_Channel3, &DMA_InitStructure);
}/*******************************************************************************
* Function Name : uartWrite
* Input : char * data data to send 要发送的数据的首地址
* uint16_t num number of data 数据长度
* Return : RESET UART6 busy,failed to send 发送失败
* SET send success 发送成功
*******************************************************************************/
FlagStatus uartWrite(char * data , uint16_t num) //q
{//如上次发送未完成,返回if(DMA_GetCurrDataCounter(DMA1_Channel2) != 0){return RESET;}DMA_ClearFlag(DMA1_FLAG_TC7);DMA_Cmd(DMA1_Channel2, DISABLE ); // 关 DMA 后操作DMA1_Channel2->MADDR = (uint32_t)data; // 发送缓冲区为 dataDMA_SetCurrDataCounter(DMA1_Channel2,num); // 设置缓冲区长度DMA_Cmd(DMA1_Channel2, ENABLE); // 开 DMAreturn SET;
}/*******************************************************************************
* Function Name : uartWriteStr
* Input : char * str string to send
* Return : RESET UART busy,failed to send 发送失败
* SET send success 发送成功
*******************************************************************************/
FlagStatus uartWriteStr(char * str) //1
{uint16_t num = 0;while(str[num])num++; // 计算字符串长度return uartWrite(str,num); //w
}/*******************************************************************************
* Function Name : uartReadreceive
* Description : read some bytes from receive buffer 从接收缓冲区读出一组数据
* Input : char * buffer buffer to storage the data 用来存放读出数据的地址
* uint16_t num number of data to read 要读的字节数
* Return : int number of bytes read 返回实际读出的字节数
*******************************************************************************/
uint16_t rxBufferReadPos = 0; //接收缓冲区读指针
uint32_t uartRead(char * buffer , uint16_t num)
{uint16_t rxBufferEnd = RXBUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3); //计算 DMA 数据尾的位置uint16_t i = 0;if (rxBufferReadPos == rxBufferEnd){// 无数据,返回return 0;}while (rxBufferReadPos!=rxBufferEnd && i < num){buffer[i] = RxBuffer[rxBufferReadPos];i++;rxBufferReadPos++;if(rxBufferReadPos >= RXBUF_SIZE){// 超出缓冲区,回零rxBufferReadPos = 0;}}return i;
}/*******************************************************************************
* Function Name : uartReadByte
* Description : read one byte from UART buffer 从接收缓冲区读出 1 字节数据
* Input : None
* Return : char read data 返回读出的数据(无数据也返回0)
*******************************************************************************/
char uartReadByte()
{char ret;uint16_t rxBufferEnd = RXBUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);if (rxBufferReadPos == rxBufferEnd){// 无数据,返回return 0;}ret = RxBuffer[rxBufferReadPos];rxBufferReadPos++;if(rxBufferReadPos >= RXBUF_SIZE){// 超出缓冲区,回零rxBufferReadPos = 0;}return ret;
}
/*******************************************************************************
* Function Name : uartAvailable
* Description : get number of bytes Available to read from the UART buffer 获取缓冲区中可读数据的数量
* Input : None
* Return : uint16_t number of bytes Available to read 返回可读数据数量
*******************************************************************************/
uint16_t uartAvailable()
{uint16_t rxBufferEnd = RXBUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel3);//计算 DMA 数据尾的位置// 计算可读字节if (rxBufferReadPos <= rxBufferEnd){return rxBufferEnd - rxBufferReadPos;}else{return rxBufferEnd +RXBUF_SIZE -rxBufferReadPos;}
}/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Return : None
*******************************************************************************/
int main(void)
{char buffer[1024]={"\0"};float temperature, humidity;//温湿度u16 adcx;float temp;float tem;int num;LED_Init(); //LED初始化Delay_Init(); //延时初始化USART_Printf_Init(9600);//串口初始化lcd_init(); //LCD初始化GPIO_INIT(); //IO初始化lcd_set_color(BLACK,BLUE);lcd_show_string(30, 0, 32,"Ward system");// delay_ms(100);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);printf("SystemClk:%d\r\n",SystemCoreClock);printf("EXTI0 Test\r\n");Adc_Init(); //ADC初始化DMA_INIT();USARTx_CFG(); /* USART INIT */USART_DMACmd(USART3,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE);while(AHT10_Init()) //初始化AHT10{printf("AHT10 Error");lcd_set_color(BLACK,RED);lcd_show_string(180, 176, 16,"Error");Delay_Ms(200);lcd_show_string(180, 176, 16," ");Delay_Ms(200);}lcd_set_color(BLACK,GREEN);lcd_show_string(180, 176, 16,"OK");lcd_set_color(BLACK,GREEN);lcd_show_string(180, 33, 16,"OK");lcd_set_color(BLACK,WHITE);lcd_show_string(0, 33, 16,"Patient's heart rate:");lcd_set_color(BLACK,GREEN);lcd_show_string(180, 66, 16,"OK");lcd_set_color(BLACK,WHITE);lcd_show_string(0, 66, 16,"Patient's blood oxyge:");lcd_set_color(BLACK,GREEN);lcd_show_string(180, 100, 16,"OK");lcd_set_color(BLACK,WHITE);lcd_show_string(0, 100, 16,"Patient's Temperature:");lcd_set_color(BLACK,GREEN);lcd_show_string(180, 137, 16,"OK");lcd_set_color(BLACK,WHITE);lcd_show_string(0, 137, 16,"Room LED:");lcd_set_color(BLACK,BLUE);lcd_show_string(0, 155, 16,"LED1:");lcd_set_color(BLACK,BLUE);lcd_show_string(100, 155, 16,"LED2:");while(1){temperature = AHT10_Read_Temperature(); //把返回的数据赋值给temperaturehumidity = AHT10_Read_Humidity(); //把返回的数据赋值给humiditylcd_set_color(BLACK,WHITE);lcd_show_string(0, 176, 16,"Room Temperature:");lcd_set_color(BLACK,BLUE);lcd_show_string(30, 192, 16,"Temperature : %5d", (int)(temperature));//显示当前病房的温湿度lcd_show_string(30, 208, 16,"Humidity : %5d", (int)(humidity));adcx=Get_Adc_Average(ADC_Channel_1,100);temp=(float)adcx*(3.3/4096)*1000;tem = (-0.0000084515)*temp*temp+(-0.176928)*temp+204.393;// printf("\r\nADC电压为:%s",tem);printf("%.2f\r\n",tem);lcd_show_string(0, 120, 16,"%d" ,(int)tem); //显示当前的体温// lcd_show_string(0, 120, 16,"ADC电压为:%.2f" ,tem);switch (Basic_Key_Handle()){case up: //测心率while(uartWriteStr("AT+HEART\r\n")==RESET); ///2// while(uartAvailable()==0);Delay_Ms(100);num = uartAvailable();if (num > 0 ){uartRead(buffer , num);printf("Revceived:\r\n%s",buffer);lcd_set_color(BLACK,GBLUE);lcd_show_string(0, 50, 16," ");lcd_show_string(0, 50, 16,buffer);}break;case down: //测血氧while(uartWriteStr("AT+SPO2\r\n")==RESET); ///3// while(uartAvailable()==0);Delay_Ms(100);num = uartAvailable();if (num > 0 ){uartRead(buffer , num);printf("Revceived:\r\n%s",buffer);lcd_set_color(BLACK,GBLUE);lcd_show_string(0, 83, 16," ");lcd_show_string(0, 83, 16,buffer);}break;case left: //点亮LEDlcd_set_color(BLACK,BLUE);lcd_show_string(40, 155, 16," ");lcd_show_string(40, 155, 16,"NO");GPIO_ResetBits(GPIOE,GPIO_Pin_11);break;case right:lcd_set_color(BLACK,BLUE);lcd_show_string(140, 155, 16," ");lcd_show_string(140, 155, 16,"ON");GPIO_ResetBits(GPIOE,GPIO_Pin_12);break;case sel:lcd_set_color(BLACK,BLUE);lcd_show_string(40, 155, 16," ");lcd_show_string(140, 155, 16," ");lcd_show_string(40, 155, 16,"OFF");lcd_show_string(140, 155, 16,"OFF");GPIO_SetBits(GPIOE,GPIO_Pin_11|GPIO_Pin_12);break;default:break;}}}
6.2 LED.c
#include "led.h"void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); //使能与LED相关的GPIO端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12; //配置GPIO引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO模式为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO口输出速度
GPIO_Init(GPIOE, &GPIO_InitStructure); //调用库函数,初始化GPIOAGPIO_SetBits(GPIOE,GPIO_Pin_11|GPIO_Pin_12); //设置引脚输出高电平}
6.3 AHT-10.c
#include "debug.h"
#include "AHT_10.h"
#include "IIC.h"/*** @brief 向ATH10写入数据** @param cmd 命令* @param data 要写入的数据* @param len 写入数据大小** @return u8 0,正常,其他,错误代码*/
u8 AHT10_Write_Data(u8 cmd, u8 *data, u8 len)
{u8 i=0;I2C_AcknowledgeConfig( I2C2, ENABLE );// while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET );I2C_GenerateSTART( I2C2, ENABLE );while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );I2C_Send7bitAddress(I2C2,((AHT10_IIC_ADDR << 1) | 0),I2C_Direction_Transmitter); //发送器件地址+写命令while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );I2C_SendData(I2C2,cmd); //写寄存器地址while(i < len){while( I2C_GetFlagStatus( I2C2, I2C_FLAG_TXE ) == RESET )I2C_SendData(I2C2,data[i]); //发送数据i++;}
// while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );while( I2C_GetFlagStatus( I2C2, I2C_FLAG_TXE ) == RESET );I2C_GenerateSTOP( I2C2, ENABLE );return 0;
}/*** @brief 读一个字节** @param void** @return u8 读到的数据*/
u8 AHT10_ReadOneByte(void)
{u8 res = 0;I2C_AcknowledgeConfig( I2C2, ENABLE );// while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET );I2C_GenerateSTART( I2C2, ENABLE );while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );I2C_Send7bitAddress(I2C2,(AHT10_IIC_ADDR << 1) | 0X01,I2C_Direction_Receiver); //发送器件地址+读命令//等待应答while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );//收一个字节数据while( I2C_GetFlagStatus( I2C2, I2C_FLAG_RXNE ) == RESET );res = I2C_ReceiveData( I2C2 );I2C_GenerateSTOP( I2C2, ENABLE ); //产生一个停止条件return res;
}/*** @brief 读数据** @param data 数据缓存* @param len 读数据大小** @return u8 0,正常,其他,错误代码*/
u8 AHT10_Read_Data(u8 *data, u8 len)
{u8 i=0;I2C_AcknowledgeConfig( I2C2, ENABLE );// while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET );I2C_GenerateSTART( I2C2, ENABLE );while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );I2C_Send7bitAddress(I2C2,(AHT10_IIC_ADDR << 1) | 0X01,I2C_Direction_Receiver); //发送器件地址+读命令//等待应答while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );while(i < len){if( I2C_GetFlagStatus( I2C2, I2C_FLAG_RXNE ) != RESET ){if(i == (len - 2)){I2C_AcknowledgeConfig( I2C2, DISABLE );data[i] = I2C_ReceiveData(I2C2); //读数据,发送nACK}else{data[i] = I2C_ReceiveData(I2C2); //读数据,发送ACK}i++;}}I2C_GenerateSTOP( I2C2, ENABLE ); //产生一个停止条件return 0;
}/*** @brief 读取温度数据** @param void** @return float 温度数据(单位:摄氏度)*/
float AHT10_Read_Temperature(void)
{u8 res = 0;u8 cmd[2] = {0x33, 0};u8 temp[6];float cur_temp;res = AHT10_Write_Data(AHT10_GET_DATA, cmd, 2); //发送读取数据命令if(res) return 1;Delay_Ms(80);res = AHT10_Read_Data(temp, 6); //读取数据if(res) return 1;cur_temp = ((temp[3] & 0xf) << 16 | temp[4] << 8 | temp[5]) * 200.0 / (1 << 20) - 50;return cur_temp;
}/*** @brief 读取湿度数据** @param void** @return float 湿度数据(单位:%RH)*/
float AHT10_Read_Humidity(void)
{u8 res = 0;u8 cmd[2] = {0x33, 0};u8 humi[6];float cur_humi;res = AHT10_Write_Data(AHT10_GET_DATA, cmd, 2); //发送读取数据命令if(res) return 1;Delay_Ms(80);res = AHT10_Read_Data(humi, 6); //读取数据if(res) return 1;cur_humi = ((humi[1]) << 12 | humi[2] << 4 | (humi[3] & 0xF0)) * 100.0 / (1 << 20);return cur_humi;
}/*** @brief ATH10传感器初始化** @param void** @return u8 0,初始化成功,其他,失败*/
u8 AHT10_Init(void)
{u8 res;u8 temp[2] = {0, 0};IIC_Init(200000,0x02); //初始化IIC接口:注意这里的IIC总线为:SCL-PB10 SDA-PB11res = AHT10_Write_Data(AHT10_NORMAL_CMD, temp, 2);if(res != 0) return 1;Delay_Ms(300);temp[0] = 0x08;temp[1] = 0x00;res = AHT10_Write_Data(AHT10_CALIBRATION_CMD, temp, 2);if(res != 0) return 1;Delay_Ms(300);return 0;
}
6.4 IIC.c
#include "IIC.h"
#include "debug.h"/*******************************************************************************
* Function Name : IIC_Init
* Description : Initializes the IIC peripheral.
* Input : None
* Return : None
*******************************************************************************/
void IIC_Init( u32 bound , u16 address )
{GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitTSturcture;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE );
// GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C2, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( GPIOB, &GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( GPIOB, &GPIO_InitStructure );I2C_InitTSturcture.I2C_ClockSpeed = bound;I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_16_9;I2C_InitTSturcture.I2C_OwnAddress1 = address;I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Init( I2C2, &I2C_InitTSturcture );I2C_Cmd( I2C2, ENABLE );I2C_AcknowledgeConfig( I2C2, ENABLE );
}
6.5程序流程框图
RISC-V MCU+病房系统相关推荐
- MCU多系统服务器与云平台,MCU多系统服务器与云平台
MCU多系统服务器与云平台 内容精选 换一换 云服务器创建后区域固定,不能将云服务器转移到另一个区域,也不能将云服务器转移到另一个帐号.您可以通过镜像迁移方式实现云服务器的跨帐号跨区域迁移.服务器迁移 ...
- RISC V (RV32+RV64) 架构 整体介绍
文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...
- 计组学习笔记2(RISC v版)
指令集解释 (规定:R[r]表示通用寄存器r的内容,M[addr]表示存储单元addr的内容,SEXT[imm]表示对imm进行符号扩展,ZEXT[imm]表示对imm进行零扩展) 整数运算类 -U型 ...
- 狄耐克漫云智慧病房系统助力医院评级建设
"三级医院要在2020年前实现院内服务信息互通共享"这是2019年新医改提出后,<医院智慧服务分级评估标准体系>规定的一个目标.基于物联网技术的医院智能化建设已迈入跑道 ...
- MCU裸系统下快速平方根实现
很多MCU平台均没有支持完整的数学运算指令,此时如果计算算术平方根就需要利用软件函数库,但是这些库代码一般都会占用不少的ROM空间,当ROM区域特别紧张时可能无法利用现成的库代码,此时就要自己实现一个 ...
- oracle v session表,Oracle技术之V$SESSION_LONGOPS超过系统时间
检查一个系统,意外发现数据库的v$session_longops中时间远远超过了系统时间. 查询结果如下: [oracle@datasd ~]$ sqlplus / as sysdba SQL*Plu ...
- 沁恒CH552G实现最小系统[沁恒8位机MCU最小系统]
转载著名出处. 一.目标: 学习沁恒的8位机最小系统的实现. 最小系统连接方式通用下面所有常规8位MCU 二.资料获取: 1.首先从沁恒官网下载CH552的datasheet: CH552官网手册下载 ...
- 启扬智能床旁交互终端解决方案,建设智慧病房系统
随着国家相关政策的支持以及信息技术的快速发展,我国医疗健康行业信息化正迈向新的发展阶段.大数据.人工智能.云计算.5G等技术赋能医疗领域,医院建设遵循以患者为中心的服务理念,不断提升医疗服务质量与效率 ...
- MCU - 视频会议系统中心控制设备介绍
为了实现多点会议电视系统,必须设置MCU.MCU实质上是一台多媒体信息交换机,进行多点呼叫和连接,实现视频广播.视频选择.音频混合.数据广播等功能,完成各终端信号的汇接与切换.MCU与现行交换机不同之 ...
- 安装Ubuntu RISC V toolchain失败(网速、git配置原因)
git获取大容量工程出错:RPC failed: curl GnuTLS recv error : Decryption has failed. error: RPC failed; curl 56 ...
最新文章
- 解决Linux CENTOS服务器 tree命令出现乱码 解析原因
- linux下svn的用法(转)
- Lync Server 2010标准版系列PART4:部署准备
- Hibernate实现对多个表进行关联查询
- C#里partial关键字的作用
- vim 批量注释代码
- 教你学会七种维护服务器安全最佳技巧
- vue控制元素的隐藏和显示
- java手机状态栏圆形图标,android实现状态栏添加图标的函数实例
- 2017.4.19 多项式输出 思考记录
- 【Flink】Flink UI 查看 subtask在相应的机器上的调度时间
- IE设置自动获得代理(ISA20042006中设置相应项)
- C# winform中 选择文件和保存文件
- 如何在PDF文件中快速查找关键字?
- delphi 各版本的特性
- 英文版软件工程试题模拟试题
- android分辨率选择,安卓Android手机屏幕壁纸分辨率选择技巧
- MMC子系统之SDIO卡驱动
- MVC实现类似QQ的网页聊天功能-ajax(下)
- error LNK1120: 1 个无法解析的外部命令。