/@@************* 用户系统配置 **************/ #define MAIN_Fosc 12000000L //定义主时钟 模拟串口和红外接收会自动适应。5~36MHZ #define D_TIMER0 125 //选择定时器时间 us 红外接收要求在60us~250us之间 #define User_code 0xFD02 //定义红外接收用户码 #define DECVICE_ADD 0x55<<1 /@@************* 以下宏定义用户请勿修改 **************/ #include "reg51.H" #include "string.H" #define uchar unsigned char #define uint unsigned int //#define freq_base (MAIN_Fosc / 1200) //#define Timer0_Reload (65536 - (D_TIMER0 * freq_base / 10000)) /@@************* 本地常量声明 **************/ /@@************* 本地变量声明 **************/ sbit SDA = P3^0; //SDA sbit SCL = P3^1; //SCL bit PreState; bit NowState; bit START_flag; bit STOP_flag; //uchar IR_SampleCnt; //采样计数 uchar NN; uchar DEVICE_ADR; //器件地址 uchar WORD_ADR; //内存地址 uchar REC_DATA; //接收到的内容 unsigned int *send_ptr;// code unsigned AA0[9] = {0x700x2c0x6e0x2a0x000x000x000xc0}; // code unsigned AA8[2] = {0xff0x2c}; // //code unsigned AA0[9] = {0x700x2c0x6e0x2a0x000x000x000xc0}; // code unsigned A00[33] = {0xed0xcf0x480xe60x890xe80x0c0xe8 0x970xaf0xd20x400x6d0xc20xc40x04 0xca0xd50xea0xa70xae0x430x370xe2 0x120x050x3b0x590xb70xfb0x3d0xa5 }; // code unsigned A20[33] = {0xCB0x850x8b0x540x6d0x970x3c0x05 0x460x0f0x450xb40xd10x0a0xb80x9b 0xdf0xa20x430x8d0xe60x7a0x6f0xf8 0x7f0xaa0x520x370xa60x8f0xdc0x71 }; // code unsigned A40[33] = { 0x150x670xc50x820xfe0x010x870x44 0x100xcd0xf80xe20xd70xb10x7d0xb6 0x530xc00x430x390x3a0xb30x320xba 0x5d0x840xf10x030x130xcd0x740x28 }; // code unsigned A60[33] = { 0x340x390xab0x320x3b0x320x760x4b 0xff0x6f0x2d0xd60x200xab0x8c0x73 0x6b0xd00xad0xa60x830xdf0x600xe0 0x630x510xe40x760x1e0x580x9f0x52 }; // uchar temp; /@@************* 外部函数和变量声明 *****************/ void init(void);//初如化函数 void delay_24C02(void); // 延时 5us void ACK(void);//应答 void WaitACK(void);//等待主机回复 /@@********************* 主函数 *************************/ void main(void) { uchar ggMMicount; init();//初如化 while(1) { NN=50; PreState = SDA; while(SCL && NN--) { NowState = SDA; if(PreState && !NowState) //启动 { START_flag = 1; //_DINT(); } if(!PreState && NowState) //结束 { STOP_flag = 1; //_EINT(); } PreState = NowState; if(START_flag) //如果是启动的话 { START_flag=0; while(SCL); //START时的SCL高电平状态就等待 for(gg=8;gg>0;gg--) //接收器件地址 { while(!SCL); //SCL低电平状态就等待 DEVICE_ADR<<=1; if(SDA) //数据的第一个CLK高电平来临 DEVICE_ADR |= 0x01; while(SCL); //SCL高电平状态就等待 } ACK(); //对设备地址ACK应答信 //-----------以上收到了设备地址,并知晓主机要对从机进行读还是写操作--- for(gg=8;gg>0;gg--) //接收内存单元地址 { while(!SCL); WORD_ADR<<=1; if(SDA) WORD_ADR |= 0x01; while(SCL); } //-----------以上就已经接收到内存单元地址------------ ACK(); //对内存单元ACK应答信号 //--------------------- 以上就已经接收到内存单元地址 ------------------------- delay_24C02();//5us delay_24C02(); delay_24C02();//5us delay_24C02(); MM=50; PreState = SDA; while(SCL && MM--) { NowState = SDA; if(PreState && !NowState) // 如果 SDA 下降沿且 SCL 为高 , 则示开始信号 { START_flag = 1; } } //--------------------START_Flag=1: 表示随即读数据 ------------------------- if(START_flag==1) { //--------------------------- 读取器件地址 --------------------------------- //while(!SCL); START_flag=0; // 清除标志位 while(SCL); //START 时的 SCL 高电平状态就等待 for(gg=8;gg>0;gg--) // 接收器件地址 { while(!SCL); //SCL 低电平状态就等待 DEVICE_ADR<<=1; // 高位在前 if(SDA) // 数据的第一个 CLK 高电平来临 DEVICE_ADR |= 0x01; // 上升沿读取数据位 while(SCL); //SCL 高电平状态就等待 } ACK(); // 对设备地址 ACK 应答信 //------------------ 判断地址是否为 0xa1 ,表示读数据指令 ------------------- if(DEVICE_ADR == 0xab) //( DECVICE_ADD+1) { switch(WORD_ADR) { case 0xa0: count=8; send_ptr =AA0; // memcpy(tempAA0count); break; case 0xa8: count=1; send_ptr =AA8; // memcpy(tempAA8count); break; case 0x00: count=32; send_ptr =A00; // memcpy(tempA00count); break; case 0x20: count=32; send_ptr =A20;// memcpy(tempA20count); break; case 0x40: count=32; send_ptr =A40; // memcpy(tempA40count); break; case 0x60: count=32; send_ptr =A60;// / memcpy(tempA60count); break; } for(i=0;i<count;i++) // 要 读 多 少 字 节 , 由 { //@@*send_ptr =WORD_ADR; temp = send_ptr[i]; for(gg=8;gg>0;gg--) // 输出数据给主机 { while(SCL);//如果为高,保持 if( temp & 0x80) { SDA=1; // 输出 1 } else { SDA=0; // 输出 0 } while(!SCL); //while(SCL); //SCL 为 1 ,就保持 SDA 输出不变 // SDA=1; //@@*send_ptr <<=1; temp <<=1; } WaitACK();//主机回复ACK //send_ptr++; } }//if(DEVICE_ADR==0xa1) else //如果不是,退出 { } }//if(START_flag==1) else // 如果 START_flag!=1 则表示主机对从机进行写操作 { if(WORD_ADR == 0xa9) { for(i=0;i<8;i++) { for(gg=8;gg>0;gg--) // 读取主机发来的数据 { // while(!SCL); // //READ_BUF[i] <<=1; // //SDA=0; // if(SDA) // ; // //READ_BUF[i] |= 0x01; // //SDA=0; // while(SCL); while(!SCL); while(SCL); } ACK(); // 对设备地址 ACK 应答信 } } } }// if(START_flag) }//end while(SCL && NN--) }//end while(1) } /@@******************************************************************** 函数功能:初始化函数 入口参数:无 返 回:无。 备 注:无。 ********************************************************************/ void init(void) { SDA=1; // 初始数据引脚 SCL=1; // 初始时钟引脚 // EA=1; // 开总中断 // IP=0x90; // 中断优先级设定,设为串口 >INTO>T0>INT1>T1 // EX0=1; // 开外部中断 0 } /@@******************************************************************** 函数功能:从机应答函数 入口参数:无 返 回:无。 备 注:应答函数,保证在两个时钟跳变沿 SDA 为低,则主机认为是从机应答 ********************************************************************/ void ACK(void) { // while(!SCL); // SDA=0; // 第 9 个 CLK 变高的情况下, SDA 输出 0 // while(SCL); // SDA=1; // 第 9 个 CLK 变低的情况下, SDA 输出 1 while(SCL); //低就阻塞 delay_24C02(); SDA=0; // 第 9 个 CLK 变高的情况下, SDA 输出 0 while(!SCL); //低就阻塞 while(SCL); //高就阻塞 delay_24C02(); SDA=1; // 第 9 个 CLK 变低的情况下, SDA 输出 1 } /@@******************************************************************** 函数功能:主机应答函数 入口参数:无 返 回:无。 备 注:应答函数,保证在两个时钟跳变沿 SDA 为低,则主机认为是从机应答 ********************************************************************/ void WaitACK(void) { // while(!SCL); // SDA=0; // 第 9 个 CLK 变高的情况下, SDA 输出 0 // while(SCL); // SDA=1; // 第 9 个 CLK 变低的情况下, SDA 输出 1 while(SCL); //高就阻塞 delay_24C02(); SDA=1; // 第 9 个 CLK 变高的情况下, SDA 输出 0 while(!SCL); //低就阻塞 while(SCL); //高就阻塞 delay_24C02(); //SDA=1; // 第 9 个 CLK 变低的情况下, SDA 输出 1 } /@@******************************************************************** 函数功能:延时 us 入口参数:无 返 回:无。 备 注:函数是用来实现短暂延时,用于对接上主机时钟 ********************************************************************/ void delay_24C02(void) // 延时 5us { //; ; ; ; ; uchar i; i=3; while(i--); }
一样的,IIC的时序做好了,就成功了90%了
从机是先接收,判断地址,主机是先发送地址,