本帖最后由 xld0932 于 2023-3-5 09:05 编辑

有幸参加了这次APM32E103ZET6 EVAL评估板活动,EVAL开发板与MINI BOARD相比多了很多外设功能,给我们工程师更多的DIY资源,同时也减少了我们扩展连接线时错综复杂的烦恼……

APM32E103ZET6 EVAL评估板是APM32E1系列增强型MCU的完整演示和开发平台,它带有一颗基于ARM Cortex-M3内核的MCU(APM32E103ZET6),其最高工作主频可达到120MHz,带有512KB的FLASH程序空间和128KB的SRAM空间;板载外设资源丰富,带有一个2.4英寸的TFT LCD接口(硬件SPI接口形式,像素为240*320),实现了显示功能、还有一个SPI FLASH(硬件SPI接口)、一个EEPROM(硬件I2C接口)、一个SD Card卡槽(SDIO接口)、一个SDRAM(FMC接口),实现了多元化的存储系统功能;另外还有两路CAN接口、一个USB接口、一个USB转UART TTL接口,构成了多形式的通讯系统功能;此外还有RTC实时时钟模块、ADC模拟外设等等……具备完整的开发资料和SDK软件开发包,能够让开发者快速上手。


  • 开发板
forum.jpg


  • 准备资料硬件


  • 硬件准备

  • APM32E103ZE EVAL评估板
  • J-LINK调试仿真下载器MiniUSB线,连接USB转串口,用于程序功能调试监控打印信息
  • 2.4英寸TFT LCD(240*320)


  • 实现功能

  • 基于APM32E103ZE EVAL评估板的板载资源,购置了一个与开发板接口匹配的2.4英寸TFT LCD液晶演示屏,实现功能如下:
  • 基于SysTick与MultiTimer实现任务创建、管理、调用的功能
  • 实现LED闪烁的基础功能
  • 基于KEY和MultiButton实现按键检测、事件处理的功能
  • 通过硬件I2C接口实现对EEPROM进行读写操作的功能
  • 通过硬件SPI接口结合SFUD实现对SPI FLASH进行读写操作的功能
  • 通过RTC及TIME.H库程序实现日历及显示的功能
  • 通过ADC来采样旋钮ADC电压的功能,并将结果显示在TFT LCD上
  • 通过FMC接口实现对SRAM的读写功能测试
  • 通过硬件SPI接口与相应的GPIO端口实现TFT LCD的显示功能
由于手上没有CAN分析仪、TF卡,这两部分的功能后续再去熟悉了……


  • 功能实现基于SysTick与MultiTimer实现任务创建、管理、调用的功能
通过修改system_apm32e10x.c中的宏定义将MCU的运行时候频率修改到最高的120MHz,然后将SysTick定时器设置为1ms产生一次中断,通过重载返回SysTick_Tick的当前值去注册MultiTimer,然后就可以通过MultiTimer去注册任务和调度了;我们将MultiTimer的调度放在while(1)来执行,具体程序如下所示:
volatile uint32_t SysTick_Tick = 0;

/*!
  * @brief       Get SysTick tick
  *
  * @param       None
  *
  * @retval      SysTick_Tick
  *
  */
uint64_t SysTick_GetTick(void)
{
    return (SysTick_Tick);
}

/*!
  * @brief       Main program
  *
  * @param       None
  *
  * @retval      None
  *
  */
int main(void)
{
    uint32_t PCLK1, PCLK2;

    MultiTimerInstall(SysTick_GetTick);

    SysTick_Config(SystemCoreClock / 1000);

    USART_Init(115200);

    RCM_ReadPCLKFreq(&PCLK1, &PCLK2);

    printf("\r\nAPM32E103ZE EVAL V1.0 %s %s\r\n", __DATE__, __TIME__);

    printf("\r\nSYSCLK : %dHz", RCM_ReadSYSCLKFreq());
    printf("\r\nHCLK   : %dHz", RCM_ReadHCLKFreq());
    printf("\r\nPCLK1  : %dHz", PCLK1);
    printf("\r\nPCLK2  : %dHz", PCLK2);
    printf("\r\nADCCLK : %dHz", RCM_ReadADCCLKFreq());
    printf("\r\n");

    ADC_Init();

    EEPROM_Init();

    KEY_Init();

    LED_Init();

    RTC_Init();

    SDRAM_Init();

    SPI_FLASH_Init();

    TFT_LCD_Init();

    while (1)
    {
        MultiTimerYield();
    }
}

运行结果:
forum.jpg


  • 实现LED闪烁的基础功能
LED闪烁是对GPIO功能最基本的操作了,我们通讯配置控制LED灯的GPIO端口工作在输出模式,然后注册一个LED闪烁任务,每间隔250毫秒去切换一下LED的显示状态,来达到LED灯闪烁的效果,具体程序如下所示:
MultiTimer LED_MultiTimer;

/*!
  * @brief       LED MultiTimer callback
  *
  * @param       None
  *
  * @retval      None
  *
  */
void LED_MultiTimerCallback(MultiTimer *timer, void *userData)
{
    GPIO_WriteBitValue(GPIOD, GPIO_PIN_13, (BIT_SET == GPIO_ReadOutputBit(GPIOD, GPIO_PIN_13)) ? BIT_RESET : BIT_SET);

    GPIO_WriteBitValue(GPIOD, GPIO_PIN_14, (BIT_SET == GPIO_ReadOutputBit(GPIOD, GPIO_PIN_14)) ? BIT_RESET : BIT_SET);

    GPIO_WriteBitValue(GPIOD, GPIO_PIN_15, (BIT_SET == GPIO_ReadOutputBit(GPIOD, GPIO_PIN_15)) ? BIT_RESET : BIT_SET);

    MultiTimerStart(&LED_MultiTimer, 250, LED_MultiTimerCallback, "LED");
}

/*!
  * @brief       LED Init
  *
  * @param       None
  *
  * @retval      None
  *
  */
void LED_Init(void)
{
    GPIO_Config_T  GPIO_ConfigStruct;

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);

    GPIO_ConfigStructInit(&GPIO_ConfigStruct);
    GPIO_ConfigStruct.pin   = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
    GPIO_ConfigStruct.mode  = GPIO_MODE_OUT_PP;
    GPIO_Config(GPIOD, &GPIO_ConfigStruct);

    MultiTimerStart(&LED_MultiTimer, 250, LED_MultiTimerCallback, "LED");
}

/*!
  * @brief       LED Control
  *
  * @param       Index & Enable or Disable
  *
  * @retval      None
  *
  */
void LED_Enable(uint8_t Index, uint8_t Enable)
{
    switch (Index)
    {
        case 1:
            GPIO_WriteBitValue(GPIOD, GPIO_PIN_13, (Enable) ? BIT_RESET : BIT_SET);
            break;

        case 2:
            GPIO_WriteBitValue(GPIOD, GPIO_PIN_14, (Enable) ? BIT_RESET : BIT_SET);
            break;

        case 3:
            GPIO_WriteBitValue(GPIOD, GPIO_PIN_15, (Enable) ? BIT_RESET : BIT_SET);
            break;

        default:
            break;
    }
}


  • 基于KEY和MultiButton实现按键检测、事件处理的功能
KEY是GPIO作为输入的一个基本功能,通过与MultiButton的结合,能够实现单个按键的多个事件检测和处理操作,比如按键按下、抬起、单击、双击、长按等等,再结合MultiTimer任务实现按键扫描,具体程序如下所示:
MultiTimer KEY_MultiTimer;
struct Button btnKEY1, btnKEY2, btnKEY3;

/*!
  * @brief       Read key input level
  *
  * @param       btn
  *
  * @retval      level
  *
  */
uint8_t read_pin_level(uint8_t pin_id)
{
    switch (pin_id)
    {
        case 0:
            return (GPIO_ReadInputBit(GPIOF, GPIO_PIN_9));

        case 1:
            return (GPIO_ReadInputBit(GPIOC, GPIO_PIN_13));

        case 2:
            return (GPIO_ReadInputBit(GPIOA, GPIO_PIN_0));

        default:
            break;
    }

    return (BIT_SET);
}

/*!
  * @brief       Key handler
  *
  * @param       btn
  *
  * @retval      None
  *
  */
void KEY_Handler(void *btn)
{
    Button *key = btn;
    uint8_t button_id = key->button_id + 1;

    char buffer[50];
    memset(buffer, 0, sizeof(buffer));

    switch (key->event)
    {
        case PRESS_DOWN:
            sprintf(buffer, "KEY%d : PRESS_DOWN", button_id);
            break;

        case PRESS_UP:
            sprintf(buffer, "KEY%d : PRESS_UP  ", button_id);
            break;

        case SINGLE_CLICK:
            sprintf(buffer, "KEY%d : SINGLE_CLICK", button_id);
            break;

        case DOUBLE_CLICK:
            sprintf(buffer, "KEY%d : DOUBLE_CLICK", button_id);
            break;

        case LONG_PRESS_START:
            sprintf(buffer, "KEY%d : LONG_PRESS_START", button_id);
            break;

        case LONG_PRESS_HOLD:
            sprintf(buffer, "KEY%d : LONG_PRESS_HOLD", button_id);
            break;

        default:
            break;
    }

    LCD_DisplayString(0, 140, buffer, FORECOLOR, BACKCOLOR, 16, 0);
}

/*!
  * @brief       KEY MultiTimer callback
  *
  * @param       None
  *
  * @retval      None
  *
  */
void KEY_MultiTimerCallback(MultiTimer *timer, void *userData)
{
    button_ticks();

    MultiTimerStart(&KEY_MultiTimer, 5, KEY_MultiTimerCallback, "KEY");
}

/*!
  * @brief       KEY Init
  *
  * @param       None
  *
  * @retval      None
  *
  */
void KEY_Init(void)
{
    GPIO_Config_T GPIO_ConfigStruct;

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOF);

    GPIO_ConfigStructInit(&GPIO_ConfigStruct);
    GPIO_ConfigStruct.pin  = GPIO_PIN_9;
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOF, &GPIO_ConfigStruct);

    button_init(&btnKEY1, read_pin_level, BIT_RESET, 0);
    button_attach(&btnKEY1, PRESS_DOWN, KEY_Handler);
    button_attach(&btnKEY1, PRESS_UP,   KEY_Handler);
    button_start(&btnKEY1);

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOC);

    GPIO_ConfigStructInit(&GPIO_ConfigStruct);
    GPIO_ConfigStruct.pin  = GPIO_PIN_13;
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOC, &GPIO_ConfigStruct);

    button_init(&btnKEY2, read_pin_level, BIT_RESET, 1);
    button_attach(&btnKEY2, PRESS_DOWN, KEY_Handler);
    button_attach(&btnKEY2, PRESS_UP,   KEY_Handler);
    button_start(&btnKEY2);

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);

    GPIO_ConfigStructInit(&GPIO_ConfigStruct);
    GPIO_ConfigStruct.pin  = GPIO_PIN_0;
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_PD;
    GPIO_Config(GPIOA, &GPIO_ConfigStruct);

    button_init(&btnKEY3, read_pin_level, BIT_SET, 2);
    button_attach(&btnKEY3, PRESS_DOWN, KEY_Handler);
    button_attach(&btnKEY3, PRESS_UP,   KEY_Handler);
    button_start(&btnKEY3);

    MultiTimerStart(&KEY_MultiTimer, 5, KEY_MultiTimerCallback, "KEY");
}


  • 通过硬件I2C接口实现对EEPROM进行读写操作的功能
通过硬件I2C接口来操作EEPROM进行读写,主要是参考官方提供的SDK软件包中的示例程序完成的,I2C结合DMA的操作,速度更快,CPU的干预时间更少……充分节省了MCU的开销,具体程序如下所示:
/*!
  * @brief       EEPROM Init
  *
  * @param       None
  *
  * @retval      None
  *
  */
void EEPROM_Init(void)
{
    I2C_EE_ERROR_T errSta = I2C_EE_OK;
    uint16_t i = 0;

    APM_I2C_EE_Init();

    /* initialization  Buffer*/
    for (i = 0; i < DATA_BUF_SIZE; i++)
    {
        txDataBufI2C = i;
        rxDataBufI2C = 0;
    }

    printf("\r\nI2C write Data to EEPROM \r\n");

    /* Write data to EEPROM */
    errSta = I2C_EE_BufferWrite(txDataBufI2C, EEPROM_WRITE_ADDR, DATA_BUF_SIZE);

    if (errSta == I2C_EE_OK)
    {
        printf("Write data: \r\n");
        Buffer_Print(txDataBufI2C, DATA_BUF_SIZE);

        /* Set the Number of data to be read */
        readDataSize = DATA_BUF_SIZE;

        /* Read data from EEPROM */
        errSta = I2C_EE_BufferRead(rxDataBufI2C, EEPROM_READ_ADDR, (uint16_t *)(&readDataSize));

        /* Wait till DMA transfer is complete */
        while (readDataSize > 0)
        {
        }

        if (errSta == I2C_EE_OK)
        {
            printf("\r\nRead data: \r\n");
            Buffer_Print(rxDataBufI2C, DATA_BUF_SIZE);
        }
        else
        {
            printf("I2C EE Error Code:%d\r\n", errSta);
        }
    }
    else
    {
        printf("I2C EE Error Code:%d\r\n", errSta);
    }

    /* Compare receive Buffer */
    if (Buffer_Compare(txDataBufI2C, rxDataBufI2C, DATA_BUF_SIZE) == 1)
    {
        /* Data is ok then turn on LED2 */
        printf("\r\nEEPROM AT24C32 test OK!\r\n\r\n");
    }
    else
    {
        printf("\r\nEEPROM AT24C32 test fail!\r\n\r\n");
    }
}

运行结果:
forum.jpg


  • 通过硬件SPI接口结合SFUD实现对SPI FLASH进行读写操作的功能
SFUD是针对SPI FLASH实现的一个开源的套件,通过移植硬件SPI接口对SPI FLASH的底层操作,可以轻松的实现对SPI FLASH的读写操作,极大的方便了开发者,将更多的精力关注在应用开发上,具体代码如下所示:
#define SFUD_DEMO_BUFFER_SIZE      (512)

uint8_t sfud_demo_buf[SFUD_DEMO_BUFFER_SIZE];

/*!
  * @brief       SFUD demo for the first flash device test
  *
  * @param       addr flash start address
  *
  * @param       size test flash size
  *
  * @param       size test flash data buffer
  *
  * @retval      None
  *
  */
void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{
    sfud_err result = SFUD_SUCCESS;

    const sfud_flash *flash = sfud_get_device_table() + 0;
    size_t i;

    /* prepare write data */
    for (i = 0; i < size; i++)
    {
        data = i;
    }

    /* erase test */
    result = sfud_erase(flash, addr, size);

    if (result == SFUD_SUCCESS)
    {
        printf("\r\nErase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
    }
    else
    {
        printf("\r\nErase the %s flash data failed.\r\n", flash->name);
        return;
    }

    /* write test */
    result = sfud_write(flash, addr, size, data);

    if (result == SFUD_SUCCESS)
    {
        printf("\r\nWrite the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
    }
    else
    {
        printf("\r\nWrite the %s flash data failed.\r\n", flash->name);
        return;
    }

    /* read test */
    result = sfud_read(flash, addr, size, data);

    if (result == SFUD_SUCCESS)
    {
        printf("\r\nRead the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr, size);

        printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");

        for (i = 0; i < size; i++)
        {
            if ((i % 16) == 0)
            {
                printf("[%08X] ", addr + i);
            }

            printf("%02X ", data);

            if (((i + 1) % 16 == 0) || (i == size - 1))
            {
                printf("\r\n");
            }
        }

        printf("\r\n");
    }
    else
    {
        printf("\r\nRead the %s flash data failed.\r\n", flash->name);
    }

    /* data check */
    for (i = 0; i < size; i++)
    {
        if (data != i % 256)
        {
            printf("\r\nRead and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
            break;
        }
    }

    if (i == size)
    {
        printf("\r\nThe %s flash test is success.\r\n", flash->name);
    }
}

/*!
  * @brief       SPI_FLASH Init
  *
  * @param       None
  *
  * @retval      None
  *
  */
void SPI_FLASH_Init(void)
{
    printf("\r\n");

    if (sfud_init() == SFUD_SUCCESS)
    {
        sfud_demo(0, sizeof(sfud_demo_buf), sfud_demo_buf);
    }
}

运行结果:
forum.jpg


  • 通过RTC及TIME.H库程序实现日历及显示的功能
APM32E103ZET6这款芯片的RTC是不带日历功能的,但这个RTC具备了精确的秒走时,对于我们软件开发来说,就已经具备了RTC日历功能,本程序中的实现与以往不同,之前实现日历功能都是通过软件代码去实现的换算,这里我们借助TIME.H库程序,通过时间戳的换算,可以很轻松的得到日历,代码量减少了、功能实现更简洁了……具体代码如下所示:
MultiTimer RTC_MultiTimer;
  • volatile uint32_t RTC_InterruptFlag = 0;
  • /*!
  •   * @brief       LED MultiTimer callback
  •   *
  •   * @param       None
  •   *
  •   * @retval      None
  •   *
  •   */
  • void RTC_MultiTimerCallback(MultiTimer *timer, void *userData)
  • {
  •     if (1 == RTC_InterruptFlag)
  •     {
  •         RTC_InterruptFlag = 0;
  •         time_t t      = RTC_ReadCounter();
  •         struct tm *lt = localtime(&t);
  •         char buffer[50];
  •         memset(buffer, 0, sizeof(buffer));
  •         strftime(buffer, sizeof(buffer), "%b-%d-%Y %a %H:%M:%S", lt);
  •         LCD_DisplayString(0, 80, buffer, FORECOLOR, BACKCOLOR, 16, 0);
  •     }
  •     MultiTimerStart(&RTC_MultiTimer, 100, RTC_MultiTimerCallback, "RTC");
  • }
  • /*!
  •   * @brief       RTC_LoadDefault
  •   *
  •   * @param       None
  •   *
  •   * @retval      None
  •   *
  •   */
  • struct tm RTC_LoadDefault(void)
  • {
  •     char    date[20], time[20];
  •     char    text[6][5];
  •     uint8_t index = 0, month = 0;
  •     struct tm load;
  •     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__));
  •     char *str;
  •     str = strtok(date, " ");
  •     while (str != NULL)
  •     {
  •         memcpy(text[index], str, strlen(str));
  •         index++;
  •         str = strtok(NULL, " ");
  •     }
  •     str = strtok(time, ":");
  •     while (str != NULL)
  •     {
  •         memcpy(text[index], str, strlen(str));
  •         index++;
  •         str = strtok(NULL, ":");
  •     }
  •     char *strMonth[12] =
  •     {
  •         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  •         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  •     };
  •     for (uint8_t i = 0; i < 12; i++)
  •     {
  •         if (strcmp(text[0], strMonth[i]) == 0)
  •         {
  •             month = i;
  •             break;
  •         }
  •     }
  •     load.tm_mday = atoi(text[1]);
  •     load.tm_mon  = month;
  •     load.tm_year = atoi(text[2]) - 1900;
  •     load.tm_hour = atoi(text[3]);
  •     load.tm_min  = atoi(text[4]);
  •     load.tm_sec  = atoi(text[5]);
  •     return (load);
  • }
  • /*!
  •   * @brief       RTC Init
  •   *
  •   * @param       None
  •   *
  •   * @retval      None
  •   *
  •   */
  • void RTC_Init(void)
  • {
  •     struct tm load;
  •     RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
  •     PMU_EnableBackupAccess();
  •     RCM_EnableLSI();
  •     while (RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET)
  •     {
  •     }
  •     RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
  •     RCM_EnableRTCCLK();
  •     RTC_WaitForSynchro();
  •     RTC_WaitForLastTask();
  •     RTC_EnableInterrupt(RTC_INT_SEC);
  •     RTC_WaitForLastTask();
  •     RTC_ConfigPrescaler(32767);
  •     RTC_WaitForLastTask();
  •     load = RTC_LoadDefault();
  •     time_t t = mktime(&load);
  •     RTC_ConfigCounter(t);
  •     RTC_WaitForLastTask();
  •     NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
  •     MultiTimerStart(&RTC_MultiTimer, 100, RTC_MultiTimerCallback, "RTC");
  • }
  • 复制代码


    • 通过ADC来采样旋钮ADC电压的功能,并将结果显示在TFT LCD上,具体代码如下所示:
    MultiTimer ADC_MultiTimer;

    /*!
      * @brief       ADC_MultiTimerCallback
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void ADC_MultiTimerCallback(MultiTimer *timer, void *userData)
    {
        char buffer[50];

        memset(buffer, 0, sizeof(buffer));

        ADC_EnableSoftwareStartConv(ADC1);

        while (ADC_ReadSoftwareStartConvStatus(ADC1) != BIT_RESET)
        {
        }

        ADC_ClearStatusFlag(ADC1, ADC_FLAG_EOC);

        uint32_t Value = ADC_ReadConversionValue(ADC1);

        sprintf(buffer, "ADC Voltage : %0.1fv", (float)Value / 4096.0 * 3.3);

        LCD_DisplayString(0, 110, buffer, FORECOLOR, BACKCOLOR, 16, 0);

        MultiTimerStart(&ADC_MultiTimer, 100, ADC_MultiTimerCallback, "ADC");
    }

    /*!
      * @brief       ADC Init
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void ADC_Init(void)
    {
        ADC_Config_T  ADC_ConfigStruct;
        GPIO_Config_T GPIO_ConfigStruct;

        RCM_ConfigADCCLK(RCM_PCLK2_DIV_4); /* ADCCLK = PCLK2/4 */

        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOC);

        GPIO_ConfigStructInit(&GPIO_ConfigStruct);
        GPIO_ConfigStruct.pin   = GPIO_PIN_0;
        GPIO_ConfigStruct.mode  = GPIO_MODE_ANALOG;
        GPIO_Config(GPIOC, &GPIO_ConfigStruct);

        ADC_ConfigStructInit(&ADC_ConfigStruct);
        ADC_ConfigStruct.mode               = ADC_MODE_INDEPENDENT;
        ADC_ConfigStruct.scanConvMode       = DISABLE;
        ADC_ConfigStruct.continuosConvMode  = ENABLE;
        ADC_ConfigStruct.externalTrigConv   = ADC_EXT_TRIG_CONV_None;
        ADC_ConfigStruct.dataAlign          = ADC_DATA_ALIGN_RIGHT;
        ADC_ConfigStruct.nbrOfChannel       = 1;
        ADC_Config(ADC1, &ADC_ConfigStruct);

        ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_10, 1, ADC_SAMPLETIME_239CYCLES5);

        ADC_Enable(ADC1);

        ADC_ResetCalibration(ADC1);

        while (ADC_ReadResetCalibrationStatus(ADC1))
        {
        }

        ADC_StartCalibration(ADC1);

        while (ADC_ReadCalibrationStartFlag(ADC1))
        {
        }

        MultiTimerStart(&ADC_MultiTimer, 100, ADC_MultiTimerCallback, "ADC");
    }


    • 通过FMC接口实现对SRAM的读写功能测试
    通过FMC接口扩展的SRAM存储,可以让我们在应对需要大容量RAM时,给以应对的最好方案……通过对SRAM的基础读写操作,来熟悉SRAM的操作方法;后面有机会可以尝试一下在系统启动的时候直接映射成系统内存,直接使用;具体代码如下所示:
    /**
      * @brief    W/R Err Count structure definition
      */
    typedef struct
    {
        uint32_t    ByteCount;
        uint32_t    HalfWordCount;
        uint32_t    WordCount;
    } Err_Count_T;

    Err_Count_T Err;

    /* printf message */
    #define MESSAGE0          "*******************************"
    #define MESSAGE1          "* APM32E103xE DMC SDRAM Demo "
    #define MESSAGE2          "* SystemCoreClock      :"
    #define MESSAGE3          "* SDRAMClock           :"
    #define MESSAGE4          "*  8 bit W/R Err Count :"
    #define MESSAGE5          "* 16 bit W/R Err Count :"
    #define MESSAGE6          "* 32 bit W/R Err Count :"

    #define  RCM_SDRAM_GPIO_PERIPH   \
            (RCM_APB2_PERIPH_AFIO |  \
             RCM_APB2_PERIPH_GPIOB | \
             RCM_APB2_PERIPH_GPIOC | \
             RCM_APB2_PERIPH_GPIOD | \
             RCM_APB2_PERIPH_GPIOE | \
             RCM_APB2_PERIPH_GPIOF | \
             RCM_APB2_PERIPH_GPIOG)

    #define  RCM_SDRAM_PERIPH (RCM_AHB_PERIPH_SMC)

    #define SDRAM_START_ADDR  ((uint32_t)0x60000000)
    #define SDRAM_END_ADDR    ((uint32_t)0x60200000)

    /*!
      * @brief       SDRAM GPIO Config
      *
      * @param       None
      *
      * @retval      None
      *
      */
    static void SDRAM_GPIO_ConfigStruct(void)
    {
        GPIO_Config_T GPIO_ConfigStruct;

        RCM_EnableAPB2PeriphClock(RCM_SDRAM_GPIO_PERIPH);

        /** SDRAM pins assignment */
        /**
          +-------------------------+--------------------------+--------------------------+
          | PB10 <-> MMC_SDRAM_UNQM | PC10 <-> MMC_SDRAM_D8    | PD2  <-> MMC_SDRAM_D10   |
          | PB11 <-> MMC_SDRAM_CKE  | PC11 <-> MMC_SDRAM_D9    | PD3  <-> MMC_SDRAM_D11   |
          |                         |                          | PD4  <-> MMC_SDRAM_D12   |
          |                         |                          | PD5  <-> MMC_SDRAM_D13   |
          |                         |                          | PD6  <-> MMC_SDRAM_D14   |
          +-------------------------+--------------------------+--------------------------+
          | PE3  <-> MMC_SDRAM_D4   | PF0  <-> MMC_SDRAM_D7    | PG0  <-> MMC_SDRAM_D15   |
          | PE5  <-> MMC_SDRAM_D5   | PF2  <-> MMC_SDRAM_NCS   | PG9  <-> MMC_SDRAM_D9    |
          | PE6  <-> MMC_SDRAM_D6   | PF4  <-> MMC_SDRAM_NRAS  | PG12 <-> MMC_SDRAM_D0    |
          | PE8  <-> MMC_SDRAM_A4   | PF5  <-> MMC_SDRAM_NCAS  | PG13 <-> MMC_SDRAM_D1    |
          | PE9  <-> MMC_SDRAM_A5   | PF6  <-> MMC_SDRAM_NWE   | PG14 <-> MMC_SDRAM_D2    |
          | PE10 <-> MMC_SDRAM_A6   | PF10 <-> MMC_SDRAM_LDQM  | PG15 <-> MMC_SDRAM_D3    |
          | PE11 <-> MMC_SDRAM_A7   | PF11 <-> MMC_SDRAM_Bank  |                          |
          | PE12 <-> MMC_SDRAM_A8   | PF12 <-> MMC_SDRAM_A10   |                          |
          | PE13 <-> MMC_SDRAM_A9   | PF13 <-> MMC_SDRAM_A0    |                          |
          | PE14 <-> MMC_SDRAM_A5   | PF14 <-> MMC_SDRAM_A1    |                          |
          | PE15 <-> MMC_SDRAM_CLK  | PF15 <-> MMC_SDRAM_A2    |                          |
          +-------------------------+--------------------------+--------------------------+
          */

        GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
        GPIO_ConfigStruct.mode  = GPIO_MODE_AF_PP;

        GPIO_ConfigStruct.pin = GPIO_PIN_10 | GPIO_PIN_11;
        GPIO_Config(GPIOB, &GPIO_ConfigStruct);

        GPIO_ConfigStruct.pin = GPIO_PIN_10 | GPIO_PIN_11;
        GPIO_Config(GPIOC, &GPIO_ConfigStruct);

        GPIO_ConfigStruct.pin = GPIO_PIN_2 | GPIO_PIN_3 |
                         GPIO_PIN_4 | GPIO_PIN_5 |
                         GPIO_PIN_6;
        GPIO_Config(GPIOD, &GPIO_ConfigStruct);

        GPIO_ConfigStruct.pin = GPIO_PIN_3 | GPIO_PIN_5 |
                         GPIO_PIN_6 | GPIO_PIN_8 |
                         GPIO_PIN_9 | GPIO_PIN_10 |
                         GPIO_PIN_11 | GPIO_PIN_12 |
                         GPIO_PIN_13 | GPIO_PIN_15;
        GPIO_Config(GPIOE, &GPIO_ConfigStruct);

        GPIO_ConfigStruct.pin = GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_4 |
                         GPIO_PIN_5 | GPIO_PIN_6 |
                         GPIO_PIN_10 | GPIO_PIN_11 |
                         GPIO_PIN_12 | GPIO_PIN_13 |
                         GPIO_PIN_14 | GPIO_PIN_15;
        GPIO_Config(GPIOF, &GPIO_ConfigStruct);

        GPIO_ConfigStruct.pin = GPIO_PIN_0 | GPIO_PIN_9 |
                         GPIO_PIN_12 | GPIO_PIN_13 |
                         GPIO_PIN_14 | GPIO_PIN_15;
        GPIO_Config(GPIOG, &GPIO_ConfigStruct);
    }

    /*!
      * @brief       SDRAM DMC Config
      *
      * @param       None
      *
      * @retval      None
      *
      */
    static void SDRAM_DMC_ConfigStruct(void)
    {
        uint32_t SDRAM_Capacity;
        DMC_Config_T DMC_ConfigStruct;
        DMC_TimingConfig_T DMC_TimingConfigStruct;

        RCM_EnableAHBPeriphClock(RCM_SDRAM_PERIPH);

        DMC_TimingConfigStruct.latencyCAS = DMC_CAS_LATENCY_3;     //!< Configure CAS latency period
        DMC_TimingConfigStruct.tARP       = DMC_AUTO_REFRESH_10;   //!< Configure auto refresh period
        DMC_TimingConfigStruct.tRAS       = DMC_RAS_MINIMUM_5;     //!< Configure line activation and precharging minimum time
        DMC_TimingConfigStruct.tCMD       = DMC_ATA_CMD_7;         //!< Configure active to active period
        DMC_TimingConfigStruct.tRCD       = DMC_DELAY_TIME_2;      //!< Configure RAS To CAS delay Time
        DMC_TimingConfigStruct.tRP        = DMC_PRECHARGE_2;       //!< Configure precharge period
        DMC_TimingConfigStruct.tWR        = DMC_NEXT_PRECHARGE_2;  //!< Configure time between the Last Data and The Next Precharge for write
        DMC_TimingConfigStruct.tXSR       = 6;                     //!< Configure XSR0
        DMC_TimingConfigStruct.tRFP       = 0xC3;                  //!< Configure refresh Cycle

        DMC_ConfigStruct.bankWidth     = DMC_BANK_WIDTH_1;      //!< Configure bank address width
        DMC_ConfigStruct.clkPhase      = DMC_CLK_PHASE_REVERSE; //!< Configure clock phase
        DMC_ConfigStruct.rowWidth      = DMC_ROW_WIDTH_11;      //!< Configure row address width
        DMC_ConfigStruct.colWidth      = DMC_COL_WIDTH_8;       //!< Configure column address width
        DMC_ConfigStruct.memorySize    = DMC_MEMORY_SIZE_2MB;
        DMC_ConfigStruct.timing        = DMC_TimingConfigStruct;

        DMC_Config(&DMC_ConfigStruct);
        DMC_ConfigOpenBank(DMC_BANK_NUMBER_2);
        DMC_EnableAccelerateModule();

        DMC_Enable();

        /* SDRAM_Capacity = row * col * 16bit * bank (16bit == 2Bytes) */
        SDRAM_Capacity = (1 << (DMC_ConfigStruct.rowWidth + 1)) * (1 << (DMC_ConfigStruct.colWidth + 1)) * 2 * (1 << (DMC_ConfigStruct.bankWidth + 1));

        printf("This is an example of DMC SDRAM \r\n");
        printf("> Row Address Width    :%d bit\r\n", DMC_ConfigStruct.rowWidth + 1);
        printf("> Column Address Width :%d bit\r\n", DMC_ConfigStruct.colWidth + 1);
        printf("> Bank Address Width   :%d bit band addr\r\n", DMC_ConfigStruct.bankWidth + 1);
        printf("> capacity             :%d MByte\r\n\r\n", SDRAM_Capacity / 1024 / 1024);
    }

    /*!
      * @brief       SDRAM Write Word
      *
      * @param       address:the address to be programmed.
      *
      * @param       data: the data to be programmed.
      *
      * @retval      None
      *
      */
    void SDRAM_WriteWord(uint32_t address, uint32_t data)
    {
        *(__IOM uint32_t *)address = data;
    }

    /*!
      * @brief       SDRAM Write Half Word
      *
      * @param       address:the address to be programmed.
      *
      * @param       data: the data to be programmed.
      *
      * @retval      None
      *
      */
    void SDRAM_WriteHalfWord(uint32_t address, uint16_t data)
    {
        *(uint16_t *)address = (uint16_t)data;
    }

    /*!
      * @brief       SDRAM Write Byte
      *
      * @param       address:the address to be programmed.
      *
      * @param       data: the data to be programmed.
      *
      * @retval      None
      *
      */
    void SDRAM_WriteByte(uint32_t address, uint8_t data)
    {
        *(uint8_t *)address = data;
    }

    /*!
      * @brief       SDRAM Word Test
      *
      * @param       None
      *
      * @retval      i : W/R Err Count
      *
      */
    uint32_t SDRAM_Word_Test(void)
    {
        uint32_t Addr = 0;
        uint32_t i    = 0;

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x4)
        {
            SDRAM_WriteWord(Addr, (uint32_t)Addr);
        }

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x4)
        {
            if (*(__IO uint32_t *)(Addr) != (uint32_t)Addr)
            {
                i++;
            }
        }

        return (i);
    }

    /*!
      * @brief       SDRAM HalfWord Test
      *
      * @param       None
      *
      * @retval      i : W/R Err Count
      *
      */
    uint32_t SDRAM_HalfWord_Test(void)
    {
        uint32_t Addr = 0;
        uint32_t i    = 0;

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x2)
        {
            SDRAM_WriteHalfWord(Addr, (uint16_t)Addr);
        }

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x2)
        {
            if (*(__IO uint16_t *)(Addr) != (uint16_t)Addr)
            {
                i++;
            }
        }

        return (i);
    }

    /*!
      * @brief       SDRAM Byte Test
      *
      * @param       None
      *
      * @retval      i : W/R Err Count
      *
      */
    uint32_t SDRAM_Byte_Test(void)
    {
        uint32_t Addr = 0;
        uint32_t i    = 0;

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x1)
        {
            SDRAM_WriteByte(Addr, (uint8_t)Addr);
        }

        for (Addr = SDRAM_START_ADDR; Addr < SDRAM_END_ADDR; Addr += 0x1)
        {
            if (*(__IO uint8_t *)(Addr) != (uint8_t)Addr)
            {
                i++;
            }
        }

        return (i);
    }

    /*!
      * @brief       SDRAM Init
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void SDRAM_Init(void)
    {
        SDRAM_GPIO_ConfigStruct();
        SDRAM_DMC_ConfigStruct();

        printf("\r\n");
        printf("%s \r\n", MESSAGE0);
        printf("%s \r\n", MESSAGE1);
        printf("%s %d MHz\r\n", MESSAGE2, RCM_ReadSYSCLKFreq() / 1000000);

        printf("%s %d MHz\r\n", MESSAGE3, RCM_ReadSYSCLKFreq() / 1000000 / (RCM->CFG_B.SDRAMPSC + 1));

        /* SDRAM byte write/read test */
        Err.ByteCount = SDRAM_Byte_Test();
        printf("%s %d\r\n", MESSAGE4, Err.ByteCount);

        /* SDRAM halfword write/read test */
        Err.HalfWordCount = SDRAM_HalfWord_Test();
        printf("%s %d\r\n", MESSAGE5, Err.HalfWordCount);

        /* SDRAM word write/read test */
        Err.WordCount = SDRAM_Word_Test();
        printf("%s %d\r\n", MESSAGE6, Err.WordCount);

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

        /* The SDRAM test failed */
        if ((Err.ByteCount != 0) || (Err.HalfWordCount != 0) || ((Err.WordCount != 0)))
        {
            printf("The SDRAM test failed\r\n");
        }
        else
        {
            printf("The SDRAM test success\r\n");
        }
    }

    运行结果:
    forum.jpg forum.jpg


    • 通过硬件SPI接口与相应的GPIO端口实现TFT LCD的显示功能
    TFT LCD液晶显示屏实现了更直观的交互体验,通过硬件SPI接口和部分GPIO实现对TFT LCD的驱动显示,在TFT LCD屏上显示当前的日期时间、ADC电压换算值、按键事件等信息,具体代码如下所示:
    #define TFT_LCD_CS_H()  GPIO_WriteBitValue(GPIOA, GPIO_PIN_4, BIT_SET)
    #define TFT_LCD_CS_L()  GPIO_WriteBitValue(GPIOA, GPIO_PIN_4, BIT_RESET)

    #define TFT_LCD_DC_H()  GPIO_WriteBitValue(GPIOA, GPIO_PIN_6, BIT_SET)
    #define TFT_LCD_DC_L()  GPIO_WriteBitValue(GPIOA, GPIO_PIN_6, BIT_RESET)

    #define TFT_LCD_RES_H() GPIO_WriteBitValue(GPIOA, GPIO_PIN_1, BIT_SET)
    #define TFT_LCD_RES_L() GPIO_WriteBitValue(GPIOA, GPIO_PIN_1, BIT_RESET)

    #define TFT_LCD_BLK_H() GPIO_WriteBitValue(GPIOA, GPIO_PIN_8, BIT_SET)
    #define TFT_LCD_BLK_L() GPIO_WriteBitValue(GPIOA, GPIO_PIN_8, BIT_RESET)

    /*!
      * @brief       TFT LCD Init SPI1
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void TFT_LCD_InitSPI1(void)
    {
        GPIO_Config_T GPIO_ConfigStruct;
        SPI_Config_T  SPI_ConfigStruct;

        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);

        GPIO_ConfigStructInit(&GPIO_ConfigStruct);
        GPIO_ConfigStruct.pin   = GPIO_PIN_7 | GPIO_PIN_5;
        GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
        GPIO_ConfigStruct.mode  = GPIO_MODE_AF_PP;
        GPIO_Config(GPIOA, &GPIO_ConfigStruct);

        GPIO_ConfigStructInit(&GPIO_ConfigStruct);
        GPIO_ConfigStruct.pin   = GPIO_PIN_4;
        GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
        GPIO_ConfigStruct.mode  = GPIO_MODE_OUT_PP;
        GPIO_Config(GPIOA, &GPIO_ConfigStruct);

        TFT_LCD_CS_H();

        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SPI1);

        SPI_ConfigStructInit(&SPI_ConfigStruct);
        SPI_ConfigStruct.mode           = SPI_MODE_MASTER;
        SPI_ConfigStruct.length         = SPI_DATA_LENGTH_8B;
        SPI_ConfigStruct.phase          = SPI_CLKPHA_2EDGE;
        SPI_ConfigStruct.polarity       = SPI_CLKPOL_HIGH;
        SPI_ConfigStruct.nss            = SPI_NSS_SOFT;
        SPI_ConfigStruct.firstBit       = SPI_FIRSTBIT_MSB;
        SPI_ConfigStruct.direction      = SPI_DIRECTION_2LINES_FULLDUPLEX;
        SPI_ConfigStruct.baudrateDiv    = SPI_BAUDRATE_DIV_2;
        SPI_ConfigStruct.crcPolynomial  = 7;
        SPI_Config(SPI1, &SPI_ConfigStruct);

        SPI_Enable(SPI1);
    }

    /*!
      * @brief       LCD SPI sends a byte through the SPI
      *
      * @param       data: byte send
      *
      * @retval      The error code
      *
      */
    void TFT_LCD_SPI_ReadWriteByte(uint8_t Data)
    {
        while (RESET == SPI_I2S_ReadStatusFlag(SPI1, SPI_FLAG_TXBE))
        {
        }

        SPI_I2S_TxData(SPI1, Data);

        while (RESET != SPI_I2S_ReadStatusFlag(SPI1, SPI_FLAG_BSY))
        {
        }
    }

    /*!
      * @brief       TFT LCD Init GPIO
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void TFT_LCD_InitGPIO(void)
    {
        GPIO_Config_T GPIO_ConfigStruct;

        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);

        GPIO_ConfigStructInit(&GPIO_ConfigStruct);
        GPIO_ConfigStruct.pin   = GPIO_PIN_1 | GPIO_PIN_6 | GPIO_PIN_8;
        GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
        GPIO_ConfigStruct.mode  = GPIO_MODE_OUT_PP;
        GPIO_Config(GPIOA, &GPIO_ConfigStruct);

        TFT_LCD_DC_H();

        TFT_LCD_RES_H();
        TFT_LCD_BLK_H();
    }

    /*!
      * @brief       TFT LCD Write Byte
      *
      * @param       Data
      *
      * @retval      None
      *
      */
    void TFT_LCD_WriteByte(uint8_t Data)
    {
        TFT_LCD_DC_H();
        TFT_LCD_CS_L();
        TFT_LCD_SPI_ReadWriteByte(Data);
        TFT_LCD_CS_H();
    }

    /*!
      * @brief       TFT LCD Write Half-word
      *
      * @param       Data
      *
      * @retval      None
      *
      */
    void TFT_LCD_WriteHalfword(uint16_t Data)
    {
        TFT_LCD_DC_H();
        TFT_LCD_CS_L();
        TFT_LCD_SPI_ReadWriteByte(Data >> 8);
        TFT_LCD_SPI_ReadWriteByte(Data >> 0);
        TFT_LCD_CS_H();
    }

    /*!
      * @brief       TFT LCD Write Command
      *
      * @param       Data
      *
      * @retval      None
      *
      */
    void TFT_LCD_WriteCommand(uint8_t Data)
    {
        TFT_LCD_DC_L();
        TFT_LCD_CS_L();
        TFT_LCD_SPI_ReadWriteByte(Data);
        TFT_LCD_CS_H();
    }

    /*!
      * @brief       TFT LCD Set Cursor Address
      *
      * @param       StartX
      *
      * @param       StartY
      *
      * @param       EndX
      *
      * @param       EndY
      *
      * @retval      None
      *
      */
    void TFT_LCD_SetCursorAddress(uint16_t StartX, uint16_t StartY, uint16_t EndX, uint16_t EndY)
    {
        TFT_LCD_WriteCommand(0x2A);
        TFT_LCD_WriteHalfword(StartX);
        TFT_LCD_WriteHalfword(EndX);

        TFT_LCD_WriteCommand(0x2B);
        TFT_LCD_WriteHalfword(StartY);
        TFT_LCD_WriteHalfword(EndY);

        TFT_LCD_WriteCommand(0x2C);
    }

    /*!
      * @brief       TFT LCD Draw Point
      *
      * @param       x: Row Lable
      *
      * @param       y: Column Lable
      *
      * @param       Color: Color To Be Filled
      *
      * @retval      None
      *
      */
    void TFT_LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t Color)
    {
        TFT_LCD_SetCursorAddress(x, y, x, y);
        TFT_LCD_WriteHalfword(Color);
    }

    /*!
      * @brief       LCD clear content
      *
      * @param       StartX
      *
      * @param       StartY
      *
      * @param       EndY
      *
      * @param       EndY
      *
      * @param       Color
      *
      * @retval      None
      *
      */
    void TFT_LCD_Clear(uint16_t StartX, uint16_t StartY, uint16_t EndX, uint16_t EndY, uint16_t Color)
    {
        TFT_LCD_SetCursorAddress(StartX, StartY, EndX - 1, EndY - 1);

        for (uint16_t y = StartY; y < EndY; y++)
        {
            for (uint16_t x = StartX; x < EndX; x++)
            {
                TFT_LCD_WriteHalfword(Color);
            }
        }
    }

    /*!
      * @brief       TFT LCD Display Character
      *
      * @param       x: Row Lable
      *
      * @param       y: Column Lable
      *
      * @param       ForeColor: Foreground Color
      *
      * @param       BackColor: Background Color
      *
      * @param       FontSize: Font Size
      *
      * @param       Mode: Superposition Mode
      *
      * @retval      None
      *
      */
    void LCD_DisplayChar(uint16_t x, uint16_t y, char ch, uint16_t ForeColor, uint16_t BackColor, uint8_t FontSize, uint8_t Mode)
    {
        const uint8_t *FontTable;
        uint8_t        TableSize = 0;

        uint8_t FontHeight = FontSize;
        uint8_t FontWidth  = FontSize / 2;

        uint16_t StartX    = x;

        switch (FontSize)
        {
            case 12:
                FontTable = &ASCII_FONT_1206[ch - 0x20][0];
                TableSize = 12;
                break;

            case 16:
                FontTable = &ASCII_FONT_1608[ch - 0x20][0];
                TableSize = 16;
                break;

            case 24:
                FontTable = &ASCII_FONT_2412[ch - 0x20][0];
                TableSize = 48;
                break;

            case 32:
                FontTable = &ASCII_FONT_3216[ch - 0x20][0];
                TableSize = 64;
                break;

            default:
                break;
        }

        if (0 == Mode)
        {
            TFT_LCD_SetCursorAddress(x, y, x + FontWidth - 1, y + FontHeight - 1);

            for (uint8_t i = 0; i < TableSize; i++)
            {
                for (uint8_t j = 0; j < 8; j++)
                {
                    if (FontTable & (0x01 << j))
                    {
                        TFT_LCD_WriteHalfword(ForeColor);
                    }
                    else
                    {
                        TFT_LCD_WriteHalfword(BackColor);
                    }

                    x++;

                    if (x % FontWidth == 0)
                    {
                        x = 0;
                        break;
                    }
                }
            }
        }
        else
        {
            for (uint8_t i = 0; i < TableSize; i++)
            {
                for (uint8_t j = 0; j < 8; j++)
                {
                    if (FontTable & (0x01 << j))
                    {
                        TFT_LCD_DrawPoint(x, y, ForeColor);
                    }

                    x++;

                    if ((x - StartX) == FontWidth)
                    {
                        x = StartX;
                        y = y + 01;
                        break;
                    }
                }
            }
        }
    }

    /*!
      * @brief       TFT LCD Display String
      *
      * @param       x: Row Lable
      *
      * @param       y: Column Lable
      *
      * @param       ForeColor: Foreground Color
      *
      * @param       BackColor: Background Color
      *
      * @param       str: Point To String Buffer
      *
      * @param       FontSize: Font Size
      *
      * @param       Mode: Superposition Mode
      *
      * @retval      None
      *
      */
    void LCD_DisplayString(uint16_t x, uint16_t y, const char *str, uint16_t ForeColor, uint16_t BackColor, uint8_t FontSize, uint8_t Mode)
    {
        while (*str != '\0')
        {
            LCD_DisplayChar(x, y, *str, ForeColor, BackColor, FontSize, Mode);

            switch (FontSize)
            {
                case 12:
                    x += 6;
                    break;

                case 16:
                    x += 8;
                    break;

                case 24:
                    x += 12;
                    break;

                case 32:
                    x += 16;
                    break;

                default:
                    break;
            }

            if(x >= 240)
            {
                x  = 0;
                y += FontSize;
            }

            str++;
        }
    }

    /*!
      * @brief       TFT LCD DelayMS
      *
      * @param       Tick
      *
      * @retval      None
      *
      */
    void TFT_LCD_DelayMS(uint32_t Tick)
    {
        extern volatile uint32_t SysTick_Tick;

        uint32_t Start = SysTick_Tick;

        if ((UINT32_MAX - Start) >= Tick)
        {
            while ((SysTick_Tick - Start) != Tick)
            {
            }
        }
        else
        {
            while ((SysTick_Tick + (UINT32_MAX - Start)) != Tick)
            {
            }
        }
    }

    /*!
      * @brief       TFT LCD Configure
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void TFT_LCD_Configure(void)
    {
        TFT_LCD_WriteCommand(0x11);
        TFT_LCD_DelayMS(120);

        TFT_LCD_WriteCommand(0xCF);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0xD9);
        TFT_LCD_WriteByte(0X30);

        TFT_LCD_WriteCommand(0xED);
        TFT_LCD_WriteByte(0x64);
        TFT_LCD_WriteByte(0x03);
        TFT_LCD_WriteByte(0X12);
        TFT_LCD_WriteByte(0X81);

        TFT_LCD_WriteCommand(0xE8);
        TFT_LCD_WriteByte(0x85);
        TFT_LCD_WriteByte(0x10);
        TFT_LCD_WriteByte(0x78);

        TFT_LCD_WriteCommand(0xCB);
        TFT_LCD_WriteByte(0x39);
        TFT_LCD_WriteByte(0x2C);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0x34);
        TFT_LCD_WriteByte(0x02);

        TFT_LCD_WriteCommand(0xF7);
        TFT_LCD_WriteByte(0x20);

        TFT_LCD_WriteCommand(0xEA);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0x00);

        TFT_LCD_WriteCommand(0xC0);
        TFT_LCD_WriteByte(0x21);

        TFT_LCD_WriteCommand(0xC1);
        TFT_LCD_WriteByte(0x12);

        TFT_LCD_WriteCommand(0xC5);
        TFT_LCD_WriteByte(0x32);
        TFT_LCD_WriteByte(0x3C);

        TFT_LCD_WriteCommand(0xC7);
        TFT_LCD_WriteByte(0XC1);

        TFT_LCD_WriteCommand(0x36);
        TFT_LCD_WriteByte(0xC8);

        TFT_LCD_WriteCommand(0x3A);
        TFT_LCD_WriteByte(0x55);

        TFT_LCD_WriteCommand(0xB1);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0x18);

        TFT_LCD_WriteCommand(0xB6);
        TFT_LCD_WriteByte(0x0A);
        TFT_LCD_WriteByte(0xA2);

        TFT_LCD_WriteCommand(0xF2);
        TFT_LCD_WriteByte(0x00);

        TFT_LCD_WriteCommand(0x26);
        TFT_LCD_WriteByte(0x01);

        TFT_LCD_WriteCommand(0xE0);
        TFT_LCD_WriteByte(0x0F);
        TFT_LCD_WriteByte(0x20);
        TFT_LCD_WriteByte(0x1E);
        TFT_LCD_WriteByte(0x09);
        TFT_LCD_WriteByte(0x12);
        TFT_LCD_WriteByte(0x0B);
        TFT_LCD_WriteByte(0x50);
        TFT_LCD_WriteByte(0XBA);
        TFT_LCD_WriteByte(0x44);
        TFT_LCD_WriteByte(0x09);
        TFT_LCD_WriteByte(0x14);
        TFT_LCD_WriteByte(0x05);
        TFT_LCD_WriteByte(0x23);
        TFT_LCD_WriteByte(0x21);
        TFT_LCD_WriteByte(0x00);

        TFT_LCD_WriteCommand(0XE1);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0x19);
        TFT_LCD_WriteByte(0x19);
        TFT_LCD_WriteByte(0x00);
        TFT_LCD_WriteByte(0x12);
        TFT_LCD_WriteByte(0x07);
        TFT_LCD_WriteByte(0x2D);
        TFT_LCD_WriteByte(0x28);
        TFT_LCD_WriteByte(0x3F);
        TFT_LCD_WriteByte(0x02);
        TFT_LCD_WriteByte(0x0A);
        TFT_LCD_WriteByte(0x08);
        TFT_LCD_WriteByte(0x25);
        TFT_LCD_WriteByte(0x2D);
        TFT_LCD_WriteByte(0x0F);

        TFT_LCD_WriteCommand(0x29);
    }

    /*!
      * @brief       TFT LCD Init
      *
      * @param       None
      *
      * @retval      None
      *
      */
    void TFT_LCD_Init(void)
    {
        TFT_LCD_InitSPI1();

        TFT_LCD_InitGPIO();

        TFT_LCD_RES_L();
        TFT_LCD_DelayMS(99);
        TFT_LCD_RES_H();
        TFT_LCD_DelayMS(99);

        TFT_LCD_BLK_H();
        TFT_LCD_DelayMS(99);

        TFT_LCD_Configure();

        TFT_LCD_Clear(0, 0, 240, 320, BACKCOLOR);

        LCD_DisplayString(0, 10, "Geehy", FORECOLOR, BACKCOLOR, 32, 1);

        LCD_DisplayString(0, 50, "APM32E103ZE EVAL V1.0", FORECOLOR, BACKCOLOR, 16, 1);
    }

    运行效果:
    1.jpg


    • 软件工程源代码
    Project.zip (391.79 KB, 下载次数: 5)
    举报
    您需要登录后才可以评论 登录 立即注册
    全部回复 0
    暂无评论,快来抢沙发吧