在本教程中,我们将了解使用 PIC16F877A 微控制器中的 EEPROM 保存数据是多么容易。在大多数实时项目中,我们可能必须保存一些数据,即使关闭电源也不应删除这些数据。这听起来像是一个复杂的过程,但在XC8编译器的帮助下,只需使用一行代码即可完成此任务。如果数据在兆字节方面很大,那么我们可以连接SD卡等存储设备并将这些数据存储在其中。但是,如果数据很小,我们可以避免那些累人的过程,我们可以简单地使用PIC微控制器中存在的EEPROM来保存我们的数据并随时检索它。
PIC16F877A 中的 EEPROM:
EEPROM 代表“电子可擦除和可编程只读存储器”。顾名思义,它是PIC微控制器内部的存储器,我们可以通过编程来写入/读取数据。仅当程序中提到这样做时,保存在此中的数据才会被删除。EEPROM 中可用的存储空间量因每个微控制器而异;详细信息将照常在数据表中给出。在我们的PIC16F877A案例中,可用空间为256字节,如其规格数据表中所述。现在让我们看看如何使用这 256 字节通过简单的实验设置来读/写数据。
电路图及说明:
该项目的电路图如上所示。我们已经连接了一个LCD,以可视化保存和检索的数据。普通电位计连接到AN4模拟通道,因此馈入可变电压,该可变电压将用作要保存在EEPROM中的数据。我们还在RB0上使用了一个按钮,当按下这个按钮时,来自模拟通道的数据将保存在EEPROM中。
这种连接可以在面包板上进行。PIC微控制器的引脚排列如下表所示。
S.No: |
引脚编号 |
引脚名称 |
已连接到 |
---|
1 |
21 |
RD2 |
液晶显示器的 RS |
2 |
22 |
RD3 |
液晶显示器的E |
3 |
27 |
RD4 |
液晶屏D4 |
4 |
28 |
RD5 |
液晶屏D5 |
5 |
29 |
RD6 |
液晶屏D6 |
6 |
30 |
RD7 |
液晶屏D7 |
7 |
33 |
RBO/INT |
按钮 |
8 |
7 |
AN4 |
电位计 |
模拟使用PIC EEPROM:
该项目还涉及使用 Proteus 设计的模拟,使用它我们可以在没有任何硬件的情况下模拟项目的工作。本教程末尾给出了此模拟的程序。您可以简单地从这里使用十六进制文件并模拟整个过程。
在仿真过程中,您可以在LCD屏幕上可视化当前ADC值和保存在EEPROM中的数据。要将当前ADC值保存到EEPROM中,只需按下连接到RB0的开关即可保存。模拟的快照如下所示。
EEPROM的编程PIC:
本教程的完整代码在本教程末尾给出。在我们的程序中,我们必须从ADC模块读取值,当按下按钮时,我们必须将该值保存在EEPROM中。由于我们已经了解了ADC和LCD接口,我将进一步解释从EEPROM保存和检索数据的代码。
根据数据表“这些器件具有 4 或 8K 字的程序闪存,PIC16F877A 的地址范围从 0000h 到 1FFFh”。这意味着每个EEPROM存储空间都有一个地址,可以通过该地址访问它,在我们的MCU中,该地址从0000h到1FFFh开始。
要将数据保存在特定的EEPROM地址中,只需使用以下行。
eeprom_write(0,adc);
这里的“adc”是一个整数类型的变量,其中存在要保存的数据。“0”是保存我们数据的EEPROM地址。语法“eeprom_write”由我们的XC8编译器提供,因此编译器将自动处理寄存器。
要检索已存储在EEPROM中的数据并将其保存到变量中,可以使用以下代码行。
Sadc = (int)eeprom_read(0)
在这里,“Sadc”是保存来自EEPROM的数据的变量。“0”是我们从中检索数据的EEPROM地址。语法“eeprom_read”由我们的XC8编译器提供,因此编译器将自动处理寄存器。保存在EEPROM中的数据将采用十六进制类型。因此,我们通过在语法前加上 (int) 来将它们转换为整数类型。
加工:
一旦我们了解了代码的工作原理并准备好了硬件,我们就可以测试代码了。将代码上传到 PIC 微控制器并启动设置。如果一切按预期工作,则应在LCD中看到当前ADC值。现在,您可以按下按钮将ADC值保存到EEPROM。现在,您可以通过关闭整个系统并再次打开来检查值是否已保存。开机后,您应该会在LCD屏幕上看到之前保存的值。
#define _XTAL_FREQ 20000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//LCD Functions Developed by Circuit Digest.
void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
if(data_bit& 1)
D4 = 1;
else
D4 = 0;
if(data_bit& 2)
D5 = 1;
else
D5 = 0;
if(data_bit& 4)
D6 = 1;
else
D6 = 0;
if(data_bit& 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0;
Lcd_SetBit(a); //Incoming Hex value
EN = 1;
__delay_ms(4);
EN = 0;
}
void Lcd_Clear()
{
Lcd_Cmd(0); //Clear the LCD
Lcd_Cmd(1); //Move the curser to first position
}
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a== 1)
{
temp = 0x80 + b - 1; //80H is used to move the curser
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
else if(a== 2)
{
temp = 0xC0 + b - 1;
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
}
void Lcd_Start()
{
Lcd_SetBit(0x00);
for(int i=1065244; i<=0; i--) NOP();
Lcd_Cmd(0x03);
__delay_ms(5);
Lcd_Cmd(0x03);
__delay_ms(11);
Lcd_Cmd(0x03);
Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
Lcd_Cmd(0x08); //Select Row 1
Lcd_Cmd(0x00); //Clear Row 1 Display
Lcd_Cmd(0x0C); //Select Row 2
Lcd_Cmd(0x00); //Clear Row 2 Display
Lcd_Cmd(0x06);
}
void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode
{
char Lower_Nibble,Upper_Nibble;
Lower_Nibble = data&0x0F;
Upper_Nibble = data&0xF0;
RS = 1; // => RS = 1
Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4
EN = 1;
for(int i=2130483; i<=0; i--) NOP();
EN = 0;
Lcd_SetBit(Lower_Nibble); //Send Lower half
EN = 1;
for(int i=2130483; i<=0; i--) NOP();
EN = 0;
}
void Lcd_Print_String(char *a)
{
int i;
for(i=0;a[i]!='\\0';i++)
Lcd_Print_Char(a[i]); //Split the string using pointers and call the Char function
}
/*****End of LCD Functions*****/
//**ADC FUnctions***//
void ADC_Initialize()
{
ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected
ADCON1 = 0b11000000; // Internal reference voltage is selected
}
unsigned int ADC_Read(unsigned char channel)
{
ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
ADCON0 |= channel<<3; //Setting the required Bits
__delay_ms(2); //Acquisition time to charge hold capacitor
GO_nDONE = 1; //Initializes A/D Conversion
while(GO_nDONE); //Wait for A/D Conversion to complete
return ((ADRESH<<8)+ADRESL); //Returns Result
}
//***End of ADC Functions***//
int main()
{
int adc=0; //Variable to read ADC value
int a1,a2,a3,a4; //Variable to split ADC value into char
int Sadc=0; //Variable to read ADC value
int Sa1,Sa2,Sa3,Sa4; //Variable to split ADC value into char
TRISD = 0x00; //PORTD declared as output for interfacing LCD
TRISA4 =1; //AN4 declared as input
TRISB0 = 1;
OPTION_REG=0b00000000;
ADC_Initialize();
Lcd_Start();
Lcd_Clear();
while(1)
{
adc=ADC_Read(4); //Read ADC
//**Display ADC**//
a1 = (adc/1000)%10;
a2 = (adc/100)%10;
a3 = (adc/10)%10;
a4 = (adc/1)%10;
Lcd_Set_Cursor(1,1);
Lcd_Print_String("ADC:");
Lcd_Print_Char(a1+'0');
Lcd_Print_Char(a2+'0');
Lcd_Print_Char(a3+'0');
Lcd_Print_Char(a4+'0');
//**Display SADC**//
Sa1 = (Sadc/1000)%10;
Sa2 = (Sadc/100)%10;
Sa3 = (Sadc/10)%10;
Sa4 = (Sadc/1)%10;
Lcd_Set_Cursor(2,1);
Lcd_Print_String("Saved ADC:");
Lcd_Print_Char(Sa1+'0');
Lcd_Print_Char(Sa2+'0');
Lcd_Print_Char(Sa3+'0');
Lcd_Print_Char(Sa4+'0');
/*These devices have 4 or 8K words of
program Flash, with an address range from 0000h to
1FFFh for the PIC16F877A*/
if (RB0==0)
{eeprom_write(0,adc);}
Sadc = (int)eeprom_read(0);
Lcd_Set_Cursor(1,1);
Lcd_Print_String("ADC:");
}
return 0;
}