这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 第二期-智能手环DIY-显示及心率模块驱动

共1条 1/1 1 跳转至

第二期-智能手环DIY-显示及心率模块驱动

工程师
2025-10-05 13:51:45     打赏

硬件连接如下:

1759640715747343.jpg1759641273322469.png

先来看OLED驱动

OLED是比较常用的器件,网上的驱动程序很多,直接COPY一下,P0_16和P0_17引脚

#include "oled.h"
#include "stdlib.h"
#include "string.h"
#include <stdint.h>
#include "board.h"
#include "mxc_device.h"
#include "i2c.h"

#define SSD1306_ADDR 0x3C // SSD1306 I2C 地址
#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
//OLED显存总共分为4页
//每页8行,一行128个像素点
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127 (0~7)行
//[1]0 1 2 3 ... 127 (8~15)行
//[2]0 1 2 3 ... 127 (16~23)行
//[3]0 1 2 3 ... 127 (24~31)行

//数组每个bit存储OLED每个像素点的颜色值(1-亮(白色),0-灭(黑色))
//每个数组元素表示1列8个像素点,一共128列
uint8_t Flash_OLED_Buffer[1025] = {0};
uint8_t * OLED_buffer = Flash_OLED_Buffer+1 ;

#define I2C_MASTER MXC_I2C1 // SCL P0_16; SDA P0_17
#define I2C_SCL_PIN 16
#define I2C_SDA_PIN 17

#define I2C_FREQ 400000 // 100kHZ
mxc_i2c_req_t reqMaster;  //声明结构体

void i2cm_Init(void)
{
       int error;

        //Setup the I2CM
        error = MXC_I2C_Init(I2C_MASTER, 1, 0);
        if (error != E_NO_ERROR) {
            printf("-->I2C Master Initialization failed, error:%d\n", error);
            return;
        } else {
            printf("\n-->I2C Master Initialization Complete\n");
        }

        printf("-->Scanning started\n");
        MXC_I2C_SetFrequency(I2C_MASTER, I2C_FREQ);

        reqMaster.i2c = I2C_MASTER;
        reqMaster.addr = 0;
        reqMaster.tx_buf = NULL;
        reqMaster.tx_len = 0;
        reqMaster.rx_buf = NULL;
        reqMaster.rx_len = 0;
        reqMaster.restart = 0;
        reqMaster.callback = NULL;

}

/*******************************************************************
 * @name       :void OLED_WR_Byte(unsigned dat,unsigned cmd)
 * @date       :2018-08-27
 * @function   :Write a byte of content to the OLED screen
 * @parameters :dat:Content to be written
                cmd:0-write command
                                    1-write data
 * @retvalue   :None
********************************************************************/
void OLED_WR_Byte(unsigned char dat,unsigned char cmd) {
    unsigned char i2c_tx_buff[2];
    int error;
    if(cmd) {
        i2c_tx_buff[0] = 0x40;
    } else {
        i2c_tx_buff[0] = 0x00;
    }
    i2c_tx_buff[1] = dat;
    reqMaster.tx_buf = i2c_tx_buff;
    reqMaster.addr = SSD1306_ADDR;
    reqMaster.tx_len = 2;
    error = MXC_I2C_MasterTransaction(&reqMaster);
    if (error != E_NO_ERROR) {
        printf("-->I2C send failed, error:%d\n", error);
        return;
    }

}

/*******************************************************************
 * @name       :void OLED_Set_Pos(unsigned char x, unsigned char y)
 * @date       :2018-08-27
 * @function   :Set coordinates in the OLED screen
 * @parameters :x:x coordinates
                y:y coordinates
 * @retvalue   :None
********************************************************************/
void OLED_Set_Pos(unsigned char x, unsigned char y) {
    OLED_WR_Byte(YLevel+y/OLED_PAGE_SIZE,OLED_CMD);
    OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
    OLED_WR_Byte((x&0x0f),OLED_CMD);
}


/*******************************************************************
 * @name       :void OLED_Display_On(void)
 * @date       :2018-08-27
 * @function   :Turn on OLED display
 * @parameters :None
 * @retvalue   :None
********************************************************************/
void OLED_Display_On(void) {
    OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
    OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
    OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}

/*******************************************************************
 * @name       :void OLED_Display_Off(void)
 * @date       :2018-08-27
 * @function   :Turn off OLED display
 * @parameters :None
 * @retvalue   :None
********************************************************************/
void OLED_Display_Off(void) {
    OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
    OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
    OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}


/*******************************************************************
 * @name       :void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)
 * @date       :2018-08-27
 * @function   :set the value of pixel to RAM
 * @parameters :x:the x coordinates of pixel
                y:the y coordinates of pixel
                                color:the color value of the point
                                      1-white
                                            0-black
 * @retvalue   :None
********************************************************************/
void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color) {
    if(color) {
        OLED_buffer[(y/OLED_PAGE_SIZE)*WIDTH+x]|= (1<<(y%OLED_PAGE_SIZE))&0xff;
    } else {
        OLED_buffer[(y/OLED_PAGE_SIZE)*WIDTH+x]&= ~((1<<(y%OLED_PAGE_SIZE))&0xff);
    }
}



/*******************************************************************
 * @name       :void OLED_Display(void)
 * @date       :2018-08-27
 * @function   :Display in OLED screen
 * @parameters :None
 * @retvalue   :None
********************************************************************/
void OLED_Display(void) {

    OLED_WR_Byte(0x21, 0); // 设置列地址
    OLED_WR_Byte(0x00, 0); // 起始列地址
    OLED_WR_Byte(SSD1306_WIDTH - 1, 0); // 结束列地址
    OLED_WR_Byte(0x22, 0); // 设置页地址
    OLED_WR_Byte(0x00, 0); // 起始页地址
    OLED_WR_Byte(OLED_PAGE_SIZE - 1, 0); // 结束页地址
    Flash_OLED_Buffer[0] = 0x40;
    reqMaster.tx_buf = Flash_OLED_Buffer;
    reqMaster.tx_len = 1025;
    reqMaster.addr = SSD1306_ADDR;
    MXC_I2C_MasterTransaction(&reqMaster);

}

/*******************************************************************
 * @name       :void OLED_Clear(unsigned dat)
 * @date       :2018-08-27
 * @function   :clear OLED screen
 * @parameters :dat:0-Display full black
                    1-Display full white
 * @retvalue   :None
********************************************************************/
void OLED_Clear(unsigned char dat) {
    if(dat) {
        memset(OLED_buffer,0xff,SSD1306_WIDTH * OLED_PAGE_SIZE);
    } else {
        memset(OLED_buffer,0,SSD1306_WIDTH * OLED_PAGE_SIZE);
    }
}

void OLED_Init(void) {
//  delay_ms(200);
    i2cm_Init();
///**************初始化SSD1306*****************/
    OLED_WR_Byte(0xAE, 0); // 关闭显示
    OLED_WR_Byte(0x20, 0); // 设置内存寻址模式
    OLED_WR_Byte(0x00, 0); // 水平寻址模式
    OLED_WR_Byte(0xB0, 0); // 设置页地址
    OLED_WR_Byte(0xC8, 0); // 设置扫描方向
    OLED_WR_Byte(0x00, 0); // 设置列地址低 4 位
    OLED_WR_Byte(0x10, 0); // 设置列地址高 4 位
    OLED_WR_Byte(0x40, 0); // 设置显示起始行
    OLED_WR_Byte(0x81, 0); // 设置对比度
    OLED_WR_Byte(0xFF, 0); // 最大对比度
    OLED_WR_Byte(0xA1, 0); // 设置段重映射
    OLED_WR_Byte(0xA6, 0); // 设置正常显示
    OLED_WR_Byte(0xA8, 0); // 设置多路复用率
    OLED_WR_Byte(0x3F, 0); // 1/64 多路复用
    OLED_WR_Byte(0xA4, 0); // 恢复整体显示
    OLED_WR_Byte(0xD3, 0); // 设置显示偏移
    OLED_WR_Byte(0x00, 0); // 无偏移
    OLED_WR_Byte(0xD5, 0); // 设置时钟分频比/振荡器频率
    OLED_WR_Byte(0xF0, 0); // 设置分频比
    OLED_WR_Byte(0xD9, 0); // 设置预充电周期
    OLED_WR_Byte(0x22, 0); // 设置预充电周期
    OLED_WR_Byte(0xDA, 0); // 设置 COM 引脚硬件配置
    OLED_WR_Byte(0x12, 0); // 设置 COM 引脚硬件配置
    OLED_WR_Byte(0xDB, 0); // 设置 VCOMH 取消选择级别
    OLED_WR_Byte(0x20, 0); // 设置 VCOMH 取消选择级别
    OLED_WR_Byte(0x8D, 0); // 设置电荷泵
    OLED_WR_Byte(0x14, 0); // 启用电荷泵
    OLED_WR_Byte(0xAF, 0); // 开启显示
}

MAX30102使用模拟I2C,引脚使用P2_6和P2_7。

#include "max30102.h"
#include "mxc_device.h"
#include "xiic.h"

#include "stdlib.h"
#include "stdio.h"
#include "board.h"
#include "max78000.h"
/*define ---------------------------------------------------------------------*/
#define max30100_WR_address 0x57<<1



void hardIIC_init(void)
{
    IIC_GPIO_INIT();

}

uint8_t max30102_Bus_Write(uint8_t Register_Address, uint8_t Word_Data)
{
    uint8_t data[1];
    data[0] = Word_Data;
    return IIC_Write_Array(max30100_WR_address,Register_Address,data,1);

}



uint8_t max30102_Bus_Read(uint8_t Register_Address)
{
   return IIC_Read_Byte(max30100_WR_address,Register_Address);
}





void max30102_init(void)
{
    hardIIC_init();
    max30102_reset();
    max30102_Bus_Write(REG_INTR_ENABLE_1, 0xc0); // INTR setting
    max30102_Bus_Write(REG_INTR_ENABLE_2, 0x00);
    max30102_Bus_Write(REG_FIFO_WR_PTR, 0x00); // FIFO_WR_PTR[4:0]
    max30102_Bus_Write(REG_OVF_COUNTER, 0x00); // OVF_COUNTER[4:0]
    max30102_Bus_Write(REG_FIFO_RD_PTR, 0x00); // FIFO_RD_PTR[4:0]
    max30102_Bus_Write(REG_FIFO_CONFIG, 0x0f); // sample avg = 1, fifo rollover=false, fifo almost full = 17
    max30102_Bus_Write(REG_MODE_CONFIG, 0x03); // 0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
    max30102_Bus_Write(REG_SPO2_CONFIG, 0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
    max30102_Bus_Write(REG_LED1_PA, 0x24);     // Choose value for ~ 7mA for LED1
    max30102_Bus_Write(REG_LED2_PA, 0x24);     // Choose value for ~ 7mA for LED2
    max30102_Bus_Write(REG_PILOT_PA, 0x7f);    // Choose value for ~ 25mA for Pilot LED
}

void max30102_reset(void)
{
    max30102_Bus_Write(REG_MODE_CONFIG, 0x40);
//    max30102_Bus_Write(REG_MODE_CONFIG, 0x40);
}


void maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)
{
    uint32_t un_temp;
    unsigned char uch_temp;
    unsigned char ach_i2c_data[6];
    *pun_red_led = 0;
    *pun_ir_led = 0;
    // read and clear status register
    max30102_Bus_Read(REG_INTR_STATUS_1);
    max30102_Bus_Read(REG_INTR_STATUS_2);

    IIC_Read_Array(max30100_WR_address,REG_FIFO_DATA,ach_i2c_data,6);
    un_temp = (unsigned char)ach_i2c_data[0];
    un_temp <<= 16;
    *pun_red_led += un_temp;
    un_temp = (unsigned char)ach_i2c_data[1];
    un_temp <<= 8;
    *pun_red_led += un_temp;
    un_temp = (unsigned char)ach_i2c_data[2];
    *pun_red_led += un_temp;
    un_temp = (unsigned char)ach_i2c_data[3];
    un_temp <<= 16;
    *pun_ir_led += un_temp;
    un_temp = (unsigned char)ach_i2c_data[4];
    un_temp <<= 8;
    *pun_ir_led += un_temp;
    un_temp = (unsigned char)ach_i2c_data[5];
    *pun_ir_led += un_temp;
    *pun_red_led &= 0x03FFFF; // Mask MSB [23:18]
    *pun_ir_led &= 0x03FFFF;  // Mask MSB [23:18]
       
        if(*pun_red_led<=10000)
        {
            *pun_red_led = 0;
        }
        if(*pun_ir_led<=10000)
        {
            *pun_ir_led = 0;
        }
}

再来就是心率读取和显示

#include "algorithm.h"
#include "max30102.h"

#include "stdio.h"
#include "gui.h"
#include "oled.h"
#include "blood.h"
#include "math.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

uint16_t g_fft_index = 0;               //fft输入输出下标

struct compx s1[FFT_N+16];              //FFT输入和输出:从S[1]开始存放,根据大小自己定义
struct compx s2[FFT_N+16];              //FFT输入和输出:从S[1]开始存放,根据大小自己定义


static uint16_t sample_index = 0;


struct
{
    float   Hp  ;           //血红蛋白  
    float   HpO2;           //氧合血红蛋白
   
}g_BloodWave;//血液波形数据

BloodData g_blooddata = {0};                    //血液数据存储

#define CORRECTED_VALUE         47              //标定血液氧气含量

// 同步机制
SemaphoreHandle_t xBufferMutex;
TaskHandle_t xDataProcessingHandle; // 新增:保存数据处理任务句柄

// 数据处理函数声明
void process_buffer();

// =============== 数据采集任务 ===============
void vTaskDataCollection(void *pvParameters)
{
    uint32_t fifo_red, fifo_ir;
    int num_samples = 0;
    max30102_reset();
    max30102_init();
    printf("start max30102\n");
     for (;;)
    {
        num_samples = max30102_Bus_Read(REG_OVF_COUNTER)& 0x0F;

        if (num_samples == 0)
        {
            vTaskDelay(50); // 控制采样率
        }
        else
        {
            for(int i = 0; i < num_samples; i++)
            {
                    maxim_max30102_read_fifo(&fifo_red, &fifo_ir);
                    // 写入当前缓冲区
                    s1[sample_index].real = fifo_red;
                    s2[sample_index].real = fifo_ir;
                    s1[sample_index].imag = 0;
                    s2[sample_index].imag = 0;
                    sample_index++;
                    // 缓冲满时切换并通知
                    if (sample_index >= FFT_N)
                    {
                            sample_index = 0;
//                          xTaskNotifyGive(xDataProcessingHandle);
                            process_buffer();
                    }
            }
        }
    }
}

// 数据处理函数 - 适配原有血液信息转换逻辑
void process_buffer()
{
    float n_denom;
        uint16_t i;
        float dc_red =0;
        float dc_ir =0;
        float ac_red =0;
        float ac_ir =0;

        for (i=0 ; i<FFT_N ; i++ )
        {
            dc_red += s1[i].real ;
            dc_ir +=  s2[i].real ;
        }
            dc_red =dc_red/FFT_N ;
            dc_ir =dc_ir/FFT_N ;
        for (i=0 ; i<FFT_N ; i++ )
        {
            s1[i].real =  s1[i].real - dc_red ;
            s2[i].real =  s2[i].real - dc_ir ;
        }

        for(i = 1;i < FFT_N-1;i++)
        {
                n_denom= ( s1[i-1].real + 2*s1[i].real + s1[i+1].real);
                s1[i].real=  n_denom/4.00;

                n_denom= ( s2[i-1].real + 2*s2[i].real + s2[i+1].real);
                s2[i].real=  n_denom/4.00;
        }
        //八点平均滤波
        for(i = 0;i < FFT_N-8;i++)
        {
                n_denom= ( s1[i].real+s1[i+1].real+ s1[i+2].real+ s1[i+3].real+ s1[i+4].real+ s1[i+5].real+ s1[i+6].real+ s1[i+7].real);
                s1[i].real=  n_denom/8.00;

                n_denom= ( s2[i].real+s2[i+1].real+ s2[i+2].real+ s2[i+3].real+ s2[i+4].real+ s2[i+5].real+ s2[i+6].real+ s2[i+7].real);
                s2[i].real=  n_denom/8.00;

                //UsartPrintf(USART_DEBUG,"%f\r\n",s1[i].real);
        }

        g_fft_index = 0;
        FFT(s1);
        FFT(s2);
        //解平方
        //UsartPrintf(USART_DEBUG,"开始FFT算法****************************************************************************************************\r\n");
        for(i = 0;i < FFT_N;i++)
        {
            s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
            s1[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
        }
        //计算交流分量
        for (i=1 ; i<FFT_N ; i++ )
        {
            ac_red += s1[i].real ;
            ac_ir +=  s2[i].real ;
        }

        int s1_max_index = find_max_num_index(s1, 30);
        int s2_max_index = find_max_num_index(s2, 30);

        float Heart_Rate = 60.00 * ((100.0 * s1_max_index )/ 512.00)+20;
        g_blooddata.heart = Heart_Rate;
        float R = (ac_ir*dc_red)/(ac_red*dc_ir);
        float sp02_num =-45.060*R*R+ 30.354 *R + 94.845;
        g_blooddata.SpO2 = sp02_num;
        printf("Heart:%d\r\n",(int)Heart_Rate)  ;
        printf("SpO2:%.2f\r\n",sp02_num);
}

// =============== 初始化函数(需在main中调用) ===============
void Blood_Init(void)
{
    // 创建互斥锁

    xTaskCreate(
        vTaskDataCollection,
        "DataCollection",
        4096,
        NULL, // 直接传递句柄
        tskIDLE_PRIORITY + 1,
        NULL);
}

相关内容整合后在main中调用就可以正常显示结果了

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "board.h"
#include "mxc_device.h"
#include "mxc_delay.h"
#include "nvic_table.h"
#include "i2c.h"
#include "oled.h"
#include "gui.h"
#include "rtc.h"
#include "max30102.h"
#include "blood.h"
/***** Definitions *****/

#define MSEC_TO_RSSA(x) \
    (0 - ((x * 4096) /  \
          1000)) /* Converts a time in milleseconds to the equivalent RSSA register value. */

#define SECS_PER_MIN 60
#define SECS_PER_HR (60 * SECS_PER_MIN)
#define SECS_PER_DAY (24 * SECS_PER_HR)


TaskHandle_t xTask1Handle = NULL;
extern BloodData g_blooddata ;
/* 任务函数声明 */
void vTask1(void *pvParameters);

// 判断是否为闰年
int isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
// 获取指定年份中每个月的天数
void getDaysInMonth(int year, int daysInMonth[]) {
    daysInMonth[0] = 0;  // 不使用索引0
    daysInMonth[1] = 31;
    daysInMonth[2] = isLeapYear(year) ? 29 : 28;  // 闰年2月29天
    daysInMonth[3] = 31;
    daysInMonth[4] = 30;
    daysInMonth[5] = 31;
    daysInMonth[6] = 30;
    daysInMonth[7] = 31;
    daysInMonth[8] = 31;
    daysInMonth[9] = 30;
    daysInMonth[10] = 31;
    daysInMonth[11] = 30;
    daysInMonth[12] = 31;
}

// 将从2000年1月1日起的时间戳转换为日期时间
void timestampToDateTime(long timestamp, int *year, int *month, int *day, int *hour, int *minute, int *second) {
    long sec = timestamp;

    // 计算时、分、秒(已有代码)
    // 计算天数(从2000年1月1日起)
    long dayCount = sec / SECS_PER_DAY;
    sec -= dayCount * SECS_PER_DAY;  // 剩余秒数用于计算时、分、秒

    // 计算时、分、秒
    *hour = sec / SECS_PER_HR;
    sec -= *hour * SECS_PER_HR;

    *minute = sec / SECS_PER_MIN;
    sec -= *minute * SECS_PER_MIN;

    *second = sec;

    // 计算天数(从2000年1月1日起)


    // 计算年份
    *year = 2000;
    while (1) {
        int daysInYear = isLeapYear(*year) ? 366 : 365;
        if (dayCount < daysInYear) break;
        dayCount -= daysInYear;
        (*year)++;
    }

    // 计算月份和日期
    int daysInMonth[13];
    getDaysInMonth(*year, daysInMonth);

    *month = 1;
    while (*month <= 12) {
        if (dayCount < daysInMonth[*month]) break;
        dayCount -= daysInMonth[*month];
        (*month)++;
    }

    *day = (int)dayCount + 1;  // +1是因为天数从0开始计数,而日期从1开始
}
// 计算从2000年1月1日起的天数
int daysSince2000(int year, int month, int day) {
    int days = 0;
    int i;

    // 计算完整年份的天数
    for (i = 2000; i < year; i++) {
        days += isLeapYear(i) ? 366 : 365;
    }

    // 计算当年到目标月份的天数
    int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (isLeapYear(year)) {
        daysInMonth[2] = 29;  // 闰年2月29天
    }

    for (i = 1; i < month; i++) {
        days += daysInMonth[i];
    }

    // 加上当月的天数
    days += day;

    return days;
}

void printTime(void)
{

    int year, month, day, hour, minute, second,err;
    uint32_t rtc_readout;
    uint8_t buff[24];
    do {
        err = MXC_RTC_GetSeconds(&rtc_readout);
    } while (err != E_NO_ERROR);

    // 转换时间戳为日期时间
        timestampToDateTime(rtc_readout, &year, &month, &day, &hour, &minute, &second);

        printf("timestamp %ld datetime: %04d-%02d-%02d %02d:%02d:%02d\n",
                rtc_readout, year, month, day, hour, minute, second);
        sprintf(buff, "%02d:%02d:%02d",hour, minute, second);
        OLED_Clear(0);
        GUI_ShowString(16,0,buff,16,0);
        sprintf(buff, "HpO2:%.2f", g_blooddata.SpO2);
        GUI_ShowString(16,16,buff,16,0);
        sprintf(buff, "Hear::%d", (int)g_blooddata.heart);
        GUI_ShowString(16,32,buff,16,0);
        OLED_Display();
}

/* 任务1的实现 */
void vTask1(void *pvParameters)
{
    OLED_Clear(0);
    GUI_ShowString(0,0,(uint8_t *)"OLED show",16,0);
    OLED_Display();
    Blood_Init();
    /* 任务循环 */
    for(;;)
    {
        /* 任务要执行的代码 */
        LED_On(LED1);
        /* 延时一段时间 */
        printTime();
        vTaskDelay(pdMS_TO_TICKS(1000)); /* 延时1秒 */
        LED_Off(LED1);
        vTaskDelay(pdMS_TO_TICKS(1000)); /* 延时1秒 */
    }

    /* 注意:任务函数不应该返回,如果返回则必须调用vTaskDelete(NULL) */
    vTaskDelete(NULL);
}



void show_task(void *pvParameters) ;
// *****************************************************************************
int main(void)
{
    printf("start...!\n");
    OLED_Init();
    // 目标日期:2025年10月05日16:07:00
        int year = 2025;
        int month = 10;
        int day = 5;
        int hour = 16;
        int minute = 7;
        int second = 0;

        // 计算从2000年1月1日起的总秒数
        int totalDays = daysSince2000(year, month, day);
        long timestamp = (long)totalDays * SECS_PER_DAY +
                        hour * SECS_PER_HR +
                        minute * SECS_PER_MIN +
                        second;

        printf("从2000年1月1日00:00:00到%04d-%02d-%02d %02d:%02d:%02d的时间戳为: %ld\n",
               year, month, day, hour, minute, second, timestamp);

    if (MXC_RTC_Init(timestamp, 0) != E_NO_ERROR) {
            printf("Failed RTC Initialization\n");
            printf("Example Failed\n");

            while (1) {}
        }
    if (MXC_RTC_Start() != E_NO_ERROR) {
            printf("Failed RTC_Start\n");
            printf("Example Failed\n");

            while (1) {}
        }

        printf("RTC started\n");
    xTaskCreate(
                vTask1,                   /* 任务函数 */
                "Task1",                  /* 任务名称 */
                2048, /* 栈大小 */
                NULL,                     /* 传递给任务函数的参数 */
                1,                        /* 任务优先级 */
                &xTask1Handle             /* 任务句柄 */
            );
    /* 启动调度器 */
    printf("start scheduler...!\n");

    vTaskStartScheduler();
    printf("ERROR: FreeRTOS did not start due to above error!\n");
    while (1) {
        LED_On(LED1);
        MXC_Delay(500000);
        LED_Off(LED1);
        MXC_Delay(500000);
    }
    return 0;
}

//OLED显示任务函数
void show_task(void *pvParameters)
{
        char buff[40];
        OLED_Init();
        OLED_Clear(0);
        GUI_ShowString(0,0,(uint8_t *)"OLED show",16,0);
        OLED_Display();
    while(1)
    {
        printf("start show\n");
            vTaskDelay(600);
    }
}

最终显示效果如下:

1759641370807830.jpg1759641371492858.jpg

TIPS:

所有的程序官方的老师已经都分享出来了,跟着学习就一定可以成功。如果程序看不懂,可以直接在VSCODE进行询问,让他帮忙加加注释。AI真是太方便了

1759643423983797.png






关键词: DIY     手环     MAX78000     MAX30102    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]