求助:PIC12F1501校准模式写入2个16位Flash数据及读取实现
Solution for PIC12F1501 Flash Write/Read with Minimal RAM Usage
Sounds like you're hitting the classic RAM crunch on small PICs—totally get it, since the 12F1501 only has 128 bytes of RAM total. That 32-byte global ramBuf was eating up way too much precious space. Let's fix this by optimizing memory usage and adjusting the Flash logic to only consume RAM when absolutely needed (i.e., just during that one-time calibration).
Key Optimizations
- Move the Flash buffer from global RAM to the stack (local variable in the calibration function) so it only occupies memory during calibration, then releases it automatically for normal mode.
- Add interrupt safety to Flash operations (critical for reliable writes on PICs—they can't handle interrupts mid-erase/write).
- Simplify the write logic to focus exactly on your use case: writing two consecutive 16-bit values.
Modified Code
main.c Changes
First, ditch the global ramBuf—we'll declare it locally only when we need it:
/* Flash 存储器 */ #define NCOFreq_addr 0x0380 // 确保地址是字对齐的(偶数,PIC Flash按16位字寻址) /* RAM 内存分配定义 */ uint16_t PWMValue[2]; // 移除全局的uint16_t ramBuf[WRITE_FLASH_BLOCKSIZE]; void Calibrate() { // 只在校准时分配栈缓冲区,执行完自动释放 uint16_t ramBuf[WRITE_FLASH_BLOCKSIZE]; uint16_t blockStartAddr; uint8_t offset; uint8_t i; // --- 保留你的扫频和ADC检测逻辑 --- PWMValue[0] = PWMSweep; // 扫频得到的最优频率值 PWMValue[1] = ADC_GetConversion(0); // 对应最优工作点的ADC值 // --- Flash写入准备 --- // 计算要擦除的块起始地址和目标偏移 blockStartAddr = (uint16_t)(NCOFreq_addr & ((END_FLASH-1) ^ (ERASE_FLASH_BLOCKSIZE-1))); offset = (uint8_t)(NCOFreq_addr & (ERASE_FLASH_BLOCKSIZE-1)); // 1. 读取当前Flash块的所有内容到缓冲区(避免擦除丢失其他数据) for (i = 0; i < ERASE_FLASH_BLOCKSIZE; i++) { ramBuf[i] = FLASH_ReadWord(blockStartAddr + i); } // 2. 更新缓冲区中的目标位置 ramBuf[offset] = PWMValue[0]; ramBuf[offset + 1] = PWMValue[1]; // 3. 安全写入Flash:关中断 -> 擦除块 -> 写入块 -> 开中断 INTCONbits.GIE = 0; // 全局关中断,防止写入被打断 FLASH_EraseBlock(blockStartAddr); FLASH_WriteBlock(blockStartAddr, ramBuf); INTCONbits.GIE = 1; // 恢复中断 Calib_DONE = 0x01; // 设置校准完成标志 __delay_ms(1000); } void ReadData() { // 读取Flash中的两个16位值(保留你的原有逻辑) PWMValue[0] = FLASH_ReadWord(NCOFreq_addr); PWMValue[1] = FLASH_ReadWord(NCOFreq_addr + 1); // 初始化NCO寄存器 NCO1INCH = PWMValue[0] >> 8; NCO1INCL = PWMValue[0] & 0xFF; Freq_read = 0x01; // 设置读取完成标志 __delay_ms(1000); } /* 主应用程序 */ void main(void) { SYSTEM_Initialize(); Calib_DONE = 0x00; Freq_read = 0x00; while (1) { if (EN_CALIB_GetValue() == 0) // 校准模式(根据你的引脚逻辑调整) { if (!(Calib_DONE & 0x01)) { Calibrate(); } } else // 正常运行模式 { if (!(Freq_read & 0x01)) { ReadData(); } // 其他正常模式功能代码 } } }
memory.c Changes (Simplify for Reusability)
If you want to keep a reusable FLASH_WriteWord function, update it to include interrupt safety and work with local buffers:
void FLASH_WriteWord(uint16_t flashAddr, uint16_t *ramBuf, uint16_t *word) { uint16_t blockStartAddr = (uint16_t)(flashAddr & ((END_FLASH-1) ^ (ERASE_FLASH_BLOCKSIZE-1))); uint8_t offset = (uint8_t)(flashAddr & (ERASE_FLASH_BLOCKSIZE-1)); uint8_t i; // 读取现有块内容到缓冲区 for (i = 0; i < ERASE_FLASH_BLOCKSIZE; i++) { ramBuf[i] = FLASH_ReadWord(blockStartAddr + i); } // 更新目标位置的两个值 ramBuf[offset] = word[0]; ramBuf[offset + 1] = word[1]; // 安全执行Flash操作 INTCONbits.GIE = 0; FLASH_EraseBlock(blockStartAddr); FLASH_WriteBlock(blockStartAddr, ramBuf); INTCONbits.GIE = 1; }
Critical Notes
- Stack Size Check: The local
ramBufuses 32 bytes of stack space. Double-check your linker map file to ensure total stack usage (including other local variables and function calls) doesn't exceed the 128-byte RAM limit. - Flash Address Alignment:
NCOFreq_addrmust be word-aligned (even value). Your current0x0380is valid—avoid odd addresses, as they'll cause misaligned writes. - Flash Endurance: PIC12F1501 has a minimum of 10,000 erase/write cycles. Since calibration is one-time, this isn't a risk, but don't accidentally run calibration repeatedly in testing.
- Interrupt Safety: Never skip disabling interrupts during Flash operations—mid-write interrupts can corrupt Flash or crash the device.
Why This Works
- By moving
ramBufto the stack inCalibrate(), we only use those 32 bytes during the one-time calibration. Once calibration finishes, the stack space is freed for normal mode. - Adding interrupt safety guarantees the Flash write completes reliably.
- We follow PIC's required Flash workflow: read existing block → modify buffer → erase block → write updated buffer, ensuring no data loss outside your target addresses.
内容的提问来源于stack exchange,提问作者JSr
相关产品推荐
相关产品推荐

