• How to Save Data using EEPROM in PIC16F877A Microcontroller - Cách lưu dữ liệu bằng EEPROM trong Vi điều khiển PIC16F877A

QC

How to Save Data using EEPROM in PIC16F877A Microcontroller - Cách lưu dữ liệu bằng EEPROM trong Vi điều khiển PIC16F877A

 


Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách dễ dàng lưu dữ liệu bằng EEPROM có trong Vi điều khiển PIC16F877A. Trong hầu hết các dự án thời gian thực, chúng tôi có thể phải lưu một số dữ liệu không được xóa ngay cả khi tắt nguồn. Điều này nghe có vẻ như một quá trình phức tạp, nhưng với sự trợ giúp của Trình biên dịch XC8, nhiệm vụ này có thể được thực hiện chỉ bằng cách sử dụng một dòng mã. Nếu dữ liệu lớn tính theo Mega byte thì chúng ta có thể giao diện một thiết bị lưu trữ như thẻ SD và lưu trữ những dữ liệu đó trên chúng. Nhưng chúng ta có thể tránh những quá trình mệt mỏi đó nếu dữ liệu nhỏ, chúng ta có thể chỉ cần sử dụng EEPROM có trong Vi điều khiển PIC để lưu dữ liệu của chúng ta và truy xuất bất cứ lúc nào chúng ta muốn.


Hướng dẫn PIC EEPROM này là một phần của chuỗi các Hướng dẫn về Vi điều khiển PIC trong đó chúng tôi bắt đầu từ cấp độ rất cơ bản. Nếu bạn chưa học các hướng dẫn trước thì tốt hơn là nên xem chúng ngay bây giờ, vì hướng dẫn này giả định rằng bạn đã quen với Giao diện LCD với Vi điều khiển PIC và Sử dụng ADC với Vi điều khiển PIC.


EEPROM in PIC16F877A:

EEPROM là viết tắt của “Bộ nhớ chỉ đọc có thể xóa và lập trình được bằng điện tử”. Như tên cho thấy nó là một bộ nhớ hiện diện bên trong Vi điều khiển PIC, trong đó chúng ta có thể ghi / đọc dữ liệu bằng cách lập trình nó để làm như vậy. Dữ liệu được lưu trong này sẽ chỉ bị xóa nếu nó được đề cập đến việc làm như vậy trong chương trình. Dung lượng lưu trữ có sẵn trong EEPROM khác nhau tùy theo từng vi điều khiển; thông tin chi tiết sẽ được cung cấp trong Datasheet như bình thường. Trong trường hợp của chúng tôi đối với PIC16F877A, không gian khả dụng là 256 byte như đã đề cập trong biểu dữ liệu thông số kỹ thuật của nó. Bây giờ chúng ta hãy xem cách chúng ta có thể sử dụng 256 byte này để đọc / ghi dữ liệu bằng cách sử dụng một thiết lập thử nghiệm đơn giản.

Circuit Diagram and Explanation:



Sơ đồ mạch cho dự án được hiển thị ở trên. Chúng tôi đã giao diện một màn hình LCD để trực quan hóa dữ liệu được lưu và truy xuất. Một chiết áp bình thường được kết nối với kênh AN4 Analog nên nguồn cấp vào điện áp thay đổi, điện áp thay đổi này sẽ được sử dụng làm dữ liệu được lưu trong EEPROM. Chúng tôi cũng đã sử dụng một nút nhấn trên RB0, khi nhấn nút này, dữ liệu từ kênh Analog sẽ được lưu trong EEPROM.

Kết nối này có thể được thực hiện trên breadboard. Sơ đồ chân của Vi điều khiển PIC được hiển thị trong bảng dưới đây.


S.No:Pin NumberPin NameConnected to
121RD2RS of LCD
222RD3E of LCD
327RD4D4 of LCD
428RD5D5 of LCD
529RD6D6 of LCD
630RD7D7 of LCD
733RBO/INTPush button
87AN4Potentiometer


Simulation of Using PIC EEPROM :

Dự án này cũng liên quan đến một Mô phỏng được thiết kế bằng Proteus, sử dụng nó mà chúng ta có thể mô phỏng hoạt động của dự án mà không cần bất kỳ phần cứng nào. Chương trình cho mô phỏng này được đưa ra ở cuối hướng dẫn này. Bạn chỉ cần sử dụng tệp Hex từ đây và mô phỏng toàn bộ quá trình.

Trong quá trình mô phỏng, bạn có thể hình dung giá trị ADC hiện tại và dữ liệu được lưu trong EEPROM trên màn hình LCD. Để lưu giá trị ADC hiện tại vào EEPROM chỉ cần nhấn công tắc kết nối với RB0 và nó sẽ được lưu. Ảnh chụp nhanh của mô phỏng được hiển thị bên dưới.


Programming PIC for EEPROM:

Mã hoàn chỉnh cho hướng dẫn này được đưa ra ở cuối hướng dẫn này. Trong chương trình của chúng tôi, chúng tôi phải đọc các Giá trị từ mô-đun ADC và khi một nút được nhấn, chúng tôi phải lưu giá trị đó trong EEPROM của chúng tôi. Vì chúng ta đã tìm hiểu về ADC và giao diện LCD, tôi sẽ giải thích thêm về mã để lưu và truy xuất dữ liệu từ EEPROM.

Theo Datasheet “Các thiết bị này có 4 hoặc 8K từ chương trình Flash, với dải địa chỉ từ 0000h đến 1FFFh cho PIC16F877A”. Điều này có nghĩa là mỗi không gian lưu trữ EEPROM có một địa chỉ mà qua đó nó có thể được truy cập và trong MCU của chúng tôi, địa chỉ bắt đầu từ 0000h đến 1FFFh.

Để lưu dữ liệu bên trong một địa chỉ EEPROM cụ thể, chỉ cần sử dụng dòng dưới đây.

eeprom_write(0,adc);
Ở đây “adc” là một biến kiểu số nguyên, trong đó dữ liệu sẽ được lưu hiện diện. Và “0” là địa chỉ của EEPROM mà dữ liệu của chúng ta được lưu trên đó. Cú pháp “eeprom_write” được cung cấp bởi trình biên dịch XC8 của chúng tôi, do đó các thanh ghi sẽ được trình biên dịch tự động quản lý.

Để truy xuất dữ liệu đã được lưu trữ trong EEPROM và lưu nó vào một biến, có thể sử dụng dòng mã sau.

  Sadc = (int)eeprom_read(0);
Ở đây, “Sadc” là biến trong đó dữ liệu từ EEPROM sẽ được lưu. Và “0” là địa chỉ của EEPROM mà từ đó chúng ta đang truy xuất dữ liệu. Cú pháp “eeprom_read” được cung cấp bởi trình biên dịch XC8 của chúng tôi, do đó các thanh ghi sẽ được trình biên dịch tự động quản lý. Dữ liệu được lưu trong EEPROM sẽ ở kiểu thập lục phân. Do đó, chúng tôi chuyển đổi chúng sang kiểu số nguyên bằng cách thêm tiền tố a (int) trước cú pháp.

Working:

Khi chúng tôi hiểu cách mã hoạt động và sẵn sàng với phần cứng, chúng tôi có thể kiểm tra mã. Tải mã lên Vi điều khiển PIC của bạn và cấp nguồn cho thiết lập. Nếu mọi thứ hoạt động như mong đợi thì bạn sẽ thấy các giá trị ADC hiện tại được hiển thị trên màn hình LCD. Bây giờ bạn có thể nhấn nút để lưu giá trị ADC vào EEPROM. Bây giờ bạn kiểm tra xem giá trị đã được lưu chưa bằng cách tắt toàn bộ hệ thống và bật lại. Khi bật nguồn, bạn sẽ thấy giá trị đã lưu trước đó trên màn hình LCD.


Hoạt động hoàn chỉnh của dự án này để sử dụng Vi điều khiển PIC EEPROM được hiển thị trong video dưới đây. Hy vọng bạn đã hiểu hướng dẫn và thích làm nó. Nếu bạn có bất kỳ nghi ngờ nào, bạn có thể viết chúng trong phần bình luận bên dưới hoặc đăng chúng trên diễn đàn của chúng tôi.



#define _XTAL_FREQ 20000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
 
#include <xc.h>
 
#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;
}




















Nap Code vào PY32F003 dùng Stlink

 Nap Code vào PY32F003 dùng Stlink Bước 1: Cài đặt  KeilC v5.39 theo link sau ( chú ý 5.39 keil c mới nạp ok). https://edge07.111.ir.cdn.ir/...