蓝桥杯突击7-AT24C02(使用蓝桥杯官方提供的库函数并且修正了错误)

学习CT107D上搭载的AT24C02(EEPROM)芯片:

       比赛时虽然给出了IIC的驱动程序, 但是程序里面有点小错误, 里面的时序延时时间太短.

       我们要将驱动库函数中的somenop改为如下:

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();       _nop_();_nop_();_nop_();_nop_();_nop_();    _nop_();_nop_();_nop_();_nop_();_nop_();       _nop_();_nop_();_nop_();_nop_();_nop_();    _nop_();_nop_();_nop_();_nop_();_nop_();       _nop_();_nop_();_nop_();_nop_();_nop_();}

AT24C02的作用是可以在掉电后存储256个字节的数据, 以下是芯片的引脚说明:

                  

由于蓝桥杯开发板上只搭载了一个AT24C02, 所以其外设地址为:0xA0

                                        

根据IIC与外设通信的方法, 敲下代码:

iic.c代码:

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/

#include "iic.h"

//总线启动条件
void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}

//应答位控制
void IIC_Ack(unsigned char ackbit)
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

//等待应答
bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  
	{ 
		SCL = 0;
		return 1;
	}
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80)              //如果byte最高位是0,那么成立
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

void Write_AT24C02(uchar addr,uchar dat)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
	somenop;
}

uchar Read_AT24C02(uchar addr)
{
	uchar dat;
	
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	dat=IIC_RecByte();
	IIC_Ack(0);
	IIC_Stop();
	
	return dat;
}

 

iic.h代码:

#ifndef _IIC_H
#define _IIC_H

#include "reg52.h"
#include "intrins.h"

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();	_nop_();_nop_();_nop_();_nop_();_nop_();	_nop_();_nop_();_nop_();_nop_();_nop_();	_nop_();_nop_();_nop_();_nop_();_nop_();	_nop_();_nop_();_nop_();_nop_();_nop_();	_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

typedef unsigned char uchar;
typedef unsigned int uint;

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

//函数声明
void IIC_Start(void); 
void IIC_Stop(void);  
void IIC_Ack(unsigned char ackbit); 
void IIC_SendByte(unsigned char byt); 
bit IIC_WaitAck(void);  
unsigned char IIC_RecByte(void); 
void Write_AT24C02(uchar addr,uchar dat);
uchar Read_AT24C02(uchar addr);

#endif

main.c:

/*
函数的功能为独立按键第三个按键为数码管数字的增加, 第四个为清零功能,第一个按键为将当前数字保存在AT24C02中,第二个按键为翻看保存的数据. 已经存储的数据掉电不丢失,只用在重新写入代码时丢失.
*/

#include <reg52.h>
#include "iic.h"

sbit BUZZ=P0^6;
sbit RELAY=P0^4;
sbit k1=P3^0;
sbit k2=P3^1;
sbit k3=P3^2;
sbit k4=P3^3;

uchar table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,  0x88,0x83,0xC6,0xA1,0x86,0x8E};
uchar keyflag1,keyflag2,keyflag3,keyflag4;
uchar num=0,addr,flag;

void CloseBUZZ();
void CloseLED();
void Key();
void Display();

void main()
{
	CloseBUZZ();
	CloseLED();
	while (1)
	{
		Key();
		Display();
	}
}

void CloseBUZZ()
{
	BUZZ=0;
	RELAY=0;
	P2=(P2&0x1f)|0xa0;
	P2&=0x1f;
}

void CloseLED()
{
	P0=0xff;
	P2=(P2&0x1f)|0x80;
	P2&=0x1f;
}

void Key()
{
	if (k1==0 && keyflag1==0)
	{
		Write_AT24C02(addr,num);
		addr++;
		if (addr==10)
			addr=0;
		keyflag1=1;
	}
	else if (k1!=0)
		keyflag1=0;
	
	
	if (k2==0 && keyflag2==0)
	{
		num=Read_AT24C02(flag);
		flag++;
		if (flag==10)
			flag=0;
		keyflag2=1;
	}
	else if (k2!=0)
		keyflag2=0;
	
	
	if (k3==0 && keyflag3==0)
	{
		num++;
		flag=0;
		if (num>=255)
			num=0;
		keyflag3=1;
	}
	else if (k3!=0)
		keyflag3=0;
	
	
	if (k4==0 && keyflag4==0)
	{
		num=0;
		flag=0;
		keyflag4=1;
	}
	else if (k4!=0)
		keyflag4=0;
}

void Display()
{
	if (num/100!=0)
	{
		P0=0xff;
		P2=(P2&0x1f)|0xe0;
		P2&=0x1f;
	
		P0=0x20;
		P2=(P2&0x1f)|0xc0;
		P2&=0x1f;
	
		P0=table[num/100];
		P2=(P2&0x1f)|0xef;
		P2&=0x1f;
	}
	
	
	if (num%100/10!=0)
	{
		P0=0xff;
		P2=(P2&0x1f)|0xe0;
		P2&=0x1f;
	
		P0=0x40;
		P2=(P2&0x1f)|0xc0;
		P2&=0x1f;
	
		P0=table[num%100/10];
		P2=(P2&0x1f)|0xef;
		P2&=0x1f;
	}
	
	P0=0xff;
	P2=(P2&0x1f)|0xe0;
	P2&=0x1f;
	
	P0=0x80;
	P2=(P2&0x1f)|0xc0;
	P2&=0x1f;
	
	P0=table[num%10];
	P2=(P2&0x1f)|0xef;
	P2&=0x1f;	
}

 

函数的功能为:独立按键第三个按键为数码管数字的增加, 第四个为清零功能,第一个按键为将当前数字保存在AT24C02中,第二个按键为翻看保存的数据. 已经存储的数据掉电不丢失,只用在重新写入代码时丢失.