1 系统原理图
2 现象
当按键Key1被按下时,LCD1602显示的数值加1,每按下一次,自增1;当按键Key2被按下时,LCD1602显示的数值自减1;当按键Key3被按下时,单片机将LCD1602显示的数值保存在AT24C02中,掉电不丢失;当按键Key4被按下时,单片机从AT24C02中读取数据,并显示在LCD1602。
3 参考程序
(1)主函数
#include
#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
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
#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
#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
_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);