在本教程中,我們將了解使用 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 // Oscillat
or Selec
tion 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 Prog
ramming 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); //W
ait 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;
}
評論