久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4116|回復: 9
收起左側

對于51單片機I2C傳送的問題

[復制鏈接]
ID:254333 發表于 2018-2-14 20:47 | 顯示全部樓層 |閱讀模式
//************向AT24C02寫入數據*******************//
bit write_byte(uchar write_data)
{
        uchar i;
        bit ack_bit;        //定義應答信號
        for(i=0;i<8;i++)    // 循環移入8個位
        {
                SDA=(bit)(write_data & 0x80);
                _nop_();
                SCL = 1;
                _nop_();
                    _nop_();
                SCL = 0;
                write_data=write_data<<1;
        }
        SDA = 1;                        // 讀取應答
        _nop_();
        _nop_();
        SCL = 1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        ack_bit=SDA;
        SCL = 0;
        return ack_bit;                        // 返回AT24Cxx應答位
}
這是原函數
1、SDA=(bit)(write_data & 0x80);我的這行代碼有一些疑惑,不知道我的理解是否正確,我們寫入的數據比如說是1000 0000&1000 0000那么結果就是1000 0000只取最高位,是這樣嗎?
2、SDA = 1;                        // 讀取應答
        _nop_();
        _nop_();
        SCL = 1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        ack_bit=SDA;
        SCL = 0;
        return ack_bit;                        // 返回AT24Cxx應答位
主機和從機的SDA是同一根線吧?SDA=1是設置總線為空閑狀態,SCL從1到0是為了傳輸傳輸信號。定義的應答信號是從機的嗎?最后返回應答位給主調函數。還是不太明白這個ack_bit存在的意義。
求解

回復

使用道具 舉報

ID:279646 發表于 2018-2-28 18:30 | 顯示全部樓層
我來給你解答一下吧。
第一個問題 C51里面有bit這個關鍵字。這個關鍵字定義了一個位,我們在單片機里所說的置位和復位,一個是把位變成1,一個是把位變成0. 這里SDA=(bit)(write_data & 0x80);  bit加了小括號代表強制類型轉換。也就是說 后面的(write_data & 0x80) 做了與運算以后, 如果不是0,就會被強制轉化為1,如果是0那么就是0.你說的write_data=0x80的時候 運算以后是 0x80,強制類型轉換就變成了1.
第二個問題的原因在于,你沒有理解I2C總線的時序。不要只看代碼,你要去深刻理解時序圖。樓上給的圖很好。你看看,不管是應答0 還是非應答1. 讀取這個應答信號的時候SCL都要為高電平。在代碼里面就是SCL=1,根據時序圖先延時一下。然后再采樣SDA線上的數據,于是4個延時以后ack_bit=SDA; 這個時候SDA上的狀態就放到了這個ack_bit里。然后看這個變量是0還是1來判斷從機是否有應答。一開始SDA=1,釋放了總線。如果有應答,器件就會把SDA線拉低變成0.如果沒有應答,那么SDA一直為高。

評分

參與人數 1黑幣 +80 收起 理由
admin + 80 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

ID:123289 發表于 2018-2-16 10:31 | 顯示全部樓層

回帖獎勵 +10

如果你想知道線上的數據是什么,當然是可以調用一個子程序來實現。
你想啊,調用結束后,線上的數據會在哪里呢?
回復

使用道具 舉報

ID:254333 發表于 2018-2-16 22:07 | 顯示全部樓層
yzwzfyz 發表于 2018-2-16 10:31
如果你想知道線上的數據是什么,當然是可以調用一個子程序來實現。
你想啊,調用結束后,線上的數據會在哪 ...

我把全文貼出來吧
#include<reg51.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
bit flag=0;   //寫24C02的標志位類型bit可以定義一個位類型的變量,它的值是一個二進制位,只有一個0或者1
sbit SDA=P3^7;                    
sbit SCL=P3^6;
sbit shi=P3^0;
sbit ge=P3^1;
uchar sec,tcnt;//sec表示讀出的數據,tcnt表示定時器中斷次數
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//******************** 延時函數 *********************//
void delayms(uint ms)
{
        uchar i;
        while(ms--)
        {
                for(i=0;i<120;i++);
        }
}
//***********起始信號 ********************//
void start()
{
        SDA=1;
        SCL=1;
        _nop_();
        _nop_();
        SDA=0;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SCL=0;
}

//***********停止信號 ********************//       
void stop()
{
        SDA=0;
        _nop_();
        _nop_();
        SCL=1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SDA=1;               
}
//************從AT24C02讀取數據*******************//
uchar read_byte( )
{
        uchar i,da;
        for(i=0; i<8;i++)
        {
                SCL=1;
                da=da<<1;
                da=da|(uchar)SDA;
                SCL=0;
        }
        return(da);
}
//************向AT24C02寫入數據*******************//
bit write_byte(uchar write_data)
{
        uchar i;
        bit ack_bit;        //定義應答信號
        for(i=0;i<8;i++)    // 循環移入8個位
        {
                SDA=(bit)(write_data & 0x80);
                _nop_();
                SCL = 1;
                _nop_();
            _nop_();
                SCL = 0;
                write_data=write_data<<1;
        }
        SDA = 1;                        // 讀取應答
        _nop_();
        _nop_();
        SCL = 1;
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        ack_bit=SDA;
        SCL = 0;
        return ack_bit;                        // 返回AT24Cxx應答位
}
//************向AT24C02指定地址寫入數據************//
void write_byte_add(uchar addr, uchar write_data)
{
        start();
        write_byte(0xa0);//E2PROM的地址碼,最后一位0寫方向位
        write_byte(addr);
        write_byte(write_data);
        stop();
        delayms(10);               
}
//************從AT24C02當前地址讀取數據************//
unsigned char read_current()
{
        uchar read_data;
        start();
        write_byte(0xa1);//同理為地址碼,最后一位1讀方向位
        read_data=read_byte();
        stop();
        return read_data;
}
//************從AT24C02指定地址讀取數據************//
unsigned char read_random(uchar random_addr)
{
        start();
        write_byte(0xa0);
        write_byte(random_addr);
        return(read_current());
}

//*******************顯示函數 **************//
void display(uchar bai_c,uchar sh_c)
{
        shi=1;
        P2=table[bai_c];  //顯示第一位
        delayms(5);
        shi=0;
        P2=table[sh_c];  //顯示第二位
        ge=1;
        delayms(5);
        ge=0;
}

//*******************主函數 **************//
void main()
{
        SDA = 1;//總線初始化
        SCL = 1;//總線初始化
        sec=read_random(0x02); //讀出保存的數據賦予sec
        if(sec>100)                 //防止首次讀出錯誤數據
                sec=0;
        TMOD=0x01;   //定時器T0工作在定時方式1
        ET0=1;                  //T0中斷允許
        EA=1;                  //CPU中斷允許
        TH0=(65536-50000)/256; //
        TL0=(65536-50000)%256; //TH0、TL0送初值
        TR0=1;  //啟動T0
        while(1)
        {
                display(sec/10,sec%10);
                if(flag==1)   //判斷計時器是否計時1秒
                {
                        flag=0;   //清0
                        write_byte_add(2,sec); //在24C02的地址02中寫入數據sec
                }
        }
}
//*******************定時器T0中斷函數**************//
void t0() interrupt 1
{
        TH0=(65536-50000)/256; //
        TL0=(65536-50000)%256; //重裝TH0、TL0送初值
        tcnt++;  //50ms         tcnt加1
        if(tcnt==20)
        {
                tcnt=0;         //
                sec++;
                flag=1; //1秒寫一次24C02
                if(sec==100)
                {
                        sec=0;
                }
        }
}
謝謝了,線上的數據是具有記憶功能秒表的時間,0~99
回復

使用道具 舉報

ID:254333 發表于 2018-2-26 20:43 | 顯示全部樓層
求助,有沒有大佬可以回答一下我的問題。
回復

使用道具 舉報

ID:280512 發表于 2018-2-26 22:37 | 顯示全部樓層
(bit)是個轉換類型符。只要write_data非零,(bit)(write_data & 0x80)就為“1”,然后,write_data左移,寫入一位。ack_bit,是你定義的一位返回值的位,是這樣吧?
回復

使用道具 舉報

ID:280512 發表于 2018-2-26 22:40 | 顯示全部樓層
你需要的是最高位,所以,要用0x80作為判斷的條件
回復

使用道具 舉報

ID:111634 發表于 2018-2-26 22:56 | 顯示全部樓層

回帖獎勵 +10

本帖最后由 zl2168 于 2018-2-26 23:03 編輯

能讀懂IIC收發時序圖就能理解。介紹你一本書,《80C51單片機實用教程——基于Keil C和Proteus》高等教育出版社ISBN 978-7-04-044532-9,內有IIC詳細講解。
I2C總線基本信號.jpg I2C總線數據傳送時序.jpg
回復

使用道具 舉報

ID:247040 發表于 2018-2-28 18:42 | 顯示全部樓層
同求ack_bit存在的意義樓主解決沒
回復

使用道具 舉報

ID:304404 發表于 2018-4-24 08:59 | 顯示全部樓層
樓主有沒有仿真圖  讓我參考一下
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 亚洲在线免费 | 99精品视频一区二区三区 | 国产一区 | 操皮视频 | av一区二区三区在线观看 | 中文字幕av在线一二三区 | 国产综合精品一区二区三区 | 久久国产欧美日韩精品 | 91精品国产一区二区三区香蕉 | 老司机深夜福利网站 | 日韩二区三区 | 成人一区二区三区视频 | 国产高清精品在线 | 午夜小电影 | 国产精品久久影院 | 毛片黄片免费看 | 久一精品 | 91福利电影在线观看 | 成人免费在线观看 | 久久亚洲二区 | 伊人天堂网 | 日韩在线精品视频 | 久草欧美 | 午夜影院免费体验区 | 欧美久久久久久 | 日韩成人免费视频 | 亚洲欧美一区二区三区国产精品 | 国产色婷婷久久99精品91 | 亚洲免费视频在线观看 | 日韩中文字幕一区二区三区 | 在线免费亚洲视频 | 911精品国产 | 嫩草黄色影院 | 亚洲网站在线 | 亚洲一区二区av | 黄一级| jlzzjlzz欧美大全 | 免费黄色片在线观看 | 欧美一级欧美一级在线播放 | 国产网站在线免费观看 | 中文字幕免费在线 |