#include "gd32f4xx_gpio.h"
#include "gd32f4xx_rcu.h"
#include "gd32f4xx_sdio.h"
#include "gd32f4xx_misc.h"
#include "Serial.h"
#include "sdcard.h"
#include "Delay.h"
#include "ff.h"
#include <string.h>
#include <stdio.h>
uint32_t SD_Get_RCA(void) {
//发送 CMD3(请求分配 RCA)
sdio_command_response_config(3, 0, SDIO_RESPONSETYPE_SHORT);
// uint32_t timeout = 1000;
// while (!sdio_flag_get(SDIO_FLAG_CMDRECV)) {
// if (timeout-- == 0) {
// return 0;
// }
// }
sdio_flag_clear(SDIO_FLAG_CMDRECV);
//从 RESP1 寄存器提取 RCA(高16位)
uint32_t RCA = (sdio_response_get(SDIO_RESPONSE0) >> 16);
return RCA;
}
void TF_Init()
{
uint32_t RCA=SD_Get_RCA();
rcu_periph_clock_enable(RCU_SDIO);
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC,GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO_PIN_9);
gpio_output_options_set(GPIOC,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9);
sdio_clock_config(SDIO_SDIOCLKEDGE_RISING,SDIO_CLOCKBYPASS_DISABLE,SDIO_CLOCKPWRSAVE_DISABLE,256);
sdio_bus_mode_set(SDIO_BUSMODE_4BIT);
sdio_clock_enable();
sdio_power_state_set(SDIO_POWER_ON);
Delay_ms(2);
// sdio_wait_type_set();
sdio_command_response_config(0,0,SDIO_RESPONSETYPE_NO); //发送CMD0,复位卡
while(sdio_flag_get(SDIO_FLAG_CMDSEND)==SET);
sdio_command_response_config(8,0x1AA,SDIO_RESPONSETYPE_SHORT); //发送CMD8,检查电压支持
uint32_t response = sdio_response_get(SDIO_RESP0);
sdio_command_response_config(55,RCA<<16,SDIO_RESPONSETYPE_SHORT); //发送CMD55,下次命令时特定应用命令
sdio_command_response_config(41,(1UL << 30) | 0x00FF8000,SDIO_RESPONSETYPE_LONG);
while((response&0x80000000)==0);
sdio_csm_enable();
sdio_dsm_enable();
sdio_command_response_config(2,0,SDIO_RESPONSETYPE_LONG);
sdio_command_response_config(7,RCA,SDIO_RESPONSETYPE_SHORT); //发送CMD7,选择卡
sdio_command_response_config(16,512,SDIO_RESPONSETYPE_SHORT);
}
void TF_WriteData(uint8_t *data,uint32_t Len,uint32_t timeout,uint32_t WritAddr)
{
uint32_t RCA=SD_Get_RCA();
sdio_command_response_config(24,WritAddr,SDIO_RESPONSETYPE_SHORT); //CMD24单块写,CMD25多块写
sdio_wait_type_set(SDIO_WAITTYPE_NO);
while(sdio_flag_get(SDIO_FLAG_CMDRECV));
sdio_flag_clear(SDIO_FLAG_CMDRECV);
sdio_data_config(timeout,Len,SDIO_DATABLOCKSIZE_512BYTES);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK,SDIO_TRANSDIRECTION_TOCARD);
sdio_dma_disable();
sdio_command_response_config(13,RCA<<16,SDIO_RESPONSETYPE_SHORT);
for(uint16_t i=0;i<128;i++)
{
sdio_data_write(*(uint32_t*)data);
data+=4;
}
while(sdio_flag_get(SDIO_FLAG_DTEND));
sdio_flag_clear(SDIO_FLAG_DTEND);
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(SDIO_IRQn,2,2);
sdio_interrupt_enable(SDIO_INT_DTCRCERR);
sdio_interrupt_enable(SDIO_INT_FLAG_DTEND);
}
uint32_t TF_ReadData(uint8_t *buffer,uint32_t timeout)
{
uint32_t RCA=SD_Get_RCA();
sdio_command_response_config(17,RCA,SDIO_RESPONSETYPE_SHORT); //发送CMD17,读取单个块
sdio_data_config(timeout,512,SDIO_DATABLOCKSIZE_512BYTES);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK,SDIO_TRANSDIRECTION_TOSDIO);
sdio_dma_disable(); //禁用DMA,使用轮询
while (sdio_flag_get(SDIO_FLAG_RXDTVAL)==SET) //等待数据可用
for(uint16_t i=0;i<128;i++)
{
buffer[i]=sdio_data_read();
}
while (sdio_flag_get(SDIO_FLAG_DTEND)==SET) //等待数据可用
sdio_flag_clear(SDIO_FLAG_DTEND);
return *buffer;
}
void SDIO_IRQHandler()
{
if(sdio_interrupt_flag_get(SDIO_INT_FLAG_DTCRCERR)==SET)
{
sdio_command_response_config(12,0,SDIO_RESPONSETYPE_SHORT);
}
sdio_interrupt_flag_clear(SDIO_INT_FLAG_DTCRCERR);
if(sdio_interrupt_flag_get(SDIO_INT_FLAG_DTEND)==SET)
{
TF_Init();
}
sdio_interrupt_flag_clear(SDIO_INT_FLAG_DTEND);
}
#define CONFIG_FILE "config.ini"
#define FLASH_RATIO_ADDR 0x0000 // 变比存储地址
#define FLASH_LIMIT_ADDR 0x0004 // 阈值存储地址
FATFS fs; // FatFs文件系统对象
FIL fil; // 文件对象
FRESULT fr; // 文件操作结果
// 解析配置文件
int parse_config(const char* buffer, float* ratio, float* limit) {
if (buffer == NULL || ratio == NULL || limit == NULL)
return 0;
char *p = (char*)buffer;
*ratio = 0.0f;
*limit = 0.0f;
int found = 0;
// 查找Ratio部分
while ((p = strstr(p, "[Ratio]")) != NULL) {
p += strlen("[Ratio]");
char *ch0 = strstr(p, "Ch0");
if (ch0 && sscanf(ch0, "Ch0 = %f", ratio) == 1) {
found++;
break;
}
}
p = (char*)buffer;
// 查找Limit部分
while ((p = strstr(p, "[Limit]")) != NULL) {
p += strlen("[Limit]");
char *ch0 = strstr(p, "Ch0");
if (ch0 && sscanf(ch0, "Ch0 = %f", limit) == 1) {
found++;
break;
}
}
return (found == 2);
}
sd_error_enum sd_init_status = SD_ERROR; // SD卡初始化状态
void update_config_from_sd(void) {
FIL config_file;
UINT bytes_read;
char buffer[256];
float ratio = 0.0f, limit = 0.0f;
// SD卡重新初始化
if(sd_init_status != SD_OK) {
printf("Reinitializing SD card...\r\n");
sd_init_status = sd_init();
if(sd_init_status != SD_OK) {
printf("SD init failed: %d\r\n", sd_init_status);
return;
}
}
// 挂载文件系统(带超时)
FRESULT fr;
uint32_t mount_timeout = 5000;
do {
fr = f_mount(0,&fs); // 挂载到根目录
if(fr == FR_OK) break;
delay_1ms(1);
} while(mount_timeout-- > 0);
if(fr != FR_OK) {
printf("Mount error: %d\r\n", fr);
return;
}
printf("Filesystem mounted\r\n");
// 检查文件是否存在 - 使用绝对路径
FILINFO fno;
fr = f_stat("config.ini", &fno); // 关键修复:添加根目录前缀
if(fr != FR_OK) {
printf("config.ini not found! Error: %d\r\n", fr);
f_mount(0, NULL);
return;
}
// 打开文件
f_mkdir("/"); // 确保根目录存在
fr = f_open(&config_file, "config.ini", FA_READ); // 使用绝对路径
if(fr != FR_OK) {
printf("File open error: %d\r\n", fr);
f_mount(0, NULL);
return;
}
// 读取文件内容
fr = f_read(&config_file, buffer, sizeof(buffer)-1, &bytes_read);
if(fr != FR_OK || bytes_read == 0) {
printf("Read error: %d, Bytes: %d\r\n", fr, bytes_read);
f_close(&config_file);
f_mount(0, NULL);
return;
}
buffer[bytes_read] = '\0';
f_close(&config_file);
printf("File content:\r\n%s\r\n", buffer); // 打印文件内容
// 解析配置
if(parse_config(buffer, &ratio, &limit)) {
printf("Parsed: Ratio=%.2f, Limit=%.2f\r\n", ratio, limit);
// 保存到FLASH
spi_flash_sector_erase(FLASH_RATIO_ADDR);
spi_flash_buffer_write((uint8_t*)&ratio, FLASH_RATIO_ADDR, sizeof(ratio));
spi_flash_sector_erase(FLASH_LIMIT_ADDR);
spi_flash_buffer_write((uint8_t*)&limit, FLASH_LIMIT_ADDR, sizeof(limit));
} else {
printf("Config parse failed\r\n");
}
// 卸载文件系统
f_mount(0, NULL);
printf("Config update complete\r\n");
}
// 命令处理函数
void process_command(const char* cmd) {
if (strcmp(cmd, "conf") == 0) {
USART0_SendData((uint16_t*)"Updating config...\r\n", 20);
update_config_from_sd();
}
else if (strcmp(cmd, "help") == 0) {
USART0_SendData((uint16_t*)"Available commands:\r\n", 21);
USART0_SendData((uint16_t*)" conf - Update config from SD card\r\n", 36);
USART0_SendData((uint16_t*)" help - Show this help\r\n", 25);
}
else {
char unknown_msg[64];
sprintf(unknown_msg, "Unknown command: %s\r\n", cmd);
USART0_SendData((uint16_t*)unknown_msg, strlen(unknown_msg));
USART0_SendData((uint16_t*)"Type 'help' for available commands\r\n", 36);
}
}
FATFS fs;
FIL current_log_file, current_sample_file, current_overlimit_file, current_hidedata_file;
uint8_t log_file_open = 0, sample_file_open = 0, overlimit_file_open = 0, hidedata_file_open = 0;
uint32_t log_id = 0;
// 辅助函数:获取日期时间字符串
void get_datetime_string(char* datetime_str) {
// 需要实现RTC获取时间功能
// 格式: YYYYMMDDHHMMSS
sprintf(datetime_str, "20250101120000"); // 示例
}
// 辅助函数:从Flash获取下一个日志ID
uint32_t get_next_log_id(void) {
uint32_t id = 0;
// 从Flash读取ID (地址0x2000)
// spi_flash_buffer_read((uint8_t*)&id, 0x2000, 4);
return id;
}
// 辅助函数:保存日志ID到Flash
void save_log_id_to_flash(uint32_t id) {
// spi_flash_sector_erase(0x2000);
// spi_flash_buffer_write((uint8_t*)&id, 0x2000, 4);
}
// 1. 存储系统初始化
void storage_init(void) {
FRESULT res;
// 挂载文件系统
res = f_mount(1,&fs);
if (res != FR_OK) {
USART0_SendData((uint16_t*)"SD mount failed\r\n", 16);
return;
}
// 创建存储目录
f_mkdir("sample");
f_mkdir("overLimit");
f_mkdir("log");
f_mkdir("hideData");
// 初始化日志ID
log_id = get_next_log_id();
// 创建日志文件
char log_filename[32];
sprintf(log_filename, "log/log%u.txt", log_id);
res = f_open(¤t_log_file, log_filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res == FR_OK) {
log_file_open = 1;
// 更新日志ID并保存
save_log_id_to_flash(log_id + 1);
}
}
void log_operation(const char* operation) {
if (!log_file_open) return;
char datetime_str[16];
get_datetime_string(datetime_str);
char log_entry[128];
sprintf(log_entry, "[%s] %s\r\n", datetime_str, operation);
UINT bytes_written;
f_write(¤t_log_file, log_entry, strlen(log_entry), &bytes_written);
f_sync(¤t_log_file);
}
void store_sample_data(float voltage) {
if (!sample_file_open) {
char datetime_str[16];
get_datetime_string(datetime_str);
char filename[32];
sprintf(filename, "sample/sampleData%s.txt", datetime_str);
if (f_open(¤t_sample_file, filename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
sample_file_open = 1;
}
}
if (sample_file_open) {
char data_line[64];
sprintf(data_line, "%.1fV\r\n", voltage);
UINT bytes_written;
f_write(¤t_sample_file, data_line, strlen(data_line), &bytes_written);
f_sync(¤t_sample_file);
}
}
void store_overlimit_data(float voltage, float limit) {
if (!overlimit_file_open) {
char datetime_str[16];
get_datetime_string(datetime_str);
char filename[32];
sprintf(filename, "overLimit/overLimit%s.txt", datetime_str);
if (f_open(¤t_overlimit_file, filename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
overlimit_file_open = 1;
}
}
if (overlimit_file_open) {
char data_line[64];
sprintf(data_line, "%.1fV > %.1fV\r\n", voltage, limit);
UINT bytes_written;
f_write(¤t_overlimit_file, data_line, strlen(data_line), &bytes_written);
f_sync(¤t_overlimit_file);
}
}
void store_hidedata(float voltage) {
if (!hidedata_file_open) {
char datetime_str[16];
get_datetime_string(datetime_str);
char filename[32];
sprintf(filename, "hideData/hideData%s.txt", datetime_str);
if (f_open(¤t_hidedata_file, filename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) {
hidedata_file_open = 1;
}
}
if (hidedata_file_open) {
char data_line[64];
sprintf(data_line, "HIDE: %.1fV\r\n", voltage);
UINT bytes_written;
f_write(¤t_hidedata_file, data_line, strlen(data_line), &bytes_written);
f_sync(¤t_hidedata_file);
}
}
void save_config_to_file(float ratio, float limit) {
FIL config_file;
if (f_open(&config_file, "config.ini", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) {
return;
}
char config_data[128];
sprintf(config_data,
"[Ratio]\r\n"
"Ch0 = %.1f\r\n"
"\r\n"
"[Limit]\r\n"
"Ch0 = %.1f\r\n",
ratio, limit);
UINT bytes_written;
f_write(&config_file, config_data, strlen(config_data), &bytes_written);
f_close(&config_file);
}
// 写入Flash的辅助函数
void write_config_to_flash(float ratio, float limit) {
spi_flash_sector_erase(FLASH_RATIO_ADDR);
spi_flash_buffer_write((uint8_t*)&ratio, FLASH_RATIO_ADDR, sizeof(ratio));
spi_flash_sector_erase(FLASH_LIMIT_ADDR);
spi_flash_buffer_write((uint8_t*)&limit, FLASH_LIMIT_ADDR, sizeof(limit));
}
// 读取配置文件
void read_config_file(void) {
UINT bytes_read;
char buffer[256]; // 读取缓冲区
float ratio = 0.0f, limit = 0.0f;
// 挂载文件系统
fr = f_mount(1,&fs);
if (fr != FR_OK) {
// 错误处理
return;
}
// 打开配置文件
fr = f_open(&fil, CONFIG_FILE, FA_READ);
if (fr == FR_OK) {
// 读取文件内容
fr = f_read(&fil, buffer, sizeof(buffer) - 1, &bytes_read);
if (fr == FR_OK) {
buffer[bytes_read] = '\0'; // 确保字符串结束
// 解析配置
if (parse_config(buffer, &ratio, &limit)) {
// 写入Flash
write_config_to_flash(ratio, limit);
}
}
f_close(&fil); // 关闭文件
}
}
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occured in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Acces denied due to prohibited access or directory full */
FR_EXIST, /* (8) Acces denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file shareing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
====system init====
conf
Command received: conf
Updating config from SD card...
Filesystem mounted
SD init success
config.ini not found! Error: 3
> test
Command received: test
====System selftest=====
flash.......ok
flash ID:0xC84013
TF card...........ok
TF card memory: 30721024 KB
RTC:
Current time: 2025-05-01 : 08:32:47
====system selftest====
TF卡在读卡器中识别到了相应的配置文件,优化代码,解决问题
最新发布