|
本帖最后由 ketose 于 2017-11-20 15:26 编辑
两周时间又过去了,今天在这里记录一下这两周所做的事情。上上篇我们已经把硬件全部弄就绪,这两周主要是软件部分。软件部分主要是1、实现LCD的驱动2、实现心跳数据测量
3、实现体温的测量
4、时钟表的实现
我的健康手环显示部分使用Nokia5110,这比较老了,现在已经没有生产了,市面上能看到的基本上都是拆机的。不过使用起来挺简单了。它的主要特点是 1、单芯片 LCD 控制/驱动 2、48 行,84 列输出 3、显示数据 RAM 48*84 位,至于它的使用我这里也不多啰嗦了,有兴趣的朋友可以直接到网上搜索。我这里给出在STM32F103的驱动部分。
- /**
- ******************************************************************************
- * @file lcd5110.c
- * @author sun xiao wu
- * @version V1.0.0
- * @date 2017/11/18
- * @brief NOKIA5110 LCD驱动文件
- ******************************************************************************
- */
- #include "stm32f10x.h"
- #include "LCD5110.h"
- #include "LCDFont.h"
- #include "delay.h"
- LCD_Output_Number lcd_output_number = LCD_write_shu;
- #define uchar unsigned char
- //-------------------------------------------------------------------
- // Nokia5510指令集
- // D7 D6 D5 D4 D3 D2 D1 D0
- // 0 0 1 0 0 PD V H
- // | | |_______1->扩展指令集 0->基本指令集
- // | |___________1->垂直寻址 0->水平寻址
- // |_______________1->低功耗模式 0->正常模式
- //-------------------------------------------------------------------
- // 显示模式
- // D7 D6 D5 D4 D3 D2 D1 D0
- // 0 0 0 0 1 D 0 E
- // | |_______0 0 1 1
- // |_______________0 1 0 1
- // 白屏 正常 全显 反转
- //-------------------------------------------------------------------
- #ifdef HW_SPI
- void LCD_GPIO_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
- RCC_APB2PeriphClockCmd(LCDRCC_CLK|RCC_APB2Periph_SPI1|RCC_APB2Periph_AFIO, ENABLE); //激活GPIOA clock
- GPIO_InitStructure.GPIO_Pin = LCD_RST|LCD_DC|LCD_BGL|LCD_CE; //设置GPIOB0、GPIOB1、GPIOB12
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO速度为10MHZ
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置以上三个GPIO为输出
- GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);
- /*硬件SPI*/
- GPIO_InitStructure.GPIO_Pin = LCD_CLK|LCD_MOSI;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);
- //将以上设置参数写入
- SPI_Cmd(SPI1, DISABLE);
- SPI_StructInit(&SPI_InitStructure);
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CRCPolynomial = 0x07;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
- SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
- SPI_Init(SPI1,&SPI_InitStructure);
-
- SPI_Cmd(SPI1,ENABLE);
- SPI_I2S_SendData(SPI1,0x0);
- }
- #else
- void LCD_GPIO_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(LCDRCC_CLK|RCC_APB2Periph_AFIO, ENABLE); //激活GPIOA clock
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
- GPIO_InitStructure.GPIO_Pin = LCD_RST|LCD_DC|LCD_BGL|LCD_CLK|LCD_MOSI|LCD_CE; //设置GPIOB0、GPIOB1、GPIOB12
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; //设置GPIO速度为10MHZ
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置以上三个GPIO为输出
- GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);
- }
- #endif
- //---------------------------------------
- //名称: 使用SPI接口写数据到LCD
- //参数:dt:写入的数据 command: 1-数据/0-命令
- //作者:ketose
- //-----------------------------------------
- #ifdef HW_SPI
- void LCD_write_byte(unsigned char dt, unsigned char command)
- {
- SCE_Low;
- if(command)
- DC_DAT;
- else
- DC_CMD;
- SPI_I2S_SendData(SPI1,dt);
- while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
- }
- #else
- void LCD_write_byte(unsigned char dt, unsigned char command)
- {
- SCE_Low;
- if(command)
- DC_DAT;
- else
- DC_CMD;
-
- for(int i=0;i<8;i++)
- {
- if(dt&0x80)
- SDIN_High;
- else
- SDIN_Low;
- dt=dt<<1;
- SCLK_Low;
- SCLK_High;
- SCLK_Low;
- }
- }
- #endif
- //---------------------------------------
- //名称: 5110LCD初始化函数
- //作者:ketose
- //-----------------------------------------
- void LCD_init(void)
- {
- SCE_High;
- LCD_Set;
- HAL_Delay_ms(10);
- SCE_Low;
- HAL_Delay_ms(100);
- LCD_Set;
- HAL_Delay_ms(10);
- LCD_write_byte(0x21,LCD_CMD);//LCD功能设置:芯片活动,水平寻址,使用扩展指令
- LCD_write_byte(0xC8,LCD_CMD);//设置VOP值,室温下的编程范围为3.00-10.68
- //Vlcd=3.06+(VOP)*0.06,本例VOP为0B0101 0000为十进制的80,Vlcd=7.86V
- LCD_write_byte(0X06,LCD_CMD);//温度校正
- LCD_write_byte(0x13,LCD_CMD);//1:48
- LCD_write_byte(0x20,LCD_CMD);//LCD功能设置:芯片活动,水平寻址,使用基本指令
- LCD_write_byte(0x0C,LCD_CMD);//设定显示配置:普通模式
- SCE_High;
- }
- //---------------------------------------
- //名称: 设置坐标函数
- //参数:X:0-83 Y:0-5
- //作者:ketose
- //-----------------------------------------
- void LCD_set_XY(unsigned char X, unsigned char Y)
- {
- LCD_write_byte(0x40 | Y, LCD_CMD);// column
- LCD_write_byte(0x80 | X, LCD_CMD);// row
- SCE_High;
- }
- //---------------------------------------
- //名称: LCD清屏函数
- //作者:ketose
- //-----------------------------------------
- void LCD_clear(void)
- {
- LCD_set_XY(0,0);
- for(int t=0; t<6; t++)
- {
- for(int k=0; k<84; k++)
- {
- LCD_write_byte(0x00,LCD_DAT);
- }
- }
- SCE_High;
- }
- //---------------------------------------
- //名称: 显示英文字符
- //参数:c:显示的字符在font6x8表格中的位置
- //作者:ketose
- //-----------------------------------------
- void LCD_write_char(unsigned char c)
- {
- c -= 32;
- for (int line=0; line<6; line++)
- LCD_write_byte(font6x8[c][line], LCD_DAT);
- }
- //---------------------------------------
- //名称: 英文字符串显示函数
- //参数:*s:英文字符串指针 8*8点阵
- //作者:ketose
- //-----------------------------------------
- void LCD_write_String(unsigned char X,unsigned char Y,char *s)
- {
- LCD_set_XY(X,Y);
- while (*s)
- {
- LCD_write_char(*s);
- s++;
- }
- }
- //---------------------------------------
- //名称: 写一个字符到LCD函数(8*16点阵)
- //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
- //作者:ketose
- void LCD_write_shu(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
- {
- LCD_set_XY(row*8, page);// 列,页
- for(int i=0; i<8; i++)
- {
- LCD_write_byte(shuzi[c*16+i],LCD_DAT);
- }
- LCD_set_XY(row*8, page+1);// 列,页
- for(int i=8; i<16; i++)
- {
- LCD_write_byte(shuzi[c*16+i],LCD_DAT);
- }
- SCE_High;
- }
- //---------------------------------------
- //名称: 写一个字符到LCD函数(8*16点阵)
- //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
- //作者:ketose
- void LCD_write_inverse_shu(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
- {
- LCD_set_XY(row*8, page);// 列,页
- for(int i=0; i<8; i++)
- {
- LCD_write_byte(~shuzi[c*16+i],LCD_DAT);
- }
- LCD_set_XY(row*8, page+1);// 列,页
- for(int i=8; i<16; i++)
- {
- LCD_write_byte(~shuzi[c*16+i],LCD_DAT);
- }
- SCE_High;
- }
- //---------------------------------------
- //名称: 写一个字符到LCD函数(12*16点阵)
- //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
- //作者:ketose
- void LCD_write_digital(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
- {
- LCD_set_XY(row*12, page);// 列,页
- for(int i=0; i<12; i++)
- {
- LCD_write_byte(Digital[c*24+i],LCD_DAT);
- }
- LCD_set_XY(row*12, page+1);// 列,页
- for(int i=12; i<24; i++)
- {
- LCD_write_byte(Digital[c*24+i],LCD_DAT);
- }
- SCE_High;
- }
- //---------------------------------------
- //名称: 写一个汉字到LCD函数 16*16
- //参数:x,y:写入汉字的地址 address: 写入汉字在han表格中的位置
- //作者:ketose
- //-----------------------------------------
- void LCD_write_hanzi(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
- {
- LCD_set_XY(row*16, page);// 列,页
- for(int i=0; i<16; i++)
- {
- LCD_write_byte(han[c*2][i],LCD_DAT);[/i]
- }
- LCD_set_XY(row*16, page+1);// 列,页
- for(int i=0; i<16; i++)
- {
- LCD_write_byte(han[c*2+1],LCD_DAT);
- }
- SCE_High;
- }
复制代码
显示部份有了,接下来就是最重要的体温和心跳部分的数据显示了。
体温用的是DS18B20,这个网上的资料也是分析的很透彻。我就不再把其它地方的资料再搬上来了。只接用代码说话吧。
- /**
- ******************************************************************************
- * @file ds18b20.c
- * @author sun xiao wu
- * @version V1.0.0
- * @date 2017/11/09
- * @brief DS18B20温度传感器驱动文件
- ******************************************************************************
- */
-
- #include "ds18b20.h"
- #include "delay.h"
- /**
- * @brief 复位DS18B20.
- * @note 单总线复位,总线主机拉低总线至少480us. 然后释放总线
- * @param[in] none
- * @param[out] none.
- * @retval none
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- void DS18B20_Rst(void)
- {
- DS18B20_IO_OUT(); //SET PA11 OUTPUT
- DS18B20_DQ_OUT=0; //拉低DQ
- HAL_Delay_us(550); //拉低550us
- DS18B20_DQ_OUT=1; //DQ=1
- HAL_Delay_us(15); //15US
- }
- /**
- * @brief 等待DS18B20的回应.
- * @note 在单总线复位后,检测总线上是否有60-240s 的低电平信号.
- * @param[in] none
- * @param[out] none.
- * @retval 返回1:未检测到DS18B20的存在
- * 返回0:存在
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- uint8_t DS18B20_Check(void)
- {
- //重试次数
- u8 retry=0;
-
- DS18B20_IO_IN();//SET PA11 INPUT
- while (DS18B20_DQ_IN && retry<200)
- {
- retry++;
- HAL_Delay_us(1);
- };
- if(retry>=200)
- return 1;
- else
- retry=0;
- while (!DS18B20_DQ_IN && retry<240)
- {
- retry++;
- HAL_Delay_us(1);
- };
- if(retry>=240)
- return 1;
- return 0;
- }
- /**
- * @brief 从DS18B20读取一个bit位.
- *
- * @param[in] none
- * @param[out] none.
- * @retval 返回1,0
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- uint8_t DS18B20_Read_Bit(void) // read one bit
- {
- u8 data;
- DS18B20_IO_OUT();//SET PA11 OUTPUT
- DS18B20_DQ_OUT=0; //r拉低总线
- HAL_Delay_us(2);
- DS18B20_DQ_OUT=1; //释放总线
- HAL_Delay_us(12);
- DS18B20_IO_IN();//SET PA11 INPUT
- if(DS18B20_DQ_IN)
- data=1;
- else
- data=0;
- HAL_Delay_us(50); //时隙持续时间的要求(至少60μs)
- return data;
- }
- /**
- * @brief 从DS18B20读取一个字节.
- *
- * @param[in] none
- * @param[out] none.
- * @retval 返回了个字节数据
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- uint8_t DS18B20_Read_Byte(void) // read one byte
- {
- u8 i,j,dat;
- dat=0;
- for (i=1;i<=8;i++)
- {
- j=DS18B20_Read_Bit();
- dat=(j<<7)|(dat>>1);
- }
- return dat;
- }
- /**
- * @brief 写一个字节到DS18B20.
- *
- * @param[in] dat 要写入的字节
- * @param[out] none.
- * @retval none
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- void DS18B20_Write_Byte(uint8_t dat)
- {
- u8 j;
- u8 testb;
- DS18B20_IO_OUT();//SET PA11 OUTPUT;
- for (j=1;j<=8;j++)
- {
- testb=dat&0x01;
- dat=dat>>1;
- if (testb)
- {
- DS18B20_DQ_OUT=0;// Write 1
- HAL_Delay_us(2);
- DS18B20_DQ_OUT=1;
- HAL_Delay_us(60);
- }
- else
- {
- DS18B20_DQ_OUT=0;// Write 0
- HAL_Delay_us(60);
- DS18B20_DQ_OUT=1;
- HAL_Delay_us(2);
- }
- }
- }
- /**
- * @brief 启动DS18B20进行温度转换.
- *
- * @param[in] none
- * @param[out] none.
- * @retval none
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- void DS18B20_Start(void)// ds1820 start convert
- {
- DS18B20_Rst();
- DS18B20_Check();
- DS18B20_Write_Byte(0xcc);// skip rom
- DS18B20_Write_Byte(0x44);// convert
- }
-
- /**
- * @brief 初始化DS18B20的IO口 DQ 同时检测DS的存在.
- *
- * @param[in] none
- * @param[out] none.
- * @retval 0:不存在
- * 1:存在
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- uint8_t DS18B20_Init(void)
- {
- GPIO_InitTypeDef gpio_1;
- //RCC->APB2ENR|=1<<8; //使能PORTG口时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
-
- // GPIOA->CRH&=0XFFFF0FFF;//PORTA.11 推挽输出
- // GPIOA->CRH|=0X00003000;
- // GPIOA->ODR|=1<<11; //输出1
- gpio_1.GPIO_Mode = GPIO_Mode_Out_PP;
- gpio_1.GPIO_Pin = GPIO_Pin_11;
- gpio_1.GPIO_Speed = GPIO_Speed_2MHz;
-
- GPIO_Init(GPIOA,&gpio_1);
- GPIO_SetBits(GPIOA,GPIO_Pin_11);
-
- DS18B20_Rst();
- return DS18B20_Check();
- }
- /**
- * @brief 从ds18b20得到温度值.
- * @note 精度:0.1C
- * @param[in] none
- * @param[out] none.
- * @retval 温度值 (-550~1250)
- * @par 标识符
- * 保留
- * @par 其它
- * 无
- * @par 修改日志
- * sun xiao wu于2017-11-01创建
- */
- float DS18B20_Get_Temp(void)
- {
- uint8_t temp;
- uint8_t TL,TH;
- short tem;
- float result;
- DS18B20_Start (); // ds1820 start convert
- DS18B20_Rst();
- DS18B20_Check();
- DS18B20_Write_Byte(0xcc);// skip rom
- DS18B20_Write_Byte(0xbe);// convert
- HAL_Delay_ms(750);
- TL=DS18B20_Read_Byte(); // LSB
- TH=DS18B20_Read_Byte(); // MSB
-
- if(TH>7)
- {
- TH=~TH;
- TL=~TL;
- temp=0;//温度为负
- }else temp=1;//温度为正
- tem=TH; //获得高八位
- tem<<=8;
- tem+=TL;//获得底八位
- result=(float)tem*0.0625;//转换
- if(temp)
- return result; //返回温度值
- else
- return -result;
- }
- /**************************************************************************************
- * 名 称: adjust_res
- * 功 能: 调整分辨率
- * 参 数: 分辨率值
- * 返 回 值: 无
- **************************************************************************************/
-
- void adjust_res(unsigned char res) ///res 分别等于 0x1f, 0x3f, 0x5f,0x7f温度读数分辨率分别对应 0.5, 0.25, 0.125,0.0625
- {
- DS18B20_Rst(); //复位
- DS18B20_Write_Byte(0xcc); //跳过Rom
- DS18B20_Write_Byte(0x4e); //写暂存器
- DS18B20_Write_Byte(0x02); //写TH
- DS18B20_Write_Byte(0x01); //写TL
- DS18B20_Write_Byte(res); //写结构寄存器
- DS18B20_Rst(); //复位
- DS18B20_Write_Byte(0xcc); //跳过Rom
- DS18B20_Write_Byte(0x48); //把暂存器内容写到EPRam中
- }
复制代码
接下来的部分就是心率的测量了,这部分看了SON1303的资料,觉得可以用外部中断上升沿下降沿和定时器可以解决问题,可是以测试的时候发现外部中断很不稳定,心跳有抖动。没办法用外部中断,所以想了个笨的办法,直接测高低电平的时间,这样即便是在高电平上有点小的抖动,也能很好的去抖动。代码了做了详细的注释,大这看就能看明白。- /**
- ******************************************************************************
- * @file son1303.c
- * @author sun xiao wu
- * @version V1.0.0
- * @date 2017/11/16
- * @brief 心率传感器son1303驱动文件
- ******************************************************************************
- */
-
- #include "son1303.h"
- HEARTRATE Hreat; //心率
- uint32_t risingTimes = 0; //高电平持续时间 ms
- uint32_t fallingTimes = 0; //低电平持续时间 ms
- /**
- @brief: SON1303的GPIO初始化,PB3开启心跳仪,PB4心跳输入
- @param: None
- @return: None
- */
- void SON1303_GPIO_init(void)
- {
- GPIO_InitTypeDef gpio_t;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
- gpio_t.GPIO_Pin = GPIO_Pin_3;
- gpio_t.GPIO_Mode = GPIO_Mode_Out_PP;
- gpio_t.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOB,&gpio_t);
- GPIO_ResetBits(GPIOB,GPIO_Pin_3);
- gpio_t.GPIO_Pin = GPIO_Pin_4;
- gpio_t.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- gpio_t.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOB,&gpio_t);
- }
- /**
- @brief: SON1303传感器初始化,PB4心跳输入
- @param: None
- @return: None
- */
- void SON1303_init(void)
- {
- NVIC_InitTypeDef nvic_1;
- TIM_TimeBaseInitTypeDef tim_t;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
- /*心跳计时 TIM3 1000Hz 1ms*/
- TIM_TimeBaseStructInit(&tim_t);
- tim_t.TIM_CounterMode = TIM_CounterMode_Up;
- tim_t.TIM_Period = 2000-1;
- tim_t.TIM_ClockDivision = TIM_CKD_DIV1;
- tim_t.TIM_Prescaler = 35;
- TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
- TIM_TimeBaseInit(TIM3,&tim_t);
- nvic_1.NVIC_IRQChannel = TIM3_IRQn;
- nvic_1.NVIC_IRQChannelPreemptionPriority = 0;
- nvic_1.NVIC_IRQChannelSubPriority = 1;
- nvic_1.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&nvic_1);
- }
- /**
- @brief: 启动 SON1303传感器
- @param: None
- @return: None
- */
- void SON1303_start(void)
- {
- GPIO_SetBits(GPIOB,GPIO_Pin_3);
- TIM_Cmd(TIM3,ENABLE);
- }
- /**
- @brief: 停止 SON1303传感器
- @param: None
- @return: None
- */
- void SON1303_stop(void)
- {
- GPIO_ResetBits(GPIOB,GPIO_Pin_3);
- TIM_Cmd(TIM3,DISABLE);
- }
- /**
- @brief: 计算心率
- @param: None
- @return: 心率
- */
- uint32_t CalcHeartRate(void)
- {
- uint32_t result = 0;
- uint32_t avg = 0;
- if(Hreat.TestStable)
- {
- avg = TESTCOUNT;
- int maxHeart = 0;
- int minHeart = 0;
- for(int i=0; i<avg; i++)
- {
- maxHeart = maxHeart > Hreat.HeartRate[i] ? maxHeart : Hreat.HeartRate;[/i]
- minHeart = minHeart < Hreat.HeartRate ? minHeart : Hreat.HeartRate;
- result += Hreat.HeartRate;
- }
- result = result - maxHeart - minHeart;
- avg = TESTCOUNT - 2;
- }
- else
- {
- avg = Hreat.TestTimes;
- for(int i=0; i<avg; i++)
- result += Hreat.HeartRate;
- }
- result = result / avg;
- return result;
- }
- /**
- @brief: 配置PA2为ADC,检测是否配带,PA2
- @param: None
- @return: None
- */
- void SON1303_ADC_init()
- {
- GPIO_InitTypeDef gpio_t;
- ADC_InitTypeDef adc_t;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);
- gpio_t.GPIO_Pin = GPIO_Pin_2;
- gpio_t.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init(GPIOA,&gpio_t);
- ADC_DeInit(ADC1);
- adc_t.ADC_Mode = ADC_Mode_Independent;
- adc_t.ADC_ScanConvMode = DISABLE;
- adc_t.ADC_ContinuousConvMode = DISABLE;
- adc_t.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
- adc_t.ADC_DataAlign = ADC_DataAlign_Right;
- adc_t.ADC_NbrOfChannel = 1;
- ADC_Init(ADC1,&adc_t);
- ADC_Cmd(ADC1,ENABLE);
- ADC_RegularChannelConfig(ADC1,ADC_Channel_2,1,ADC_SampleTime_239Cycles5);
- ADC_ResetCalibration(ADC1);
- while(ADC_GetResetCalibrationStatus(ADC1));
- ADC_StartCalibration(ADC1);
- while(ADC_GetCalibrationStatus(ADC1));
- }
- /**
- @brief: 检测是否配带
- @param: None
- @return: 配带返回true
- */
- bool IsWeared(void)
- {
- ADC_SoftwareStartConvCmd(ADC1,ENABLE);
- while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
- uint32_t adValue = ADC_GetConversionValue(ADC1);
- return (adValue<0xD20);
- }
- void TIM3_IRQHandler(void)
- {
- /*PB4 心跳输入*/
- static uint8_t last_status = 0;
- if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
- {
- if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4) == Bit_SET)
- {
- /*上次状态是0,证明心跳了一次*/
- if(last_status == 0)
- {
- uint32_t sumTimes = risingTimes + fallingTimes;//心跳一次的总时间
- uint32_t tmp = 60000 / sumTimes; //一分钟是60000ms
- /**/
- if(tmp > 50 && tmp < 200)
- {
- if(Hreat.TestTimes >=TESTCOUNT)
- {
- Hreat.TestTimes = 0;
- }
- Hreat.HeartRate[Hreat.TestTimes] = tmp;
- Hreat.TestTimes++;
- }
- risingTimes = 0;
- }
- last_status = 1;
- risingTimes++;//增加高电平的时间
- }
- else
- {
- if(last_status == 1)
- fallingTimes = 0;
- last_status = 0;
- fallingTimes++;//增加低电平的时间
- }
- TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
- }
- }
复制代码
接下来就是主程序文件。这个逻辑就简单很多。
- /**
- ******************************************************************************
- * @file mainc.c
- * @author sun xiao wu
- * @version V1.0.0
- * @date 2017/11/06
- * @brief 穿戴数据终端主程序文件
- ******************************************************************************
- */
-
- #include "stm32f10x.h" // Device header
- #include "LCD5110.h"
- #include "ds18b20.h"
- #include "son1303.h"
- #include "delay.h"
- #include "rtc.h"
- #include "key.h"
- #include <stdio.h>
- #include <time.h>
- void Clock_Init(void);
- char printBuffer[16];
- extern LCD_Output_Number lcd_output_number;
- extern bool Key_Mode_Press;
- extern bool Key_Back_Press;
- extern bool Key_Up_Press;
- extern bool Key_Down_Press;
- extern enum KeySelect KeyValue;
- extern uint32_t LedDelay;
- extern bool bShowHeart; //显示心跳和体温标记
- int ShowStatus=0;
- void GPIO_Configuration(void);
- void Show_time(void);
- void Show_Temperature(void);
- void Show_HeartRate(void);
- void Show_Logo(void);
- void Show_Power(void);
- int main()
- {
- //时钟初始化
- Clock_Init();
- GPIO_Configuration();
- RTC_init();
- //延时初始化
- HAL_Delay_Init();
- //DS18B20初始化
- DS18B20_Init();
- //心率传感器初始化
- SON1303_init();
- SON1303_ADC_init();
- //Nokia5110初始化
- LCD_init();
- LCD_clear();
-
- KEY_GPIO_init();
- KEY_NVIC_init();
- SON1303_start();
-
- for(;;)
- {
- //交替显示心跳和体温
- if(bShowHeart)
- {
- if(ShowStatus == 1)
- {
- /*如果是从显示体温界面转过来,则进行清屏,防止脱影*/
- LCD_clear();
- }
- Show_HeartRate();
- ShowStatus = 0;
- }
- else
- {
- if(ShowStatus == 0)
- {
- /*如果是从显示心跳界面转过来,则进行清屏,防止脱影*/
- LCD_clear();
- }
- Show_Temperature();
- ShowStatus = 1;
- }
- //显示EEWORLD DIY
- Show_Logo();
- //显示电量
- Show_Power();
- //显示时间
- Show_time();
- HAL_Delay_ms(200);
- }
- }
- /**
- @brief: stm32芯片时钟初始化
- @param: None
- @return: None
- */
- void Clock_Init(void)
- {
- // RCC_DeInit();
- // /* Enable HSE */
- // RCC_HSEConfig(RCC_HSE_ON);
- // /* Wait till HSE is ready and if Time out is reached exit */
- // while(!RCC_WaitForHSEStartUp());
- // /* Configure HCLK such as HCLK = SYSCLK */
- // RCC_HCLKConfig(RCC_SYSCLK_Div1);
- // /* Configure PCLK1 such as PCLK1 = HCLK/2 */
- // RCC_PCLK1Config(RCC_HCLK_Div2);
- // /* Configure PCLK2 such as PCLK2 = HCLK */
- // RCC_PCLK2Config(RCC_HCLK_Div1);
- //
- // FLASH_SetLatency(FLASH_Latency_2);
- // FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
- //
- // /* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */
- // RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
- // /* Enable the PLL */
- // RCC_PLLCmd(ENABLE);
- // while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
- //
- // /* Select the PLL as system clock source */
- // RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
- // while(RCC_GetSYSCLKSource() != 0x08);
- }
- /**
- @brief: GPIO初始化
- @param: None
- @return: None
- */
- void GPIO_Configuration(void)
- {
- LCD_GPIO_init();
- SON1303_GPIO_init();
- }
- /**
- @brief: 显示时间
- @param: None
- @return: None
- */
- void Show_time(void)
- {
- uint32_t t = RTC_GetCounter();
- struct tm *ptm = localtime(&t);
- if(LedDelay>0)
- BkLED_On;
- else
- BkLED_Off;
- if(Key_Mode_Press)
- {
- switch(KeyValue)
- {
- case Hour:
- lcd_output_number = LCD_write_inverse_shu;
- lcd_output_number(2,4,ptm->tm_hour/10);
- lcd_output_number(3,4,ptm->tm_hour%10);
- lcd_output_number = LCD_write_shu;
- lcd_output_number(4,4,47);
- lcd_output_number(5,4,ptm->tm_min/10);
- lcd_output_number(6,4,ptm->tm_min%10);
- lcd_output_number(7,4,47);
- lcd_output_number(8,4,ptm->tm_sec/10);
- lcd_output_number(9,4,ptm->tm_sec%10);
- break;
- case Minute:
- lcd_output_number(2,4,ptm->tm_hour/10);
- lcd_output_number(3,4,ptm->tm_hour%10);
- lcd_output_number(4,4,47);
- lcd_output_number = LCD_write_inverse_shu;
- lcd_output_number(5,4,ptm->tm_min/10);
- lcd_output_number(6,4,ptm->tm_min%10);
- lcd_output_number = LCD_write_shu;
- lcd_output_number(7,4,47);
- lcd_output_number(8,4,ptm->tm_sec/10);
- lcd_output_number(9,4,ptm->tm_sec%10);
- break;
- case Second:
- lcd_output_number(2,4,ptm->tm_hour/10);
- lcd_output_number(3,4,ptm->tm_hour%10);
- lcd_output_number(4,4,47);
- lcd_output_number(5,4,ptm->tm_min/10);
- lcd_output_number(6,4,ptm->tm_min%10);
- lcd_output_number(7,4,47);
- lcd_output_number = LCD_write_inverse_shu;
- lcd_output_number(8,4,ptm->tm_sec/10);
- lcd_output_number(9,4,ptm->tm_sec%10);
- lcd_output_number = LCD_write_shu;
- break;
- }
- }
- else
- {
- LCD_write_shu(2,4,ptm->tm_hour/10);
- LCD_write_shu(3,4,ptm->tm_hour%10);
- LCD_write_shu(4,4,47);
- LCD_write_shu(5,4,ptm->tm_min/10);
- LCD_write_shu(6,4,ptm->tm_min%10);
- LCD_write_shu(7,4,47);
- LCD_write_shu(8,4,ptm->tm_sec/10);
- LCD_write_shu(9,4,ptm->tm_sec%10);
- }
- //LCD_write_hanzi(0,4,0);
- }
- /**
- @brief: 显示温度
- @param: None
- @return: None
- */
- void Show_Temperature(void)
- {
- int temperature = (int)DS18B20_Get_Temp();
-
- LCD_write_hanzi(4,2,8);
- int x = temperature / 10;
- LCD_write_digital(2,2,x);
- x = temperature % 10;
- LCD_write_digital(3,2,x);
- }
- /**
- @brief: 显示心率
- @param: None
- @return: None
- */
- void Show_HeartRate(void)
- {
- uint32_t hr = CalcHeartRate();
- LCD_write_hanzi(0,2,11);
- int x = hr / 100;
- LCD_write_digital(2,2,x);
- x = (hr % 100) / 10;
- LCD_write_digital(3,2,x);
- x = hr % 10;
- LCD_write_digital(4,2,x);
- }
- /**
- @brief: 显示LOGO
- @param: None
- @return: None
- */
- void Show_Logo(void)
- {
- LCD_write_String(0,0,"EEWORLD DIY");
- }
- /**
- @brief: 显示电量
- @param: None
- @return: None
- */
- void Show_Power(void)
- {
- //LCD_write_shu(0,1,48);
- }
复制代码
按键部分,延时部分,RTC时间的代码我就不贴了,贴出来太多了。如果有人需要跟贴,我就把它们也贴出来。
还有一部分工作没有完成,就是电量显示,和低功耗部分。这部分在后面会慢慢实现。
先看下目前完成的情况。
操作视频:
如果打不开,可以直接用这个地址看:http://v.youku.com/v_show/id_XMzE2OTQxNDg2OA==.html
这两天不知道怎么的,手上起了很多水泡,网上查了下是汗泡疹。大家有没有什么好的治疗办法分享一下,手上很多泡实在是很痒。
此内容由EEWORLD论坛网友ketose原创,如需转载或用于商业用途需征得作者同意并注明出处
|
赞赏
-
1
查看全部赞赏
-
|