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