[MM32软件]【灵动微电子MM32F5330测评】6.SPI驱动LCD屏幕+RTC时钟测试

SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线(CS、SCK、MOSI、MISO),根据实际使用情况可以只用其中的2根或3根。
MISO:主设备输入、从设备输出引脚。传输方向为从设备发送到主设备。
MOSI:主设备输出、从设备输入引脚。传输方向为主设备发送到从设备。
SCK:串口时钟,由主设备产生并提供给从设备。
NSS:从设备选择。
 


开发板上集成了一颗W25Q80,这是一颗容量为 8M-bit的串行 Flash 存储器
 


例程里有读写代码这里就不重复实现了,换用SPI驱动LCD显示屏。
驱动这块屏幕需要用到5个IO:CS、RST、A0、SCK、MOSI
 


初始化SPI,只用发送模式就行,手动控制CS、RST、A0
 

复制

void APP_SpiInit(void)

{

    GPIO_InitTypeDef GPIO_InitStruct;

    SPI_InitTypeDef  SPI_InitStruct;



    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);



    SPI_StructInit(&SPI_InitStruct);

    SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;

    SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;

    SPI_InitStruct.SPI_DataWidth = 8;

    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_High;

    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_2Edge;

    SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;

    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;

    SPI_InitStruct.SPI_FirstBit  = SPI_FirstBit_MSB;

    SPI_Init(SPI1, &SPI_InitStruct);



    SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);



    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3,  GPIO_AF_5);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5,  GPIO_AF_5);



    GPIO_StructInit(&GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_5;

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;

    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &GPIO_InitStruct);



    SPI_Cmd(SPI1, ENABLE);

}



void APP_SpiWriteByte(SPI_TypeDef *spix,uint8_t dat)

{

    SPI_SendData(spix, dat);

    while (RESET == SPI_GetFlagStatus(spix, SPI_FLAG_TXEPT));

}



YUYY_HS12864G18B_DEV_Type lcd_dev;

YUYY_GPIO_DEV_Type gpio_cs;

YUYY_GPIO_DEV_Type gpio_rst;

YUYY_GPIO_DEV_Type gpio_a0;

void APP_LcdInit(void)

{

    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_StructInit(&GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;

    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &GPIO_InitStruct);

    

    gpio_cs.gpio = GPIOB;

    gpio_cs.pin = GPIO_Pin_6;

    gpio_a0.gpio = GPIOB;

    gpio_a0.pin = GPIO_Pin_4;

    gpio_rst.gpio = GPIOB;

    gpio_rst.pin = GPIO_Pin_7;

    

    lcd_dev.cs_pin = &gpio_cs;

    lcd_dev.a0_pin = &gpio_a0;

    lcd_dev.rst_pin = &gpio_rst;

    lcd_dev.spix = SPI1;

    lcd_dev.spi_sendbyte_func = (YUYY_HS12864G18B_SpiWriteByteFunc_Type)APP_SpiWriteByte;

    lcd_dev.gpio_setlev_func = (YUYY_HS12864G18B_GPIO_SetLevFunc_Type)YUYY_GPIO_SetLev;

    lcd_dev.delayus_func = (YUYY_HS12864G18B_DelayUsFunc_Type)YUYY_DelayUs;

    

    YUYY_HS12864G18B_Init(&lcd_dev);

    YUYY_HS12864G18B_ClearScreen(&lcd_dev);

    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0," MM32F5330 TEST");

    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,"   LCD use SPI");

    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,"  bbs.21ic.com");

    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,6,0,"Code by yuyy1989");

    YUYY_HS12864G18B_DisplayFinish(&lcd_dev);

}

运行效果
 


实时时钟(RTC)是嵌入式系统中的一种重要组件,它提供了精确的时间跟踪功能,即使在系统关机时也能保持准确。RTC通常由一个专用的硬件模块组成,用于跟踪当前的年、月、日、时、分、秒以及星期等时间信息。MM32F5330的RTC模块内部包含一组连续计数的计数器。它作为一个独立的定时器,在相应软件配置下,可提供时钟功能。修改计数器的值可以重新设置系统当前的时间。MM32F5330的RTC提供的是一个32位的计数器,需要自行实现秒到日期时间的转换

复制

enum

{

    YUYY_TIME_WEEK_SUNDAY = 0,

    YUYY_TIME_WEEK_MONDAY,

    YUYY_TIME_WEEK_TUESDAY,

    YUYY_TIME_WEEK_WEDNESDAY,

    YUYY_TIME_WEEK_THURSDAY,

    YUYY_TIME_WEEK_FRIDAY,

    YUYY_TIME_WEEK_SATURDAY,

};

typedef struct

{

    uint8_t month;

    uint8_t day;

    uint8_t week;

    uint8_t hour;

    uint8_t minutes;

    uint8_t seconds;

    uint16_t year;

} YUYY_DateTimeType;

const uint8_t kMonthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool YUYY_TIME_IsLeapYear(uint16_t year)

{

    if(year%100!=0)

    {

        return (year%4==0);

    }

    else

    {

        return (year%400==0);

    }

}

uint32_t YUYY_TIME_GetSecondFromDateTime(YUYY_DateTimeType *datetime,uint16_t since_year)

{

    uint16_t i = 0,leap_count = 0;

    uint32_t alldays = 0;

    if(datetime->year < since_year)

        return 0;

    i = since_year;

    while (i < datetime->year)

    {

        if(YUYY_TIME_IsLeapYear(i))

            leap_count += 1;

        i+=1;

    }

    alldays = (datetime->year - since_year)*365+leap_count;

    printf("%d \n",leap_count);

    i = 1;

    while (i < datetime->month)

    {

        if(i == 2 && YUYY_TIME_IsLeapYear(datetime->year))

            alldays += 29;

        else

            alldays += kMonthDays[i-1];

        i+=1;

    }

    alldays += datetime->day - 1;

    return alldays*24*3600 + datetime->hour*3600 + datetime->minutes*60 + datetime->seconds;

}

void YUYY_TIME_GetDateTimeFromSecond(uint32_t sec,YUYY_DateTimeType *datetime,uint16_t since_year,uint8_t since_week)

{

    uint16_t i = 0,leap_count = 0;

    uint32_t alldays = 0;

    datetime->seconds = sec%60;

    sec /= 60;

    datetime->minutes = sec%60;

    sec /= 60;

    datetime->hour = sec%24;

    alldays = sec/24;

    i = since_year;

    datetime->week = ((alldays%7)+since_week)%7;

    while (alldays > 365)

    {

        alldays -= 365;

        if(YUYY_TIME_IsLeapYear(i))

        {

            if(alldays>0)

                alldays -= 1;

            else

                break;

        }

        i+=1;

    }

    datetime->year = i;

    i = 0;

    while (alldays >= kMonthDays[i])

    {

        alldays -= kMonthDays[i];

        if(i == 1 && YUYY_TIME_IsLeapYear(datetime->year))

        {

            if(alldays > 0)

                alldays -= 1;

            else

                break;

        }

        i+=1;

    }

    datetime->month = i+1;

    datetime->day = alldays+1;

}


初始化RTC

复制

void APP_RTCInit(void)

{



    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);

    BKP_DeInit();

    if (BKP_ReadBackupRegister(BKP_DR1) != 0x5B5B)

    {

        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_WaitForLastTask();

        RTC_SetPrescaler(32767);

        RTC_WaitForLastTask();

        RTC_SetCounter(0);

        RTC_WaitForLastTask();

        BKP_WriteBackupRegister(BKP_DR1, 0x5B5B);

    }

    else

    {

        RTC_WaitForSynchro();

        RTC_WaitForLastTask();

    }

}


按下按键后修改为指定的时间

复制

#define RTC_START_YEAR 2024

#define RTC_START_WEEK YUYY_TIME_WEEK_MONDAY

char *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"};

void APP_SetTestRTC(void)

{

    YUYY_DateTimeType datetime;

    datetime.year = 2024;

    datetime.month = 6;

    datetime.day = 30;

    datetime.hour = 20;

    datetime.minutes = 30;

    datetime.seconds = 30;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);

    RTC_SetCounter(YUYY_TIME_GetSecondFromDateTime(&datetime,RTC_START_YEAR));

    RTC_WaitForLastTask();

}


打印时间到LCD屏幕

复制

int main(void)

{

    char out[20];

    YUYY_DateTimeType datetime;

    uart_init();

    led_init();

    keys_init();

    exit_init();

    APP_SpiInit();

    APP_LcdInit();

    APP_RTCInit();

    while (1)

    {

        YUYY_DelayMs(1000);

        led_toggle(LED_NO_1);

        YUYY_TIME_GetDateTimeFromSecond(RTC_GetCounter(),&datetime,RTC_START_YEAR,RTC_START_WEEK);

        sprintf(out," %04d-%02d-%02d %s ",datetime.year, datetime.month, datetime.day,WeekdayStr[datetime.week]);

        YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,out);

        sprintf(out,"    %02d:%02d:%02d    ",datetime.hour, datetime.minutes, datetime.seconds);

        YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,4,0,out);

    }

}


运行效果


---------------------
作者:yuyy1989
链接:https://bbs.21ic.com/icview-3387314-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值