目次
1. 前に書く
- AT24C02 チップには I2C インターフェイスがありますが、51 マイクロコントローラには I2C インターフェイスがなく、ソフトウェア プログラムを使用して I2C バスをシミュレートします。
- 51 マイコンがホスト マシン、AT24C02 がスレーブ マシンです。この実験で最も重要なことは、マスターとスレーブのどちらがデータを送信しているのか、受信しているのかを確認することです。
- デフォルトでは、ホストが SCL および SDA ラインを制御します。スレーブが SDA ラインを制御してデータを送信する場合、マスターはバスを解放する必要があります (SDA=1)。
2. 機能説明
マイコンを使用してAT24C02とのI2C通信をシミュレートし、AT24C02にデータを書き込み、AT24C02の機能を利用して停電後も失われないデータを保存し、マイコンを再起動すると、対応するアドレスのデータを読み出すことができます。 。
3. 主要モジュールの紹介
3.1 I2C バスの概要
I2C バス (Inter IC Bus) には 2 本の双方向信号線のみがあります。1 つはデータ ライン SDA であり、もう 1 つはクロック ライン SCL です。クロック ラインがあり、マスターが送信してスレーブが受信する、またはスレーブが送信してマスターが受信するため、I2C は同期の半二重通信方式です。
3.2 I2C バスプロトコル
3.2.1 データの有効性に関する規制
I2C バスがデータを送信する場合、クロック信号が High レベルの間、データ ラインのデータは安定している必要があり、クロック ラインの信号が Low レベルの場合にのみ、データ ラインの High レベルまたは Low レベルの状態が維持されます。変更を許可できます。
3.2.2 スタート信号とストップ信号
- スタート信号:SCLがハイレベルのとき、SDAはハイレベルからローレベルに変化します。
- ストップ信号:SCL がハイレベルのとき、SDA はローレベルからハイレベルに変化します。
スタート信号とストップ信号はいずれもホストから送信され、スタート信号発生後はバスが占有状態となり、ストップ信号発生後はバスがアイドル状態になります。
開始信号と停止信号は、プログラムによって次のようにシミュレートされます。
/*
*函数名: I2C_star()
*函数功能:I2C的起始信号
*输入: 无
*输出: 无
*/
void I2C_star()
{
I2C_SDA=1;
I2C_SCL=1;
I2C_SDA=0;
I2C_SCL=0;
}
/*
*函数名: I2C_stop()
*函数功能:I2C的停止信号
*输入: 无
*输出: 无
*/
void I2C_stop()
{
I2C_SDA=0;
I2C_SCL=1;
I2C_SDA=1;
}
3.2.3 レスポンスの送信とレスポンスの受信
応答の送信と受信はホストに対して相対的です。応答はローレベルパルス、非応答はハイレベルパルスです。
- 応答の送信: ホストがスレーブによって送信されたデータを受信すると、ホストはデータの送信を継続するかどうかの応答信号をスレーブに送信します。
- レスポンスの受信:マスターがスレーブにデータを送信した後、スレーブはSDAを制御してレスポンス信号を送信し(この時点でホストはバスを解放したい)、ホストはそのレスポンス信号に基づいてデータを送信するかどうかを決定します。
プログラムのシミュレーションは次のとおりです。
/*
*函数名: I2C_SendAck(bit ack)
*函数功能: 主机发送应答
*输入: ack:发送的一个应答
*输出: 无
*/
void I2C_SendAck(bit ack)//主机发送应答
{
I2C_SDA=ack;
I2C_SCL=1;
I2C_SCL=0;
}
/*
*函数名: I2C_ReadAck()
*函数功能: 主机接收应答
*输入: 无
*输出: ack:接收的应答
*/
bit I2C_ReadAck()//主机接收应答
{
bit ack=0;
I2C_SDA=1;//释放总线
I2C_SCL=1;
ack=I2C_SDA;
I2C_SCL=0;
return ack;
}
3.2.4 ホストはバイトを送信し、バイトを受信します
- ホストは 1 バイトのデータを送信します。SCL が Low の場合、ホストはデータを SDA ラインに順番に書き込み (High ビットが最初)、その後 SCL を High に引き上げます。SCL が High の間にスレーブはデータ ビットを読み取り、8 をループします。回、1 バイトのデータを送信できます。
- ホストはデータのバイトを受信します。最初にホストがバスを解放し (SDA=1)、SCL が Low のとき、スレーブはデータを SDA ラインに順番に書き込み (High ビットが最初)、次に SCL を High にプルすると、ホストは通常時にデータビットを読み取り、8 回サイクルして 1 バイトのデータを受信します。
手順は次のとおりです。
/*
*函数名: I2C_Writebyte(unsigned char byte)
*函数功能: I2C总线主机发送一个字节数据
*输入: byte:要发送的字节数据
*输出: 无
*/
void I2C_Writebyte(unsigned char byte)//主机发送一个字节的数据
{
unsigned char i=0;
for(i=0;i<8;i++)
{
I2C_SDA=byte&(0x80>>i);
I2C_SCL=1;
I2C_SCL=0;
}
}
/*
*函数名: I2C_Readbyte()
*函数功能: I2C总线主机接收一个字节数据
*输入: 无
*输出: byte:读取的数据
*/
unsigned char I2C_Readbyte()//主机接收一个字节数据
{
unsigned char i,byte=0;
I2C_SDA=1;//释放总线
for(i=0;i<8;i++)
{
I2C_SCL=1;
if(I2C_SDA==1){byte|=(0x80>>i);}//I2C_SDA上的数据已经是从机发送的数据
I2C_SCL=0;
}
return byte;
}
3.3 AT24C02 の概要
当社の開発ボードはAT24C02 (EEPROM) チップを使用しています. このチップは I2C 通信インターフェースを備えています. チップに保存されたデータは電源を切っても失われることがないため、通常はより重要なデータを保存するために使用されます。
3.3 バイト書き込みとランダム読み取り
I2C バスのアドレッシングは、スレーブ アドレスのビット数に応じて 7 ビットと 10 ビットの 2 種類に分けられます。7 ビットのアドレス指定バイトのビット定義は次のとおりです。
スレーブの 7 ビットのアドレス指定ビットのうち、4 ビットは固定ビット、3 ビットはプログラム可能ビットです。
- AT24C02 の固定値は 1010 で、この開発ボードのプログラマブル ビット値は 000 です。スレーブ アドレスに読み取り/書き込みビット (0/1) を加えたものが、開始信号の後の最初のバイトになります。
- バイト書き込みの順序: スタート信号 + リード/ライトビット (0/1) 付きスレーブアドレス + 受信レスポンス + 書き込みデータを指定するアドレス + 受信レスポンス + 書き込みデータ + 受信レスポンス + ストップ信号。
- ランダムリードのシーケンス: スタート信号 + リード/ライトビット付きスレーブアドレス(0/1) + 受信レスポンス + リードデータを指定するアドレス + 受信レスポンス + スタート信号 + リードライトビット付きスレーブアドレス(0/1) +応答受信 + ホスト受信データ + 応答送信 + 停止信号。
手順は次のとおりです。
#define AT24C02_address 0xA0 //AT24C02的地址
/*
*函数名: AT24C02_Writebyte(unsigned char word_address,byte)
*函数功能:向AT24C02中的某个地址写入一个字节数据
*输入: word_address:字节地址 byte:写入的字节数据
*输出: 无
*/
void AT24C02_Writebyte(unsigned char word_address,byte)
{
bit ack=0;
I2C_star();
I2C_Writebyte(AT24C02_address);
ack=I2C_ReadAck();
I2C_Writebyte(word_address);
ack=I2C_ReadAck();
I2C_Writebyte(byte);
ack=I2C_ReadAck();
I2C_stop();
}
/*
*函数名: AT24C02_Readbyte(unsigned char word_address)
*函数功能: 主机读取AT24C02的指定地址的数据
*输入: word_address:数据的地址
*输出: byte:被读取的字节数据
*/
unsigned char AT24C02_Readbyte(unsigned char word_address)
{
unsigned char byte=0;
bit ack=0;
I2C_star();
I2C_Writebyte(AT24C02_address);
ack=I2C_ReadAck();
I2C_Writebyte(word_address);
ack=I2C_ReadAck();
I2C_star();
I2C_Writebyte(AT24C02_address|0x01);
ack=I2C_ReadAck();
byte=I2C_Readbyte();
I2C_SendAck(1);
I2C_stop();
return byte;
}
4. テストファイルtest.c
#include <REGX52.H>
#include"I2C.h"
#include"LCD1602.h"
#include"AT24C02.h"
#include"Independentkey.h"
#include"Delay.h"
int main()
{
unsigned char keynum,num=0;
LCD_Init();
LCD_ShowNum(1,1,0,3);
AT24C02_Writebyte(0x01,1);
Delay(5);
AT24C02_Writebyte(0x02,2);
Delay(5);
AT24C02_Writebyte(0x03,3);
Delay(5);
AT24C02_Writebyte(0x04,4);
Delay(5);
while(1)
{
keynum=Independentkey();
if(keynum!=0)
{
if(keynum==1)
{
num=AT24C02_Readbyte(0x01);
LCD_ShowNum(1,1,num,3);
}
if(keynum==2)
{
num=AT24C02_Readbyte(0x02);
LCD_ShowNum(1,1,num,3);
}
if(keynum==3)
{
num=AT24C02_Readbyte(0x03);
LCD_ShowNum(1,1,num,3);
}
if(keynum==4)
{
num=AT24C02_Readbyte(0x04);
LCD_ShowNum(1,1,num,3);
}
}
}
}
5. 現象の説明
AT24C02 のアドレス 0x01、0x02、0x03、0x04 に 1、2、3、4 を書き込み、独立したボタンを押してそれぞれを読み出し (電源をオフにしてもデータは失われません)、LCD1602 に表示されます。
- 巻末に書かれている「わからないことやプログラムがうまくいかないときは、「なんでこんなに難しいの?」と愚痴をこぼさず、まずは落ち着いてください。一度理解できなかったら、 2回聞きます、両方理解できない場合は3回聞きます、理解できるまで。散歩に出かけ、自分の考えを明確にしてから、戻ってビデオを見ることもできます。他の人はあなたが知っていると思っていても言わないこともありますが、実際にはあなたは知らないこともあります。これは混乱につながります。考えているうちに、なぜこんなことになるのか不思議に思って、長い間そこから立ち往生してしまいます。上に書いた内容は私が動画を見ていて知らなかった点、注目すべき点です。プログラムが実行できない場合は、問題の原因を注意深く調べてください。以前は、Warning は役に立たないと思っていました。警告を報告するだけですが、プログラムは実行できます。今回は、問題の原因を探すのに時間がかかりました。等しいかどうかだけをチェックする if () ステートメントがあることがわかりました。「=」記号があり、コンパイラは警告を報告しましたが、エラーは報告しませんでした。プログラムのどこかが間違って書かれているのではないかと思いました。再度変更しましたが、かなりの時間を無駄にしました。最後に、問題に遭遇したときに最も重要なことは、落ち着いて問題の原因を注意深く見つけて問題を解決することです。