📄 i2c.c
字号:
//********************************************************************************************
//
// Title : MP3测试 - 软I2C驱动程序
// Author : Ant (gz_ant@126.com)
// Created : 2005/02/16
// Revised : 2005/02/19
// Version : 0.1
// Target MCU : MEGA16
// Editor Tabs : 4
//
// 注: 本代码用于测试STA013硬件及其驱动程序, 并非一个完整的MP3播放器程序.
// 上电后,会循环不停播放一段约2秒的MP3音乐.
// 硬件没有连接RAM缓冲及储存MP3文件的设备, MP3数据是保存在AVR的FLASH中.
// 本代码经测试, 但可能存有Bugs, 若你发现有任何Bug或有任何建议,
// 请来信告知: gz_ant@126.com
//// 本代码部分来自"Procyon AVRlib": http://hubbard.engr.scu.edu/embedded/avr/avrlib/release_notes.html
// 特此感谢它的创始人: Pascal Stang !
//
// 感谢在www.21icbbs.com帮助过winsu的朋友, 希望使用者能发扬网络的 "自由,开放" 精神.
//********************************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/twi.h>
#include "type.h"
#include "main.h"
#include "I2C.h"
#define SDA_DirPort DDRC
#define SDA_OutPort PORTC
#define SDA_InPort PINC
#define SDA 1
#define SCK_DirPort DDRC
#define SCK_OutPort PORTC
#define SCK 0
#define SDAMask (1<<SDA)
#define WriteDeviceAddress 0xA0
#define ReadDviceAddress 0xA1
#define IIC_TWO_ADDR 0
//定义I2C的延迟参数
#define DelayX 5 //7.3M=>1; 8.4M=>2.建议5,因为将来的ClockCPU可以是16M
#define SCL_1 {sbi(SCK_OutPort, SCK);_Nop(DelayX);}
#define SCL_0 {cbi(SCK_OutPort, SCK);_Nop(DelayX);}
#define SDA_1 {sbi(SDA_OutPort, SDA);_Nop(DelayX);}
#define SDA_0 {cbi(SDA_OutPort, SDA);_Nop(DelayX);}
void _Nop(u8 dly);
void I2C_Ini(void);
void IICStart(void);
void IICStop(void);
u8 IICRecAck(void);
void IICACK(void);
void IICNoAck(void);
void IICSendByte(unsigned char sendbyte);
unsigned char IICReceiveByte(void);
//=======================================================================
void _Nop(u8 dly) //延时
{
while(dly--);
}
//=======================================================================
//初始化端口
void I2C_Ini(void)
{
sbi(SCK_DirPort,SCK); //SCK为输出
sbi(SDA_DirPort,SDA); //SDA为双向的,先设置为输出
// sbi(WP_DirPort,WP); //WP为输出
}
//=======================================================================
//启动总线。根据IIC协议,SCL为1时,SDA从1转变为0。
void IICStart(void)
{
SCL_0;
SDA_1;
SCL_1;
SDA_0;
SCL_0;
}
//=======================================================================
//停止IIC总线。根据IIC协议,SCL为1时,SDA从0转变为1。
void IICStop(void)
{
SCL_0;
SDA_0;
SCL_1;
SDA_1;
SCL_0;
}
//=======================================================================
//检查应答位,向I2C写数据时,I2C设备(EEPROM)正常接受到数据后在第9周期发出0应答,
//如果不正常接受到数据,则不以0应答而进入待命状态。
//写数据后需检查I2C设备是否有0应答。
u8 IICRecAck(void)
{
u8 ack;
SCL_0;
SDA_0;
SCL_1;
cbi(SDA_DirPort, SDA); //设置为输入
sbi(SDA_OutPort, SDA); //上拉
ack=(SDA_InPort & SDAMask); //读SDA应答位
sbi(SDA_DirPort, SDA); //恢复为输出
SCL_0;
return(ack);
}
//=======================================================================
//对IIC总线产生应答。读I2C设备时,如果下一步还要读则产生0应答。
void IICACK(void)
{
SDA_0;
SCL_1;
SCL_0;
SDA_1;
}
//=======================================================================
//不对IIC总线产生应答。读I2C设备时,如果下一步不需要读则产生1应答(即不应答)。
void IICNoAck(void)
{
SDA_1;
SCL_1;
SCL_0;
}
//=======================================================================
//向IIC总线写数据。SCL=0时SDA的数据可改变,SCL=1时需保持SDA数据稳定。
void IICSendByte(unsigned char sendbyte)
{
unsigned char j=8;
for(;j>0;j--)
{
SCL_0;
if(sendbyte&0x80) SDA_1 //SCL=0时写数据到SDA
else SDA_0
sendbyte<<=1;
SCL_1;
}
SCL_0;
}
//=======================================================================
//从IIC总线上读数据。
unsigned char IICReceiveByte(void)
{
u8 receivebyte=0,i=8;
cbi(SDA_DirPort, SDA); //设置SDA为输入
sbi(SDA_OutPort, SDA); //上拉
SCL_0;
while(i--)
{
SCL_1;
receivebyte <<= 1;
if(SDA_InPort & SDAMask) receivebyte |= 1;
SCL_0;
}
sbi(SDA_DirPort, SDA); //恢复SDA为输出
return(receivebyte);
}
void ReadIC(u16 addr,u8 ReadLen,u8 *buff)
{
u8 ERRORCOUNT=10;
addr &= 0x0FFF;
addr |= 0xA000;
while(ERRORCOUNT--)
{
IICStart();
IICSendByte((addr >> 8) & (~0x01));
if(IICRecAck()) continue;
IICSendByte((u8)addr);
if(IICRecAck()) continue;
IICStart();
IICSendByte((addr >> 8) | 0x01);
if(IICRecAck()) continue;
while(--ReadLen)
{
*buff++=IICReceiveByte();
IICACK();
}
*buff=IICReceiveByte();
IICNoAck();
break;
}
IICStop();
}
//在指定地址写1Byte的数据。
void WriteICByte(u16 addr, u8 data)
{
u8 ERRORCOUNT=10;
addr &= 0x0FFF;
addr |= 0xA000;
while(ERRORCOUNT--)
{
IICStart();
IICSendByte((addr >> 8) & (~0x01));
if(IICRecAck()) continue;
IICSendByte((u8)addr);
if(IICRecAck()) continue;
IICSendByte(data);
IICACK();
break;
}
IICStop();
}
//
void WriteICPage(u16 addr,u8 ReadLen,u8 *buff)
{
u8 ERRORCOUNT=10;
addr &= 0x0FFF;
addr |= 0xA000;
while(ERRORCOUNT--)
{
IICStart();
IICSendByte((addr >> 8) & (~0x01));
if(IICRecAck()) continue;
IICSendByte((u8)addr);
if(IICRecAck()) continue;
while(ReadLen--)
{
IICSendByte(*buff++);
IICACK();
}
break;
}
IICStop();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -