本帖最后由 qjp1988113 于 2021-2-22 14:24 编辑
今天我们来做下PIC16F15244 内部FLASH读写。这个几乎没有什么配置.打开MCC,选上MEMORY功能。
生成对应的代码,下面我们直接调用代码即可:
/**
MEMORY Generated Driver File
@Company
Microchip Technology Inc.
[url=home.php?mod=space&uid=288409]@file[/url] Name
memory.c
@Summary
This is the generated driver implementation file for the MEMORY driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs
@Description
This file provides implementations of driver APIs for MEMORY.
Generation Information :
Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.5
Device : PIC16F15244
Driver Version : 2.01
The generated drivers are tested against the following:
Compiler : XC8 2.20 and above
MPLAB : MPLAB X 5.40
*/
/*
(c) 2018 Microchip Technology Inc. and its subsidiaries.
Subject to your compliance with these terms, you may use Microchip software and any
derivatives exclusively with Microchip products. It is your responsibility to comply with third party
license terms applicable to your use of third party software (including open source software) that
may accompany Microchip software.
THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS
FOR A PARTICULAR PURPOSE.
IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP
HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO
THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT
OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS
SOFTWARE.
*/
/**
Section: Included Files
*/
#include <xc.h>
#include "memory.h"
/**
Section: Flash Module APIs
*/
uint16_t FLASH_ReadWord(uint16_t flashAddr)
{
uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
INTCONbits.GIE = 0; // Disable interrupts
NVMADRL = (flashAddr & 0x00FF);
NVMADRH = ((flashAddr & 0xFF00) >> 8);
NVMCON1bits.NVMREGS = 0; // Deselect Configuration space
NVMCON1bits.RD = 1; // Initiate Read
NOP();
NOP();
INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
return ((uint16_t)((NVMDATH << 8) | NVMDATL));
}
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;
// Entire row will be erased, read and save the existing data
for (i=0; i<ERASE_FLASH_BLOCKSIZE; i++)
{
ramBuf[i] = FLASH_ReadWord((blockStartAddr+i));
}
// Write at offset
ramBuf[offset] = word;
// Writes ramBuf to current block
FLASH_WriteBlock(blockStartAddr, ramBuf);
}
int8_t FLASH_WriteBlock(uint16_t writeAddr, uint16_t *flashWordArray)
{
uint16_t blockStartAddr = (uint16_t )(writeAddr & ((END_FLASH-1) ^ (ERASE_FLASH_BLOCKSIZE-1)));
uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
uint8_t i;
// Flash write must start at the beginning of a row
if( writeAddr != blockStartAddr )
{
return -1;
}
INTCONbits.GIE = 0; // Disable interrupts
// Block erase sequence
FLASH_EraseBlock(writeAddr);
// Block write sequence
NVMCON1bits.NVMREGS = 0; // Deselect Configuration space
NVMCON1bits.WREN = 1; // Enable wrties
NVMCON1bits.LWLO = 1; // Only load write latches
for (i=0; i<WRITE_FLASH_BLOCKSIZE; i++)
{
// Load lower 8 bits of write address
NVMADRL = (writeAddr & 0xFF);
// Load upper 6 bits of write address
NVMADRH = ((writeAddr & 0xFF00) >> 8);
// Load data in current address
NVMDATL = flashWordArray[i];
NVMDATH = ((flashWordArray[i] & 0xFF00) >> 8);
if(i == (WRITE_FLASH_BLOCKSIZE-1))
{
// Start Flash program memory write
NVMCON1bits.LWLO = 0;
}
NVMCON2 = 0x55;
NVMCON2 = 0xAA;
NVMCON1bits.WR = 1;
NOP();
NOP();
writeAddr++;
}
NVMCON1bits.WREN = 0; // Disable writes
INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
return 0;
}
void FLASH_EraseBlock(uint16_t startAddr)
{
uint8_t GIEBitValue = INTCONbits.GIE; // Save interrupt enable
INTCONbits.GIE = 0; // Disable interrupts
// Load lower 8 bits of erase address boundary
NVMADRL = (startAddr & 0xFF);
// Load upper 6 bits of erase address boundary
NVMADRH = ((startAddr & 0xFF00) >> 8);
// Block erase sequence
NVMCON1bits.NVMREGS = 0; // Deselect Configuration space
NVMCON1bits.FREE = 1; // Specify an erase operation
NVMCON1bits.WREN = 1; // Allows erase cycles
// Start of required sequence to initiate erase
NVMCON2 = 0x55;
NVMCON2 = 0xAA;
NVMCON1bits.WR = 1; // Set WR bit to begin erase
NOP();
NOP();
NVMCON1bits.WREN = 0; // Disable writes
INTCONbits.GIE = GIEBitValue; // Restore interrupt enable
}
/**
Section: Data EEPROM Module APIs
*/
void DATAEE_WriteByte(uint16_t bAdd, uint8_t bData)
{
uint8_t GIEBitValue = INTCONbits.GIE;
NVMADRH = ((bAdd >> 8) & 0xFF);
NVMADRL = (bAdd & 0xFF);
NVMDATL = bData;
NVMCON1bits.NVMREGS = 1;
NVMCON1bits.WREN = 1;
INTCONbits.GIE = 0; // Disable interrupts
NVMCON2 = 0x55;
NVMCON2 = 0xAA;
NVMCON1bits.WR = 1;
// Wait for write to complete
while (NVMCON1bits.WR)
{
}
NVMCON1bits.WREN = 0;
INTCONbits.GIE = GIEBitValue; // restore interrupt enable
}
uint8_t DATAEE_ReadByte(uint16_t bAdd)
{
NVMADRH = ((bAdd >> 8) & 0xFF);
NVMADRL = (bAdd & 0xFF);
NVMCON1bits.NVMREGS = 1;
NVMCON1bits.RD = 1;
NOP(); // NOPs may be required for latency at high frequencies
NOP();
return (NVMDATL);
}
/**
End of File
*/
这里要说明的是,我们用来作为存储一些设定数字的FLASH地址一定要大于程序本身生成的代码,最好用最后面几个地址。
同时要计时个数,不能超出范围,不然会死机。
我们的MCU对应的FLASH地址范围 0X000~0XFFF
FLASH具有划分及堆栈模式:
可以在IDE左下侧,查看当前使用情况。
我们这里向首地址为0XF00的位置写入"Hello,world!",然后再把它读出来,看是否正确!
main.c定义变量:
#define FLASH_ROW_ADDRESS 0x0F00
uint16_t wrBlockData[12] ={'H', 'e', 'l', 'l', 'o', ',', 'w', 'o', 'r','l','d','!'};
uint16_t receData[12]={0};
添加到main里面:
for(i=0;i<12;i++)
{
receData[i]=0;
}
// write to Flash memory block
FLASH_WriteBlock((uint16_t)FLASH_ROW_ADDRESS, (uint16_t*)wrBlockData);
__delay_ms(500);
for(i=0;i<12;i++)
{
receData[i]=FLASH_ReadWord((uint16_t)FLASH_ROW_ADDRESS+i);
__delay_ms(2);
}
__delay_ms(500);
printf("\r\n the readata is: %c%c%c%c%c%c%c%c%c%c%c%c \r\n",receData[0],receData[1],receData[2],receData[3],
receData[4],receData[5],receData[6],receData[7],receData[8],receData[9],receData[10],receData[11]);
就不做数值转字符串的代码了,编译下载,直接显示:
使用起来还行,但奈何本身空间就很小,当程序代码多时,慎用,会出现莫名其妙的问题。
之前我在循环里面加了读取ADC,并串口输出,然后大数据的转换处理就出现问题了,出现一个不稳定的值~
|
|