如何使用PIC18写入和读取存储器?

时间:2013-05-07 16:33:32

标签: c microcontroller microchip mplab pic18

我想将数字存储到PIC18,然后保留它,即使电源丢失或设备复位也是如此。我认为我的编写代码部分看起来很好,只是在重置单元后它的读取部分看起来很奇怪。

我使用的是Microchip提供的以下代码。

代码:

unsigned int value;
unsigned int DEEdata = 1;
unsigned int  DEEaddr = 0x04;

DataEEInit();
dataEEFlags.val = 0;

DataEEWrite(DEEdata,DEEaddr);
value = DataEERead(DEEaddr);
Nop();
printf("%d",value);

输出:1

然而,当我重置单位并且只使用阅读代码时,我总是得到255.

要阅读的代码

DataEEInit();
value = DataEERead(DEEaddr);
printf("%d",value);

输出:255

为什么会这样?我假设可能没有保存值或读取部分不正确。谢谢!

7 个答案:

答案 0 :(得分:1)

您正在使用的设备除了Flash之外没有内部非易失性存储器,通常用于存储代码。

我可以看到两个选项:

  1. 使用一些外部闪存或EEPROM,并将其连接到此PIC上提供的外部存储器总线(参见系列数据表的第97页)。
  2. 重新映射内部Flash以保留一小部分可用于存储数据(以便它不会干扰专门用于代码的内存区域)并将数据写入此区域(第87页)。 / LI>

    多年来我一直没有与PIC合作,所以不能为实现细节提供太多帮助,但我怀疑有很多例子可以从Microchip的网站上找到。

    从本质上讲,你的代码不起作用的原因是因为你试图访问那些不存在的内存。如果它存在,那么界面不正确。

    编辑:

    我已经浏览了Microchip网站上PIC18的代码示例页面,但找不到任何用于写入程序存储器的C示例。不幸的是,看起来你必须在汇编程序中实现它。我不知道MPLAB编译器的语义,但一般情况下,如果你要内联它,它将是这样的东西

    void my_assembler_function(void)
    {
        // Inline assembler code, actioned via C.
        asm("MOV x y");
        asm("MOV y z");
    }
    

    或者,许多用于微处理器的C编译器允许您使用C函数调用调用外部.s文件,从而使您无需内联。

    我认为您可以按照我找到here的示例来实际实现您所追求的功能。

答案 1 :(得分:1)

SRAM不能用于存储非易失性数据......

SRAM会在电源循环期间丢失数据......

选项: 1.如果可用,请使用内部EEPROM。 2.通过I2C或SPI的外部EEPROM。 3. PIC18数据仿真库。

答案 2 :(得分:1)

两个功能:使用64字节缓冲区@ 8字节块写入闪存和读取/比较闪存功能。

对于器件:PIC18F46K80

头文件的填充:

#define PRGM_BUFFER_SIZE 8
#define TABLE_WRITE_SIZE 64

#define LOAD_TBL_PTR(x) { TBLPTRU = ((((x)>>8)>>8)&0xff);\
                      TBLPTRH = (((x) >> 8) & 0xff);\
                      TBLPTRL = ((x) & 0xff);\
                    }

写入闪光灯功能:

/******************************************************
 * Function     : write_block
 * Input        : uint16_t position in destination flash
 * Global       : uint8_t buffer[64] - Location of source data
 * Output       : None
 * Description  : Writes the contents of the 64 byte
 * data buffer to program flash space.  Only 64 bytes
 * can be written at once.   The process of writing
 * to flash is: Erase->Write.
 ******************************************************/
static void write_block(uint16_t addr)
{
    int r, c;

    // Erase flash block first.  Erases a 64 byte block at a time.

    LOAD_TBL_PTR(addr);

    EECON1bits.EEPGD = 1;   // Point to flash program memory
    EECON1bits.CFGS = 0;    // Access flash memory
    EECON1bits.WREN = 1;    // Enable write to memory
    EECON1bits.FREE = 1;    // Enable Erase operation

    EECON2 = 0x55;
    EECON2 = 0xAA;

    EECON1bits.WR = 1;      // Clear the flash

    asm("NOP");             // Stall

    // Write buffer to internal buffer.  This process writes 8 bytes at a time
    // so we need to loop 8 times (8*8 = 64).)

    for (r = 0; r < 8; r++)
    {
        LOAD_TBL_PTR((addr + (r * 8)));

        for (c = 0; c < PRGM_BUFFER_SIZE; c++)
        {
            TABLAT = buffer[(r * 8) + c];

            asm("TBLWT*+");      // Push byte and then inc to next internal buffer cell
        }

        // Write the block to flash

        asm("TBLRD*-");         // Point back to original row

        // Write internal buffer to flash

        EECON1bits.EEPGD = 1;   // Point to flash program memory
        EECON1bits.CFGS = 0;    // Access flash program memory
        EECON1bits.WREN = 1;    // Enable write to memory
        INTCONbits.GIE = 0;     // Disable interrupts

        EECON2 = 0x55;
        EECON2 = 0xAA;

        EECON1bits.WR = 1;      // Start programming flash
        INTCONbits.GIE = 1;     // Re-enable interrupts
        EECON1bits.WREN = 0;    // Disable write to memory
    }
}

验证书面数据(演示闪存读取)

/******************************************************
 * Function     : compare_block
 * Input        : uint16_t position in destination flash
 * Global       : uint8_t buffer[64] - Location of previous written data
 * Output       : bool true=successful, false=did not match
 * Description  : Reads a 64 byte block of flash memory and
 * compares it to the data found in the global buffer.
 ******************************************************/
static bool compare_block(uint16_t addr)
{
    bool retVal = true; // succeeds
    uint8_t i = 0;

    INTCONbits.GIE = 0;     // Disable interrupts

    LOAD_TBL_PTR(addr);

    for (i = 0; i < TABLE_WRITE_SIZE && retVal == true; i++)
    {
        asm("TBLRD*+");

        if (buffer[i] != TABLAT)
            retVal = false;
    }

    INTCONbits.GIE = 1;     // Enable interrupts

    return retVal;
}

此致, 布莱恩威尔切特

答案 3 :(得分:1)

这是对PIC18的解释:

/* EEPROM Read and Write Functions -- WORKING
 * Used PIC18F45K22 and MPLAB and C18
 * Read and Write functions work.
 * EEPROM has 256 bytes of memory (256 distinct characters)
 * Select "Window" -> "PIC Memory Views" -> "EE Data Memory"
 * Download program to PIC18
 * Hold PIC in Reset (circle arrow with pause button)
 * Open EE Data Memory Tab and click "Read Device Memory" button (Top left of EE Data tab) while PIC is held in Reset
 */

这是有用的代码:

#include <p18cxxx.h>
#include <p18f45k22.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#pragma config FOSC = INTIO67, PLLCFG = OFF, PRICLKEN = ON, FCMEN = ON,     PWRTEN = OFF
#pragma config BOREN = SBORDIS, BORV = 250, WDTEN = OFF, WDTPS = 2048,    PBADEN = OFF, WRTD = OFF
#pragma config HFOFST = OFF, MCLRE = EXTMCLR, STVREN = ON, LVP = OFF, DEBUG = ON, CPD = OFF

void EE_Write(unsigned char addr, unsigned char value);
unsigned char EE_Read(unsigned char addr);

unsigned char test;

void main(void){
    OSCTUNEbits.PLLEN = 1;
    OSCCON = 0x4C; //Set to use internal clock.
    OSCCON2 = 0x00; // No 4x PLL

    TRISB = 0x00;
    ANSELB = 0x00;
    PORTB = 0x00;

    EE_Write(05, 0x5A);
    Delay10KTCYx(50);
    test = EE_Read(05);

    Delay10KTCYx(50);
    PORTB = 0xFF;

    Delay10KTCYx(50);
    PORTB = 0x00;

}

void EE_Write(unsigned char addr, unsigned char value)         
{         
    unsigned char SaveGIE = 0;         

    // Set EEPROM address                
    EEADR  = addr%256;         
    // Set EEPROM data         
    EEDATA = value;         
    // Select Data         
    EECON1bits.EEPGD = 0;         
    // Select EEPROM         
    EECON1bits.CFGS = 0;         
    // Enable write         
    EECON1bits.WREN = 1;         
    // Save current global interrupt enable state         
    SaveGIE = INTCONbits.GIE;         
    // Disable interrupts         
    INTCONbits.GIE = 0;         
    // Write unlock sequence         
    EECON2 = 0x55;         
    EECON2 = 0xaa;         
    // Start write         
    EECON1bits.WR = 1;         
    // Restore previous interrupts enable state         
    INTCONbits.GIE = SaveGIE;         
    // Wait for write completion         
    while(EECON1bits.WR);        
    // Disable writes         
    EECON1bits.WREN = 0;         
}

unsigned char EE_Read(unsigned char addr){

    while(EECON1bits.RD || EECON1bits.WR); // check the WR&RD bit to see    if a RD/WR is in progress
    EEADR = addr; // Write the address to EEADR.
    EECON1bits.CFGS = 0;
    EECON1bits.EEPGD = 0;
    EECON1bits.RD = 1; // Set the RD bit to trigger the eeprom read  operation.
    return(EEDATA);
}

答案 4 :(得分:0)

除内部闪存外,某些PIC18 micro还具有内部EEPROM。 18F87J11没有这个,所以你有两个选择:

1)写入闪存 - 这是存储程序的地方。确保您的应用程序的写入/读取周期数量正常。

2)使用外部i2c或spi内存进行配置设置

您正在使用的DataEEWrite来自微芯片的“eeprom仿真”库(在下面的评论中链接。有几件事需要注意:

  • 注意重新编程闪光灯!您可能会覆盖您的设置
  • 记住它不是真的eeprom!写周期有限,你必须擦除大部分内存 - 你不能擦除单个字节

答案 5 :(得分:0)

值255是EEPROM存储器的默认值。我想在更改代码后,您再次编程微控制器IC。因此,EEPROM存储器将被擦除并返回其默认值。如果使用MPLAB作为编译器,则可以转到“Programmer”选项卡&gt;设置..&gt;程序存储器&gt;程序选项,然后单击程序上的保留EEPROM。 希望它有效。

答案 6 :(得分:-2)

要保留电源循环的值,应使用SRAM存储器。请确认您是否首先提供SRAM内存。