整整花了两天时间,在调试的时候时间花费最多的地方就是硬件模块连续读数据,因为这种polling 方式连续读取在官方文档上是没有的,并且在网络上也很难找到(至少我没有找到)。
最终还是通过摸索找到了一个很好办法,正如 iic_rx_byte 函数(硬件方式)的实现,我用IIC1C_TX=1;成功替代了官方示例中停止信号后读数据寄存器的的方式,现在迫不及待的将这些代码贴出来,与大家共享!
/** EEPROM.c
* 软/硬两种方式读写AT24CXX
* MCU:MC9S08AC16
* 时钟:总线16MHz
* 编译:CodeWarrior for HCS08 v6.3
*
* http;//www.chipart.cn
* EMAIL: chipart@qq.com
* 2011-11-07
*/
#include "common.h"
// PTC1 -- SDA -- 外部已接上拉电阻
// PTC0 -- SCL -- 外部已接上拉电阻
// PTC2 -- WE
// #define USE_SOFT_IIC //如使用软件模拟IIC将此注释去掉
#ifdef USE_SOFT_IIC //如果是软件模拟 /////////////////////////////////
#define SCL_high {PTCD_PTCD0 = 1; iic_wait();}
#define SCL_low {PTCD_PTCD0 = 0; iic_wait();}
#define SCL_output {PTCDD_PTCDD0 = 1;}
#define SDA_high {PTCD_PTCD1 = 1; iic_wait();}
#define SDA_low {PTCD_PTCD1 = 0; iic_wait();}
#define SDA_output {PTCDD_PTCDD1 = 1;}
#define SDA_input {PTCDD_PTCDD1 = 0;}
#define SDA_value (PTCD_PTCD1)
static void iic_tx_bit_1( void ); //transmits a logic 1
static void iic_tx_bit_0( void ); //transmits a logic 0
static uint8_t iic_rx_bit( void ); //receives a bit
static void iic_wait( void )
{
volatile unsigned char i;
for ( i = 0; i < 50; i++ )
;;
}
static void iic_tx_bit_1( void ) //transmits a logic 1
{
SCL_low;
SDA_output;
SDA_high;
SCL_high;
SCL_low;
}
static void iic_tx_bit_0( void ) //transmits a logic 0
{
SCL_low;
SDA_output;
SDA_low;
SCL_high;
SCL_low;
}
static uint8_t iic_rx_bit( void ) //receives a bit,returns ACK status
{
unsigned char retval;
SDA_input;
SCL_low;
SCL_high;
retval = SDA_value;
SCL_low;
return retval;
}
#define iic_restart iic_start
static void iic_start( void ) //issues a START condition
{
SDA_output;
SDA_high;
SCL_high;
SDA_low;
}
static void iic_stop( void ) //issues a STOP condition
{
SDA_output;
SDA_low;
SCL_high;
SDA_high;
}
void iic_init( void ) //initializes IIC system
{
SCL_output;
SDA_output;
iic_stop();
}
static uint8_t iic_tx_byte( uint8_t B )
{
unsigned char i;
for ( i = 0; i < 8; i++ )
{
if( B & 0x80 )iic_tx_bit_1();
else iic_tx_bit_0();
B = B << 1;
};
i = iic_rx_bit();
return (!i);
}
static uint8_t iic_rx_byte( uint8_t acknowledge )
{
unsigned char i, retval;
retval = 0;
for ( i = 0; i < 8; i++ )
{
retval = (retval << 1);
if( iic_rx_bit())
retval++;
}
if( acknowledge )
iic_tx_bit_0();
else
iic_tx_bit_1();
return retval;
}
#else //使用硬件iic模块/////////////////////////////////////////////////
void wait_iflag(void)//等待中断标记
{
uint16_t i;
for(i=0;i<0XFF;i++)
if(IIC1S_IICIF)
break;
IIC1S_IICIF=1;
}
uint8_t wait_ack(void) //等待应答
{
uint16_t i;
for(i=0;i<0XFF;i++)
{
if(!IIC1S_RXAK)
break;
}
if(i<0xff)
return 1;
return 0;
}
void iic_init (void)
{
IIC1C=0X88;
IIC1F = 0x94; // 16M/4/80=50kHz 总线频率 = 16MHz;
}
#define iic_start() (IIC1C_MST =1)
#define iic_restart() (IIC1C_RSTA =1)
static void iic_stop( void )
{
uint8_t i;
IIC1C_MST = 0; //发送停止信号
for(i=0;i<100;i++) //延时,以保证下一个开始信号不会立即发生
;
}
static uint8_t iic_tx_byte(uint8_t data)
{
IIC1C_TX = 1; //设置发送;
IIC1D = data;
wait_iflag();
return wait_ack();
}
static uint8_t iic_rx_byte( uint8_t acknowledge )
{
uint8_t ret;
IIC1C_TX = 0; //设置为接收
if(acknowledge)
IIC1C_TXAK = 0; //接收完成时应答
else
IIC1C_TXAK = 1; //接收完成不应答
ret = IIC1D; // 触发读操作
wait_iflag();
IIC1C_TX=1; //状态转换,以便读寄存器不触发总线上的读操作
ret=IIC1D;
return ret;
}
#endif
//复位从器件
void iic_general_reset( void ) // reset all devices into the IIC system
{
uint8_t dummy;
iic_start();
dummy = iic_tx_byte(0x00); // All addresses listen to me
dummy = iic_tx_byte(0x06); // I'm sending the general reset command
iic_stop();
}
/////////////////////以下为24C08操作部分////////////////////////////////////////
#define IIC_WRITE 0
#define IIC_READ 1
#define IIC_ACK 1
#define IIC_NOACK 0
/**
以下宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
#define EEPROM_WRITE_PORT_INIT PTCDD_PTCDD2=1
#define EEPROM_WRITE_ENABLE PTCD_PTCD2=0
#define EEPROM_WRITE_DISABLE PTCD_PTCD2=1
static uint8_t g_DeviceAddr=0;//器件地址
//器件忙检测,原理:器件忙时不会对主机的写操作应答
void At24cxxWaitBusy(void)
{
uint8_t i;
//检测EEPROM是否忙
for(;;)
{
iic_start();
i=iic_tx_byte(g_DeviceAddr);
iic_stop();
if(i==1)
break;
}
return ;
}
/** 设置当前操作器件的地址,并初台化IO口
AT24C01 1 0 1 0 A2 A1 A0 0
AT24C02 1 0 1 0 A2 A1 A0 0
AT24C04 1 0 1 0 A2 A1 0 0
AT24C08 1 0 1 0 A2 0 0 0
AT24C16 1 0 1 0 0 0 0 0
A0,A1,A2为芯片地址引脚连接配置
*/
void At24cxxConfig(uint8_t device_addr)
{
//WE引脚初始化
EEPROM_WRITE_PORT_INIT;
EEPROM_WRITE_DISABLE;
iic_init();
g_DeviceAddr=device_addr;
iic_general_reset();
}
//随机写一字节函数
void At24cxxWriteByte(unsigned int addr,uint8_t dat)
{
uint8_t ADDL,ADDH;
ADDH=(addr>>8);
ADDH<<=1;
ADDL=(uint8_t)addr;
At24cxxWaitBusy();
EEPROM_WRITE_ENABLE;
iic_start();
iic_tx_byte(g_DeviceAddr | ADDH | IIC_WRITE);
iic_tx_byte(ADDL);//写地址低字节
iic_tx_byte(dat);//写数据字节
iic_stop();
EEPROM_WRITE_DISABLE;
}
//随机读一字节函数
uint8_t At24cxxReadByte(unsigned int addr)
{
uint8_t ret,ADDL,ADDH;
ADDH=(addr>>8);
ADDH<<=1;
ADDL=(uint8_t)addr;
IIC1C_TXAK = 0;
iic_start();
iic_tx_byte(g_DeviceAddr|ADDH|IIC_WRITE);//写地址
iic_tx_byte(ADDL);
iic_restart();
iic_tx_byte(g_DeviceAddr | ADDH | IIC_READ);
ret=iic_rx_byte(IIC_NOACK);//NO ACK
iic_stop();
return ret;
}
//随机读多字节函数
void At24cxxRead(uint8_t *buf,uint16_t addr,uint8_t len)
{
uint8_t i,ADDL,ADDH;
if(len<1)
return ;
ADDH=(addr>>8);
ADDH<<=1;
ADDL=(uint8_t)addr;
IIC1C_TXAK = 0;
iic_start();
iic_tx_byte(g_DeviceAddr|ADDH|IIC_WRITE);//写地址
iic_tx_byte(ADDL);
iic_restart();
iic_tx_byte(g_DeviceAddr | ADDH | IIC_READ);
for(i=0;i<len-1;i++)
buf[i]=iic_rx_byte(IIC_ACK);
buf[i]=iic_rx_byte(IIC_NOACK);//NO ACK
iic_stop();
}
|
|