Integrated programming of single chip microcomputer I2C and EEPROM

Integrated programming of single chip microcomputer I2C and EEPROM

The memory function of TV channel, the setting of traffic light countdown time and the memory function of outdoor LED advertising may all use memory devices such as EEPROM. The advantage of such devices is that the stored data can not only be changed, but also the data will not be lost after power failure. Therefore, they are widely used in various electronic products.

Our routine in this class is a little similar to the advertising screen. After power on, the first line of 1602 displays 16 characters of EEPROM starting from 0x20 address, and the second line displays 16 characters of EERPOM starting from 0x40. We can change the data in EEPROM through UART serial communication, and also change the content displayed in 1602. The updated content will be displayed directly when we power on next time.

All the relevant contents of this program have been mentioned earlier. But this program is embodied in a comprehensive application capability. This program uses 1602 LCD, UART serial communication, EEPROM read-write operation and other comprehensive applications. It's easy to write a small light, but if we want to really learn MCU well, we must learn the application of this comprehensive program and realize multiple modules to participate in the work at the same time. Therefore, students should seriously establish the project, write the program line by line, and finally consolidate it.

/I2C.c file program source code * * / (omitted here, refer to the code in the previous chapter) / Lcd1602.c file program source code * * / (omitted here, refer to the code in the previous chapter) / eeprom.c file program source code / (omitted here, refer to the code in the previous chapter) / Uart.c file program source code * / (omitted here, refer to the code in the previous chapter)

/*****************************main.c File program source code******************************/
#include <reg52.h>
unsigned char T0RH = 0; //High byte of T0 overload value
unsigned char T0RL = 0; //Low byte of T0 overload value

void InitShowStr();
void ConfigTimer0(unsigned int ms);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
extern void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
extern void UartDriver();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartWrite(unsigned char *buf, unsigned char len);

void main(){
    EA = 1; //On total interrupt
    ConfigTimer0(1); //Configure T0 timing 1ms
    ConfigUART(9600); //The baud rate is 9600
    InitLcd1602(); //Initialize LCD
    InitShowStr(); //Initial display content

    while (1){
        UartDriver(); //Call serial driver
/* Process the initial display content of LCD */
void InitShowStr(){
    unsigned char str[17];

    str[16] = '\0';//Add a string terminator at the end to ensure that the string can end
    E2Read(str, 0x20, 16); //Read the first line of string, and its E2 starting address is 0x20
    LcdShowStr(0, 0, str); //Display to LCD
    E2Read(str, 0x40, 16); //Read the second line of string, and its E2 starting address is 0x40
    LcdShowStr(0, 1, str); //Display to LCD
/* The memory comparison function compares whether the memory data pointed to by the two pointers are the same,
ptr1-Pointer to be compared 1, ptr2 pointer to be compared 2, len length to be compared
 Return value - returns 1 when the two memory data are exactly the same, and 0 when different */
bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len){
    while (len--){
        if (*ptr1++ != *ptr2++){ //0 is returned immediately when unequal data is encountered
            return 0;
    return 1; //If all length data are equal after comparison, 1 is returned
/* Sort a string into a fixed length string of 16 bytes, and fill in spaces in the insufficient part
out-Sorted string output pointer, in - string pointer to be sorted */
void TrimString16(unsigned char *out, unsigned char *in){
    unsigned char i = 0;
    while (*in != '\0'){ //Copy the string until the end of the input string
        *out++ = *in++;
        if (i >= 16){ //When the copy length has reached 16 bytes, the loop is forced to jump out
    for ( ; i<16; i++){ //If it is less than 16 bytes, fill it with spaces
        *out++ = ' ';
    *out = '\0'; //Last add Terminator
/* The serial port action function executes the response action according to the received command frame
buf-Received command frame pointer, len command frame length */
void UartAction(unsigned char *buf, unsigned char len){
    unsigned char i;
    unsigned char str[17];
    unsigned char code cmd0[] = "showstr1 "; //First line character display command
    unsigned char code cmd1[] = "showstr2 "; //Second line character display command

    unsigned char code cmdLen[] = { //Command length summary
        sizeof(cmd0)-1, sizeof(cmd1)-1,
    unsigned char code *cmdPtr[] = { //Command pointer summary
        &cmd0[0], &cmd1[0],
    for (i=0; i<sizeof(cmdLen); i++){ //Traverse the command list to find the same command
        if (len >= cmdLen[i]){ //First, the received data length should not be less than the command length
            if (CmpMemory(buf, cmdPtr[i], cmdLen[i])){ //Exit the loop at the same time
    switch (i){ //Execute the corresponding command according to the comparison results
        case 0:
            buf[len] = '\0'; //Adds a terminator to the received string
            TrimString16(str, buf+cmdLen[0]); //Collate into 16 byte fixed length string
            LcdShowStr(0, 0, str); //Display string 1
            E2Write(str, 0x20, sizeof(str)); //Save string 1, starting at 0x20
        case 1:
            buf[len] = '\0'; //Adds a terminator to the received string
            TrimString16(str, buf+cmdLen[1]); //Collate into 16 byte fixed length string
            LcdShowStr(0, 1, str); //Display string 1
            E2Write(str, 0x40, sizeof(str)); //Save string 2, starting at 0x40
        default: //When no matching command is found, send the prompt of "wrong command" to the computer
            UartWrite("bad command.\r\n", sizeof("bad command.\r\n")-1);
    buf[len++] = '\r'; //After the valid command is executed, it is added after the original command frame
    buf[len++] = '\n'; //After the carriage return line feed character is returned to the upper computer, it indicates that it has been executed
    UartWrite(buf, len);
/* Configure and start T0, ms-T0 timing time */
void ConfigTimer0(unsigned int ms){
    unsigned long tmp; //Temporary variable
    tmp = 11059200 / 12; //Timer count frequency
    tmp = (tmp * ms) / 1000; //Calculate the required count value
    tmp = 65536 - tmp; //Calculate timer overload value
    tmp = tmp + 33; //Compensate the error caused by interrupt response delay

    T0RH = (unsigned char)(tmp>>8); //The timer overload value is split into high and low bytes
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0; //Clear the control bit of T0
    TMOD |= 0x01; //Configure T0 to mode 1
    TH0 = T0RH; //Load T0 overload value
    TL0 = T0RL;
    ET0 = 1; //Enable T0 interrupt
    TR0 = 1; //Start T0
/* T0 Interrupt service function to execute serial port receiving monitoring and buzzer driving */
void InterruptTimer0() interrupt 1{
    TH0 = T0RH; //Reload overloaded values
    TL0 = T0RL;
    UartRxMonitor(1); //Serial port receiving monitoring

When we learn UART communication, we also use the IO port to simulate the UART communication process at the beginning, and finally realize the communication with the computer. Then, because STC89C52 has UART hardware communication module, we can easily realize the UART communication of single chip microcomputer directly through the configuration register. Similarly, if there is a hardware module inside the single chip microcomputer, the single chip microcomputer can directly and automatically realize I2C communication. We don't need to start, send and end the simulation of IO port simulation. After configuring the registers, the single chip microcomputer will do all these work.

However, our STC89C52 MCU does not have I2C hardware module, so if we use STC89C52 for I2C communication, we must use IO port to simulate. Using IO port to simulate I2C is actually more conducive to our thorough understanding of the essence of I2C communication. Of course, by learning the analog communication of IO port, if you encounter a single chip microcomputer with I2C module in the future, you should also do it easily. Using the internal hardware module can improve the execution efficiency of the program.

Added by Gaoshan on Sat, 25 Dec 2021 13:33:24 +0200