蓝桥杯突击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中,第二个按键为翻看保存的数据. 已经存储的数据掉电不丢失,只用在重新写入代码时丢失.