AT24C02数据存储+普中51单片机+江科大自化协

1 系统原理图

 

2 现象

 

  当按键Key1被按下时,LCD1602显示的数值加1,每按下一次,自增1;当按键Key2被按下时,LCD1602显示的数值自减1;当按键Key3被按下时,单片机将LCD1602显示的数值保存在AT24C02中,掉电不丢失;当按键Key4被按下时,单片机从AT24C02中读取数据,并显示在LCD1602。

3 参考程序

(1)主函数

#include <REGX52.H>
#include "delayms.h"
#include "key.h"
#include "lcd1602.h"
#include "at24c02.h"

unsigned char KeyNum;
unsigned int Num;

void main()
{
    LCD1602_Init();
    LCD1602_ShowNum(1,1,Num,5);
    while(1)
    {
        KeyNum=key();
        if(KeyNum==1)    //K1按键,Num自增
        {
            Num++;
            LCD1602_ShowNum(1,1,Num,5);
        }
        if(KeyNum==2)    //K2按键,Num自减
        {
            Num--;
            LCD1602_ShowNum(1,1,Num,5);
        }
        if(KeyNum==3)    //K3按键,向AT24C02写入数据
        {
            AT24C02_WriteByte(0,Num%256);
            delayms(5);
            AT24C02_WriteByte(1,Num/256);
            delayms(5);
            LCD1602_ShowString(2,1,"Write is OK");
            delayms(1000);
            LCD1602_ShowString(2,1,"           ");
        }
        if(KeyNum==4)    //K4按键,从AT24C02读取数据
        {
            Num=AT24C02_ReadByte(0);
            Num|=AT24C02_ReadByte(1)<<8;
            LCD1602_ShowNum(1,1,Num,5);
            LCD1602_ShowString(2,1,"Read is OK");
            delayms(1000);
            LCD1602_ShowString(2,1,"           ");
        }
    }
}

(2)I2C函数

#ifndef _i2c_h_
#define _i2c_h_

void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);
    
#endif
#include <REGX52.H>

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

/**
  * @brief  I2C通信开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
    I2C_SCL=1;    //空闲状态
    I2C_SDA=1;    //空闲状态
    I2C_SDA=0;
    I2C_SCL=0;
}

/**
  * @brief  I2C通信结束
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
    I2C_SDA=0;    
    I2C_SCL=1;    //回到空闲状态
    I2C_SDA=1;    //回到空闲状态
}

/**
  * @brief  I2C主机向从机发送一个字节,SCL为同步信号,低电平写数据
  * @param  Byte 要发送的字节
  * @retval 无
  */
void I2C_SendByte(unsigned char Byte)
{
    unsigned char i;
    for(i=0;i<8;i++)            //一个字节,8bit
    {
        I2C_SDA=Byte&(0x80>>i);    //SCL为低电平,主机为发送器,写数据
        I2C_SCL=1;                //SCL为高电平,从机为接收器,读数据
        I2C_SCL=0;                //时序要求,51单片机速度比较慢
    }
}

/**
  * @brief  I2C主机接收从机一个字节,SCL为同步信号,高电平读数据
  * @param  无
  * @retval 接收到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
    unsigned char i,Byte=0x00;
    I2C_SDA=1;                //主机释放数据线SDA
    for(i=0;i<8;i++)
    {
        I2C_SCL=1;            //主机作为接收器
        if(I2C_SDA) Byte|=(0x80>>i);    //读数据
        I2C_SCL=0;            //从机作为发送器,写数据
    }    
    return Byte;
}

/**
  * @brief  I2C主机发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void I2C_SendAck(unsigned char AckBit)
{
    I2C_SDA=AckBit;
    I2C_SCL=1;
    I2C_SCL=0;
}

/**
  * @brief  I2C主机接收应答位
  * @param  无
  * @retval 接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
    unsigned char AckBit;
    I2C_SDA=1;
    I2C_SCL=1;
    AckBit=I2C_SDA;
    I2C_SCL=0;
    return AckBit;
}

(3)AT24C02函数

#ifndef _at24c02_h_
#define _at24c02_h_

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
    
#endif

 

#include <REGX52.H>
#include "i2c.h"

#define AT24C02_ADDRESS 0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
    I2C_Start();
    I2C_SendByte(AT24C02_ADDRESS);
    I2C_ReceiveAck();
    I2C_SendByte(WordAddress);
    I2C_ReceiveAck();
    I2C_SendByte(Data);
    I2C_ReceiveAck();
    I2C_Stop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
    unsigned char Data;
    I2C_Start();
    I2C_SendByte(AT24C02_ADDRESS);
    I2C_ReceiveAck();
    I2C_SendByte(WordAddress);
    I2C_ReceiveAck();
    
    I2C_Start();
    I2C_SendByte(AT24C02_ADDRESS|0x01);
    I2C_ReceiveAck();
    Data=I2C_ReceiveByte();
    I2C_SendAck(1);
    I2C_Stop();
    return Data;
}

(4)LCD1602函数

#ifndef __LCD1602_H__
#define __LCD1602_H__
    
    void LCD1602_WriteCommand(unsigned char Command);
    void LCD1602_WriteData(unsigned char Data);

    void LCD1602_Init(void);
    void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
    void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
    void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    
#endif
#include <REGX52.H>
#include "intrins.h"

//引脚配置,硬件原理图,普中A2
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E  = P2^7;
#define LCD1602_DATAPORT P0


/**
  * @brief  LCD1602延时函数
  * @param  xms=1, 延时1ms
  * @retval 无
  */
void LCD1602_Delayms(unsigned char xms)        //@11.0592MHz
{
    unsigned char i, j,k;

    for(k=0;k<xms;k++)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }

}

/**
  * @brief  LCD1602写命令,时序图
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD1602_WriteCommand(unsigned char Command)
{
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DATAPORT  = Command;
    LCD1602_E  = 1;
    LCD1602_Delayms(1);    //延时1ms
    LCD1602_E  = 0;
    LCD1602_Delayms(1);    //延时1ms
}

/**
  * @brief  LCD1602写数据,时序图
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD1602_WriteData(unsigned char Data)
{
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DATAPORT  = Data;
    LCD1602_E  = 1;
    LCD1602_Delayms(1);    //延时1ms
    LCD1602_E  = 0;
    LCD1602_Delayms(1);    //延时1ms
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD1602_Init(void)
{
    LCD1602_WriteCommand(0x38);    //0011_1000 功能设置,设置16x2显示,5x7点阵,8位数据接口
    LCD1602_WriteCommand(0x0C);    //0000_1100 显示开关控制,显示开,光标关,闪烁关    
    LCD1602_WriteCommand(0x06);    //0000_0110 输入方式设置,数据写后,AC自动加一,画面不动
    LCD1602_WriteCommand(0x01);    //0000_0001 清屏,数据指针清零、所有显示清零
}
/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD1602_SetCursor(unsigned char Line,unsigned char Column)
{
    if(Line == 1)
    {
        LCD1602_WriteCommand(0x80|(Column-1)); //设置要存入数据的DDROM地址,第一行地址
    }
    else
    {
        LCD1602_WriteCommand(0x80|(Column-1)+0x40); //设置要存入数据的DDROM地,第二行地址
    }
}
    

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
    LCD1602_SetCursor(Line,Column);
    LCD1602_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置上显示所给字符串
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符串
  * @retval 无
  */
void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)        //指针
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=0;String[i]!='\0';i++)    //字符串结束标志'\0'
    {
        LCD1602_WriteData(String[i]);
    }
    
}

/**
  * @brief  返回值=X的Y次方,指数运算
  */
int LCD_Power(int X,int Y)
{
    unsigned char i;
    int result = 1;
    for(i=0;i<Y;i++)
    {
        result = result * X;
    }
    return result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number/LCD_Power(10,i-1)%10); // '0'=0x30,转换为字符显示;
        
        /** 
          * 789, 789/100%10, 取出百位
          * 789, 789/10%10, 取出十位
          * 789, 789/1%10, 取出个位
         */
    }
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{
    unsigned char i;
    unsigned int Number1; 
    LCD1602_SetCursor(Line,Column);
    if(Number >= 0)
    {
        LCD1602_WriteData('+');
        Number1 = Number;
    }
    else
    {
        LCD1602_WriteData('-');
        Number1 = -Number;     //-32768
    }
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number1/LCD_Power(10,i-1)%10); 
    }
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xffff
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    unsigned char SingleNumber;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        SingleNumber = Number/LCD_Power(16,i-1)%16; //从高位到低位,取出每一个十六进制数字
        if(SingleNumber < 10)
            LCD1602_WriteData('0'+SingleNumber); 
        else
            LCD1602_WriteData('A'+SingleNumber-10); //SingleNumber已含有10+x
    }
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111_1111_1111_1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number/LCD_Power(2,i-1)%2); //从高位到低位,取出每一个二进制数字
    }
}

(5)独立按键函数

#ifndef _key_h_
#define _key_h_

    unsigned char key();

#endif
#include <reg52.h>
#include "delayms.h"

sbit key1 = P3^1;
sbit key2 = P3^0;
sbit key3 = P3^2;
sbit key4 = P3^3;

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
  */

unsigned char key()
{
    unsigned char KeyNumber = 0;
    if(key1==0){delayms(20);while(key1==0);delayms(20);KeyNumber=1;}
    if(key2==0){delayms(20);while(key2==0);delayms(20);KeyNumber=2;}
    if(key3==0){delayms(20);while(key3==0);delayms(20);KeyNumber=3;}
    if(key4==0){delayms(20);while(key4==0);delayms(20);KeyNumber=4;}
    return KeyNumber;
}

(6)延时函数

#ifndef _delayms_h_
#define _delayms_h_

    delayms(unsigned int xms);
    
#endif
#include <intrins.h>

void delayms(unsigned int xms)        //@11.0592MHz
{
    unsigned char i, j;

    while(xms--)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);    
    }
}

 

posted @ 2023-01-03 20:44  豌豆茶  阅读(402)  评论(0编辑  收藏  举报