这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【Mini-F5265-OB】3、OLED时钟

共7条 1/1 1 跳转至

【Mini-F5265-OB】3、OLED时钟

助工
2024-12-29 20:37:52     打赏

【目录】

1、【Mini-F5265-OB】1、新建模版工程-电子产品世界论坛

2、【Mini-F5265-OB】2、移植FreeRTOS-电子产品世界论坛

【前言】

在前面的基础之上,这篇移植RTC以及OLED驱动,实现一个OLED实时时钟。

【步骤】

在前面的工程之上,我先移植OLED驱动。

1、下载江科大的OLED驱动到工程中:

image.png

2、修改IIC初始化函数:

void OLED_GPIO_Init(void)
{
	  GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef  I2C_InitStruct;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    I2C_DeInit(I2C1);

    I2C_StructInit(&I2C_InitStruct);
    I2C_InitStruct.I2C_Mode       = I2C_MODE_MASTER;
    I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS;
    I2C_InitStruct.I2C_ClockSpeed = 1000000;
    I2C_Init(I2C1, &I2C_InitStruct);

    I2C_TargetAddressConfig(I2C1, OLED_I2C_ADDRESS);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_4);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_4);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOC, &GPIO_InitStruct);
    I2C_Cmd(I2C1, ENABLE);

}

3、实现IIC的发送数据函数,由于发送指令,只需要发送两个byte,因为采用polling发送即可:

void I2C_TxData_Polling(uint8_t *Buffer, uint8_t Length)
{
    uint8_t i = 0;

    for (i = 0; i < Length; i++)
    {
        I2C_SendData(I2C1, Buffer[i]);
        while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
        {
        }
    }
		I2C_GenerateSTOP(I2C1, ENABLE);
    while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
    {
    }
}

4、发送数据,所发送的数据多,采用DMA方式发送:

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void OLED_TxData_DMA_Polling(uint8_t *Buffer, uint8_t Length)
{
    DMA_InitTypeDef  DMA_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(DMA1_Channel6);

    DMA_StructInit(&DMA_InitStruct);
    DMA_InitStruct.DMA_PeripheralBaseAddr    = (uint32_t)&(I2C1->DR);
    DMA_InitStruct.DMA_MemoryBaseAddr        = (uint32_t)Buffer;
    DMA_InitStruct.DMA_DIR                   = DMA_DIR_PeripheralDST;
    DMA_InitStruct.DMA_BufferSize            = Length;
    DMA_InitStruct.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
    DMA_InitStruct.DMA_MemoryInc             = DMA_MemoryInc_Enable;
    DMA_InitStruct.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_Word;
    DMA_InitStruct.DMA_MemoryDataSize        = DMA_MemoryDataSize_Byte;
    DMA_InitStruct.DMA_Mode                  = DMA_Mode_Normal;
    DMA_InitStruct.DMA_Priority              = DMA_Priority_Low;
    DMA_InitStruct.DMA_M2M                   = DMA_M2M_Disable;
    DMA_InitStruct.DMA_Auto_Reload           = DMA_Auto_Reload_Disable;
    DMA_Init(DMA1_Channel6, &DMA_InitStruct);

    I2C_DMACmd(I2C1, I2C_DMA_TXEN, ENABLE);

    DMA_Cmd(DMA1_Channel6, ENABLE);

    while (RESET == DMA_GetFlagStatus(DMA1_FLAG_TC6))
    {
    }

    I2C_DMACmd(I2C1, I2C_DMA_TXEN, DISABLE);

    DMA_Cmd(DMA1_Channel6, DISABLE);
}

5、修改OLED基于IIC的写命令与写数据的两个函数:

/**
  * 函    数:OLED写命令
  * 参    数:Command 要写入的命令值,范围:0x00~0xFF
  * 返 回 值:无
  */
void OLED_WriteCommand(uint8_t Command)
{
	uint8_t commadDat[2];
	commadDat[0] = 0x00;
	commadDat[1] = Command;
	I2C_TxData_Polling(commadDat, 2);
}

/**
  * 函    数:OLED写数据
  * 参    数:Data 要写入数据的起始地址
  * 参    数:Count 要写入数据的数量
  * 返 回 值:无
  */
void OLED_WriteData(uint8_t *Data, uint8_t Count)
{
	uint8_t dat[1];
	dat[0]= 0x40;
	OLED_TxData_DMA_Polling(dat,1);
	OLED_TxData_DMA_Polling(Data,Count);
	I2C_GenerateSTOP(I2C1, ENABLE);
	while (RESET == I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE))
	{
	}
}

到这里主要的代码就移植完毕,具体代码我会附工程。

【RTC初始化以及获取】

1、在工程的示例中有RTC的示例,我将他的RTC代码复制到工程里即可。

具体代码如下:

/***********************************************************************************************************************
    @file    rtc_calendar.c
    @author  FAE Team
    @date    1-Sep-2023
    @brief   THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
  **********************************************************************************************************************
    @attention

    <h2><center>&copy; Copyright(c) <2023> <MindMotion></center></h2>

      Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
    following conditions are met:
    1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
       the following disclaimer in the documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
       promote products derived from this software without specific prior written permission.

      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *********************************************************************************************************************/

/* Define to prevent recursive inclusion */
#define _RTC_CALENDAR_C_

/* Files include */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
#include "rtc_calendar.h"

/**
  * @addtogroup MM32F5260_LibSamples
  * @{
  */

/**
  * @addtogroup RTC
  * @{
  */

/**
  * @addtogroup RTC_Calendar
  * @{
  */

/* Private typedef ****************************************************************************************************/

/* Private define *****************************************************************************************************/

/* Private macro ******************************************************************************************************/

/* Private variables **************************************************************************************************/
const uint8_t RTC_DayOfMonth[12] =
{
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

RTC_CalendarTypeDef RTC_Calendar;

/* Private functions **************************************************************************************************/

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
uint8_t RTC_LeapYear(uint16_t Year)
{
    if (
        (((Year % 400) == 0)) ||                   /* Century Leap Year */
        (((Year % 100) != 0) && ((Year % 4) == 0)) /* Normal  Leay Year */
        )
    {
        return (1);
    }
    else
    {
        return (0);
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)
{
    int w, c, y;

    /* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */
    if ((Month == 1) || (Month == 2))
    {
        Month += 12;
        Year  -= 1;
    }

    w = 0;                             /* Weekday */
    c = Year / 100;                    /* Century */
    y = Year % 100;                    /* Year    */

    w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;

    while (w < 0)
    {
        w += 7;
    }

    w %= 7;

    return (w);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_UpdateCalendar(void)
{
    static uint32_t PreTotalDay = 0;
    uint32_t TotalSecond = 0;
    uint32_t TotalDay    = 0;
    uint16_t Year  = 1970;
    uint8_t  Month = 0;

    TotalSecond = RTC_GetCounter();
    TotalDay    = TotalSecond / 86400;

    if (PreTotalDay != TotalDay)
    {
        PreTotalDay = TotalDay;

        while (TotalDay >= 365)
        {
            if (RTC_LeapYear(Year) == 1)
            {
                if (TotalDay >= 366)
                {
                    TotalDay -= 366;
                }
                else
                {
                    break;
                }
            }
            else
            {
                TotalDay -= 365;
            }

            Year++;
        }

        RTC_Calendar.year = Year;

        while (TotalDay >= 28)
        {
            if ((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1))
            {
                if (TotalDay >= 29)
                {
                    TotalDay -= 29;
                }
                else
                {
                    break;
                }
            }
            else
            {
                if (TotalDay >= RTC_DayOfMonth[Month])
                {
                    TotalDay -= RTC_DayOfMonth[Month];
                }
                else
                {
                    break;
                }
            }

            Month++;
        }

        RTC_Calendar.month = Month + 1;
        RTC_Calendar.day   = TotalDay + 1;

        RTC_Calendar.week  = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
    }

    RTC_Calendar.hour   = (TotalSecond % 86400) / 3600;
    RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60;
    RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60;
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_SetDateTime(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second)
{
    uint32_t TotalSecond = 0;
    uint16_t y = 0;
    uint8_t  m = 0;

    if ((Year >= 1970) && (Year <= 2099))
    {
        for (y = 1970; y < Year; y++)
        {
            if (RTC_LeapYear(y) == 1)
            {
                TotalSecond += 31622400; /* Total Seconds Of Leap   Year */
            }
            else
            {
                TotalSecond += 31536000; /* Total Seconds Of Normal Year */
            }
        }

        for (m = 0; m < (Month - 1); m++)
        {
            TotalSecond += RTC_DayOfMonth[m] * 86400; /* Total Seconds Of Month */

            if ((RTC_LeapYear(Year) == 1) && (m == 1))
            {
                TotalSecond += 86400;
            }
        }

        TotalSecond += (uint32_t)(Day - 1) * 86400; /* Total Seconds Of Day    */
        TotalSecond += (uint32_t)Hour * 3600;       /* Total Seconds Of Hour   */
        TotalSecond += (uint32_t)Minute * 60;       /* Total Seconds Of Minute */
        TotalSecond += Second;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);

        PWR_BackupAccessCmd(ENABLE);

        RTC_SetCounter(TotalSecond);
        RTC_WaitForLastTask();

        RTC_UpdateCalendar();
    }
    else
    {
        printf("\r\nError Date & Time!!!\r\n");
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_PrintDateTime(void)
{
    printf("\r\n%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);

    switch (RTC_Calendar.week)
    {
        case 0:
            printf(" SUN ");
            break;

        case 1:
            printf(" MON ");
            break;

        case 2:
            printf(" TUE ");
            break;

        case 3:
            printf(" WED ");
            break;

        case 4:
            printf(" THU ");
            break;

        case 5:
            printf(" FRI ");
            break;

        case 6:
            printf(" SAT ");
            break;

        default:
            break;
    }

    printf("%02d:%02d:%02d\r\n", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_LoadDefault(void)
{
    char    Date[20], Time[20];
    char    Text[6][5];
    uint8_t i = 0, Index = 0, Month = 0;
    char *MonthTable[12] =
    {
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    };
    char *str;

    memset(Date, 0, sizeof(Date));
    memset(Time, 0, sizeof(Time));
    memset(Text, 0, sizeof(Text));

    memcpy(Date, __DATE__, sizeof(__DATE__));
    memcpy(Time, __TIME__, sizeof(__TIME__));

    str = strtok(Date, " ");

    while (str != NULL)
    {
        memcpy(Text[Index++], str, strlen(str));

        str = strtok(NULL, " ");
    }

    str = strtok(Time, ":");

    while (str != NULL)
    {
        memcpy(Text[Index++], str, strlen(str));

        str = strtok(NULL, ":");
    }

    for (i = 0; i < 12; i++)
    {
        if (0 == strcmp(Text[0], MonthTable[i]))
        {
            Month = i + 1;
        }
    }

    RTC_Calendar.day    = atoi(Text[1]);
    RTC_Calendar.month  = Month;
    RTC_Calendar.year   = atoi(Text[2]);

    RTC_Calendar.hour   = atoi(Text[3]);
    RTC_Calendar.minute = atoi(Text[4]);
    RTC_Calendar.second = atoi(Text[5]);

    RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day, RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_Configure(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);

    BKP_DeInit();

    if (BKP_ReadBackupRegister(BKP_DR1) != 0x5D5D)
    {
        RCC_LSEConfig(RCC_LSE_ON);

        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
        {
        }

        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

        RCC_RTCCLKCmd(ENABLE);

        RTC_WaitForSynchro();
        RTC_WaitForLastTask();

        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();

        RTC_SetPrescaler(32767);
        RTC_WaitForLastTask();

        printf("\r\n%s", __FUNCTION__);

        BKP_WriteBackupRegister(BKP_DR1, 0x5D5D);
    }
    else
    {
        printf("\r\nNeed't to configure RTC...");

        RTC_WaitForSynchro();

        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
    }

    NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 4;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    RTC_LoadDefault();
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_Calendar_Sample(void)
{
    printf("\r\nTest %s", __FUNCTION__);

    RTC_Configure();


}

/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

/********************************************** (C) Copyright MindMotion **********************************************/

2、由于工程是采用中断方式来定期获取时间的更新,在mm32f5260_it.c中我们还需要添加中断回调函数:

/***********************************************************************************************************************
  * @brief  This function handles RTC Handler
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void RTC_IRQHandler(void)
{
    if (RESET != RTC_GetITStatus(RTC_IT_SEC))
    {
        RTC_UpdateCalendar();

        RTC_ClearITPendingBit(RTC_IT_SEC);
        RTC_WaitForLastTask();
    }
}

【测试】

1、在main主函数中添加OLED初始化以及显示demo的代码,最后别忘记添加oled_update来更新屏幕。

		OLED_Init();
	  OLED_Clear();
		OLED_Printf(0,0,OLED_8X16,"MM32F5260_DEMO");
		OLED_Printf(10,16,OLED_8X16,"FreeRTOS_RTC");
		OLED_Update();		

2、在任务1中添加RTC初始化,在while中添加更新日期、时钟的显示函数:

//LED0任务函数 
void led1_task(void *pvParameters)
{
		RTC_Calendar_Sample();
    while(1)
    {
			OLED_Printf(10,32,OLED_8X16,"%04d-%02d-%02d", RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
			OLED_Printf(16,48,OLED_8X16,"%02d:%02d:%02d", RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
			OLED_Update();
			vTaskDelay(1000);

    }
}

【实现效果】

2173220398986f9930164c9e83a8190.jpg

【小结】

在此次的移植过程中,我们需要有一定的积累,一是oled的移植,他主要是初始化IIC,然后添加写命令、数据的两个函数。在RTC中,直接使用厂家的示例即可,在freertos中,定时来刷新屏幕,即可实现一个简单的OLED时钟。

附工程源码:My_oled.zip





关键词: Mini-F5265-OB     时钟     OLED     RTC    

专家
2024-12-30 07:57:17     打赏
2楼

感谢分享


工程师
2024-12-30 08:23:23     打赏
3楼

谢谢分享。


专家
2024-12-30 20:03:01     打赏
4楼

漂亮!谢谢分享!


专家
2024-12-30 21:47:18     打赏
5楼

感谢分享


专家
2024-12-30 21:48:43     打赏
6楼

感谢分享


助工
2024-12-31 11:03:49     打赏
7楼

感谢分享


共7条 1/1 1 跳转至

回复

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