zoukankan      html  css  js  c++  java
  • 通过I2C总线向EEPROM中写入数据,记录开机次数

    没买板子之前,用protues画过电路图,实现了通过i2c总线向EEPROM中写入和读出数据。

    今天,在自己买的板子上面写关于i2c总线的程序,有个地方忘了延时,调程序的时候很蛋疼。下面说说我对I2c总线的理解

    i2c总线共有两根线,一根是时钟信号线,一根是数据线。这里我只实现了,指定EEPROM片内地址,并向其中写入一个字节。从EEPROM中指定地址读出一个字节。

    写入过程

    1.需要发一个启动信号

    2.发送EEPROM设备地址

    3.发送EEPROM片内地址

    4.发送你要写入的数据

    5.发送结束信号

    读出过程:

    1.发送启动信号

    2.发送设备地址(注意这里是伪写  和写入过程前两个步骤一样  注意仔细看EEPROM文档)

    3.发送EEPROM片内地址

    4.发送启动信号(读数据需要启动两次)

    5.发送设备地址(这里和读过程不同的是r/w位  前面是低电平  这里是高电平)

    6.读取数据

    7.发送结束信号

    6.发送结束信号

    当然单片机向总线写数据完成后,要注意检测应答信号,读取数据后,单片机应向设备发送,非应答信号或者叫应答非信号。

      1 /*=================================================================================
      2     功能:通过i2c总线向EEPROM中写入数据 并读回数据 验证I2C总线通信 实现记录开机次数
      3     电路图:P2.0接SCL
      4             P2.1接SDA
      5             P1口接led发光二极管
      6             P2.3接 数码管位选信号
      7             P2.2接段选信号
      8             P0口接数码管
      9     注意理解设备发出的应答
     10         和单片机发出的非应答或者叫应答非
     11         两者使得通信完整 只不过方向不一样
     12 ====================================================================================*/
     13 #include <reg51.h>
     14 #include <intrins.h>
     15 #define uchar unsigned char
     16 #define uint unsigned int
     17 #define TIME_SET 50000            /* 一次定时时间 */
     18 
     19 sbit scl = P2^0;
     20 sbit sda = P2^1;
     21 
     22 bit ack;
     23 
     24 uchar code table[] = {
     25     0x3F,0x06,0x5b,0x4f,0x66,0x6d,
     26     0x7d,0x07,0x7f,0x6f,0x77,0x7c,
     27     0x39,0x5e,0x79,0x71,0x00
     28 }; //led亮的数字
     29 
     30 sbit wela = P2^3;//位选信号
     31 sbit dula = P2^2;//段选
     32 uchar times; 
     33 
     34 void start();                    /* 开始信号 */
     35 void stop();                    /* 结束信号 */
     36 void write(uchar byte);            /* 向EEPROM中写入一个字节 */
     37 void delay(uchar time_delay);    /* 延时函数 */
     38 void write_address(uchar byte, uchar address);         /* 根据地址向EEPROM中写入数据 */
     39 uchar read_address(uchar address);                    /* 从指定地址读出数据 */        
     40 void no_ack();                    /* 发送一个非应答信号 */
     41 void display(uchar num_display);                    /* 显示开机次数 */
     42 void init();
     43 
     44 void main()
     45 {    
     46     init();
     47     times = read_address(0x50);    
     48     times += 1;
     49     write_address(times, 0x50);
     50     display(times);
     51     while(1);
     52 }
     53 /*==========================
     54     功能:发送启动信号
     55     输入:无
     56     输出:启动信号 SDA负跳变
     57 ============================*/
     58 void start()
     59 {
     60     sda = 1;
     61 //    _nop_();                            /* ? */
     62     scl = 1;
     63     delay(1);
     64     sda = 0;
     65     delay(1);
     66     scl = 0;                               /* scl为什么要拉低 */
     67     delay(1);                            /* ? */        
     68 }
     69 /*==========================
     70     功能:发送结束信号
     71     输入:无
     72     输出:启动信号 SDA正跳变
     73 ============================*/
     74 void stop()
     75 {
     76     sda = 0;
     77     _nop_();                        
     78     scl = 1;
     79     delay(5);
     80     sda = 1;
     81     delay(5);    
     82 }
     83 /*==============================================
     84     功能:延时函数 time_delay = 10 延时大约0.5MS
     85     输入:延时时间
     86     输出:延时
     87 ================================================*/
     88 void delay(uchar time_delay)
     89 {
     90     uchar i,j;
     91     for(i = time_delay; i > 0; i--)
     92         for(j = time_delay; j > 0; j --)
     93         {}
     94 }
     95 /*=====================================
     96     功能:向数据线上写一个字节 先写高位
     97     输入:待写字节
     98     输出:写到数据总线上
     99 =======================================*/
    100 void write(uchar byte)
    101 {
    102     uchar i = 0;
    103 
    104     for(; i < 8; i ++)
    105     {
    106         if((byte << i) & 0x80)
    107             sda=1; 
    108         else
    109             sda = 0;
    110         delay(1);                    /* 为啥要延时 */
    111         scl = 1;
    112         delay(1);
    113         scl = 0;
    114     }
    115     delay(1);                        
    116 
    117     sda = 1;
    118     delay(1);
    119     scl = 1;
    120     delay(1);
    121     if(sda == 0)
    122         ack = 0;
    123     else 
    124         ack = 1;
    125 
    126     scl = 0;                
    127 }
    128 
    129 /*=========================================
    130     功能:向指定地址写入一个字节数据
    131     输入:address写入地址,byte写入字节数据
    132     输出:无
    133 ===========================================*/
    134 void write_address(uchar byte, uchar address)
    135 {
    136     start();
    137     delay(5);
    138     write(0xae);        /* 写入设备地址 */
    139     delay(5);
    140     write(address);
    141     delay(5);
    142     write(byte);
    143 
    144     delay(5);
    145 
    146     stop();
    147     delay(200);      /* 延时很重要!!??? */
    148 }
    149 /*==========================
    150     功能:从指定地址读出数据
    151     输入:数据地址
    152     输出:指定地址的数据
    153 ============================*/
    154 uchar read_address(uchar address)
    155 {
    156     uchar i;
    157     uchar result = 0;
    158     start();
    159  
    160     write(0xae);    /* 写入设备地址 */
    161 
    162     write(address);
    163         
    164     start();        /* 第二次设置开始信号 */ 
    165 
    166     write(0xaf);
    167 
    168     sda = 1;
    169 
    170     for(i = 0; i < 8; i ++)            /* 读出数据 */
    171     {
    172         scl = 0;
    173         delay(1);
    174         scl = 1;
    175         delay(1);
    176         result <<= 1;        /* result <<= 1? */
    177         if(sda == 1)
    178             result = result + 1;
    179 
    180          delay(1);
    181     }
    182     scl = 0;                    /* 为啥要拉低 */
    183     delay(1);    
    184 
    185     no_ack();                    /* 发送非应答信号 */
    186 
    187     stop();
    188     return result;
    189 }
    190 /*=======================
    191     功能:初始化变量
    192     输入:无
    193     输出:初始化后的变量
    194 ========================*/
    195 void init()
    196 {
    197     ack = 1;
    198     scl = 1;
    199     sda = 1;
    200 
    201     times = 0;
    202     EA = 1;
    203     ET0 = 1;
    204     TH0 = (65536 - TIME_SET) / 256;
    205     TL0 = (65536 - TIME_SET) % 256;
    206     TR0 = 1;
    207 }
    208 /*==========================
    209     功能:发送一个非应答信号
    210     输入:无
    211     输出:非应答信号
    212 ============================*/
    213 void no_ack()
    214 {
    215     sda = 1;
    216     delay(5);
    217     scl = 1;
    218     delay(5);
    219     scl= 0;
    220     delay(5);
    221 }
    222 /*======================
    223     功能:定时器中断函数
    224     输入:定时器0中断
    225     输出:刷新数码管显示
    226 ========================*/
    227 void timer0() interrupt 1
    228 {
    229     TH0 = (65536 - TIME_SET) / 256;
    230     TL0 = (65536 - TIME_SET) % 256;
    231     display(times);
    232 }
    233 /*==========================
    234     功能:数码管显示开机次数
    235     输入:开机次数
    236     输出:数码管显示开机次数
    237 ============================*/
    238 void display(uchar num_display)
    239 {
    240     uchar ge,shi;//个位和十位
    241 
    242     ge = num_display % 10;
    243     shi = num_display / 10;
    244     //消影
    245     P0 = 0xff;
    246     wela = 1;
    247     wela = 0;
    248     P0 = 0;
    249     dula = 1;
    250     dula = 0;
    251 
    252 
    253     //显示十位数字
    254     P0 = 0xfe;
    255     wela = 1;
    256     wela = 0;
    257     P0 = table[shi];
    258     dula = 1;
    259     dula = 0; 
    260     delay(15);
    261 
    262     //消影
    263     P0 = 0xff;
    264     wela = 1;
    265     wela = 0;
    266     P0 = 0;
    267     dula = 1;
    268     dula = 0;
    269 
    270     //显示个位数字
    271     P0 = 0xfd;
    272     wela = 1;
    273     wela = 0;
    274     P0 = table[ge];
    275     dula = 1;
    276     dula = 0;
    277     delay(15);                         
    278 }
  • 相关阅读:
    react中实现滚动到指定位置固定显示导航栏,反之浸入背景
    activeElement解决ios滚动到底部显示内容时,键盘挡住显示内容的问题
    公积金无租房备案提取如何办理?(以成都为例)
    公积金状态封存怎么解封?
    你应该知道的公积金基础知识科普
    react antd表单不用form.create方法怎么设置input 回显值
    简述个人账户向公司账户转账的方法
    js拖拽进入和离开重复触发的问题
    Electron截屏功能
    Electron在mac下快捷键失效的问题及解决
  • 原文地址:https://www.cnblogs.com/huifeidewoniu/p/3451110.html
Copyright © 2011-2022 走看看