• IIC读写AT24C02代码2——串口命令控制多页读写


    通过串口输入 R 、W 进行控制程序读写IIC设备。波特率9600bps,晶振115200HZ。

    main.c

    /*-----------------------------------------------
      IIC编程 1
      编写:Louis 
      邮箱:kaly.liu@163.com
      日期:2015.06.01
      改动:通过串口命令R/W,控制EEPROM的读R写W。并从串口提示。

    改进:添加对页读写功能 晶振:11.0592MHZ NOTE:*通过实測发现。AT24C02能够连续写入16BYTE字节。并且地址要连续的两个页。就是0~15,16~31,。。。 ------------------------------------------------*/ #include <REG52.H> #include<string.h> #include"uart.h" #include "iic.h" sbit WP=P1^0; sbit LED7=P1^7; unsigned char idata temp[8]; unsigned char rxnum; unsigned char flag2; unsigned char EEPROM_WR_FLAG=0; code const char str1[] = "The string is 来自单片机! "; code const char str2[] = "Author: louis "; //const 限定一个变量不同意被改变。在一定程度上提高程序安全性和可靠性 //code 存储区间为 程序存储区 /***************函数声明*******************/ void InitUART(void); void SendOneByte(uint8); void SendrStr(uint8 *ptr); void main(void) { unsigned char Control,*p1,*p2; unsigned char buf1[]="The first page!!The second page!The third page!!"; /* 发送缓冲区 */ unsigned char idata buf2[49]; /* 接收缓冲区 */ unsigned char Length; unsigned int addr ,i=0; /* 24Cxx片内地址 */ WP=0; // P4SW|= 0x10; LED7=1; InitUART(); while(str2[i]!='') { SendOneByte(str2[i++]); } SendrStr(str1); ES =1; EA =1; p1=buf1; p2=buf2; addr=0; ////片内地址 AT24C02为0~255 , 32page*8byte = 256个字节///// Length=48; ////// 读写长度 ////// enumer=AT2402; /// 读写AT24C02//// while(1){ if(EEPROM_WR_FLAG=='W'){ Control=0xae; /// 1010 1110 写操作/// RW24xx(p1,Length,addr,Control,enumer); // 写操作 // for(i=0;i<10000;i++); //要添加延时···才可正确的读取数据! //在STOP和START之间有个 write cycle,一般有个最大值Twr.这是设备内部进行写入数据须要的时间,所以此处的延迟须要 大于这个 最大值Twr。 // Delay(1000);//1:6.18us; 2:8.36us 3:10.55us △=2.18us EEPROM_WR_FLAG=0; } if(EEPROM_WR_FLAG=='R'){ Control=0xaf; ///读操作/// RW24xx(p2,Length,addr,Control,enumer);// 读 EEPROM_WR_FLAG=0; SendrStr(p2); SendrStr(" "); } }//while } /****************中断服务函数***************/ void UART_ISR(void) interrupt 4 { uint8 RX_Data; //仅仅响应"接收"中断,"发送"中断来了就直接抹掉 if(RI) { RI = 0; //串口中断标志不能自己清除。须要手动清除 RX_Data=SBUF; EEPROM_WR_FLAG = RX_Data; SendOneByte(EEPROM_WR_FLAG); SendrStr(": "); } else TI = 0; //串口发中断是发送完缓冲区数据之后产生 }



    uart.h头文件

     
    /*-----------------------------------------------
    
      编写:刘宗铭 
      邮箱:kaly.liu@163.com
      日期:2015.05
      修改:无
    
    ------------------------------------------------*/
    
    #include<reg52.h> //包括头文件。普通情况不须要修改。头文件包括特殊功能寄存器的定义                        
    
    /*******************************************************************
    请提前计算一下所选晶振能达到的最快速度,波特率不能超过最快速度
    (1) 波特率加倍(SMOD=1):  Max_Baud = FOSC/12/16
    (2) 波特率不加倍(SMOD=0):Max_Baud = FOSC/12/32
    比如:22.1184MHz晶振,波特率加倍时,最大波特率=22118400/12/16=115200
    *******************************************************************/
    #define FOSC	11059200		//振荡频率
    #define BAUD	9600			//波特率
    #define SMOD	1			//是否波特率加倍
    #if SMOD
    	#define TC_VAL	(256-FOSC/16/12/BAUD)
    #else
    	#define TC_VAL	(256-FOSC/32/12/BAUD)
    #endif
    
    typedef unsigned char uint8;
    typedef unsigned int uint16;
    
    
    
    
    
    /****************串口初始化函数*************/
    void InitUART(void)
    {
        TMOD = 0x20;    //定时器1,模式2工作模式	   
        SCON = 0x50;    //串口工作模式1。同意REN   /* SCON: 模式 1,  8-bit UART, 使能接收         */
        TH1 = TC_VAL;
        TL1 = TH1;
        PCON = 0x80; 	//发送速率加倍
        ES = 1;
        EA = 1;
        TR1 = 1;
    }
    /**************串口发送字符函数*************/
    void SendOneByte(uint8 c)
    {
        ES = 0;			//禁止中断,让串口安心工作啊
        SBUF = c;
        while(!TI);		//等待发送完成
        TI = 0;			//清TI中断
        ES = 1;			//打开中断
    }
    /**************串口发送字符串函数*************/
    
    /**************串口发送字符串函数*************/
    void SendrStr(const uint8 *ptr)
    {
        
    	for(;*ptr!='';ptr++)
    	{
    	   SendOneByte(*ptr);
    	}
    }
    


    IIC.h头文件

    /*-----------------------------------------------
    
      编写:<span style="font-family: Arial, Helvetica, sans-serif;">Louis </span>
    
      邮箱:kaly.liu@163.com
      日期:2015.05
      改动:加入多页读写功能
      器件的型号 我用的是AT24C02   32PAGE*8BYTE = 2Kbit
    ------------------------------------------------*/
    #include <intrins.h>
    #include<reg52.h>
    
    
    #define  ERROR 10     //同意ERROR的最大次数  
    	     
    sbit     SDA=P1^2;
    sbit     SCL=P1^1;
    
    
    enum  eepromtype {AT2401,AT2402,AT2404,AT2408,AT2416,AT2432,AT2464,AT24128,AT24256};/*器件的型号 我用的是AT24C02*/
    enum  eepromtype enumer;   //定义一个枚举变量
    
    
    
    
    /* * * * * * * * 一个简单延时程序 * * * * * * * * * * * * */
    void Delay(unsigned char DelayCount)
    { while(DelayCount--);		  //推断 + 运行 2个机器周期
    }
    /* * * * * 下面是对IIC总线的操作子程序 * * * * */
    /* * * * * * 启动总线 * * * * */
    void Start(void)
    { SCL=0; /* SCL处于高电平时,SDA从高电平转向低电平表示 */
      SDA=1; /* 一个"開始"状态,该状态必须在其它命令之前运行 */
      Delay(2);
      SCL=1;
      Delay(2);
      SDA=0;
      Delay(2);
      SCL=0;
      SDA=1;
      Delay(2);     
    }
    
    
    
    /* * * * * 停止IIC总线 * * * * */
    void Stop(void)
    { SCL=0; /*SCL处于高电平时,SDA从低电平转向高电平 */
      SDA=0; /*表示一个"停止"状态,该状态终止全部通讯 */
      Delay(2);
      SCL=1;
      Delay(2); /* 空操作 */
      SDA=1;
      Delay(2);
      SCL=0;
      Delay(1000);
    }
    
    
    /* * * * * 检查应答位 * * * * */
    bit RecAck(void)
    { SCL=0;
      SDA=1;
      Delay(20);
      SCL=1;
      Delay(2);
      Delay(2);
      CY=SDA;     /* 由于返回值总是放在CY中的 */
      SCL=0;
      Delay(20);
      return(CY);
    }
    
    
    /* * * * *对IIC总线产生应答 * * * * */
    void Ack(void)
    { SDA=0; /* EEPROM通过在收到每一个地址或数据之后, */
      SCL=1; /* 置SDA低电平的方式确认表示收到读SDA口状态 */
      Delay(2);
      SCL=0;
      Delay(2);
      SDA=1;
    }
    
    
    /* * * * * * * * * 不对IIC总线产生应答 * * * * */
    void NoAck(void)
    { SDA=1;
      SCL=1;
      Delay(2);
      SCL=0;
    }
    
    /* * * * * * * * * 向IIC总线写数据 * * * * */
    void Send(unsigned char sendbyte)
    { unsigned char data j=8;
      for(;j>0;j--)
      { SCL=0;
        sendbyte <<= 1; /* 使CY=sendbyte^7; */
        SDA=CY; /* CY 进位标志位 */
    	Delay(2);
        SCL=1;
    	Delay(20);
      }
      SCL=0;
      Delay(2);
    }
    
    /* * * * * * * * * 从IIC总线上读数据子程序 * * * * */
    unsigned char Receive(void)
    { register receivebyte,i=8;
      SCL=0;
      while(i--)
      { SCL=1;
        receivebyte = (receivebyte <<1 ) | SDA;
    	Delay(2);
        SCL=0;
     //  receivebyte = (receivebyte <<1 ) | SDA;	  //不能放在这里啊,放这里接受数据出错··!!

    Delay(2); } return(receivebyte); } /* ----- AT24C01~AT24C256 的读敲代码 ------ */ bit RW24xx(unsigned char *DataBuff,unsigned char Length,unsigned int Addr, unsigned char Control,enum eepromtype enumer) { unsigned char data j,i=ERROR; unsigned int k; bit errorflag=1; /* 出错标志 */ while(i--) { Start(); /* 启动总线 */ Send(Control & 0xfe); /* 向IIC总线写数据,器件地址 */ if(RecAck()) continue; /* 如写不对结束本次循环 */ if(enumer > AT2416) { Send((unsigned char)(Addr >> 8));//把整型数据转换为字符型数据:弃高取低,仅仅取低8位.假设容量大于32K位,使用16位地址寻址,写入高八位地址 if(RecAck()) continue; } Send((unsigned char)Addr); /* 向IIC总线写数据 */ if(RecAck()) continue; /* 如写不对结束本次循环 */ if(!(Control & 0x01)) //推断是读器件还是写器件 假设是写 0 就进去运行 { j=Length; errorflag=0; /* 清错误特征位 */ while(j--) { //******************此段推断页***多页读写功能***********************// if(Addr%16==0) { Stop(); for(k=0;k<10000;k++); Start(); /*启动总线*/ Send(Control & 0xfe); /*发送器件地址*/ if(RecAck()) continue; /* 如写不对结束本次循环 */ if(enumer > AT2416) { Send((unsigned char)(Addr >> 8));//把整型数据转换为字符型数据:弃高取低。仅仅取低8位. //假设容量大于32K位,使用16位地址寻址。写入高八位地址 if(RecAck()) continue; /* 如写不对结束本次循环 */ } Send((unsigned char)Addr); /*发送器件子地址*/ if(RecAck()) continue; /* 如写不对结束本次循环 */ } Addr++; //********************此段推断页***多页读写功能**************************// /*发送数据*/ Send(*DataBuff++); /* 向IIC总线写数据 */ if(!RecAck()) continue; /* 如写正确结束本次循环 */ errorflag=1; break; } if(errorflag==1) continue; // SendOneByte('O'); break; } else { Start(); /* 启动总线 */ Send(Control); /* 向IIC总线写数据 */ if(RecAck()) continue;//器件没应答结束本次本层循环 while(--Length) /* 字节长为0结束 */ { *DataBuff ++= Receive(); Ack(); /* 对IIC总线产生应答 */ } *DataBuff=Receive(); /* 读最后一个字节 */ NoAck(); /* 不对IIC总线产生应答 */ errorflag=0; break; } } Stop(); /* 停止IIC总线 */ if(!(Control & 0x01)) { Delay(255); Delay(255); Delay(255); Delay(255); } return(errorflag); }



  • 相关阅读:
    h5混合开发好用的下拉刷新插件
    设置窗体可以使用鼠标拖动大小 通过
    C# 使用System.Data.OleDb;避免oracle中文乱码问题
    C# 开启一个新进程并为新进程设置工作目录
    WPF窗体程序入口 自定义窗体启动页面
    WorkFlow WF如何为一个集合赋值
    第三方框架的使用
    AppIcon应用图标 and Launchimage启动图标的制作
    在didSelectRowAtIndexPath 里面取cell的方法
    iOS 开发技术体系
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6752878.html
Copyright © 2020-2023  润新知