天天看點

學習STM32程式設計——參數持久化存儲應用程式設計

作者:華26104121

關鍵代碼:

diskio.c

DSTATUS disk_status (
BYTE pdrv  /*  磁盤的驅動器編号 */
)
{
    DSTATUS stat = STA_NOINIT;
    switch (pdrv) {
    /*  解析磁盤驅動器編号 */
        case DEV_SDIO_SD :
            stat &= ~STA_NOINIT;
            return stat;
        case DEV_SPI_FLASH :
            return stat;
    }
    return STA_NOINIT;
}
/*-----------------------------------*/
/* 初始化磁盤 */
/*-----------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv  /*  磁盤的驅動器編号 */
)
{
    DSTATUS stat = STA_NOINIT;
    switch (pdrv) {
        case DEV_SDIO_SD :
            if( SD_Init() == SD_OK )
            {
                stat &= ~STA_NOINIT;
                return stat;
            }
        case DEV_SPI_FLASH :
            return stat;
    }
    return STA_NOINIT;
}
/*------------------------------------*/
/* 讀磁盤扇區 */
/*------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /*  磁盤的驅動器編号 */
BYTE *buff, /*  存放讀取資料的緩存區 */
DWORD sector,  /* LBA 模式下的起始扇區 */
UINT count /*  要讀取的扇區數 */
)
{
    DRESULT res = RES_PARERR;
    SD_Error SD_status;
    switch (pdrv) {
        case DEV_SDIO_SD :
            /*  從位址 0 開始讀取多個位元組資料 */
            SD_status = SD_ReadMultiBlocks(buff, sector*SDCardInfo.CardBlockSize,
            SDCardInfo.CardBlockSize, count);
            if(SD_status != SD_OK)
                return res = RES_ERROR;
            /*  判斷是否傳輸已完畢 */
            SD_status = SD_WaitReadOperation();
            if(SD_status != SD_OK)
                return res = RES_ERROR;
            while(SD_GetStatus() != SD_TRANSFER_OK);
            res = RES_OK;
            return res;
        case DEV_SPI_FLASH :
            res = RES_OK;
            return res;
    }
    return RES_PARERR;
}
/*------------------------------------------*/
/* 寫入磁盤扇區 */
/*------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /*  磁盤的驅動器編号 */
const BYTE *buff,  /*  要寫入的資料 */
DWORD sector,  /* LBA 模式下的起始扇區 */
UINT count /*  要寫入的扇區數 */
)
{
    DRESULT res = RES_PARERR;
    SD_Error SD_status;
    if (!count) {
        return RES_PARERR;  /*  指明參數錯誤 */
    }
    switch (pdrv) {
        case DEV_SDIO_SD :
            /*  向位址 0 寫入多個位元組 */
            SD_status = SD_WriteMultiBlocks((uint8_t *)buff, sector * \
            SDCardInfo.CardBlockSize,SDCardInfo.CardBlockSize, count);
            /*  判斷是否傳輸已經結束 */
            if(SD_status != SD_OK)
                return res = RES_ERROR;
            SD_status = SD_WaitWriteOperation();
            if(SD_status != SD_OK)
                return res = RES_ERROR;
            while(SD_GetStatus() != SD_TRANSFER_OK) ;
            res = RES_OK;
            return res;
        case DEV_SPI_FLASH :
            res = RES_OK;
            return res;
    }
    return RES_PARERR;
}
#endif
/*------------------------------------------*/
/* 磁盤控制的其他功能 */
/*------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /*  磁盤驅動器的編号 (0..) */
BYTE cmd,  /*  控制碼 */
void *buff /*  存放收發控制資料的緩存 */
)
{
    DRESULT res = RES_PARERR;
    switch (pdrv)
    {
        case DEV_SDIO_SD :
            switch (cmd)
            {
            case CTRL_SYNC:
                res = RES_OK;
                break;
            /*  擷取扇區數量 */
            case GET_SECTOR_COUNT:
                *(DWORD *)buff = SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize;
                res = RES_OK;
                break;
            /*  擷取扇區大小 */
            case GET_SECTOR_SIZE :
                *(WORD * )buff = SDCardInfo.CardBlockSize;
                res = RES_OK;
                break;
            /*  擷取塊的大小 */
            case GET_BLOCK_SIZE :
                *(DWORD * )buff = 1;
                res = RES_OK;
                break;
            default:
                res = RES_PARERR;
                break;
            }
            break;
        case DEV_SPI_FLASH :
        /*  在這裡處理 SPIFlash 操作相關的指令 */
            break;
    }
    return res;
}
__weak uint32_t get_fattime(void)
{
    uint16_t year;
    uint8_t month,day,hour,minute,second;
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_DateTypeDef RTC_DateStructure;
    /*  擷取日期和時間 */
    RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
    RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);
    /*  日期和時間指派 */
    year = RTC_DateStructure.RTC_Year + 2000;
    month = RTC_DateStructure.RTC_Month;
    day = RTC_DateStructure.RTC_Date;
    hour = RTC_TimeStructure.RTC_Hours;
    minute = RTC_TimeStructure.RTC_Minutes;
    second = RTC_TimeStructure.RTC_Seconds;
    /*  傳回目前時間戳 */
    return ((uint32_t)(year - 1980) << 25) /*  年 */
    | ((uint32_t)month << 21)  /*  月 */
    | ((uint32_t)day << 16) /*  日 */
    | ((uint32_t)hour << 11) /*  小時 */
    | ((uint32_t)minute << 5)  /*  分鐘 */
    | ((uint32_t)second >> 1);  /*  秒 */
}           

bsp_rtc.c

/**
* @brief RTC 配置:選擇 RTC 時鐘源,設定 RTC_CLK 的分頻系數
* @param 0:  時鐘源選擇 LSI , 1:  時鐘源選擇 LSE
* @retval None
*/
void RTC_CLK_Config(uint8_t RTC_Clock_Type)
{
    RTC_InitTypeDef RTC_InitStructure;
    /*  使能 PWR  時鐘 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    /*  使能 RTC 、 RTC 備份寄存器和備份 SRAM 的通路 */
    PWR_BackupAccessCmd(ENABLE);
    if(RTC_Clock_Type == 0)
    { 
        /*  使能 LSI */
        RCC_LSICmd(ENABLE);
        /*  等待 LSI 穩定 */
        while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
        /*  選擇 LSI 作為 RTC 的時鐘源 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    }
    else if(RTC_Clock_Type == 1)
    {
        /*  使能 LSE */
        RCC_LSEConfig(RCC_LSE_ON);
        /*  等待 LSE 穩定 */
        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
        /*  選擇 LSE 作為 RTC 的時鐘源 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    }
    RCC_RTCCLKCmd(ENABLE); // 使能 RTC 時鐘
    RTC_WaitForSynchro();  // 等待 RTC 的 APB 寄存器同步
    /*  設定異步預分頻器的值 */
    RTC_InitStructure.RTC_AsynchPrediv = ASYNCH_PREDIV;
    /*  設定同步預分頻器的值 */
    RTC_InitStructure.RTC_SynchPrediv = SYNCH_PREDIV;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    /*  用 RTC_InitStructure 的内容初始化 RTC 寄存器 */
    if(RTC_Init(&RTC_InitStructure) == ERROR)
    {
        printf("\n\r RTC 時鐘初始化失敗 \r\n");
    }
    else
    {
        printf("\n\r RTC 時鐘初始化成功 \r\n");
    }
}
/**
* @brief 設定日期和時間
* @param None
* @retval None
*/
void RTC_Set_DateTime(void)
{
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_DateTypeDef RTC_DateStructure;
    /*  初始化日期 */
    RTC_DateStructure.RTC_WeekDay = WEEKDAY;
    RTC_DateStructure.RTC_Date = DATE;
    RTC_DateStructure.RTC_Month = MONTH;
    RTC_DateStructure.RTC_Year = YEAR;
    RTC_SetDate(RTC_Format_BINorBCD, &RTC_DateStructure);
    /*  初始化時間 */
    RTC_TimeStructure.RTC_H12 = RTC_H12_AMorPM;
    RTC_TimeStructure.RTC_Hours = HOURS;
    RTC_TimeStructure.RTC_Minutes = MINUTES;
    RTC_TimeStructure.RTC_Seconds = SECONDS;
    RTC_SetTime(RTC_Format_BINorBCD, &RTC_TimeStructure);
    /*  往備份域寄存器 0 寫入一個值 */
    RTC_WriteBackupRegister(RTC_BKP_DR0, 0x5F5F);
}
/**
* @brief 擷取目前日期和時間
* @param None
* @retval None
*/
static void RTC_Get_DateTime(void)
{
    RTC_GetTime(RTC_Format_BIN, &myRTC_TimeStructure);
    RTC_GetDate(RTC_Format_BIN, &myRTC_DateStructure);
}
/*  以下函數用于擷取目前的“年 / 月 / 日 / 星期 / 小時 / 分鐘 / 秒”值 */
uint8_t RTC_Get_Year(void)
{
    RTC_Get_DateTime();
    return myRTC_DateStructure.RTC_Year;
}
uint8_t RTC_Get_Month(void)
{
    RTC_Get_DateTime();
    return myRTC_DateStructure.RTC_Month;
}
uint8_t RTC_Get_Date(void)
{
    RTC_Get_DateTime();
    return myRTC_DateStructure.RTC_Date;
}
uint8_t RTC_Get_WeekDay(void)
{
    RTC_Get_DateTime();
    return myRTC_DateStructure.RTC_WeekDay;
}
uint8_t RTC_Get_Hour(void)
{
    RTC_Get_DateTime();
    return myRTC_TimeStructure.RTC_Hours;
}
uint8_t RTC_Get_Minute(void)
{
    RTC_Get_DateTime();
    return myRTC_TimeStructure.RTC_Minutes;
}
uint8_t RTC_Get_Second(void)
{
    RTC_Get_DateTime();
    return myRTC_TimeStructure.RTC_Seconds;
}           

main.c

/**
* @brief 判斷目前時間是否是整點時間
* @param None
* @retval None
*/
bool Check_Certain_Hour(void)
{
    uint8_t hour,minute,second;
    RTC_TimeTypeDef RTC_TimeStructure;
    RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);
    hour = RTC_TimeStructure.RTC_Hours;
    minute = RTC_TimeStructure.RTC_Minutes;
    second = RTC_TimeStructure.RTC_Seconds;
    if(minute == 0 && second == 0)
    {
        if(hour != currentHour)
        {
            currentHour = hour;
            return true;
        }
    }
    return false;
}
/**
* @brief 存儲時間戳與環境參數函數
* @param None
* @retval None
*/
void Save_Data(void)
{
    uint16_t year;
    uint8_t month,day,hour,minute,second;
    /*  在 SD 存儲卡挂載檔案系統 */
    res = f_mount(&sysFs,"3:",1);
    if(res == FR_NO_FILESYSTEM)
    {
        printf(">>> No file system, formatting...\r\n");
        res = f_mkfs("3:", FM_FAT32,  Buff, sizeof(Buff));
        if(res == FR_OK)
        {
            printf(">>> SD memory card is successfully formatted.\r\n");
            res = f_mount(NULL,"3:",1); // 格式化後,先取消挂載
            res = f_mount(&sysFs,"3:",1);  // 重新挂載
        }
        else
        {
        printf(">>> Format failed. (%d)\r\n",res);
        while(1);
        }
    }
    else if(res != FR_OK)
    {
        printf(">>> Mount FS failed. (%d)\r\n",res); // 給出錯誤提示和錯誤類型
        while(1);
    }
    else if(res == FR_OK)
    {
        printf(">>> Mount FS success, you can operate read write test.\r\n");
    } 
    /*  采集環境參數 */
    bh1750Light = BH1750_Measure(); // 讀取 BH1750 的光照強度值
    DHT11_Read_Data(&temperature,&humidity);  // 讀取 DHT11 的溫濕度值
    /*  獲得目前日期和時間 */
    year = RTC_Get_Year() + 2000;  // “年份”值需要加 2000
    month = RTC_Get_Month();
    day = RTC_Get_Date();
    hour = RTC_Get_Hour();
    minute = RTC_Get_Minute();
    /*  将各資料組合成字元串 */
    sprintf(strFinal,"%d;%0.2d-%0.2d;%0.2d:00;%d;%d;%d\r\n",year,month,day,\
    hour,temperature,humidity,bh1750Light);
    /*  打開檔案,如果檔案不存在則建立它 */
    res = f_open(&fil, "sd:/Data.txt", FA_OPEN_ALWAYS | FA_WRITE );
    /*  檔案讀寫指針定位到最後 */
    f_lseek(&fil, f_size(&fil));
    if (res == FR_OK)
    {
        printf(">>> Open/Create file(.txt) success, writting...\r\n");
        /*  将指定存儲區内容寫入檔案内 */
        res=f_write(&fil,strFinal,strlen(strFinal),&fnum);
        if(res==FR_OK)
        {
            printf(">>>  檔案寫入成功,共寫入位元組資料: %d\r\n",fnum);
            printf(">>>  此次寫入的資料是 :\r\n%s\r\n",strFinal);
        }
        else
        {
            printf(">>>  檔案寫入失敗 :(%d)\n",res);
        }
        /*  不再讀寫,關閉檔案 */
        f_close(&fil);
    }
    else
    {
        printf(">>> Open/Create file(.txt) failed.\r\n");
    }
}
int main(void)
{
    delay_init(168); // 延時函數初始化
    LED_Init(); //LED 端口初始化
    Key_Init(); // 按鍵初始化
    EXTIx_Init();  // 外部中斷初始化
    USART1_Init(115200);  //USART1 初始化
    IIC_Init(); //IIC 總線初始化
    BH1750_Init(); //BH1750 初始化
    RTC_CLK_Config(1); //RTC 配置,時鐘源選擇 LSE
    SDIO_NVIC_Configuration(); //SDIO 中斷和 DMA 中斷 NVIC 初始化
    while(DHT11_Init()) //DHT11 初始化
    {
        printf("DHT11 Init Error!\r\n");
        delay_ms(500);
    }
    printf("DHT11 Init Success!\r\n");
    /*  若備份區域讀取的值不符 */
    if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x5F5F)
    {
        RTC_Set_DateTime(); // 重新設定時間和日期
    }
    else
    {
        printf("\r\n  不需要重新配置 RTC....\r\n");
        /*  使能 PWR  時鐘 */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
        /* PWR_CR:DBF 置 1 ,使能 RTC 、 RTC 備份寄存器和備份 SRAM 的通路 */
        PWR_BackupAccessCmd(ENABLE);
        /*  等待 RTC APB  寄存器同步 */
        RTC_WaitForSynchro();
    }
    currentHour = RTC_Get_Hour();  // 首次擷取目前小時值
    printf("System Started!\r\n");
    while(1)
    {
    /*  左鍵按下, SDIO 基本讀寫 SD 存儲卡測試 */
        if(keyValue == KEY_L_PRESS)
        {
            SD_Test();
            keyValue = 0;
        }
        /*  如果目前為整點 */
        if(Check_Certain_Hour())
        {
            printf(" 過了一個小時 \r\n");
            Save_Data();// 存儲時間戳和環境參數至 SD 存儲卡
        }
    }
}           

繼續閱讀