打印
[活动]

【APM32F411V Tiny Board测评】5.SPI驱动LCD并显示RTC时间

[复制链接]
801|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
要驱动的屏幕是这个

选用PA5和PA7作为SCK 和MOSI,PA4 PA6 PA8分别作为CS RST A0

初始化SPI,用只发送模式
void spi_init()
{
    GPIO_Config_T GPIO_InitStructure;
    SPI_Config_T  SPI1_InitStructure;
    RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);
   
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_5, GPIO_AF_SPI1);
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_SPI1);
   
    GPIO_ConfigStructInit(&GPIO_InitStructure);
    GPIO_InitStructure.pin = GPIO_PIN_5 | GPIO_PIN_7;
    GPIO_InitStructure.speed = GPIO_SPEED_100MHz;
    GPIO_InitStructure.mode = GPIO_MODE_AF;
    GPIO_InitStructure.otype = GPIO_OTYPE_PP;
    GPIO_InitStructure.pupd = GPIO_PUPD_NOPULL;
    GPIO_Config(GPIOA, &GPIO_InitStructure);
   
    SPI_ConfigStructInit(&SPI1_InitStructure);
    SPI1_InitStructure.direction = SPI_DIRECTION_1LINE_TX;
    SPI1_InitStructure.mode = SPI_MODE_MASTER;
    SPI1_InitStructure.length = SPI_DATA_LENGTH_8B;
    SPI1_InitStructure.polarity = SPI_CLKPOL_HIGH;
    SPI1_InitStructure.phase = SPI_CLKPHA_2EDGE;
    SPI1_InitStructure.nss = SPI_NSS_SOFT;
    SPI1_InitStructure.baudrateDiv = SPI_BAUDRATE_DIV_8;
    SPI1_InitStructure.firstBit = SPI_FIRSTBIT_MSB;
    SPI1_InitStructure.crcPolynomial = 7;
    SPI_Config(SPI1, &SPI1_InitStructure);
    SPI_DisableCRC(SPI1);
    SPI_DisableSSOutput(SPI1);
    SPI_Enable(SPI1);
}
void lcd_spiwritebyte(SPI_T *spix,uint8_t byte)
{
    while (SPI_I2S_ReadStatusFlag(spix, SPI_FLAG_TXBE) == RESET);
    SPI_I2S_TxData(spix, byte);
}
LCD驱动代码
void YUYY_HS12864G18B_writebyte(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t dat)
{
    uint8_t i = 0;
    if(hs12864_dev->spix)
        hs12864_dev->spi_sendbyte_func(hs12864_dev->spix, dat);
    else
    {
        while(i<8)
        {
            hs12864_dev->sck_setlev_func(&(hs12864_dev->sck),YUYY_GPIO_LEV0);
            if(dat & 0x80)
                hs12864_dev->mo_setlev_func(&(hs12864_dev->mo),YUYY_GPIO_LEV1);
            else
                hs12864_dev->mo_setlev_func(&(hs12864_dev->mo),YUYY_GPIO_LEV0);
            hs12864_dev->sck_setlev_func(&(hs12864_dev->sck),YUYY_GPIO_LEV1);
            dat <<= 1;
            i += 1;
        }
    }
}

void YUYY_HS12864G18B_cs(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
{
    hs12864_dev->delayus_func(5);
    hs12864_dev->cs_setlev_func(&(hs12864_dev->cs),lev);
    hs12864_dev->delayus_func(5);
}
void YUYY_HS12864G18B_rst(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
{
    hs12864_dev->rst_setlev_func(&(hs12864_dev->rst),lev);
}
void YUYY_HS12864G18B_a0(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE lev)
{
    hs12864_dev->a0_setlev_func(&(hs12864_dev->a0),lev);
}


/*
* com 0指令 1数据
*/
void YUYY_HS12864G18B_writedata(YUYY_HS12864G18B_DEV_Type *hs12864_dev,YUYY_GPIO_LEV_TYPE com,uint8_t dat)
{
    YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
    YUYY_HS12864G18B_a0(hs12864_dev,com);
    YUYY_HS12864G18B_writebyte(hs12864_dev,dat);
}

void YUYY_HS12864G18B_Init(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
{
    if(!hs12864_dev->a0_setlev_func)
        hs12864_dev->a0_setlev_func = YUYY_GPIO_SetLev;
    if(!hs12864_dev->cs_setlev_func)
        hs12864_dev->cs_setlev_func = YUYY_GPIO_SetLev;
    if(!hs12864_dev->mo_setlev_func)
        hs12864_dev->mo_setlev_func = YUYY_GPIO_SetLev;
    if(!hs12864_dev->rst_setlev_func)
        hs12864_dev->rst_setlev_func = YUYY_GPIO_SetLev;
    if(!hs12864_dev->sck_setlev_func)
        hs12864_dev->sck_setlev_func = YUYY_GPIO_SetLev;
    if(!hs12864_dev->delayus_func)
        hs12864_dev->delayus_func = (YUYY_DELAY_Func_Type)YUYY_DelayUs;
        
    YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
    YUYY_HS12864G18B_rst(hs12864_dev,YUYY_GPIO_LEV0);/*低电平复位*/
    hs12864_dev->delayus_func(20);
    YUYY_HS12864G18B_rst(hs12864_dev,YUYY_GPIO_LEV1);/*复位完毕*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xE2);/*软复位*/
    hs12864_dev->delayus_func(50);
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2C); /*升压步聚 1*/
    hs12864_dev->delayus_func(50);
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2E); /*升压步聚 2*/
    hs12864_dev->delayus_func(50);
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x2F); /*升压步聚 3*/
    hs12864_dev->delayus_func(50);
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x24); /*0x24粗调对比度,可设置范围0x20~0x27*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x81); /*微调对比度*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x08); /*0x28,微调对比度的值,可设置范围0x00~0x3f  1f*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xA2); /*1/9偏压比(bias)*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xC8); /*行扫描顺序:从上到下*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xA0); /*列扫描顺序:从左到右*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0x40); /*起始行:第一行开始*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xAF); /*开显示*/
    YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV1);
}

void YUYY_HS12864G18B_address(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t page,uint8_t column)
{
    YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV0);
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,0xB0+page); //设置页地址。每页是 8行。一个画面的 64行被分成 8个页*/
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,((column>>4)&0x0F)+0x10); //设置列地址的高4位
    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV0,column&0x0F); //设置列地址的低4位
}

/*全屏清屏*/
void YUYY_HS12864G18B_ClearScreen(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
{
    uint8_t i,j;
    for(i=0;i<8;i+=1)
    {
        YUYY_HS12864G18B_address(hs12864_dev,i,0);
        for(j=0;j<132;j+=1)
        {
            YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,0x00);
        }
    }
}

//===显示测试画面:例如全显示,隔行显示,隔列显示,雪花显示=====
void YUYY_HS12864G18B_TestDisplay(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t data1,uint8_t data2)
{
    uint8_t i,j;
    for(j=0;j<8;j+=1)
    {
        YUYY_HS12864G18B_address(hs12864_dev,j,0);
        for(i=0;i<64;i+=1)
        {
            YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,data1);
            YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,data2);
        }
    }
}


void YUYY_HS12864G18B_DisplayDatas(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp,uint8_t width,uint8_t height)
{
    uint8_t rev,i=0,j=0,k=0,hp=height/8;
    rev = option&YUYY_FONT_DATAS_REVERSE;
    if((option&YUYY_FONT_DATAS_COL_COL) == 0)
    {
        while (i<hp)
        {
            YUYY_HS12864G18B_address(hs12864_dev,page+i,column);
            j=0;
            while (j<width)
            {
                if(rev == 0)
                    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,*dp);
                else
                    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,~*dp);
                dp+=1;
                j+=1;
            }
            
            i+=1;
        }
    }
    else
    {
        while (i<hp)
        {
            YUYY_HS12864G18B_address(hs12864_dev,page+i,column);
            k=i;
            j=0;
            while (j<width)
            {
                if(rev == 0)
                    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,dp[k]);
                else
                    YUYY_HS12864G18B_writedata(hs12864_dev,YUYY_GPIO_LEV1,~dp[k]);
                j+=1;
                k+=hp;
            }
            i+=1;
        }
    }
}

/*显示 128x64点阵图像*/
void YUYY_HS12864G18B_GisplayGraphic128x64(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
{
    YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,128,64);
}

/*显示 32x32点阵图像、汉字、生僻字或 32x32点阵的其他图标*/  
void YUYY_HS12864G18B_GisplayGraphic32x32(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
{
    YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,32,32);
}
/*显示 16x16点阵图像、汉字、生僻字或 16x16点阵的其他图标*/
void YUYY_HS12864G18B_GisplayGraphic16x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
{
    YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,16,16);
}
/*显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标*/
void YUYY_HS12864G18B_GisplayGraphic8x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,uint8_t *dp)
{
    YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,dp,8,16);
}
/*显示8x16ASCII字符串*/
void YUYY_HS12864G18B_DisplayString8x16(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,char *text)
{
    uint8_t i=0,j;
    option &= 0x01;
    while(text[i]>0x00)
    {
        if((text[i] > 0x1F)&&(text[i] < 0x7F))
        {
            j=text[i]-0x20;
            YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,(uint8_t *)(YUYY_FONT_ASCII_TABLE_8x16+j),8,16);
            column+=8;
        }
        i+=1;
    }
}
/*显示6x8ASCII字符串*/
void YUYY_HS12864G18B_DisplayString6x8(YUYY_HS12864G18B_DEV_Type *hs12864_dev,uint8_t option,uint8_t page,uint8_t column,char *text)
{
    uint8_t i=0,j;
    option &= 0x01;
    while(text[i]>0x00)
    {
        if((text[i]>0x1F)&&(text[i]<0x7F))
        {
            j=text[i]-0x20;
            YUYY_HS12864G18B_DisplayDatas(hs12864_dev,option,page,column,(uint8_t *)(YUYY_FONT_ASCII_TABLE_6x8+j),6,8);
            column+=6;
        }
        i+=1;
    }
}


void YUYY_HS12864G18B_DisplayFinish(YUYY_HS12864G18B_DEV_Type *hs12864_dev)
{
    YUYY_HS12864G18B_cs(hs12864_dev,YUYY_GPIO_LEV1);
}
LCD初始化
YUYY_HS12864G18B_DEV_Type lcd_dev;
void lcd_init()
{
    GPIO_Config_T gpioConfigStruct;
    RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOA);
    GPIO_ConfigStructInit(&gpioConfigStruct);
    gpioConfigStruct.mode = GPIO_MODE_OUT;
    gpioConfigStruct.speed = GPIO_SPEED_100MHz;
    gpioConfigStruct.pin = GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8;
    gpioConfigStruct.otype = GPIO_OTYPE_PP;
    gpioConfigStruct.pupd = GPIO_PUPD_NOPULL;
    GPIO_Config(GPIOA, &gpioConfigStruct);
   
    lcd_dev.cs.gpio = GPIOA;
    lcd_dev.cs.pin = GPIO_PIN_4;
    lcd_dev.rst.gpio = GPIOA;
    lcd_dev.rst.pin = GPIO_PIN_6;
    lcd_dev.a0.gpio = GPIOA;
    lcd_dev.a0.pin = GPIO_PIN_8;
    lcd_dev.spix = SPI1;
    lcd_dev.spi_sendbyte_func = (YUYY_HS12864G18B_SpiWriteByteFunc_Type)lcd_spiwritebyte;
   
    YUYY_HS12864G18B_Init(&lcd_dev);
    YUYY_HS12864G18B_ClearScreen(&lcd_dev);
    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0," APM32F411 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,使用外部低速晶振作为时钟源

void rtc_init()
{
    RTC_Config_T Struct;
    RTC_TimeConfig_T timeConfig;
    RTC_DateConfig_T dateConfig;

    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();
    RCM_ConfigLSE(RCM_LSE_OPEN);
    while(RCM_ReadStatusFlag(RCM_FLAG_LSERDY) == RESET)
    {
    }

    RCM_ConfigRTCCLK(RCM_RTCCLK_LSE);

    RCM_EnableRTCCLK();
    RTC_WaitForSynchro();
    RTC_ConfigStructInit(&Struct);
    Struct.format = RTC_HOURFORMAT_24;
    RTC_Config(&Struct);
   
    RTC_DisableWriteProtection();
    timeConfig.hours = 8;
    timeConfig.minutes = 20;
    timeConfig.seconds = 30;
    RTC_ConfigTime(RTC_FORMAT_BIN,&timeConfig);
    dateConfig.year = 24;
    dateConfig.month = RTC_MONTH_MAY;
    dateConfig.date = 12;
    dateConfig.weekday = RTC_WEEKDAY_SUNDAY;
    RTC_ConfigDate(RTC_FORMAT_BIN,&dateConfig);
    RTC_EnableWriteProtection();
}
实现LCD显示RTC时间
char *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"};
uint8_t ertc_int_flag = 0;
void showrtc()
{
    RTC_TimeConfig_T time;
    RTC_DateConfig_T date;
    char out[20];
    RTC_ReadDate(RTC_FORMAT_BIN,&date);
    sprintf(out," 20%02d-%02d-%02d %s ",date.year, date.month, date.date,WeekdayStr[date.weekday%7]);
    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,0,0,out);
    RTC_ReadTime(RTC_FORMAT_BIN,&time);
    sprintf(out,"    %02d:%02d:%02d    ",time.hours, time.minutes, time.seconds);
    YUYY_HS12864G18B_DisplayString8x16(&lcd_dev,0,2,0,out);
}
运行效果



使用特权

评论回复
沙发
szt1993| | 2024-5-23 18:06 | 只看该作者
SPI显示屏驱动速率应该比较稳定

使用特权

评论回复
板凳
逢dududu必shu| | 2024-8-17 01:12 | 只看该作者
在极海MCU APM32F103上使用SPI驱动LCD并显示RTC时间的过程涉及硬件初始化、SPI通信、RTC设置和时间获取、以及LCD显示更新。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

146

主题

698

帖子

6

粉丝