以下为TWI模块的接口函数实现:
twi.h:
//twi.h
#ifndef TWI_H
#define TWI_H
void TwiInit(void);
uint8_t TwiStart(void);
void TwiStop(void);
uint8_t TwiWriteByte(uint8_t c);
//读一字节 ack: 1时发TW_ACK,0时发TW_NOACK
uint8_t TwiReadByte(uint8_t *c, uint8_t ack);
//当I/O口模拟时此值为1
//当硬件 TWI接口时此值为0x18,即发送SLA+W后接收到ACK状态
#define NO_BUSY 0x18
#endif
twi.c:
/********************************
AVR单片机硬件TWI模块操作接口程序
文件名:twi.c
编译:WinAVR-20070122
硬件:CA-M8X
配置:外部4MHz
打开:S7(1,2,3) - EEPROM连接
S6(1,2) - 4MHz晶振连接
S5(5,6) - UART连接
注:PC3连接写保护引脚
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
#include
#include
#include
#define TWI_BAUD 10000 //波特率(10k)
void TwiInit(void)
{
TWSR=0XF8;//不分频
//设置波特率,请确保TWBR不小于10
TWBR=((F_CPU/TWI_BAUD)-16)/8;
PORTC|=_BV(PC4)|_BV(PC5);
}
uint8_t TwiStart(void)
{
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
while ((TWCR & _BV(TWINT)) == 0) ;
return TW_STATUS;
}
//产生一停止信号
void TwiStop(void)
{
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
while(TWCR&_BV(TWSTO));/*等等停止信号完成*/
}
//写一字节
uint8_t TwiWriteByte(uint8_t c)
{
TWDR = c;
TWCR = _BV(TWINT) | _BV(TWEN);
while ((TWCR & _BV(TWINT)) == 0);
return TW_STATUS;
}
//读一字节 ack: 1时应答,0时不应答
uint8_t TwiReadByte(uint8_t *c, uint8_t ack)
{
uint8_t tmp=_BV(TWINT)|_BV(TWEN);
if(ack)
tmp|=_BV(TWEA);
TWCR=tmp;
while ((TWCR & _BV(TWINT)) == 0) ;
*c=TWDR;
return TW_STATUS;
}
以下为AT24CXX的操作函数实现:
at24cxx.h:
//AT24CXX.H
#ifndef AT24CXX_H
#define AT24CXX-H
void At24cxxWaitBusy(void);
void At24cxxConfig(uint8_t device_addr,uint8_t page_size);
void At24cxxWriteByte(uint16_t addr,uint8_t dat);
uint8_t At24cxxReadByte(uint16_t addr);
void At24cxxWritePage(uint16_t page_index,uint8_t *buf);
void At24cxxReadPage(uint16_t page_index,uint8_t *buf);
#endif
at24cxx.c:
/********************************
通用AT24CXX操作接口程序
本程序适合于AT24C32/64,AT24C128/256等器件
文件名:at.c
编译:WinAVR-20070122
硬件:CA-M8X
注:本程序需要I/O模拟或硬件实现的I2C总线接口函数
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
#include
#include
#include "twi.h" //i2c接口函数声明处
#define TW_WRITE 0
#define TW_READ 1
#define TW_ACK 1
#define TW_NOACK 0
/*以下两个宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
//在CA-M8X板上该引脚通过S7(3)连接MEGA8的PC3
#define EEPROM_WRITE_ENABLE PORTC&=~_BV(PC3),DDRC|=_BV(PC3)
#define EEPROM_WRITE_DISABLE PORTC|=_BV(PC3),DDRC|=_BV(PC3)
static uint8_t g_PageSize=0;//页大小(按字节)
static uint8_t g_DeviceAddr=0;//器件地址
static uint8_t g_PageBitCount;//一页所占用的位数(如一页为64字节,则6)
/*器件忙检测,原理:器件忙时不会对主机的写操作应答*/
//忙检测接口函数,只有一种情况才需要调用这个函数
//即:当刚写完成,要读数据时
//而连续的读或者写操作之间不需要调用这个函数
void At24cxxWaitBusy(void)
{
uint8_t i;
//检测EEPROM是否忙
while(1)
{
TwiStart();
i=TwiWriteByte(g_DeviceAddr);
TwiStop();
if(i==NO_BUSY)
break;
}
return ;
}
/* 设置当前操作器件的地址和页大小
device_addr最低位必须为0
只有在使用页访问器件时page_size有用
不使用页访问时可指定page_size为0 */
void At24cxxConfig(uint8_t device_addr,uint8_t page_size)
{
uint8_t i;
g_DeviceAddr=device_addr;
g_PageSize=page_size;
g_PageBitCount=0;
if(page_size==0)
return ;
//计算一页所占用位数
for(i=1;i<10;i++)//不能大于9次
{
if(page_size==(1<
{
g_PageBitCount=i;
break;
}//if
}//for
}
//AT24CXX通用随机写一字节函数
void At24cxxWriteByte(uint16_t addr,uint8_t dat)
{
At24cxxWaitBusy();
EEPROM_WRITE_ENABLE;
TwiStart();
TwiWriteByte(g_DeviceAddr );//= |TW_WRITE
TwiWriteByte(addr>>8);//写地址高字节
TwiWriteByte(addr);//写地址低字节
TwiWriteByte(dat);//写数据字节
TwiStop();
EEPROM_WRITE_DISABLE;
}
//AT24CXX通用随机读一字节函数
uint8_t At24cxxReadByte(uint16_t addr)
{
uint8_t ret;
TwiStart();
TwiWriteByte(g_DeviceAddr);//写地址
TwiWriteByte(addr>>8);
TwiWriteByte(addr);
TwiStart();
TwiWriteByte(g_DeviceAddr | TW_READ);
TwiReadByte(&ret,TW_NOACK);//NO ACK
TwiStop();
return ret;
}
//AT24CXX通用写页函数,page_index为页地址,即表示第几页
void At24cxxWritePage(uint16_t page_index,uint8_t *buf)
{
uint8_t i;
//页索引调整到绝对地址
page_index<<=g_PageBitCount;
//检测EEPROM是否忙
At24cxxWaitBusy();
//写一页
EEPROM_WRITE_ENABLE;
TwiStart();
TwiWriteByte(g_DeviceAddr );//= |TW_WRITE
TwiWriteByte(page_index>>8);//写地址高字节
TwiWriteByte(page_index);//写地址低字节
for(i=0;i
TwiWriteByte(buf[i]);
TwiStop();
EEPROM_WRITE_DISABLE;
}
//AT24CXX通用读页函数,page_index为页地址,即表示第几页
void At24cxxReadPage(uint16_t page_index,uint8_t *buf)
{
uint8_t i;
//页索引调整到绝对地址
page_index<<=g_PageBitCount;
TwiStart();
TwiWriteByte(g_DeviceAddr);//写地址
TwiWriteByte(page_index>>8);
TwiWriteByte(page_index);
TwiStart();
TwiWriteByte(g_DeviceAddr | TW_READ);
for(i=0;i
TwiReadByte(&buf[i],TW_ACK);
TwiReadByte(&buf[i],TW_NOACK);//最后一字节不应答
TwiStop();
}
测试部分:
uart.c:
/****************************************
文件名:uart.c
****************************************/
#include
#include
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}
void StdIoInit(void)
{
UCSRB=0;
UBRRH=0;
UBRRL=25; //9600
UCSRB=_BV(TXEN);
stdout = &mystdout;
stderr = &mystdout;
printf("Uart初始化完成!\n");
}
test.c:
/********************************
AVR单片机TWI模块操作AT24CXX的通用程序
文件名:main.c
编译:WinAVR-20070122
硬件:CA-M8X
配置:外部4MHz
打开:S7(1,2,3) - EEPROM连接
S6(1,2) - 4MHz晶振连接
S5(5,6) - UART连接
注:PC3连接写保护引脚
芯艺设计室 2004-2007 版权所有
转载请保留本注释在内的全部内容
WEB: http://www.chipart.cn
Email: changfutong@sina.com
*******************************/
#include
#include
#include
#include "twi.h"
#include "at24cxx.h"
#define AT24C256_PAGE_SIZE 64 //AT24C256页大小
#define AT24C32_PAGE_SIZE 32 //AT24C32页大小
#define MAX_PAGE_SIZE 64 //最大可能用到的缓冲,在定义缓冲时使用
#define AT24C256A_ADDR 0xA0 //CAM8X第一片AT24C256芯片地址
#define AT24C256B_ADDR 0xA2 //CAM8X第二片AT24C256芯片地址(CAM8X标准配置没有焊接这块存储器芯片)
#define AT24C32_ADDR 0xA4 //AT24C32芯片地址
static uint8_t g_PageBuffer[MAX_PAGE_SIZE];//页数据的缓冲
void StdIoInit(void);//uart.c中实现,调试用
//测试AT24C256
void test256(void)
{
uint8_t i;
printf("test at24c256:\n");
At24cxxConfig(AT24C256A_ADDR,AT24C256_PAGE_SIZE);
//测试随机读/写字节
At24cxxWriteByte(333,33);
At24cxxWaitBusy();
i=At24cxxReadByte(333);
printf("ReadByte:%d\n",i);
//测试随机读/写页
for(i=0;i
g_PageBuffer[i]=i+2;
At24cxxWritePage(3,g_PageBuffer);
At24cxxWaitBusy();
At24cxxReadPage(3,g_PageBuffer);
printf("Page:\n");
for(i=0;i
{
if((i+1)%10==0)
printf("%d\n",g_PageBuffer[i]);
else
printf("%d ",g_PageBuffer[i]);
}
printf("\n");
}
//测试at24c32
void test32(void)
{
uint8_t i;
printf("test at24c32:\n");
At24cxxConfig(AT24C32_ADDR,AT24C32_PAGE_SIZE);
//测试随机读/写字节
At24cxxWriteByte(200,170);
At24cxxWaitBusy();
i=At24cxxReadByte(200);
printf("ReadByte:%d\n",i);
//测试随机读/写页
for(i=0;i
g_PageBuffer[i]=i+33;
At24cxxWritePage(6,g_PageBuffer);
At24cxxWaitBusy();
At24cxxReadPage(6,g_PageBuffer);
printf("Page:\n");
for(i=0;i
{
if((i+1)%10==0)
printf("%d\n",g_PageBuffer[i]);
else
printf("%d ",g_PageBuffer[i]);
}
printf("\n");
}
int main(void)
{
StdIoInit();//uart打印输出初始化
TwiInit(); //TWI口初始化
test256();
test32();
while(1);
}
测试结果:
|
|