AN1113 使用C语言和硬件模块实现8051MCU与IIC串行EEPROM的接口

合集下载

单片机IIC程序设计用c8051f单片机

单片机IIC程序设计用c8051f单片机

#include <c8051f020.h> // SFR declarations//------------------------------------------------------------------------------------// Global CONSTANTS//------------------------------------------------------------------------------------#define WRITE 0x00 // SMBus WRITE command#define READ 0x01 // SMBus READ command// Device addresses (7 bits, lsb is a don't care)#define CLOCK3530_ADDRESS_RESET 0x60 //1 ack#define CLOCK3530_ADDRESS_STATUS 0x62 //2 ack#define CLOCK3530_ADDRESS_DATEHOUR 0x64 //8 ack year month day week hour minute second#define CLOCK3530_ADDRESS_HOUR 0x66 //4 ack hour minute second#define CLOCK3530_ADDRESS_INT1 0x68 //3 ack#define CLOCK3530_ADDRESS_INT2 0x6A //3 ackunion{unsigned char ClockString[7];struct RealClock{unsigned char Year,Month,Day,Week,Hour,Minute,Second;} RT;} RealTime;// SMBus states:// MT = Master Transmitter// MR = Master Receiver#define SMB_BUS_ERROR 0x00 // (all modes) BUS ERROR#define SMB_START 0x08 // (MT & MR) START transmitted#define SMB_RP_START 0x10 // (MT & MR) repeated START#define SMB_MTADDACK 0x18 // (MT) Slave address + W transmitted;// ACK received#define SMB_MTADDNACK 0x20 // (MT) Slave address + W transmitted;// NACK received#define SMB_MTDBACK 0x28 // (MT) data byte transmitted; ACK rec'vd #define SMB_MTDBNACK 0x30 // (MT) data byte transmitted; NACK rec'vd#define SMB_MTARBLOST 0x38 // (MT) arbitration lost#define SMB_MRADDACK 0x40 // (MR) Slave address + R transmitted;// ACK received#define SMB_MRADDNACK 0x48 // (MR) Slave address + R transmitted;// NACK received#define SMB_MRDBACK 0x50 // (MR) data byte rec'vd; ACK transmitted #define SMB_MRDBNACK 0x58 // (MR) data byte rec'vd; NACK transmitted//-----------------------------------------------------------------------------------//Global V ARIABLES//-----------------------------------------------------------------------------------char COMMAND; // Holds the slave address + R/W bit for use in the SMBus ISR. unsigned char *I2CDataBuff;char BYTE_NUMBER; // Used by ISR to check what data has just been// sent - High address byte, Low byte, or data byteunsigned char HIGH_ADD, LOW_ADD; // High & Low byte for EEPROM memory addressbit SM_BUSY; // This bit is set when a send or receive// is started. It is cleared by the// ISR when the operation is finished.//------------------------------------------------------------------------------------// Function PROTOTYPES//------------------------------------------------------------------------------------void SMBus_ISR (void);//------------------------------------------------------------------------------------// MAIN Routine//------------------------------------------------------------------------------------//// Main routine configures the crossbar and SMBus, and tests// the SMBus interface between the three EEPROMsvoid ResetRealClock(void){while (SM_BUSY); // Wait for SMBus to be free.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 0; // 2 address bytes.COMMAND = (CLOCK3530_ADDRESS_RESET | READ); // Chip select + READ STA = 1; // Start transferwhile (SM_BUSY); // Wait for transfer to finish }//======================写S-3530A内部实时数据寄存器程序=====================//功能:将设定年、月、日、星期、时、分、秒数据写入S-3530A |//入口:发送数据放在年、月、日、星期、时、分、秒各寄存器|//出口:NONE |//===================================================================== =====void SetRealClock(void){while (SM_BUSY); // Wait for SMBus to be free.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 7; // 2 address bytes.COMMAND = (CLOCK3530_ADDRESS_DATEHOUR | WRITE); // Chip select + WRITEI2CDataBuff = &RealTime.ClockString[0]; // Data to be writenSTA = 1; // Start transfer}//==================读S-3530A实时数据寄存器子程序===========================//功能:从S-3530A读入当前时间数据|//入口:NONE |//出口:接收数据放在年、月、日、星期、时、分、秒各寄存器|//===================================================================== =====void GetRealClock(void){while (SM_BUSY); // Wait for SMBus to befree.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 7; // 2 address bytes.COMMAND = (CLOCK3530_ADDRESS_DATEHOUR | READ); // Chip select + READI2CDataBuff = &RealTime.ClockString[0]; // Data to be writenSTA = 1; // Start transferwhile (SM_BUSY); // Wait for transfer to finish }//============================写状态寄存器程序==============================//功能:读/写S-3530A状态寄存器,对S-3530A进行设置|//入口:NONE 出口:NONE | //===================================================================== =====unsigned char GetRealClockStatus(void){unsigned char result;while (SM_BUSY); // Wait for SMBus to be free.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 1;COMMAND = (CLOCK3530_ADDRESS_STATUS | READ);I2CDataBuff = &result;STA = 1; // Start transferwhile (SM_BUSY); // Wait for transfer to finish return result;}void SetRealClockStatus(unsigned char status){while (SM_BUSY); // Wait for SMBus to be free.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 1;COMMAND = (CLOCK3530_ADDRESS_STA TUS | WRITE);I2CDataBuff = &status;STA = 1; // Start transfer}/*void SetRealClockINT1(unsigned int Int1){while (SM_BUSY); // Wait for SMBus to be free.SM_BUSY = 1; // Occupy SMBus (set to busy)SMB0CN = 0x44; // SMBus enabled, ACK on acknowledge cycleBYTE_NUMBER = 2;COMMAND = (CLOCK3530_ADDRESS_INT1 | WRITE);I2CDataBuff = (unsigned char*)&Int1;STA = 1; // Start transfer}*/#include "INTRINS.H"unsigned char revolve(unsigned char val){char i;unsigned char val1=0;for (i=0;i<8;i++){if (val&0x1)val1++;val1=_crol_(val1,1);val=_cror_(val,1);}val1=_cror_(val1,1);return val1;}/*-- 文字: 时--*/char code Shi[]={0x00,0x00,0xFC,0x44,0x44,0xFC,0x00,0x08,0x48,0x88,0x08,0xFF,0x08,0x08,0x08,0x00, 0x00,0x00,0x1F,0x04,0x04,0x0F,0x00,0x00,0x00,0x11,0x20,0x1F,0x00,0x00,0x00,0x00, };/*-- 文字: 钟--*/char code Zhong[]={0x00,0x60,0x38,0xE7,0x24,0x24,0x04,0x00,0xF8,0x88,0x88,0xFF,0x88,0x88,0xF8,0x00, 0x00,0x01,0x01,0x3F,0x11,0x09,0x01,0x00,0x01,0x00,0x00,0x3F,0x00,0x00,0x01,0x00, };void LCD_WriteHZ(char x,char y,char *Dot);void LCD_DispChar(char x,char y,char ch); //128*64 取值x=0-128 y=0-8void InitLCD(void);void Delay1ms(unsigned char T);void TestI2C (void){unsigned char var ;WDTCN = 0xde; // disable watchdog timerWDTCN = 0xad;OSCICN |= 0x03; // Set internal oscillator to highest setting// (16 MHz)XBR0 |= 0x07; // Route SMBus to GPIO pins through crossbarXBR2 |= 0x44; // Enable crossbar and weak pull-upsP0MDOUT |= 0x1D;P1MDOUT |= 0x01;SMB0CN = 0x44; // Enable SMBus with ACKs on acknowledge cycleSMB0CR = -80; // SMBus clock rate = 100kHz.EIE1 |= 2; // SMBus interrupt enableEA = 1; // Global interrupt enableSM_BUSY = 0; // Free SMBus for first transfer.// SetRealClockINT1(0x8000);var = GetRealClockStatus();ResetRealClock();var = GetRealClockStatus();SetRealClockStatus(0xc2);var = GetRealClockStatus();GetRealClock();RealTime.RT.Year=0x02;RealTime.RT.Month=0x12;RealTime.RT.Day=0x010;RealTime.RT.Week=0x05;RealTime.RT.Hour=0x11;RealTime.RT.Minute=0x59;RealTime.RT.Second=0x57;SetRealClock();GetRealClock();InitLCD();LCD_WriteHZ(0,0,Shi);LCD_WriteHZ(16,0,Zhong);//在0,2处显示00:00:00LCD_DispChar(0,2,0); //128*64 取值x=0-128 y=0-8LCD_DispChar(8,2,0);LCD_DispChar(16,2,10);LCD_DispChar(24,2,0);LCD_DispChar(32,2,0);LCD_DispChar(40,2,0xa);LCD_DispChar(48,2,0);LCD_DispChar(56,2,0);//在0,4处显示02/01/01LCD_DispChar(0,4,0); //128*64 取值x=0-128 y=0-8LCD_DispChar(8,4,2);LCD_DispChar(16,4,0xb);LCD_DispChar(24,4,0);LCD_DispChar(32,4,1);LCD_DispChar(40,4,0xb);LCD_DispChar(48,4,0);LCD_DispChar(56,4,1);for (;;){GetRealClock();LCD_DispChar(0,2,(RealTime.RT.Hour>>4)&0x03);//(RealTime.RT.Hour>>4)&0x0f); //128*64 取值x=0-128 y=0-8LCD_DispChar(8,2,RealTime.RT.Hour&0x0f);LCD_DispChar(24,2,(RealTime.RT.Minute>>4)&0x0f);LCD_DispChar(32,2,RealTime.RT.Minute&0x0f);LCD_DispChar(48,2,(RealTime.RT.Second>>4)&0x0f);LCD_DispChar(56,2,RealTime.RT.Second&0x0f);//在0,4处显示02/01/01LCD_DispChar(0,4,(RealTime.RT.Year>>4)&0x0f);LCD_DispChar(8,4,RealTime.RT.Year&0x0f);LCD_DispChar(24,4,(RealTime.RT.Month>>4)&0x0f);LCD_DispChar(32,4,RealTime.RT.Month&0x0f);LCD_DispChar(48,4,(RealTime.RT.Day>>4)&0x0f);LCD_DispChar(56,4,RealTime.RT.Day&0x0f);Delay1ms(100);}}//------------------------------------------------------------------------------------// Interrupt Service Routine//------------------------------------------------------------------------------------void SMBUS_ISR (void) interrupt 7{switch (SMB0STA){ // SMBus 状态码SMB0STA 寄存器// 主发送器/接收器起始条件已发送case SMB_START:SMB0DAT = COMMAND ; // 装入要访问的从器件的地址STA = 0; // 手动清除START 位break;//主发送器/接收器重复起始条件已发送// 该状态只应在读操作期间出现在存储器地址已发送并得到确认之后?case SMB_RP_START:SMB0DAT = COMMAND; // COMMAND 中应保持从地址+ R.STA = 0;break;// 主发送器从地址+ WRITE 已发送收到ACKcase SMB_MTADDACK:// 主发送器数据字节已发送收到ACKcase SMB_MTDBACK:if (BYTE_NUMBER){SMB0DAT = revolve(*I2CDataBuff); // If R/W=WRITE, load byte to write.I2CDataBuff++;BYTE_NUMBER--;}else{STO = 1; SM_BUSY = 0; // Free SMBus}break;// 主发送器从地址+ WRITE 已发送收到NACK// 从器件不应答发送STOP + START 重试case SMB_MTADDNACK:STO = 1; STA = 1;break;// 主发送器数据字节已发送收到NACK// 从器件不应答发送STOP + START 重试case SMB_MTDBNACK:STO = 1; STA = 1;break;// 主发送器竞争失败// 不应出现如果出现重新开始传输过程case SMB_MTARBLOST:STO = 1; STA = 1;break;// 主接收器从地址+ READ 已发送,收到ACKcase SMB_MRADDACK:AA = 1; // 在应答周期ACKif (!BYTE_NUMBER){STO = 1; SM_BUSY = 0; // 释放SMBus}break;// 主接收器从地址+ READ 已发送收到NACK// 从器件不应答发送重复起始条件重试case SMB_MRADDNACK:STA = 1;break;// 收到数据字节ACK 已发送// 该状态不应出现因为AA 已在前一状态被清0 如果出现发送停止条件case SMB_MRDBACK:if (BYTE_NUMBER){*I2CDataBuff=revolve(SMB0DA T);I2CDataBuff++;BYTE_NUMBER--;}if (!BYTE_NUMBER) AA= 0;break;// 收到数据字节NACK 已发送// 读操作已完成读数据寄存器后发送停止条件case SMB_MRDBNACK:STO = 1;SM_BUSY = 0; // 释放SMBusbreak;// 在本应用中所有其它状态码没有意义通信复位default:STO = 1; // 通信复位SM_BUSY = 0;break;}SI=0; // 清除中断标志}/*{switch (SMB0STA){ // Status code for the SMBus (SMB0STA register) case SMB_START:SMB0DAT = COMMAND; // COMMAND should hold slave address + R.break;case SMB_MTADDNACK:STO = 1;STA = 1;break;case SMB_RP_START:// SMB0DAT = COMMAND; // COMMAND should hold slave address + R.// STA = 0;// break;case SMB_MTADDACK:case SMB_MTDBACK:if (BYTE_NUMBER){if (COMMAND & 0x01) // If R/W=READ,{STA = 1;}else{SMB0DAT = *I2CDataBuff; // If R/W=WRITE, load byte to write.I2CDataBuff++;BYTE_NUMBER--;}}else{STO = 1;SM_BUSY = 0; // Free SMBus}break;// Master Transmitter: Data byte transmitted. NACK received.// Slave not responding. Send STOP followed by START to try again.case SMB_MTDBNACK:STO = 1;STA = 1;break;// Master Transmitter: Arbitration lost.// Should not occur. If so, restart transfer.case SMB_MTARBLOST:STO = 1;STA = 1;break;// Master Receiver: Slave address + READ transmitted. NACK received.// Slave not responding. Send repeated start to try again.case SMB_MRADDNACK:STA = 1;break;// Data byte received. ACK transmitted.// State should not occur because AA is set to zero in previous state.// Send STOP if state does occur.case SMB_MRDBACK:STO = 1;SM_BUSY = 0;break;// Master Receiver: Slave address + READ transmitted. ACK received.// Set to transmit NACK after next transfer since it will be the last (only) byte.case SMB_MRADDACK:// AA = 0; // NACK sent on acknowledge cycle.// break;// Data byte received. NACK transmitted.// Read operation has completed. Read data register and send STOP.case SMB_MRDBNACK:if (BYTE_NUMBER){if (COMMAND & 0x01) // If R/W=READ,{*I2CDataBuff=SMB0DA T;I2CDataBuff++;}BYTE_NUMBER--;}else{STO = 1;SM_BUSY = 0; // Free SMBus}break;// All other status codes meaningless in this application. Reset communication.default:STO = 1; // Reset communication.SM_BUSY = 0;break;}SI=0; // clear interrupt flag }*/。

51单片机模拟IIC工作时序,以EEPROM器件进行掉电保护数据

51单片机模拟IIC工作时序,以EEPROM器件进行掉电保护数据

51单片机软件模拟I2C时序,进行掉电保护数据在数码管上按顺序显示数据0—f(十六进制)模拟断电-切断单片机电源复位后接着断电前数据显示#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit sda=P2^0;sbit scl=P2^1;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39 ,0x5e,0x79,0x71} ;uchar num,sec,panju;//由定时器进行计数,计时,以数组的形式显示于数码管每隔1S读一次AT24C16中的数据//-------------------------------定时器0进行精确的计时,由AT24C16进行掉电保护----------------------------------//void delay(){;;}void init_timer0()//定时器初始化{TMOD=0X01;//工作方式1,GATE=0,C/~T=0,M0=0,M1=1;TH0=15536/256;//求模TL0=15536%256;//求余装入初值EA=1;ET0=1;//中断允许寄存器TR0=1;//TCON寄存器}//------------------------------------------------------------------------------------------------------------//void init_AT()//EEPROM器件初始化释放总线{scl=0;delay();//微秒延时sda=1;delay();scl=1;delay();}//----------------------------------------------------------------------------------------------------------//void start() //起始信号{scl=0;delay();sda=1;delay();scl=1;delay();sda=0;delay();sda=1;//释放数据总线//--------------------------------------------------------------------------------------------------------//void write_byte(uchar date)//字节写{uchar s,temp;//局部变量temp=date;//由高位一位一位的写入for(s=0;s<8;s++){temp=temp<<1;//左移溢出到PSW寄存器CY位scl=0;//允许sda进行的变化delay();sda=CY;//进行一位一位的送入数据总线delay();scl=1;//符合读走数据总线上数据的要求delay();//稳定一段时间}scl=0;//允许sda变化,以便于接受应答信号delay();sda=1;//释放数据总线,准备接收应答信号delay();}//--------------------------------------------------------------------------------------------------------//void response()//应答,可以看书page181,由接收设备发出的第九位数据,要经由sda传输给发送设备{uchar t;//局部变量scl=1;delay();while((sda==1)&&(t<250)){t++;//等待应答有一定的时间限制,sda被拉低表示有应答,由硬件控制}scl=0;delay();}//------------------------------------------------------------------------------------------------------//void stop()//停止信号,scl=1,sda形成一个正跳变{scl=0;//允许sda变化delay();sda=0;//准备形成正跳变delay();scl=1;//信号有效前提1delay();sda=1;//形成正跳变delay();//信号有效前提1}//-----------------------------------------------------------------------------------------------------//void delay1(uint z)//毫秒级延时{for(x=z;x>0;x--)for(y=10;y>0;y--);}//---------------------------------------------------------------------------------------------------------------//uchar read_byte()//带有返回值,将所读到的数据作为返回值{uchar i,d;//局部变量d=0x00;//清空存储变量的空间for(i=0;i<8;i++){scl=0;//允许变化,即允许传送数据,sda是serial dual date busdelay();scl=1;//允许读走数据delay();d=(d<<1)|sda;//将sda上数据放入存储变量d,也是8位ucharscl=0;delay();}return d;}//----------------------------------------------------------------------------------------------------------//void write_add(uchar address,uchar date) //任意位置,写任意内容{start();//起始信号write_byte(0xa0);//写入EEPROM器件地址,写入分为数据,地址数据,地址又分为器件地址和内部存储地址,例如某班级某学生座位response();//等待应答write_byte(address);//内部存储地址实际参数addressresponse();write_byte(date);//写入真正意义上的数据,由引入的实际参数dateresponse();//等待应答stop();//停止读取数据信号delay1(1);}//-------------------------------------------------------------------------------------------------------//uchar read_add(uchar address){uchar shu;start();write_byte(0xa0);//申明所读器件地址response();write_byte(address);//申明该器件中所要求读数据的位置response();start();write_byte(0xa1);response();shu=read_byte();//进行读数据操作后,非应答,budaixingcan,而是将返回值直接赋予变量stop();}//------------------------------------------------------------------------------------------------------------// void main(){P0=0X00;init_AT();sec=read_add(0X03);//将芯片中数据读出;作为基数init_timer0();//定时器初始化设置if(sec==16)sec=0;while(1){P0=table[sec];if(panju==1){panju=0;write_add(0x03,sec);}}}//---------------------------------------------------------------------------------------------------------// void timer0_break() interrupt 1{TH0=15536/256;//求模TL0=15536%256;//求余装入初值num++;if(num==20){num=0;sec++;panju=1;if(sec==16) sec=0;}}。

8051单片机的内部结构

8051单片机的内部结构

8051单片机的内部结构首先,8051单片机的核心是一个具有8位数据总线、16位地址总线和14个通用寄存器的8051中央处理器(Central Processing Unit,简称CPU)。

CPU负责执行计算、逻辑和控制指令,并与其他外设进行数据交换。

它包含一个累加器(Accumulator)和一个数据指针(Data Pointer),用于存储数据和指示数据存储区。

除了CPU外,8051单片机内还包含两个片内存储器,分别是程序存储器(Program Memory)和数据存储器(Data Memory)。

程序存储器是用于存储程序指令的地方,通常包括ROM(只读存储器)或闪存。

程序存储器采用分时复用方式,既可以存储程序指令,也可以存储常量数据。

由于8051单片机是哈佛结构,程序存储器和数据存储器是分开的,可以同时进行取指令和读写数据操作。

数据存储器主要用于存储程序运行时需要使用的数据,包括RAM(随机存储器)和片内特殊功能寄存器(Special Function Registers,简称SFR)。

RAM负责存储变量、临时数据和堆栈信息。

SFR包含IO口控制、定时器配置、计数器设置等特殊功能寄存器,通过设置和读取其值,可以对相应的硬件模块进行控制。

除了上述核心部件,8051单片机还包含多个外设,用于完成具体的输入输出任务。

其中,IO口是最常用的外设之一,用于将单片机与外部设备连接起来。

IO口可以进行数字输入输出和模拟输入输出。

每个IO口引脚都具有独立的控制寄存器,通过这些寄存器可以设置引脚的输入输出方向、电平和驱动能力。

IO口的灵活性和可扩展性给了8051单片机很大的应用空间。

此外,8051单片机还包含多个片内计数器和定时器,用于时间测量、时间控制和脉冲宽度调制等任务。

其中,定时器主要用于产生精确的时间延迟,而计数器主要用于计算外部事件的频率和脉冲个数。

最后,8051单片机内还通过中断系统实现了实时响应外部事件的能力。

51单片机c语言教程

51单片机c语言教程

51单片机c语言教程单片机是一种集成了处理器、存储器和各种输入输出接口的微型计算机。

它可以用来完成各种任务,如控制电机、采集数据、控制显示等。

在单片机中,C语言是一种常用的编程语言,通过使用C语言来编写单片机程序,可以更加方便快捷地完成各种功能。

单片机使用C语言进行编程的主要流程如下:首先,需要搭建一个适合的开发环境。

在使用C语言编写单片机程序之前,需要安装相应的开发工具,如Keil C51、IAR Embedded Workbench等。

这些开发工具可以提供编译、调试等功能,方便我们进行程序开发和调试。

接下来,需要了解单片机的硬件平台。

在编写单片机程序之前,需要了解单片机的硬件结构和各个引脚的功能。

单片机的硬件平台通常包括定时器、串口、数字转换等模块,通过对这些模块的理解,可以更好地利用它们完成各种任务。

然后,可以开始编写C语言程序。

C语言是一种结构化的高级语言,通过使用C语言,可以更方便地完成单片机程序的编写。

在编写C语言程序之前,需要了解C语言的语法和常用的函数库,如输入输出函数库、定时器函数库等。

通过灵活地使用这些函数,可以更加快速地实现想要的功能。

在编写C语言程序时,需要注意一些常见的问题。

比如,需要合理地分配内存空间,避免内存溢出等问题;需要注意函数的调用顺序,保证程序的正确执行;需要考虑编程的效率,避免不必要的计算和资源浪费;需要进行适当的程序调试,确保程序的正确性等。

最后,需要进行程序的下载和调试。

在编写完成单片机程序后,需要将程序下载到单片机的存储器中,并进行相应的调试工作,确保程序能够正常运行。

调试过程中,可以通过调试工具查看程序的执行过程,可以进行单步调试、变量跟踪等操作,帮助我们找出程序中的错误和问题,并进行修正。

通过以上步骤,可以更加方便地使用C语言来编写单片机程序。

当然,单片机的应用非常广泛,不仅仅限于C语言的编程,还可以使用汇编语言、基于图形化编程语言的开发工具等。

iic时序c语言

iic时序c语言

iic时序c语言IIC(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器和各种外围设备。

在IIC通信中,有两个主要的信号线:SDA(串行数据线)和SCL(串行时钟线)。

在C语言中,可以通过模拟这两个信号线来与IIC设备进行通信。

以下是一个简单的IIC时序C语言代码示例,用于发送一个字节的数据:```cinclude <>include <>define SDA_PIN GPIO_Pin_0define SCL_PIN GPIO_Pin_1void IIC_Start() {GPIO_SetBits(GPIOA, SDA_PIN);GPIO_SetBits(GPIOA, SCL_PIN);GPIO_ResetBits(SDA_PIN);}void IIC_Stop() {GPIO_SetBits(GPIOA, SDA_PIN);GPIO_SetBits(GPIOA, SCL_PIN);GPIO_SetBits(SDA_PIN);GPIO_ResetBits(SCL_PIN);}char IIC_ACK() {GPIO_SetBits(GPIOA, SDA_PIN);GPIO_SetBits(SCL_PIN);char flag = GPIO_ReadInputDataBit(GPIOA, SDA_PIN); GPIO_ResetBits(SCL_PIN);return flag;}void IIC_SendByte(uint8_t byte) {for (int i = 7; i >= 0; i--) {GPIO_SetBits(GPIOA, SDA_PIN);if (byte & 0x80) {GPIO_SetBits(SDA_PIN);} else {GPIO_ResetBits(SDA_PIN);}byte <<= 1;GPIO_ResetBits(SCL_PIN);}IIC_ACK(); // 等待应答信号}```在这个示例中,我们定义了四个函数:IIC_Start、IIC_Stop、IIC_ACK和IIC_SendByte。

8051单片机教程

8051单片机教程

8051单片机教程一、认识8051单片机8051单片机是一款经典的微控制器,自1981年由英特尔公司推出以来,便广泛应用于工业控制、智能家居、嵌入式系统等领域。

本教程将带领大家了解8051单片机的结构、原理及其编程方法。

1. 8051单片机的基本结构(1)中央处理器(CPU):负责执行程序指令,进行数据处理和控制。

(2)存储器:包括程序存储器(ROM)和数据存储器(RAM)。

程序存储器用于存放程序代码,数据存储器用于存放运行过程中的数据和变量。

(3)定时器/计数器:用于实现定时或计数功能,可应用于各种场合,如延时、脉冲计数等。

(4)并行I/O口:共有4个8位的并行I/O口,可用于连接外部设备,进行数据输入输出。

(5)串行通信接口:用于与其他设备进行串行通信,可实现数据的长距离传输。

(6)中断系统:允许外部设备或内部事件打断正常的程序执行流程,提高系统的实时性。

2. 8051单片机的特点(1)指令丰富:8051单片机拥有111条指令,包括数据传送、逻辑运算、算术运算、位操作等。

(2)硬件资源丰富:具备定时器、串行通信接口、中断系统等硬件资源,易于实现各种功能。

(3)扩展性强:可通过外部总线扩展存储器、I/O口等资源。

(4)功耗低:适用于电池供电的便携式设备。

(5)成本低:8051单片机价格低廉,性价比高。

二、8051单片机的编程基础1. 汇编语言与C语言2. 开发环境搭建(1)并安装Keil软件。

(2)创建一个新项目,选择8051单片机型号。

(3)编写,并将文件添加到项目中。

(4)编译、项目,可执行文件。

(5)将可执行文件到8051单片机中,进行调试和运行。

3. 基本语法与编程规范(1)变量定义:在C语言中,使用变量前需先进行定义。

例如:unsigned char count; // 定义一个无符号字符型变量count(2)数据类型:8051单片机支持多种数据类型,如char、int、long等。

EEPROMI2C操作说明

EEPROMI2C操作说明

EEPROMI2C操作说明EEPROM (Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,可以通过电子方式擦除和编程,同时可以通过I2C总线进行操作。

本文将详细介绍EEPROM的I2C操作说明。

I2C(Inter-Integrated Circuit)是一种串行通信接口协议,可以在多个设备之间进行通信。

在EEPROM的I2C操作中,需要了解以下几个重要的概念和步骤。

1.设备地址:每个通过I2C连接的设备都有一个唯一的设备地址。

在EEPROM的I2C操作中,需要使用设备地址来与EEPROM进行通信。

2.起始条件和停止条件:I2C通信中,起始条件表示通信的开始,停止条件表示通信的结束。

起始条件由一个高电平到低电平的SCL上升沿和一个低电平的SDA下降沿组成,停止条件由一个低电平到高电平的SCL上升沿和一个高电平的SDA上升沿组成。

3. 数据传输:I2C通信中,数据可以以字节的形式进行传输。

每个字节由8个bit组成,包括7个数据位和1个校验位。

在进行EEPROM的I2C操作时,通常需要经过以下几个步骤:1.发送起始条件:将SCL和SDA引脚拉高,然后将SDA引脚拉低,形成起始条件。

2.发送设备地址和写命令:根据EEPROM的设备地址,将设备地址和写命令(0)发送到SDA引脚。

3.发送要写入的地址:将要写入数据的地址发送到SDA引脚。

4.发送数据:将要写入的数据发送到SDA引脚。

5.发送停止条件:将SCL引脚拉高,然后将SDA引脚拉高,形成停止条件。

实际的EEPROM的I2C操作可能还包括以下一些操作:1.读操作:通过发送读命令(1)和读取数据的地址,可以从EEPROM 中读取数据。

读操作与写操作类似,只是需要在发送设备地址时,将写命令(0)改为读命令(1)。

2.擦除操作:EEPROM的主要特点之一是可以擦除数据。

通过发送擦除命令和要擦除的数据的地址,可以将指定数据段擦除为初始值。

8051工作原理

8051工作原理

8051工作原理8051是一款8位单片机,由Intel公司设计和生产。

它使用了哈佛结构,具有内部ROM、RAM、I/O端口和定时器等功能,可以实现复杂的计算和控制任务。

8051的工作原理可以简述为以下几个步骤:1. 初始化:首先将8051的寄存器和内存初始化为默认值,设置好时钟和外部设备。

2. 程序执行:8051按照程序存储器中的指令逐条执行,从程序存储器中读取指令并解码。

指令可以包括算术逻辑运算、数据传输、I/O操作等。

3. 存储器和寄存器访问:根据指令的要求,8051会访问存储器和寄存器来读取或写入数据。

存储器包括RAM、ROM和特殊功能寄存器(SFR),寄存器则包括通用寄存器、计数器、状态寄存器等。

4. I/O操作:如果指令需要对外部设备进行操作,8051会通过相应的I/O端口与外部设备进行数据交互。

这些外部设备可以是LED、LCD、键盘、传感器等。

5. 中断处理:当外部设备产生中断信号时,8051会暂时停止执行主程序,转向中断处理程序来处理中断请求。

中断可以是外部中断、定时器中断或串行口中断等。

6. 定时器和计数器:8051内部集成了一个或多个定时器和计数器,可以用来进行时间计数、波特率生成、定时任务等。

这些定时器和计数器可以根据需要进行配置和控制。

7. 控制跳转:根据程序中的控制语句(如if、for、while等),8051可以根据条件跳转到指定的地址继续执行相应的代码段。

上述是8051的基本工作原理,它能够通过灵活的编程和配置,实现各种不同的应用,包括嵌入式系统、自动控制系统、通信系统等。

51单片机模拟I2C总线的C语言实现

51单片机模拟I2C总线的C语言实现

51单⽚机模拟I2C总线的C语⾔实现I2C(Inter-Integrated Circuit)总线是⼀种由PHILIPS公司开发的两线式串⾏总线,⽤于连接微控制器及其外围设备。

I2C总线产⽣于在80年代,最初为⾳频和视频设备开发,如今主要在服务器管理中使⽤,其中包括单个组件状态的通信。

例如管理员可对各个组件进⾏查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。

可随时监控内存、硬盘、⽹络、系统温度等多个参数,增加了系统的安全性,⽅便了管理。

⼀、I2C总线特点 I2C总线最主要的优点是其简单性和有效性。

由于接⼝直接在组件之上,因此I2C总线占⽤的空间⾮常⼩,减少了电路板的空间和芯⽚管脚的数量,降低了互联成本。

总线的长度可⾼达25英尺,并且能够以10Kbps的最⼤传输速率⽀持40个组件。

I2C总线的另⼀个优点是,它⽀持多主控 (multimastering), 其中任何能够进⾏发送和接收的设备都可以成为主总线。

⼀个主控能够控制信号的传输和时钟频率。

当然,在任何时间点上只能有⼀个主控。

⼆、I2C总线⼯作原理2.1、总线的构成及信号类型I2C 总线是⼀种串⾏数据总线,只有⼆根信号线,⼀根是双向的数据线SDA,另⼀根是时钟线SCL。

在CPU与被控IC之间、IC与IC之间进⾏双向传送,最⾼传送速率100kbps。

各种被控制电路均并联在这条总线上,但就像电话机⼀样只有拨通各⾃的号码才能⼯作,所以每个电路和模块都有唯⼀的地址,在信息的传输过程中,I2C总线上并接的每⼀模块电路既是主控器(或被控器),⼜是发送器(或接收器),这取决于它所要完成的功能。

CPU发出的控制信号分为地址码和控制量两部分,地址码⽤来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对⽐度、亮度等)及需要调整的量。

这样,各控制电路虽然挂在同⼀条总线上,却彼此独⽴,互不相关。

2.2、位的传输SDA 线上的数据必须在时钟的⾼电平周期保持稳定数据线的⾼或低电平状态只有在SCL 线的时钟信号是低电平时才能改变。

C8051单片机中I2C接口通信问题

C8051单片机中I2C接口通信问题
// (dummy value since this device does
// not have any defined slave states)
sfr16 TMR3 = 0x94; // Timer3 counter registers
sbit LED = P1^6; // LED on P1.6
sbit SDA = P0^0; // SMBus on P0.0
// Device addresses (7 bits, lsb is a don't care)
#define SLAVE_ADDR 0xa0 // Device address for slave target
//#define MY_ADDR 0xa0 // Address of this SMBus device
bit SMB_BUSY; // Software flag to indicate when the
// SMB_Read() or SMB_Write() functions
C8051与时钟芯片PCF8583进行通信,I2C通信协议,定义到P0^0(SDL)和P0^1(SCL),两个口上。
PCF8583外围接了一个32.768K的晶振,A0接地,SDL、SCL与P口接好,上拉电阻10K,电源是3.3V供电(由C8051的调试板供电)
示波器上显示,一直在给PCF8583发地址,而且还收到了ACK(SDL为高,SCL突变一下),有可能是什么原因?
// Global VARIABLES
//-----------------------------------------------------------------------------

8051单片机硬件结构

8051单片机硬件结构

8051单片机硬件结构
8051单片机是一款广泛应用于嵌入式系统设计中的微控制器。

它由英特尔公司于1980年推出,是目前应用最广泛的8位单片机之一、8051单片机的硬件结构包括中央处理器、存储器、输入/输出接口和定时器/计数器等模块。

1.中央处理器(CPU):
8051单片机使用的是Harvard结构的CPU,包括一个8位的ALU(算术逻辑单元)、一个8位的累加器(Accumulator)和一个8位的程序计数器(PC)。

该CPU还包括4个通用寄存器(R0-R3)和1个存储器指针寄存器(DPTR)。

它还具有处理器状态字寄存器(PSW)和堆栈指针(SP),用于管理程序的执行状态和堆栈操作。

2.存储器:
3.输入/输出接口:
8051单片机提供了大量的输入/输出引脚,用于连接外部设备。

它支持多种输入/输出方式,包括双向I/O口、专用I/O口、串行口和中断端口等。

每个I/O口都可以配置为输入或输出,并且可以通过寄存器编程来控制。

4.定时器/计数器:
8051单片机内置了2个独立的定时器/计数器模块,用于生成精确的时间延迟和测量外部事件。

定时器模块可以配置为定时器或计数器,并具有可编程的预分频器和计数器。

它还可以通过中断机制触发中断请求,用于实现实时操作和时序控制。

5.中断控制器:
6.时钟源:
总之,8051单片机的硬件结构包括中央处理器、存储器、输入/输出接口、定时器/计数器、中断控制器和时钟源等模块。

这些硬件模块相互配合,实现了单片机的功能扩展和系统控制能力。

它广泛应用于各种嵌入式系统设计中,如家电控制、工业自动化、汽车电子等。

8051单片机的结构和原理

8051单片机的结构和原理

8051单片机的结构和原理中央处理器(CPU)是单片机的核心部分,由时钟发生器和控制单元组成。

时钟发生器提供CPU工作需要的时钟信号,控制单元负责指令的获取、译码和执行。

8051单片机的CPU有一个8位的累加器(ACC)和一个可分成两个4位寄存器的B寄存器。

它还具有一个地址总线和一个数据总线,用于与其他芯片进行通信。

存储器是单片机的重要组成部分,用于存储程序和数据。

8051单片机有不同类型的存储器,包括ROM(只读存储器)和RAM(随机存储器)。

ROM用于存储程序代码,而RAM用于存储变量和临时数据。

在一些高级型号的8051单片机中,还可以通过外部存储器接口扩展存储容量。

输入输出(I/O)是单片机与外部设备进行信息交互的接口。

8051单片机的I/O口有两类,即通用I/O口和特殊功能I/O口。

通用I/O口可以配置为输入口或输出口,用于与外部设备进行数字信号输入输出。

特殊功能I/O口具有特定的功能,如串行通信、定时器/计数器控制等。

定时器/计数器是8051单片机的重要辅助模块,用于生成定时延时和计数操作。

它包括两个定时器/计数器(T0和T1),可以用于测量时间、延时控制、产生波形等应用。

定时器/计数器可以通过编程设置工作模式、计数方式以及定时时间周期。

串行通信器是8051单片机与外部设备进行串行通信的接口。

它包括一个串口(UART),支持异步串行通信和同步串行通信。

通过串行通信器,8051单片机可以与计算机、终端设备、传感器等进行数据的发送和接收。

中断控制器是8051单片机的另一个重要模块,用于处理外部中断和内部中断。

当外部设备发生中断请求时,中断控制器会暂停当前任务,转而执行中断服务程序。

中断控制器包括外部中断INT0、INT1和内部中断IE0、IE1、TF0、TF1等。

8051单片机的原理是基于冯·诺依曼结构和哈佛结构的混合结构。

它具有单指令多数据流(SISD)并行处理特性,在一条指令周期内可以同时对多个数据进行处理。

单片机中的EEPROM存储技术

单片机中的EEPROM存储技术

单片机中的EEPROM存储技术单片机(Microcontroller)是一种集成了微处理器、存储器和输入输出设备的微型计算机系统。

在现代科技中,单片机被广泛应用于各种电子设备中,如家电、汽车、医疗仪器等。

其中,EEPROM (Electrically Erasable Programmable Read-Only Memory)存储技术在单片机中起着重要的作用,本文将对其进行详细介绍。

一、EEPROM存储技术概述EEPROM是一种可擦写非易失性存储器,它与传统的ROM(Read-Only Memory)相比,具有可以电擦写的特点。

EEPROM的重要特性是可重复擦写和非易失性,这意味着它可以多次进行数据擦除和写入,并且在断电后仍能保持数据内容。

这使得它成为存储单片机程序和数据的理想选择。

二、EEPROM的工作原理EEPROM的工作原理是通过在芯片内部的晶体管结构中存储电子电荷的不同状态来表示数据的0和1。

在擦写时,通过将电荷注入或释放到晶体管的栅极上,改变晶体管的导电性,从而改变其存储的数据。

EEPROM支持逐字节或逐页擦写,擦写过程可以通过单片机内部的控制电路来完成。

三、EEPROM的应用1. 单片机程序存储在单片机系统中,EEPROM主要用于存储程序代码。

由于EEPROM可以重复擦写并保持数据的非易失性,它可以作为存储器扩展或备份,用于存储关键的程序和指令集。

2. 数据存储单片机中的临时数据(如传感器数据、计数值等)可以通过EEPROM进行存储。

通过使用EEPROM,可以避免在断电情况下丢失数据,并且可以实现对数据的可编程访问。

3. 参数设置EEPROM还可用于存储设备的参数和配置信息。

通过将设备的设置和选项存储在EEPROM中,可以实现对设备行为的灵活调整和个性化配置。

这对于需要频繁更改参数的应用十分有用。

四、EEPROM的优缺点1. 优点EEPROM的主要优点是可重复擦写和非易失性,使得它适用于存储重要的程序和数据。

AN1190 使用硬件模块实现8051MCU与IIC串行EEPROM的接口

AN1190 使用硬件模块实现8051MCU与IIC串行EEPROM的接口

2011 Microchip Technology Inc.
DS01190B_CN 第 1 页
AN1190
固件说明
主函数
固件用来说明如何使用单片机上的双向 SDA 引脚产生 特定的 I2C 总线事务。本文的重点是帮助设计人员透彻 理解如何与 24XXX 系列串行 EEPROM 进行通信,为 将来编写更复杂的程序打下基础。固件适用于 NXP 的 P89LPC952 MCU,在 Keil™ µVision3® IDE 下使用 汇编语言编写,并在 Keil MCB950 评估板上开发。 主代码展示了两种不同的访问 I2C 串行 EEPROM 的方 法:字节访问和页访问。字节方法访问单个字节,其中 每个数据字节之前都有三个地址字节:器件地址、 MSB 地址和 LSB 地址。在页访问方法中, MCU 发送第一个 字节的地址, I2C 串行 EEPROM 在内部会递增地址指 针,以指向下一个数据字节。 代码已使用 24XX512 串行 EEPROM 进行测试。该 EEPROM 的存储容量为 64K x 8 (512 Kb) ,每页最 多可写入 128 字节的数据。 本应用笔记中给出了示波 器屏幕截图。所有时序均基于 MCU 的内部 RC 振荡 器 (7.373 MHz) 。如果使用更快的时钟,则必须修改代 码,以产生正确的延时。 这些示例中的总线速度约为 75 kHz。
数据字节 0
数据字节 127
AAA S101 02 1 00
顺序读操作
图 5 给出了构成顺序读操作的必要组成部分。 MCU 未 对最后一个读字节做出应答 (NACK)。这将终止顺序 读操作。
图 5:
总线活动 MCU SDA 线 总线活动
顺序读操作
器件地址 数据 (n) 数据 (n + 1) 数据 (n + 2) 数据 (n + x) 停 止 P A C K A C K A C K A C K N A C K

51单片机模拟I2C总线的C语言实现

51单片机模拟I2C总线的C语言实现

51单片机模拟I2C总线的C语言实现电路原理图EEPROM为ATMEL公司的AT24C01A。

单片机为ATMEL公司的AT89C51。

软件说明C语言为Franklin C V3.2。

将源程序另存为testi2c.c,用命令C51 testi2c.cL51 TESTI2C.OBJOHS51 TESTI2C编译,连接,得到TESTI2C.HEX文件,即可由编程器读入并进行写片,实验。

3.源程序#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define AddWr 0xa0 /*器件地址选择及写标志*/#define AddRd 0xa1 /*器件地址选择及读标志*/#define Hidden 0x0e /*显示器的消隐码*//*有关全局变量*/sbit Sda= P3^7; /*串行数据*/sbit Scl= P3^6; /*串行时钟*/sbit WP= P3^5; /*硬件写保护*/void mDelay(uchar j){ uint i;for(;j>0;j--){ for(i=0;i<125;i--){;}}}/*发送起始条件*/void Start(void) /*起始条件*/{Sda=1;Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Sda=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();}void Stop(void) /*停止条件*/{Sda=0;Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Sda=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();}void Ack(void) /*应答位*/ {Sda=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=0;}void NoAck(void) /*反向应答位*/{Sda=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=0;}void Send(uchar Data) /*发送数据子程序,Data为要求发送的数据*/ {uchar BitCounter=8; /*位数控制*/uchar temp; /*中间变量控制*/do{temp=Data;Scl=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();if((temp&0x80)==0x80)/* 如果最高位是1*/Sda=1;elseSda=0;Scl=1;temp=Data<<1; /*RLC*/Data=temp;BitCounter--;}while(BitCounter);Scl=0;}uchar Read(void) /*读一个字节的数据,并返回该字节值*/ {uchar temp=0;uchar temp1=0;uchar BitCounter=8;Sda=1;do{Scl=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();if(Sda) /*如果Sda=1;*/temp=temp|0x01; /*temp的最低位置1*/elsetemp=temp&0xfe; /*否则temp的最低位清0*/ if(BitCounter-1){ temp1=temp<<1;temp=temp1;}BitCounter--;}while(BitCounter);return(temp);}void WrToROM(uchar Data[],uchar Address,uchar Num) {uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start(); /*发送启动信号*/Send(0xa0); /*发送SLA+W*/Ack();Send(Address+i); /*发送地址*/Ack();Send(*(PData+i));Ack();Stop();mDelay(20);}}void RdFromROM(uchar Data[],uchar Address,uchar Num) {uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start();Send(0xa0);Ack();Send(Address+i);Ack();Start();Send(0xa1);Ack();*(PData+i)=Read();Scl=0;NoAck();Stop();}}void main(){uchar Number[4]={1,2,3,4};WP= 1;WrToROM(Number,4,4); /*将初始化后的数值写入EEPROM*/mDelay(20);Number[0]=0;Number[1]=0;Number[2]=0;Number[3]=0; /*将数组中的值清掉,以验证读出的数是否正确*/RdFromROM(Number,4,4);}问题:本程序中未采用块读写的方法,显得有点‘笨’,这是由于项目原因,现项目已完成,程序已写好,短时不会修改,也不会花上一定的精力去做,虽然理论上已很成熟,就这样写一下,未必不对,但与我的本栏目要求不符,所以就未做上去,如果以后我做了,将再补上。

8051单片机c语言置位与复位操作点亮led方法

8051单片机c语言置位与复位操作点亮led方法

8051单片机c语言置位与复位操作点亮led方法8051单片机作为一种经典的微控制器,被广泛应用于工业控制、嵌入式系统等领域。

C语言因其高效性和易读性,成为编写8051单片机程序的首选语言。

本文将详细介绍如何使用C语言对8051单片机进行置位和复位操作,以点亮LED灯。

### 8051单片机C语言置位与复位操作点亮LED方法#### 1.硬件环境准备在开始编程之前,需要确保硬件环境搭建正确。

所需硬件包括:- 8051单片机开发板- LED灯一个- 电阻(与LED灯的电压和电流匹配)- 面包板(用于搭建电路)将LED灯的一个引脚连接到8051单片机的某个I/O口(如P1.0),另一个引脚通过电阻接地。

#### 2.软件环境准备- 使用Keil uVision IDE作为开发环境,编写和编译C语言代码。

- 确保安装了适用于8051单片机的C编译器。

#### 3.C语言代码编写以下是使用C语言对8051单片机进行置位(点亮LED)和复位(熄灭LED)操作的示例代码:```c#include <reg51.h> // 包含8051寄存器定义的头文件#define LED P1_0 // 定义LED连接的I/O口,这里以P1.0为例void delay(unsigned int); // 延时函数声明void main() {while(1) { // 无限循环LED = 1; // 置位P1.0,LED点亮delay(10000); // 延时LED = 0; // 复位P1.0,LED熄灭delay(10000); // 延时}}// 延时函数定义,具体的延时时间取决于单片机的晶振频率void delay(unsigned int count) {unsigned int i,j;for(i=0; i<count; i++)for(j=0; j<1275; j++); // 空循环实现延时}```#### 4.置位与复位操作说明在上面的代码中,`LED = 1;` 对应的是置位操作,将P1.0口置为高电平,电流流经LED,使其点亮。

单片机课程设计-IIC总线式EEPROM存储器应用设计

单片机课程设计-IIC总线式EEPROM存储器应用设计

目录1 设计要求 (2)2 设计目的 (2)3 器件EEPROM的介绍 (2)3.1 EEPROM简介 (2)3.2 EEPROM24XX系列功能概述 (3)4 IIC协议的介绍 (3)4.1 IIC协议总线特征 (3)4.2 IIC协议工作原理 (3)4.3 IIC协议总线基本状态 (3)4.4 寻址约定 (5)5 EEPROM读写功能实现 (5)5.1写操作 (5)5.1.1 字节写操作 (6)5.1.2 页写入操作 (6)5.2 确认查询 (7)5.3 读操作 (7)5.3.1 当前地址的读操作 (8)5.3.2 随机读操作 (8)5.3.3 连续读操作 (9)6 具体设计过程 (10)6.1 程序流程设计 (10)6.2执行结果 (13)6.3 系统组成模块结构及功能 (15)6.3.1 函数定义 (15)6.3.2 主函数设计 (17)6.3.3 源程序 (19)7 设计心得体会 (27)8 参考文献 (28)IIC总线式EEPROM存储器应用设计1 设计要求利用51单片机和IIC总线式EEPROM芯片24C02进行存储器设计。

按下KEYWRITE1键,向24C02存储器写入数据1和2;按下KEYWRITE2键,向24C02存储器写入数据3和4;按下KEYREAD键,从24C02存储器读出刚写入的数据数据;写入数据显示在左两位,读出数据显示在右两位。

如图1.1所示。

图1.1 系统仿真运行图2 设计目的通过设计,了解IIC协议的基本原理,并对EEPROM读写功能的实现有个系统的概念,对其实现过程比较清楚。

同时,在设计中,巩固我们所学的理论知识。

3 器件EEPROM的介绍3.1 EEPROM简介EEPROM (Electrically Erasable Programmable Read-Only Memory),电可擦可编程只读存储器--一种掉电后数据不丢失的存储芯片。

EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。

完美的8051单片机C语言编程模板-7页文档资料

完美的8051单片机C语言编程模板-7页文档资料

《8051单片机C语言编程模板》[程序开始处的程序说明]程序名:编写人:赛杜洋编写时间:2019年12月25日硬件支持:接口说明:修改日志:NO.1-说明:[单片机SFR定义的头文件]#include <REG51.h> //通用89C51头文件#include <REG52.h> //通用89C52头文件#include <STC11Fxx.H> //STC11Fxx或STC11Lxx系列单片机头文件#include <STC12C2052AD.H> //STC12Cx052或STC12Cx052AD系列单片机头文件#include <STC12C5A60S2.H> //STC12C5A60S2系列单片机头文件[更多库函数头定义]#include <assert.h> //设定插入点#include <ctype.h> //字符处理#include <errno.h> //定义错误码#include <float.h> //浮点数处理#include <fstream.h> //文件输入/输出#include <iomanip.h> //参数化输入/输出#include <iostream.h> //数据流输入/输出#include <limits.h> //定义各种数据类型最值常量#include <locale.h> //定义本地化函数#include <math.h> //定义数学函数#include <stdio.h> //定义输入/输出函数#include <stdlib.h> //定义杂项函数及内存分配函数#include <string.h> //字符串处理#include <strstrea.h> //基于数组的输入/输出#include <time.h> //定义关于时间的函数#include <wchar.h> //宽字符处理及输入/输出#include <wctype.h> //宽字符分类#include <intrins.h> //51基本运算(包括_nop_空函数)[常用定义声明]sfr [自定义名] = [SFR地址] ; //按字节定义SFR中的存储器名。

嵌入式技术控制系统中I2C串行EEPROM器件应用

嵌入式技术控制系统中I2C串行EEPROM器件应用

嵌入式技术控制系统中I2C串行EEPROM器件应用
I2C串行EEPROM存储器因具有外形体积小、接口紧凑简单、占用引脚资源少、数据保存可靠、可在线改写、功耗低和价格低廉等显着特点,被广泛应用于嵌入式控制系统中,用于存放配置参数、调整和运行数据等信息。

但由于其为同步串行传输,通讯协议非常简单,没有提供更为复杂的纠错和检测机制,在实践中经常因使用不当造成数据丢失、数据无故改写等问题。

对于存储数据要求非常高的系统,例如计量产品、无人值守系统等,如果存储数据发生意外错误,造成的损失是致命的,因此在设计使用I2C串行EEPROM存储器时,更多地需要硬件和软件相互接合,采取一些相关的处理措施,使得产品能够在各种恶劣的使用环境中可靠、正确地运行。

 1 硬件处理措施
 硬件处理过程中,应重点考虑以下几个方面:
 (1)电源是一个控制系统可靠运行的基石,很多产品与外界的有线连接就是电源连接。

因此,在产品设计时应对电源电路进行有效滤波处理,并且应该通过EMC的试验检测来降低电源纹波噪声,抑制高频震荡和高压脉冲的侵入,减少由于噪声过大而引起的I2C串行EEPROM器件读写失误。

这一点尤为重要,因为实践中很多系统的数据不知何故而发生了错误,可能的一个重要原因就是电源的抗干扰能力有限,从而导致I2C总线干扰。

 (2)由于特殊原因,尽管对电源已经进行了有效处理,仍无法避免电磁的干扰,在使用I2C串行EEPROM时,在I2C规范限制条件下,可以采取减小上拉电阻和使用I2C总线驱动器提高输出驱动能力等措施来有效降低电磁干扰对读写的影响。

 (3)I2C串行EEPROM一般具有欠压复位电路,如果微处理器欠压复位的门。

单片机C语言之内部EEPROM、延时、数码管综合应用

单片机C语言之内部EEPROM、延时、数码管综合应用

#include <reg52.h>#define uchar unsigned char#include <stdio.h>#include <string.h>#include <intrins.h>//定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数//#define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值#define uchar unsigned char#define uint unsigned int#define RdCommand 0x01 //定义ISP的操作命令#define PrgCommand 0x02#define EraseCommand 0x03#define Error 1#define Ok 0#define WaitTime 0x01sfr ISP_DA TA=0xe2;sfr ISP_ADDRH=0xe3;sfr ISP_ADDRL=0xe4;sfr ISP_CMD=0xe5;sfr ISP_TRIG=0xe6;sfr ISP_CONTR=0xe7;sbit duan1=P2^6; //段选信号的锁存器控制sbit duan2=P2^7; //位选信号的锁存器控制sbit x0=P1^0;sbit x1=P1^1;sbit x2=P1^2;sbit x3=P1^3;sbit x4=P1^4;sbit x5=P1^5;sbit x6=P1^6;sbit x7=P1^7;sbit y0=P2^0;sbit y1=P2^1;sbit y2=P2^2;sbit y3=P2^3;sbit y4=P2^4;sbit y5=P2^5;sbit y6=P2^6;sbit y7=P2^7;sbit set=P3^2;sbit up=P3^3;sbit dn=P3^4;sbit end=P3^5;unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x7f,0xce};uchar a=0,ram=1,num1,num2,num3,num4,num5,m20=1; void delay(uchar t){uchar m,n,s; //延时函数1for(m=t;m>0;m--)for(n=10;n>0;n--)for(s=20;s>0;s--);}void delay1(uchar z) //延时函数2{uchar w,u,v;for(w=z;w>0;w--)for(u=20;u>0;u--)for(v=200;v>0;v--);}/*打开ISP,IAP 功能*/void ISP_IAP_enable(void){EA = 0;ISP_CONTR = ISP_CONTR & 0x18; /* 0001,1000 */ ISP_CONTR = ISP_CONTR | WaitTime;ISP_CONTR = ISP_CONTR | 0x80; /* ISPEN=1 */ }/*关闭ISP,IAP 功能*/void ISP_IAP_disable(void){ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */ISP_TRIG = 0x00;EA= 1;}/*公用的触发代码*/void ISPgoon(void){ISP_IAP_enable();ISP_TRIG = 0x46;ISP_TRIG = 0xb9;_nop_();}/* 字节读*/unsigned char byte_read(unsigned int byte_addr){ISP_ADDRH = (unsigned char)(byte_addr >> 8);ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8;ISP_CMD = ISP_CMD | RdCommand;ISPgoon();ISP_IAP_disable();return (ISP_DA TA);}/* 扇区擦除*/void SectorErase(unsigned int sector_addr){unsigned int iSectorAddr;iSectorAddr = (sector_addr & 0xfe00);ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);ISP_ADDRL = 0x00;ISP_CMD = ISP_CMD & 0xf8;ISP_CMD = ISP_CMD | EraseCommand;ISPgoon();ISP_IAP_disable();}/* 字节写*/void byte_write(unsigned int byte_addr, unsigned char original_data) {ISP_ADDRH = (unsigned char)(byte_addr >> 8);ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8;ISP_CMD = ISP_CMD | PrgCommand;ISP_DA TA = original_data;ISPgoon();ISP_IAP_disable();}void display(uchar a,uchar b) //显示子程序{duan1=0;duan2=1;P0=table[a];delay(2);duan1=1;duan2=0;P0=table[b];delay(2);}void keyscan() //按键操作{if(m20==1){uchar a0,a1;if(end==0&&m20==1){while(!end);m20=0;}display(a0,a1);a0=17;a1=ram%10;if(up==0&&ram<5){while(!up);ram++;}if(dn==0&&ram>1){while(!dn);ram--;}if(set==0&&a==1){delay1(10);if(set==0){while(!set);a=0;}}}if(m20==0){uchar b0,b1,off;switch(ram){case 1:off=1;break;case 2:off=2;break;case 3:off=3;break;case 4:off=4;break;case 5:off=5;break;}while(m20==0){if(num1>50){num1=20;}if(num2>50){num2=20;}if(num3>50){num3=20;}if(num4>50){num4=20;}if(num5>50){num5=20;}if(set==0){delay1(10);if(set==0){while(!set);m20=1;}}if(end==0){delay1(10);if(end==0){while(!end);SectorErase(0x2000);byte_write(0x2000,num1);byte_write(0x2001,num2);byte_write(0x2002,num3);byte_write(0x2003,num4);byte_write(0x2004,num5);m20=1;}}if(off==1){display(b0,b1);b0=num1/10;b1=num1%10;if(up==0){while(!up);num1++;}if(dn==0){while(!dn);num1--;}}if(off==2){display(b0,b1);b0=num2/10;b1=num2%10;if(up==0){while(!up);num2++;}if(dn==0){while(!dn);num2--;}}if(off==3){display(b0,b1);b0=num3/10;b1=num3%10;if(up==0){while(!up);num3++;}if(dn==0){while(!dn);num3--;}}if(off==4){display(b0,b1);b0=num4/10;b1=num4%10;if(up==0){while(!up);num4++;}if(dn==0){while(!dn);num4--;}}if(off==5){display(b0,b1);b0=num5/10;b1=num5%10;if(up==0){while(!up);num5++;}if(dn==0){while(!dn);num5--;}}}}}void main(){while(1){if(a==0){num1=byte_read(0x2000); num2=byte_read(0x2001); num3=byte_read(0x2002); num4=byte_read(0x2003); num5=byte_read(0x2004);P0=0xff;while(a==0){if(set==0&&a==0){delay1(10);if(set==0){while(!set);a=1;}}if(x0==0){delay1(num1);y0=0;delay1(num1);y0=1;}if(x1==0){delay1(num2);y1=0;delay1(num2);y1=1;}if(x2==0){delay1(num3);y2=0;delay1(num3);y2=1;}if(x3==0){delay1(num4);y3=0;delay1(num4);y3=1;}}}if(a==1){keyscan();}}}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
AN1113
使用 C 语言和硬件模块实现 8051 MCU 与 I2C™ 串行 EEPROM 的接口
作者:
Alexandru Valeanu Microchip Technology Inc. 随此应用笔记提供了相应的源代码,可帮助用户以最小 的工作量实现协议。 图 1 给出了 Microchip 24XXX 系列 I2C 串行 EEPROM 与基于 8051 的 NXP P89LPC952 MCU 之间接口的硬 件 原 理 图。该 原 理 图 给 出 了 MCU 和 所 测 试 串 行 EEPROM 之间的必要连接,以及时钟线 (SCL)和数 据线(SDA)上所需的上拉电阻。本应用笔记未介绍写 保护功能和多个器件的级联;因此, WP 引脚以及地址 。测试软件是在 引脚 A0、 A1 和 A2 连接到 VSS (地) 假定采用这些连接的情况下编写的。
简介
Microchip Technology 的 24XXX 系列串行 EEPROM 支 持双向 2 线总线和数据传输协议。总线由单片机 (主器 件)控制,该单片机可产生串行时钟(SCL) 、控制总线 访问并产生启动和停止条件,而 24XXX 串行 EEPROM 作为从器件工作。 24XXX 串行 EEPROM 兼容 I2C™, 最大时钟频率范围为 100 kHz 至 1 MHz。 24XXX 串行 EEPROM 的主要特性有: • • • • • • • • 2 线串行接口总线,兼容 I2C EEPROM 容量为 128 位至 512 Kb 总线速度为 100 kHz 至 1 MHz 电压范围为 1.7V 至 5.5V 低功耗运行 温度范围从 -40°C 到 +125°C 可耐受超过 100 万次擦 / 写 同一总线上可连接高达 8 个器件
总线活动 MCU SDA 线 总线活动 A C K
数据字节
停 止 P A C K
2011 Microchip Technology Inc.
DS01113B_CN 第 5 页
AN1113
重复启动
重复启动条件使 MCU 从发送模式切换到接收模式,串 行 EEPROM 从接收模式切换到发送模式。该位之后写 入的序列是 I2C 器件地址和 R/ W 位。 该序列如图 8 所示。
2011 Microchip Technology Inc.
DS01113B_CN 第 3 页
AN1113
初始化
初始化过程包括 MCU 中的硬件外设的初始化。具体操 作如下: • I2EN = 1; // 使能 I2C 器件 • CRSEL = 0; // 选择内部波特率发生器 • STA = STO = SI = AA = 0; // 清除启动、停止、 串行标志和 ACK 位 • 设置总线速度约为 75 kHz:I2SCLL = I2SCLH = 25 位频率 (fbit)为:
数据字节 0
数据字节 127
AAA S101 02 1 00
顺序读操作
图 5 给出了构成顺序读操作的必要组成部分。 MCU 未 对最后一个读字节做出应答 (NACK)。这将终止顺序 读操作。
图 5:
总线活动 MCU SDA 线 总线活动
顺序读操作
器件地址 数据 (n) 数据 (n + 1) 数据 (n + 2) 数据 (n + x) 停 止 P A C K A C K A C K A C K N A C K
图 8:
重复启动和 I2C™ 串行 EEPROM (从器件)地址
总线活动 MCU SDA 线 总线活动
启 动
控制字节 / 器件地址
S 1 0 1 0 0 0 0 1 A C K
DS01113B_CN 第 6 页
2011 Microchip Technology Inc.
AN1113
写器件地址和地址字节
2011 Microchip Technology Inc.
DS01113B_CN 第 1 页
AN1113
固件说明
主函数
固件用来说明如何使用单片机上的双向 SDA 引脚产生 特定的 I2C 总线事务。本文的重点是帮助设计人员透彻 理解如何与 24XXX 系列串行 EEPROM 进行通信,为 将来编写更复杂的程序打下基础。固件适用于 NXP 的 P89LPC952 MCU,在 Keil™ µVision3® IDE 下使用 C 语言编写,并在 Keil MCB950 评估板上开发。 主代码展示了两种不同的访问 I2C 串行 EEPROM 的方 法:字节访问和页访问。字节方法访问单个字节,其中 每个数据字节之前都有三个地址字节:器件地址、 MSB 地址和 LSB 地址。在页访问方法中, MCU 发送第一个 字节的地址, I2C 串行 EEPROM 在内部会递增地址指 针,以指向下一个数据字节。 代码已使用 24XX512 串行 EEPROM 进行测试。该 EEPROM 的存储容量为 64K x 8 (512 Kb) ,每页最 多可写入 128 字节的数据。 本应用笔记中给出了示波 器屏幕截图。所有时序均基于 MCU 的内部 RC 振荡 器 (7.373 MHz) 。如果使用更快的时钟,则必须修改代 码,以产生正确的延时。 这些示例中的总线速度约为 75 kHz。
读取 8 位数据
在字节读取和顺序读取操作中都使用了读取数据函数。 字节读取操作的结构如图 3 所示。顺序读取操作的结构 如图 5 所示。 在字节读取操作中, 8 位读取数据位于命令的结束处, 如图 10 所示,MCU 在与读取数据字节相对应的第 9 个 时钟脉冲处通过 NACK 位表明并未对其进行应答。 在顺序读取操作的情况下, MCU 不会应答最后读取的 字节,而其他 <n-1> 个读取的字节则会被应答。
图 9:
写入 MSB 和 LSB 地址字节
总线活动 MCU SDA 线 总线活动 A C K
MSB 地址 字节
LSB 地址 字节
A C K
A C K
2011 Microchip Technology Inc.
DS01113B_CN 第 7 页
AN1113
写入 8 位数据
字节写和页写操作中都使用了数据写入函数。字节写操 作的结构如图 2 所示。页写操作的结构如图 4 所示。两 个操作的惟一区别是在页写操作中, MCU 不是发送 1 个 字节的数据而是发送 “n”个字节的数据。 作为规则,该函数从并行格式转换为串行 I2C 格式。总 线速度跟初始化程序中一致约为 75 kHz。 MCU 在时钟的下降沿设置数据线, I 2 C 串行 EEPROM 在时钟的上升沿将其锁存。 在图 6 中可以看到在第 9 个时钟脉冲和下一个时钟脉冲 之间有一个标记为 “总线释放” (bus release)的尖 峰。该尖峰是两个器件 (MCU 和 I2C 串行 EEPROM) 释放漏极开路 SDA 线以便能继续通信的标志。
字节写操作
图 2 给出了构成字节写操作的必要组成部分。 每个 MCU 的操作均由 I2C 串行 EEPROM 在时钟的第 9 位通过下 拉 SDA 数据线进行应答(ACK);因此,每个字节传 输均持续 9 个时钟周期。
图 2:
字节写操作
控制字节 / 器件地址
总线活动 MCU SDA 线 总线活动
启 动
fPCLK = ------------------------------------------------------------2 × [ I 2 SCLH + I 2 SCLL ]
图 6:
I2C™ 启动位和从器件地址
总线活动 MCU
启 动
控制字节 / 器件地址
SDA 线 总线活动
S101 00000 A C K
写入 I2C™ 串行 EEPROM 地址和读条件
重复启动条件后, MCU 会写入 I2C 串行 EEPROM 地 址 (从器件地址) ,其中包含正确设置的 R/ W 位。 所以I2C串行EEPROM 对于读取序列, 由于R/ W位为1, 的地址为 A1h, 这表示 MCU 等待从 I2C 串行 EEPROM 读取字节。 该时序如图 8 所示。
DS01113B_CN 第 4 页
2011 Microchip Technology Inc.
AN1113
停止数据传输
MCU 在 I2C 总线上生成停止条件,以停止数据传输。 图 7 给出了字节写操作后跟随停止条件的典型示波器截 图。 I2C 总线上的每个操作都以停止条件结束。
图 7:
字节写操作和停止条件
图 3:
总线活动 MCU SDA 线 总线活动
字节读操作
启 动 控制字节 / 器件地址 MSB 地址 字节 LSB 地址 字节 启 动 位 控制字节 / 器件地址 停 止 P A C K N A C K
数据字节
S101 0 AAA0 2 1 0 A C K A C K A C K
S 1 0 1 0 A A A1 2 1 0
在启动条件结束后, MCU 写入包括器件地址,MSB 和 LSB 地址在内的三个字节。由于器件地址之后是写入两 个地址字节,因此器件地址的 R/ W 位应设置为 0。 图 9 所示波形图描述的是 MSB 地址字节(00h) 、LSB 地址字节 (60h),随后是通过字节访问方法写入的首 字节:字符串 (43h)。由于字节访问方法是访问单个 字节,因此数据字节后跟随一个停止位。 在波形图中观察到的短时间尖峰,表示在这个较短的时 间内 MCU 和 I2C 串行 EEPROM 都释放了数据总线。
启动数据传输
MCU 在 I2C 总线上生成启动条件,以启动数据传输。 图 6 给出了写操作开始以后的典型示波器截图。任何存 储器访问均以启动条件开始, 后跟 I 2C 串行 EEPROM (从器件)地址 (A0h) 。由于 R/ W 位设置为 0,总线 的下一个操作是写操作。
公式 1:
相关文档
最新文档