目录
一、AT24C20相关函数操作流程
(0)根据第十五届蓝桥杯初始iic.c进行的初步修改(便于编写后续函数)
(1)AT24C20存数据操作流程及代码
(2)AT24C02读数据操作流程及代码
(3)A624C02页写入操作流程及代码
(4)AT24C02页读取操作流程及代码
(5)完整iic头文件和源文件
二、应用举例
(1)开关机次数
(2)存取一组数据
备注:初始iic.c使用的是第十五届蓝桥杯资料中的
一、AT24C20相关函数操作流程
(0)根据第十五届蓝桥杯初始iic.c进行的初步修改(便于编写后续函数)
//iic.c
/* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求,进行代码调试和修改。
*/#include <STC15F2K60S2.H>
#include<intrins.h>
//
#define DELAY_TIME 50//总线引脚定义
sbit sda = P2^1;
sbit scl = P2^0;
//延迟
static void I2C_Delay(unsigned char n)
{do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); }while(n--);
}//总线启动条件
void I2CStart(void)
{sda = 1;scl = 1;I2C_Delay(DELAY_TIME);sda = 0;I2C_Delay(DELAY_TIME);scl = 0;
}//总线停止条件
void I2CStop(void)
{sda = 0;scl = 1;I2C_Delay(DELAY_TIME);sda = 1;I2C_Delay(DELAY_TIME);
}//通过I2C总线发送数据
void I2CSendByte(unsigned char byt)
{unsigned char i;for(i=0; i<8; i++){scl = 0;I2C_Delay(DELAY_TIME);if(byt & 0x80){sda = 1;}else{sda = 0;}I2C_Delay(DELAY_TIME);scl = 1;byt <<= 1;I2C_Delay(DELAY_TIME);}scl = 0;
}//从I2C总线上接收数据
unsigned char I2CReceiveByte(void)
{unsigned char da;unsigned char i;for(i=0;i<8;i++){ scl = 1;I2C_Delay(DELAY_TIME);da <<= 1;if(sda) da |= 0x01;scl = 0;I2C_Delay(DELAY_TIME);}return da;
}//等待应答
unsigned char I2CWaitAck(void)
{unsigned char ackbit;scl = 1;I2C_Delay(DELAY_TIME);ackbit = sda; scl = 0;I2C_Delay(DELAY_TIME);return ackbit;
}//发送应答
void I2CSendAck(unsigned char ackbit)
{scl = 0;sda = ackbit; I2C_Delay(DELAY_TIME);scl = 1;I2C_Delay(DELAY_TIME);scl = 0; sda = 1;I2C_Delay(DELAY_TIME);
}
(1)AT24C20存数据操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写)
- 被控器做出应答后
- 主控器发出地址字节(写)
- 被控器做出应答后
- 主控器发出数据字节(写)
- 被控器做出应答后
- 主控器发出停止信号
void EEPROM_wirte(unsigned char add,unsigned char dat)
{I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();
}
(2)AT24C02读数据操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写)
- 被控器做出应答后
- 主控器发出地址字节(写)
- 被控器做出应答后
- 主控器发出停止信号
- 主控器发出起始信号
- 主控器发出寻址字节(读)
- 被控器做出应答后
- 主控器从被控器读出数据字节,主控器发出应答
- 主控器发出停止信号
unsigned char EEPROM_read(unsigned char add)
{unsigned char dat;I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0XA1);I2CWaitAck();dat = I2CReceiveByte();I2CStop();return dat;
}
(3)A624C02页写入操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写)
- 被控器做出应答后
- 主控器发出数据字节(写)
- 被控器做应答后
- 主控器发出数据字节(写)
- 被控器做出应答后
- 主控器发出停止信号
void AT24C02_Read_Page(unsigned char add)
{unsigned char i = 0 ;IIC_Start();IIC_SendByte(0XA0);IIC_WaitAck();IIC_SendByte(add);IIC_WaitAck();IIC_Stop();IIC_Start();IIC_SendByte(0XA1);IIC_WaitAck();for(i=0;i<8;i++){EEPROM_Read[i] = IIC_RecByte();IIC_SendAck(0);} IIC_Stop();
}
(4)AT24C02页读取操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写)
- 被控器做出应答后
- 主控器发出地址字节(写)
- 被控器做出应答后
- 主控器发出停止信号
- 主控器发出起始信号
- 主控器发出寻址字节(读)
- 被控器做出应答后
- 主控器从被控器读出数据字节,主控器发出应答;
- 主控器发出停止信号
void EEPROM_read_Page(unsigned char add)
{unsigned char i = 0;I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0XA1);I2CWaitAck();for(i=0;i<8;i++){EEPROM_Read[i] = I2CReceiveByte();I2CSendByte(0);}I2CStop();
}
(5)完整iic头文件和源文件
#ifndef _iic_h
#define _iic_hstatic void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
void EEPROM_wirte(unsigned char add,unsigned char dat);
unsigned char EEPROM_read(unsigned char add);
void EEPROM_wirte_Page(unsigned char add);
void EEPROM_read_Page(unsigned char add);
#endif
/* # I2C代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题中对单片机时钟频率的要求,进行代码调试和修改。
*/#include <STC15F2K60S2.H>
#include<intrins.h>
//
#define DELAY_TIME 50//总线引脚定义
sbit sda = P2^1;
sbit scl = P2^0;extern unsigned char EEPROM_Write[8];
extern unsigned char EEPROM_Read[8];//延迟
static void I2C_Delay(unsigned char n)
{do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); }while(n--);
}//总线启动条件
void I2CStart(void)
{sda = 1;scl = 1;I2C_Delay(DELAY_TIME);sda = 0;I2C_Delay(DELAY_TIME);scl = 0;
}//总线停止条件
void I2CStop(void)
{sda = 0;scl = 1;I2C_Delay(DELAY_TIME);sda = 1;I2C_Delay(DELAY_TIME);
}//通过I2C总线发送数据
void I2CSendByte(unsigned char byt)
{unsigned char i;for(i=0; i<8; i++){scl = 0;I2C_Delay(DELAY_TIME);if(byt & 0x80){sda = 1;}else{sda = 0;}I2C_Delay(DELAY_TIME);scl = 1;byt <<= 1;I2C_Delay(DELAY_TIME);}scl = 0;
}//从I2C总线上接收数据
unsigned char I2CReceiveByte(void)
{unsigned char da;unsigned char i;for(i=0;i<8;i++){ scl = 1;I2C_Delay(DELAY_TIME);da <<= 1;if(sda) da |= 0x01;scl = 0;I2C_Delay(DELAY_TIME);}return da;
}//等待应答
unsigned char I2CWaitAck(void)
{unsigned char ackbit;scl = 1;I2C_Delay(DELAY_TIME);ackbit = sda; scl = 0;I2C_Delay(DELAY_TIME);return ackbit;
}//发送应答
void I2CSendAck(unsigned char ackbit)
{scl = 0;sda = ackbit; I2C_Delay(DELAY_TIME);scl = 1;I2C_Delay(DELAY_TIME);scl = 0; sda = 1;I2C_Delay(DELAY_TIME);
}//AT24C20存数据
void EEPROM_wirte(unsigned char add,unsigned char dat)
{I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();
}//读数据
void EEPROM_read(unsigned char add)
{unsigned char temp;I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0XA1);I2CWaitAck();temp=I2CReceiveByte();I2CStop();}
//
void EEPROM_wirte_Page(unsigned char add)
{unsigned char i = 0;I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();for(i=0;i<8;i++){I2CSendByte(EEPROM_Write[i]);I2CWaitAck();}I2CStop();
}
void EEPROM_read_Page(unsigned char add)
{unsigned char i = 0;I2CStart();I2CSendByte(0XA0);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0XA1);I2CWaitAck();for(i=0;i<8;i++){EEPROM_Read[i] = I2CReceiveByte();I2CSendByte(0);}I2CStop();
}
二、应用举例
(1)开关机次数
- 初始化AT24C02的某个存储区域为0
- 每次上电,把该区域数据读出,在数码管显示
- 然后将读出的数据加1,再存回去
- 特别注意:EEPROM有擦写寿命,非必要不擦写,不要在while(1)中循环擦写
#include <STC15F2K60S2.H>
#include<intrins.h>
#include<iic.h>unsigned char LED_Bit = 0XFF;
unsigned char Actuator_Bit=0X00;#define LEDx_ON(n) {LED_Bit &= _crol_(0XFE,n-1);P0=LED_Bit;P2|=0X80;P2&=0X9F;P2&=0X1F;}
#define LEDx_OFF(n) {LED_Bit &= _crol_(0X01,n-1);P0=LED_Bit;P2|=0X80;P2&=0X9F;P2&=0X1F;}#define Buzzer_ON Actuator_Bit|=0x40;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Buzzer_OFF Actuator_Bit&=0xBF;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Relay_ON Actuator_Bit|=0x10;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Relay_OFF Actuator_Bit&=0xEF;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
unsigned char KEY_Value=0;
unsigned char DigCom=0;
unsigned char DigBuf[8]={10,10,10,10,10,10,10,10};unsigned char LED = 1;
unsigned int LED_tt=0;
bit LED_Ref=0;unsigned int SEG_tt=0;
bit SEG_Ref=0;
bit SEG_Run=0;
unsigned int Num = 999;unsigned char Open = 0;unsigned char EEPROM_Write[8] = {2,3,4,5,6,7,8,9};
unsigned char EEPROM_Read[8] = {0,0,0,0,0,0,0,0};void ALL_Init(void);
void Delay_MS(unsigned int MS);
void KeyScan(void);
void ArrKeyScan(void);
void Timer0Init(void); //1毫秒@11.0592MHzvoid main(void)
{ALL_Init();Timer0Init();EA=1;ET0=1;Open = EEPROM_read(0x15); Delay_MS(5);EEPROM_wirte(0X15,++Open);Delay_MS(5);DigBuf[0]=Open/10;DigBuf[1]=Open%10;// EEPROM_wirte_Page(0X12);Delay_MS(50);
// EEPROM_read_Page(0X12); Delay_MS(50);
//
// DigBuf[0]=EEPROM_Read[0];DigBuf[1]=EEPROM_Read[1];DigBuf[2]=EEPROM_Read[2];DigBuf[3]=EEPROM_Read[3];
// DigBuf[4]=EEPROM_Read[4];DigBuf[5]=EEPROM_Read[5];DigBuf[6]=EEPROM_Read[6];DigBuf[7]=EEPROM_Read[7];
// while(1){KeyScan();if(KEY_Value==7){KEY_Value=0;SEG_Run = 1 ;}if(KEY_Value==6){KEY_Value=0;SEG_Run = 0 ;}if(KEY_Value==5){KEY_Value=0;LEDx_ON(1);Buzzer_ON;}if(KEY_Value==4){KEY_Value=0;LEDx_OFF(1);Buzzer_OFF;} }
}void KeyScan(void)
{if(P30==0){Delay_MS(10);if(P30==0)KEY_Value = 7 ; while(!P30);}else if(P31==0){Delay_MS(10);if(P31==0)KEY_Value = 6 ;while(!P31);} else if(P32==0){Delay_MS(10);if(P32==0)KEY_Value = 5 ; while(!P32);} else if(P33==0){Delay_MS(10);if(P33==0)KEY_Value = 4 ; while(!P33);}
}void Timer0(void) interrupt 1
{P0=0X00;P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器 P0=tab[DigBuf[DigCom]]; P2|=0XE0; // P2=P2|0XE0; XXXX XXXX | 1110 0000 = 111X XXXXP2&=0XFF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器P0=(0X01<<DigCom); //然后选中第一个数码管P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器if(++DigCom == 8)DigCom = 0 ;LED_tt++;if(LED_tt == 999) {LED_tt = 0 ; LED_Ref = 1 ;}if(++SEG_tt==1000){SEG_tt=0;SEG_Ref=1;}
// XXX_tt++;
// if(++XXX_tt==NNN){XXX_tt=0;XXX_Ref=1;}
}void Timer0Init(void) //1毫秒@11.0592MHz
{AUXR |= 0x80; //定时器时钟1T模式TMOD &= 0xF0; //设置定时器模式TL0 = 0xCD; //设置定时初始值TH0 = 0xD4; //设置定时初始值TF0 = 0; //清除TF0标志TR0 = 1; //定时器0开始计时
}void Delay_MS(unsigned int MS)
{unsigned char i, j;while(MS--){_nop_();_nop_();_nop_();i = 11;j = 190;do{while (--j);} while (--i);
}}void ALL_Init(void)
{P0 =0X00; //先设置关闭蜂鸣器继电器的P0输出值(全关)P2|=0XA0; // 将P27 P25 设置为1 其他位保持不变P2&=0XBF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0XFF; //先设置关闭所有的LED的P0输出值(全关)P2|=0X80; // 将P27设置为1 其他位保持不变P2&=0X9F; // 将P26 P25设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0X00; //先设置选择数码管位选的P0输出值(全不选)P2|=0XC0; // 将P27 P26 设置为1 其他位保持不变P2&=0XDF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器
}
(2)存取一组数据
#include <STC15F2K60S2.H>
#include<intrins.h>
#include<iic.h>unsigned char LED_Bit = 0XFF;
unsigned char Actuator_Bit=0X00;#define LEDx_ON(n) {LED_Bit &= _crol_(0XFE,n-1);P0=LED_Bit;P2|=0X80;P2&=0X9F;P2&=0X1F;}
#define LEDx_OFF(n) {LED_Bit &= _crol_(0X01,n-1);P0=LED_Bit;P2|=0X80;P2&=0X9F;P2&=0X1F;}#define Buzzer_ON Actuator_Bit|=0x40;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Buzzer_OFF Actuator_Bit&=0xBF;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Relay_ON Actuator_Bit|=0x10;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;
#define Relay_OFF Actuator_Bit&=0xEF;P0=Actuator_Bit;P2|=0XA0;P2&=0XBF;P2&=0X1F;unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
unsigned char KEY_Value=0;
unsigned char DigCom=0;
unsigned char DigBuf[8]={10,10,10,10,10,10,10,10};unsigned char LED = 1;
unsigned int LED_tt=0;
bit LED_Ref=0;unsigned int SEG_tt=0;
bit SEG_Ref=0;
bit SEG_Run=0;
unsigned int Num = 999;unsigned char Open = 0;unsigned char EEPROM_Write[8] = {2,3,4,5,6,7,8,9};
unsigned char EEPROM_Read[8] = {0,0,0,0,0,0,0,0};void ALL_Init(void);
void Delay_MS(unsigned int MS);
void KeyScan(void);
void ArrKeyScan(void);
void Timer0Init(void); //1毫秒@11.0592MHzvoid main(void)
{ALL_Init();Timer0Init();EA=1;ET0=1;// EEPROM_wirte(0x15,0);
// Delay_MS(1);
// Open = EEPROM_read(0x15);
// Delay_MS(5);
// DigBuf[0]=Open/10;DigBuf[1]=Open%10;EEPROM_wirte_Page(0X12);Delay_MS(50);EEPROM_read_Page(0X12); Delay_MS(50);DigBuf[0]=EEPROM_Read[0];DigBuf[1]=EEPROM_Read[1];DigBuf[2]=EEPROM_Read[2];DigBuf[3]=EEPROM_Read[3];DigBuf[4]=EEPROM_Read[4];DigBuf[5]=EEPROM_Read[5];DigBuf[6]=EEPROM_Read[6];DigBuf[7]=EEPROM_Read[7];while(1){KeyScan();if(KEY_Value==7){KEY_Value=0;SEG_Run = 1 ;}if(KEY_Value==6){KEY_Value=0;SEG_Run = 0 ;}if(KEY_Value==5){KEY_Value=0;LEDx_ON(1);Buzzer_ON;}if(KEY_Value==4){KEY_Value=0;LEDx_OFF(1);Buzzer_OFF;} }
}void KeyScan(void)
{if(P30==0){Delay_MS(10);if(P30==0)KEY_Value = 7 ; while(!P30);}else if(P31==0){Delay_MS(10);if(P31==0)KEY_Value = 6 ;while(!P31);} else if(P32==0){Delay_MS(10);if(P32==0)KEY_Value = 5 ; while(!P32);} else if(P33==0){Delay_MS(10);if(P33==0)KEY_Value = 4 ; while(!P33);}
}void Timer0(void) interrupt 1
{P0=0X00;P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器 P0=tab[DigBuf[DigCom]]; P2|=0XE0; // P2=P2|0XE0; XXXX XXXX | 1110 0000 = 111X XXXXP2&=0XFF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器P0=(0X01<<DigCom); //然后选中第一个数码管P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器if(++DigCom == 8)DigCom = 0 ;LED_tt++;if(LED_tt == 999) {LED_tt = 0 ; LED_Ref = 1 ;}if(++SEG_tt==1000){SEG_tt=0;SEG_Ref=1;}
// XXX_tt++;
// if(++XXX_tt==NNN){XXX_tt=0;XXX_Ref=1;}
}void Timer0Init(void) //1毫秒@11.0592MHz
{AUXR |= 0x80; //定时器时钟1T模式TMOD &= 0xF0; //设置定时器模式TL0 = 0xCD; //设置定时初始值TH0 = 0xD4; //设置定时初始值TF0 = 0; //清除TF0标志TR0 = 1; //定时器0开始计时
}void Delay_MS(unsigned int MS)
{unsigned char i, j;while(MS--){_nop_();_nop_();_nop_();i = 11;j = 190;do{while (--j);} while (--i);
}}void ALL_Init(void)
{P0 =0X00; //先设置关闭蜂鸣器继电器的P0输出值(全关)P2|=0XA0; // 将P27 P25 设置为1 其他位保持不变P2&=0XBF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0XFF; //先设置关闭所有的LED的P0输出值(全关)P2|=0X80; // 将P27设置为1 其他位保持不变P2&=0X9F; // 将P26 P25设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0X00; //先设置选择数码管位选的P0输出值(全不选)P2|=0XC0; // 将P27 P26 设置为1 其他位保持不变P2&=0XDF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器
}