搜索
bottom↓
回复: 32

代码共享:硬件中断方式I2C(CVAVR)

[复制链接]

出0入0汤圆

发表于 2005-11-16 20:42:16 | 显示全部楼层 |阅读模式
//i2c.h



#define TWPS0 0

#define TWPS1 1

#define TWEN  2

#define TWIE  0

#define TWEA  6

#define TWINT 7

#define TWSTA 5

#define TWSTO 4



// TWSR values (not bits)

// Master

#define TW_START                                        0x08

#define TW_REP_START                                0x10

// Master Transmitter

#define TW_MT_SLA_ACK                                0x18

#define TW_MT_SLA_NACK                                0x20

#define TW_MT_DATA_ACK                                0x28

#define TW_MT_DATA_NACK                                0x30

#define TW_MT_ARB_LOST                                0x38

// Master Receiver

#define TW_MR_ARB_LOST                                0x38

#define TW_MR_SLA_ACK                                0x40

#define TW_MR_SLA_NACK                                0x48

#define TW_MR_DATA_ACK                                0x50

#define TW_MR_DATA_NACK                                0x58

// Slave Transmitter

#define TW_ST_SLA_ACK                                0xA8

#define TW_ST_ARB_LOST_SLA_ACK                           0xB0

#define TW_ST_DATA_ACK                                0xB8

#define TW_ST_DATA_NACK                                0xC0

#define TW_ST_LAST_DATA                                0xC8

// Slave Receiver

#define TW_SR_SLA_ACK                                0x60

#define TW_SR_ARB_LOST_SLA_ACK                          0x68

#define TW_SR_GCALL_ACK                                0x70

#define TW_SR_ARB_LOST_GCALL_ACK                            0x78

#define TW_SR_DATA_ACK                                0x80

#define TW_SR_DATA_NACK                                0x88

#define TW_SR_GCALL_DATA_ACK                                    0x90

#define TW_SR_GCALL_DATA_NACK                                    0x98

#define TW_SR_STOP                                        0xA0

// Misc

#define TW_NO_INFO                                        0xF8

#define TW_BUS_ERROR                                0x00



// defines and constants

#define TWCR_CMD_MASK                                       0x0F

#define TWSR_STATUS_MASK                                  0xF8



// return values

#define I2C_OK                                                0x00

#define I2C_ERROR_NODEV                                        0x01



#define I2C_SEND_DATA_BUFFER_SIZE                          0x20

#define I2C_RECEIVE_DATA_BUFFER_SIZE                      0x20



#define F_CPU 8000000

#define TRUE  1

#define FALSE 0   

// types

typedef enum

{

        I2C_IDLE = 0, I2C_BUSY = 1,

        I2C_MASTER_TX = 2, I2C_MASTER_RX = 3,

        I2C_SLAVE_TX = 4, I2C_SLAVE_RX = 5

} eI2cStateType;





//i2c.c

#include <mega128.h>

#include "i2c.h"





// I2C标准波特率:

// 低速 100KHz

// 高速 400KHz



// I2C 状态和地址变量

static volatile eI2cStateType I2cState;

static unsigned char I2cDeviceAddrRW;

// 发送缓冲区

static unsigned char I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];

static unsigned char I2cSendDataIndex;

static unsigned char I2cSendDataLength;

// 接收缓冲区

static unsigned char I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];

static unsigned char I2cReceiveDataIndex;

static unsigned char I2cReceiveDataLength;



unsigned char localBuffer[] = "!!";

unsigned char localBufferLength = 0x20;



// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive

static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);

// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit

static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData);



//设置总线速率

void i2cSetBitrate(unsigned int  bitrateKHz)

{

        unsigned char bitrate_div;

        // SCL freq = F_CPU/(16+2*TWBR))

        #ifdef TWPS0

                // 对于用速率分频的AVR (mega128)

                // SCL freq = F_CPU/(16+2*TWBR*4^TWPS)

                // set TWPS to zero

                  TWSR&=~(1<<TWPS0);

                TWSR&=~(1<<TWPS1);

        #endif

        // 计算分频

        bitrate_div = ((F_CPU/1000l)/bitrateKHz);

        if(bitrate_div >= 16)

                bitrate_div = (bitrate_div-16)/2;

          TWBR = bitrate_div;

}



//总线初始化

void i2cInit(void)

{

        //设置总线上拉

        #ifdef _MEGA128_INCLUDED_

        //#ifdef _MEGA64_INCLUDED_

        PORTD.0=1;        // i2c SCL on ATmega128,64

        PORTD.1=1;        // i2c SDA on ATmega128,64

  #else

  PORTC.0=1;        // i2c SCL on ATmega163,323,16,32,等

  PORTC.1=1;        // i2c SDA on ATmega163,323,16,32,等

  #endif

        // 清空从发送和从接受

        i2cSlaveReceive = 0;

        i2cSlaveTransmit = 0;

        // 设置 i2c 波特率为 100KHz

        i2cSetBitrate(100);

        // I2C总线使能

        TWCR|=1<<TWEN;

        // 状态设置

        I2cState = I2C_IDLE;

        // 开I2C中断和回应

          TWCR|=1<<TWIE;

          TWCR|=1<<TWEA;

       

        #asm("sei");

}





void i2cSetLocalDeviceAddr(unsigned char deviceAddr, unsigned char genCallEn)

{

// 设置本机从地址 (从方式时)

        TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);

}



void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(unsigned char receiveDataLength, unsigned char* recieveData))

{

        i2cSlaveReceive = i2cSlaveRx_func;

}



void i2cSetSlaveTransmitHandler(unsigned char (*i2cSlaveTx_func)(unsigned char transmitDataLengthMax, unsigned char* transmitData))

{

        i2cSlaveTransmit = i2cSlaveTx_func;

}



inline void i2cSendStart(void)

{

       

  TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTA);

}



inline void i2cSendStop(void)

{

        // 发送停止条件,保持TWEA以便从接收

        TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);

}



inline void i2cWaitForComplete(void)

{

        // 等待i2c 总线操作完成

        while( !(TWCR&(1<<TWINT)) );

}



inline void i2cSendByte(unsigned char data)

{

        // 装载数据到 TWDR

          TWDR=data;

        // 发送开始

          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);

}



inline void i2cReceiveByte(unsigned char ackFlag)

{

        //开始通过 i2c 接收

        if( ackFlag )

        {

                // ackFlag = TRUE: 数据接收后回应ACK

            TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);

        }

        else

        {

                // ackFlag = FALSE: 数据接收后无回应

            TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);

        }

}



inline unsigned char i2cGetReceivedByte(void)

{

        // 返回接收到的数据

        return( TWDR );

}



inline unsigned char i2cGetStatus(void)

{

        // 返回总线状态

        return(TWSR);

}



void i2cMasterSend(unsigned char deviceAddr, unsigned char length, unsigned char* data)

{

        unsigned char i;

        // 等待总线准备完成

        while(I2cState);

        // 设置状态

        I2cState = I2C_MASTER_TX;

        // 准备数据

        I2cDeviceAddrRW = (deviceAddr & 0xFE);        // RW 为0: 写操作

        for(i=0; i<length; i++)

                I2cSendData = *data++;

        I2cSendDataIndex = 0;

        I2cSendDataLength = length;

        // 发送开始条件

        i2cSendStart();

}



void i2cMasterReceive(unsigned char deviceAddr, unsigned char length, unsigned char* data)

{

        unsigned char i;

        // 等待总线准备完成

        while(I2cState);

        // 设置状态

        I2cState = I2C_MASTER_RX;

        // 保存数据

        I2cDeviceAddrRW = (deviceAddr|0x01);        // RW 为1 : 读操作

        I2cReceiveDataIndex = 0;

        I2cReceiveDataLength = length;

        // 发送开始条件

        i2cSendStart();

        //等待数据准备好

        while(I2cState);

        // 取数据

        for(i=0; i<length; i++)

                *data++ = I2cReceiveData;

}



unsigned char i2cMasterSendNI(unsigned char deviceAddr, unsigned char length, unsigned char* data)

{

        unsigned char retval = I2C_OK;



        // 关I2C中断

        TWCR&=~(1<<TWIE);



        // 发送开始条件

        i2cSendStart();

        i2cWaitForComplete();



        // 发送器件写地址

        i2cSendByte( deviceAddr & 0xFE );

        i2cWaitForComplete();



        // 检查器件是否可用

        if( TWSR == TW_MT_SLA_ACK)

        {

                // 发送数据

                while(length)

                {

                        i2cSendByte( *data++ );

                        i2cWaitForComplete();

                        length--;

                }

        }

        else

        {

                // 如未回应器件地址,停止发送,返回错误

               

                retval = I2C_ERROR_NODEV;

        }



        // 发送停止条件,保持TWEA以便从接收

        i2cSendStop();

        while( !(TWCR&(1<<TWSTO)) );



        // 开I2C中断

        TWCR|=(1<<TWIE);



        return retval;

}



unsigned char i2cMasterReceiveNI(unsigned char deviceAddr, unsigned char length, unsigned char *data)

{

        unsigned char retval = I2C_OK;



        // 关I2C中断

          TWCR&=~(1<<TWIE);



        //发送开始条件

        i2cSendStart();

        i2cWaitForComplete();



        // 发送器件读地址

        i2cSendByte( deviceAddr | 0x01 );

        i2cWaitForComplete();



        // 检查器件是否可用

        if( TWSR == TW_MR_SLA_ACK)

        {

                // 接收数据并回应

                while(length > 1)

                {

                        i2cReceiveByte(TRUE);

                        i2cWaitForComplete();

                        *data++ = i2cGetReceivedByte();

                        length--;

                }



                //  接收数据无回应 (末位信号)

                i2cReceiveByte(FALSE);

                i2cWaitForComplete();

                *data++ = i2cGetReceivedByte();

        }

        else

        {

                // 如未回应器件地址,停止发送,返回错误

                retval = I2C_ERROR_NODEV;

        }



        // 发送停止条件,保持TWEA以便从接收

        i2cSendStop();



        // 开I2C中断

          TWCR|=TWIE;



        return retval;

}



eI2cStateType i2cGetState(void)

{

        return I2cState;

}



// I2C (TWI) 中断服务程序

interrupt [TWI] void twi_isr(void)

{

        //读状态位

        unsigned char status;

          status = TWSR & TWSR_STATUS_MASK;

        switch(status)

        {

        // 主方式

        case TW_START:                                            // 0x08: START 已发送

        case TW_REP_START:                                        // 0x10: 重复START 已发送

          // 发送器件地址

                i2cSendByte(I2cDeviceAddrRW);

                break;

       

        // 主发送,主接收状态码

        case TW_MT_SLA_ACK:                                        // 0x18: SLA+W 已发送;接收到ACK

        case TW_MT_DATA_ACK:                                // 0x28: 数据已发送;接收到ACK

               

                if(I2cSendDataIndex < I2cSendDataLength)

                {

                        // 发送数据

                        i2cSendByte( I2cSendData[I2cSendDataIndex++] );

                }

                else

                {

                        // 发送停止条件,保持TWEA以便从接收

                        i2cSendStop();

                        // 设置状态

                        I2cState = I2C_IDLE;

                }

                break;

        case TW_MR_DATA_NACK:                                // 0x58: 接收到数据;NOT ACK 已返回

               

                // 保存最终数据

                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;

                //继续发送条件

        case TW_MR_SLA_NACK:                                // 0x48: SLA+R 已发送,接收到NOT ACK

        case TW_MT_SLA_NACK:                                // 0x20: SLA+W 已发送,接收到NOT ACK

        case TW_MT_DATA_NACK:                                // 0x30: 数据已发送,接收到NOT ACK

       

                // 发送停止条件,保持TWEA以便从接收

                i2cSendStop();

                // 设置状态

                I2cState = I2C_IDLE;

                break;

        case TW_MT_ARB_LOST:                                // 0x38: SLA+W 或数据的仲裁失败

       

       

                // 释放总线

                  TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);

                // 设置状态

                I2cState = I2C_IDLE;

               

                break;

        case TW_MR_DATA_ACK:                                // 0x50: 接收到数据,ACK 已返回

       

                // 保存接收到的数据位

                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;

                // 检查是否接收完

        case TW_MR_SLA_ACK:                                        // 0x40: SLA+R 已发送,接收到ACK

       

                if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))

                        // 数据位将接收 , 回复 ACK (传送更多字节)

                        i2cReceiveByte(TRUE);

                else

                        // 数据位将接收 , 回复 NACK (传送最后字节)

                        i2cReceiveByte(FALSE);

                break;



        // 从接收状态码

        case TW_SR_SLA_ACK:                                        // 0x60: 自己的SLA+W 已经被接收,ACK 已返回

        case TW_SR_ARB_LOST_SLA_ACK:// 0x68: SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收,ACK 已返回

        case TW_SR_GCALL_ACK:                                // 0x70: 接收到广播地址,ACK 已返回

        case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: SLA+R/W 作为主机的仲裁失败;接收到广播地址,ACK 已返回

       

                // 被选中为从写入 (数据将从主机接收)

                // 设置状态

                I2cState = I2C_SLAVE_RX;

                // 缓冲准备

                I2cReceiveDataIndex = 0;

                // 接收数据,回应 ACK

                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);

                break;

        case TW_SR_DATA_ACK:                                // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回

        case TW_SR_GCALL_DATA_ACK:        // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回

               

               

                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;

                //检查接收缓冲区状态

                if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)

                {

                        // 接收数据,回应 ACK

                        i2cReceiveByte(TRUE);

                }

                else

                {

                        // 接收数据,回应 NACK

                        i2cReceiveByte(FALSE);

                }

                break;

        case TW_SR_DATA_NACK:                                // 0x88: 以前以自己的 SLA+W 被寻址;数据已经被接收,NOT ACK 已返回

        case TW_SR_GCALL_DATA_NACK:        // 0x98: 以前以广播方式被寻址;数据已经被接收,NOT ACK 已返回

       

                // 接收数据,回应 NACK

                i2cReceiveByte(FALSE);

                break;

        case TW_SR_STOP:                                        // 0xA0: 在以从机工作时接收到STOP或重复START

    TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);

                // i2c 接收完成

                if(i2cSlaveReceive)

                         i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);

                // 设置状态

                I2cState = I2C_IDLE;

                break;



        // 从发送

        case TW_ST_SLA_ACK:                                        // 0xA8: 自己的SLA+R 已经被接收,ACK 已返回

        case TW_ST_ARB_LOST_SLA_ACK:// 0xB0: SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收,ACK 已返回

       

                // 被选中为从读出 (数据将从传回主机)

                // 设置状态

                I2cState = I2C_SLAVE_TX;

                // 数据请求

                if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);

                I2cSendDataIndex = 0;

                //

        case TW_ST_DATA_ACK:                                // 0xB8: TWDR 里数据已经发送,接收到ACK

       

                // 发送数据位

                  TWDR=I2cSendData[I2cSendDataIndex++];

                if(I2cSendDataIndex < I2cSendDataLength)

                        // 回应 ACK

                          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);

                else

                        // 回应 NACK

                          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);

                break;

        case TW_ST_DATA_NACK:                                // 0xC0: TWDR 里数据已经发送接收到NOT ACK

        case TW_ST_LAST_DATA:                                // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK

               

                // 全部完成

                // 从方式开放

                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);

                // 设置状态

                I2cState = I2C_IDLE;

                break;





        case TW_NO_INFO:                                          // 0xF8: 没有相关的状态信息;TWINT = “0”

                // 无操作

               

                break;

        case TW_BUS_ERROR:                                        // 0x00: 由于非法的START 或STOP 引起的总线错误

       

                // 内部硬件复位,释放总线

                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTO)|(1<<TWEA);

                // 设置状态

                I2cState = I2C_IDLE;

                break;

        }

}





// 从操作

void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData)

{

        unsigned char i;

  //此函数在本机被选中为从写入时运行

        // 接收到的数据存入本地缓冲区

        for(i=0; i<receiveDataLength; i++)

        {

                localBuffer = *receiveData++;

        }

        localBufferLength = receiveDataLength;



}



unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)

{

        unsigned char i;



        //此函数在本机被选中为从读出时运行

        //要发送的数据存入发送缓冲区

        for(i=0; i<localBufferLength; i++)

        {

                *transmitData++ = localBuffer;

        }



        localBuffer[0]++;



        return localBufferLength;

}











#define TARGET_ADDR        0xA0

//测试 (24xxyy 器件)

void testI2cMemory(void)

{

        unsigned char i;

        unsigned char txdata[66];

        unsigned char rxdata[66];

       

        txdata[0] = 0;

        txdata[1] = 0;

       

        for(i=0; i<16; i++)

           txdata[2+i] = localBuffer;

        // 发送地址和数据

        i2cMasterSendNI(TARGET_ADDR, 18, txdata);

       



        txdata[18] = 0;



        // 发送地址

        i2cMasterSendNI(TARGET_ADDR, 2, txdata);

        // 接收数据

        i2cMasterReceiveNI(TARGET_ADDR, 16, rxdata);

        //

        rxdata[16] = 0;







}







void main(void)

{

i2cInit();

//设置从接收函数句柄(此函数在被选中为从接收时执行)

i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );

//设置从发送函数句柄(此函数在被选中为从发送时执行)

i2cSetSlaveTransmitHandler( i2cSlaveTransmitService );

testI2cMemory();



}
-----此内容被Paul于2005-11-16,20:47:18编辑过

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2005-11-16 21:27:49 | 显示全部楼层
辛苦了。

出0入0汤圆

发表于 2005-12-12 17:58:12 | 显示全部楼层
辛辛辛苦了!顺便问一句,你的程序如果要驱动24C128,要修改哪里吗?还是一句都不用改?因为我现在刚好要用到24c128,而且对avr也不是很熟。谢谢!

出0入0汤圆

发表于 2005-12-12 18:25:08 | 显示全部楼层
谢谢!

出0入0汤圆

 楼主| 发表于 2005-12-12 21:35:14 | 显示全部楼层
2楼:

i2cMasterReceiveNI和i2cMasterSendNI要改!

出0入0汤圆

发表于 2005-12-12 23:57:47 | 显示全部楼层
好帖...

出0入0汤圆

发表于 2005-12-13 08:16:58 | 显示全部楼层
谢谢!

出0入0汤圆

发表于 2005-12-14 15:01:50 | 显示全部楼层
好!

出0入0汤圆

发表于 2005-12-17 10:10:15 | 显示全部楼层
请问一下大Paul:

  我把你的程序修改成读写24c128,但读出来的是FF,请问是哪里错了呢?谢谢!我修改了以下部分,其它没变。硬件方面:24c128的1、2脚接地,3脚悬空,4脚接地,5脚接pd1,6脚接pd0,7脚接地,8脚接vcc;5、6脚经5k电阻外部拉高。



#define TARGET_ADDR  0xA0     // 器件类型码



#define F_CPU 16000000        // 我用16M的晶振,此处原来是:8000000



#define  test128  0           // 在24c128的0位存放数据



unsigned char testbuf;        // 在ram定义一个测试单元



void main(void)

{

i2cInit();

testI2cMemory();

while(1);

}



void testI2cMemory(void)

{

unsigned char *rw_ptr;



//写入数据

testbuf=0x12;

rw_ptr=(unsigned char *)&testbuf;

i2cMasterSendNI(test128, 1, rw_ptr);



//读出数据

testbuf=0x00;

rw_ptr=(unsigned char *)&testbuf;

i2cMasterReceiveNI(test128, 1, rw_ptr);

}



unsigned char i2cMasterSendNI(unsigned int deviceAddr, unsigned char length, unsigned char* data)

{

unsigned char retval = I2C_OK;



//关I2C中断

TWCR&=~(1<<TWIE);



//发送开始条件

i2cSendStart();

i2cWaitForComplete();



//发送器件写地址

i2cSendByte( TARGET_ADDR & 0xfe );

i2cWaitForComplete();



//检查器件是否可用

if(TWSR == TW_MT_SLA_ACK)

{

//发送地址

  i2cSendByte((unsigned char)(deviceAddr>>8));

  i2cWaitForComplete();

  i2cSendByte((unsigned char)deviceAddr);

  i2cWaitForComplete();

//发送数据

  while(length)

  {

   i2cSendByte( *data++ );

   i2cWaitForComplete();

   length--;

  }

}

else

{

//如未回应器件地址,停止发送,返回错误

  retval = I2C_ERROR_NODEV;

}



//发送停止条件,保持TWEA以便从接收

i2cSendStop();

while( !(TWCR&(1<<TWSTO)) );



//开I2C中断

TWCR|=(1<<TWIE);



return retval;

}



unsigned char i2cMasterReceiveNI(unsigned int deviceAddr, unsigned char length, unsigned char *data)

{

unsigned char retval = I2C_OK;



//关I2C中断

TWCR&=~(1<<TWIE);



//发送开始条件

i2cSendStart();

i2cWaitForComplete();



//发送器件读地址

i2cSendByte( TARGET_ADDR | 0x01 );

i2cWaitForComplete();



//检查器件是否可用

if(TWSR == TW_MR_SLA_ACK)

{

//发送地址

  i2cSendByte((unsigned char)(deviceAddr>>8));

  i2cWaitForComplete();

  i2cSendByte((unsigned char)deviceAddr);

  i2cWaitForComplete();

//接收数据并回应

  while(length > 1)

  {

   i2cReceiveByte(TRUE);

   i2cWaitForComplete();

   *data++ = i2cGetReceivedByte();

   length--;

  }

//接收数据无回应 (末位信号)

  i2cReceiveByte(FALSE);

  i2cWaitForComplete();

  *data++ = i2cGetReceivedByte();

}

else

{

//如未回应器件地址,停止发送,返回错误

  retval = I2C_ERROR_NODEV;

}



//发送停止条件,保持TWEA以便从接收

i2cSendStop();



//开I2C中断

TWCR|=TWIE;



return retval;

}





-----此内容被paul于2005-12-17,10:12:56编辑过


-----此内容被paul于2005-12-17,10:32:39编辑过

出0入0汤圆

发表于 2005-12-22 17:00:41 | 显示全部楼层
用楼主的列程,我的MEGA128进不了TWI的中断服务程序,何解?

现在能写,但不能读:

i2cMasterReceiveNI

{

// 检查器件是否可用

if( TWSR == TW_MR_SLA_ACK) ==》这里出错

}

出0入0汤圆

发表于 2006-1-27 22:20:55 | 显示全部楼层
我在使用pcf8563时,使用以上例程,也发现读有问题?我用avrstudio调试,发现在发送8563寄存器地址后,twint无法置位,不知有无高手解决了这个问题。

出0入0汤圆

发表于 2006-2-22 16:14:22 | 显示全部楼层
想问一下:为什么要定义i2cMasterSend和i2cMasterSendNI这两个函数,分别有什么作用和区别?

出0入0汤圆

发表于 2006-8-30 21:10:20 | 显示全部楼层
"// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive

static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);

// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit  

static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData); "







怎么没找到他的函数啊?

出0入0汤圆

发表于 2007-4-27 19:06:39 | 显示全部楼层
似乎楼主的上拉写的又问题,直接写1的话应该不能被外部器件下拉了

出0入0汤圆

发表于 2007-8-1 15:22:16 | 显示全部楼层
想问一下:为什么要定义i2cMasterSend和i2cMasterSendNI这两个函数,分别有什么作用和区别?

出0入0汤圆

发表于 2007-8-7 08:44:22 | 显示全部楼层
多谢了

收下研究了0-----

出0入0汤圆

发表于 2007-8-20 14:02:36 | 显示全部楼层
感谢LZ分享

出0入0汤圆

 楼主| 发表于 2007-8-20 14:29:50 | 显示全部楼层
各位用时当心,因当时是的时候用了个铁电的代替了EEprom的,导致用EEprom时只能写而无法读。原因是EEprom的时序和铁电的有点不一样。在这个例子中读器件时发送完地址后没有延时,而实际上是需要的,请自己修改。整个中断处理部分没有问题的,我一直在用。

出0入70汤圆

发表于 2008-1-18 15:34:48 | 显示全部楼层
学习

出0入0汤圆

发表于 2008-1-23 00:12:20 | 显示全部楼层
麻烦楼主能解释一下这几个函数的使用的目的吗?


// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive
static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit
static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData);

另外,我亲自编译了您给的程序,并且修改了一下,发现有当时用该程序做双机通信时 会出错,最终发现是下面两行的原因,请楼主解释一下为什么使用“!!”,
unsigned char localBuffer[] = "!!";
unsigned char localBufferLength = 0x20;

我改为:unsigned char localBuffer[0x40]
unsigned char localBufferLength = 0x40;

就ok了,下面是我的双机通讯的主机程序,请楼主多多指教!



//i2c.c
#include <mega128.h>
#include "i2c.h"


// I2C标准波特率:
// 低速 100KHz  
// 高速 400KHz  

// I2C 状态和地址变量
static volatile eI2cStateType I2cState;
static unsigned char I2cDeviceAddrRW;
// 发送缓冲区
static unsigned char I2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
static unsigned char I2cSendDataIndex;
static unsigned char I2cSendDataLength;
// 接收缓冲区
static unsigned char I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
static unsigned char I2cReceiveDataIndex;
static unsigned char I2cReceiveDataLength;

unsigned char localBuffer[0x40];// = "!!";
unsigned char localBufferLength = 0x40;
// 数据接收完毕
static unsigned char I2cReceiveDataOver;  

// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive
static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData);
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit  
static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData);

//设置总线速率
void i2cSetBitrate(unsigned int  bitrateKHz)
{
        unsigned char bitrate_div;
        // SCL freq = F_CPU/(16+2*TWBR))
        #ifdef TWPS0
                // 对于用速率分频的AVR (mega128)
                // SCL freq = F_CPU/(16+2*TWBR*4^TWPS)
                // set TWPS to zero
                  TWSR&=~(1<<TWPS0);
                TWSR&=~(1<<TWPS1);
        #endif
        // 计算分频
        bitrate_div = ((F_CPU/1000l)/bitrateKHz);
        if(bitrate_div >= 16)
                bitrate_div = (bitrate_div-16)/2;
          TWBR = bitrate_div;
}

//总线初始化
void i2cInit(void)
{
        //设置总线上拉
        #ifdef _MEGA128_INCLUDED_  
        //#ifdef _MEGA64_INCLUDED_  
        PORTD.0=1;        // i2c SCL on ATmega128,64
        PORTD.1=1;        // i2c SDA on ATmega128,64
  #else  
  PORTC.0=1;        // i2c SCL on ATmega163,323,16,32,等
  PORTC.1=1;        // i2c SDA on ATmega163,323,16,32,等
  #endif
        // 清空从发送和从接受
        i2cSlaveReceive = 0;
        i2cSlaveTransmit = 0;
        // 设置 i2c 波特率为 100KHz
        i2cSetBitrate(100);
        // I2C总线使能
        TWCR|=1<<TWEN;
        // 状态设置
        I2cState = I2C_IDLE;
        // 开I2C中断和回应
          TWCR|=1<<TWIE;
          TWCR|=1<<TWEA;
         
        #asm("sei");
}


void i2cSetLocalDeviceAddr(unsigned char deviceAddr, unsigned char genCallEn)
{
// 设置本机从地址 (从方式时)
        TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);
}

void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(unsigned char receiveDataLength, unsigned char* recieveData))
{
        i2cSlaveReceive = i2cSlaveRx_func;
}

void i2cSetSlaveTransmitHandler(unsigned char (*i2cSlaveTx_func)(unsigned char transmitDataLengthMax, unsigned char* transmitData))
{
        i2cSlaveTransmit = i2cSlaveTx_func;
}

inline void i2cSendStart(void)
{
         
  TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTA);
}

inline void i2cSendStop(void)
{
        // 发送停止条件,保持TWEA以便从接收
        TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO);
}

inline void i2cWaitForComplete(void)
{
        // 等待i2c 总线操作完成
        while( !(TWCR&(1<<TWINT)) );
}

inline void i2cSendByte(unsigned char data)
{
        // 装载数据到 TWDR
          TWDR=data;
        // 发送开始
          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
}

inline void i2cReceiveByte(unsigned char ackFlag)
{
        //开始通过 i2c 接收
        if( ackFlag )
        {
                // ackFlag = TRUE: 数据接收后回应ACK  
            TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
        }
        else
        {
                // ackFlag = FALSE: 数据接收后无回应
            TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
        }
}

inline unsigned char i2cGetReceivedByte(void)
{
        // 返回接收到的数据
        return( TWDR );
}

inline unsigned char i2cGetStatus(void)
{
        // 返回总线状态
        return(TWSR);
}

void i2cMasterSend(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
        unsigned char i;
        // 等待总线准备完成
        while(I2cState);
        // 设置状态
        I2cState = I2C_MASTER_TX;
        // 准备数据
        I2cDeviceAddrRW = (deviceAddr & 0xFE);        // RW 为0: 写操作
        for(i=0; i<length; i++)
                I2cSendData = *data++;
        I2cSendDataIndex = 0;
        I2cSendDataLength = length;
        // 发送开始条件
        i2cSendStart();
}

void i2cMasterReceive(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
        unsigned char i;
        // 等待总线准备完成
        while(I2cState);
        // 设置状态
        I2cState = I2C_MASTER_RX;
        // 保存数据
        I2cDeviceAddrRW = (deviceAddr|0x01);        // RW 为1 : 读操作
        I2cReceiveDataIndex = 0;
        I2cReceiveDataLength = length;
        // 发送开始条件
        i2cSendStart();
        //等待数据准备好
        while(I2cState);
        // 取数据
        for(i=0; i<length; i++)
                *data++ = I2cReceiveData;
}

unsigned char i2cMasterSendNI(unsigned char deviceAddr, unsigned char length, unsigned char* data)
{
        unsigned char retval = I2C_OK;

        // 关I2C中断
        TWCR&=~(1<<TWIE);

        // 发送开始条件
        i2cSendStart();
        i2cWaitForComplete();

        // 发送器件写地址
        i2cSendByte( deviceAddr & 0xFE );
        i2cWaitForComplete();

        // 检查器件是否可用
        if( TWSR == TW_MT_SLA_ACK)
        {
                // 发送数据
                while(length)
                {
                        i2cSendByte( *data++ );
                        i2cWaitForComplete();
                        length--;
                }
        }
        else
        {
                // 如未回应器件地址,停止发送,返回错误
                 
                retval = I2C_ERROR_NODEV;
        }

        // 发送停止条件,保持TWEA以便从接收
        i2cSendStop();
        while( !(TWCR&(1<<TWSTO)) );

        // 开I2C中断
        TWCR|=(1<<TWIE);

        return retval;
}

unsigned char i2cMasterReceiveNI(unsigned char deviceAddr, unsigned char length, unsigned char *data)
{
        unsigned char retval = I2C_OK;

        // 关I2C中断
          TWCR&=~(1<<TWIE);

        //发送开始条件
        i2cSendStart();
        i2cWaitForComplete();

        // 发送器件读地址
        i2cSendByte( deviceAddr | 0x01 );
        i2cWaitForComplete();

        // 检查器件是否可用
        if( TWSR == TW_MR_SLA_ACK)
        {
                // 接收数据并回应
                while(length > 1)
                {
                        i2cReceiveByte(TRUE);
                        i2cWaitForComplete();
                        *data++ = i2cGetReceivedByte();
                        length--;
                }

                //  接收数据无回应 (末位信号)
                i2cReceiveByte(FALSE);
                i2cWaitForComplete();
                *data++ = i2cGetReceivedByte();
        }
        else
        {
                // 如未回应器件地址,停止发送,返回错误
                retval = I2C_ERROR_NODEV;
        }

        // 发送停止条件,保持TWEA以便从接收
        i2cSendStop();

        // 开I2C中断
          TWCR|=TWIE;

        return retval;
}

eI2cStateType i2cGetState(void)
{
        return I2cState;
}  

// I2C (TWI) 中断服务程序
interrupt [TWI] void twi_isr(void)
{
        //读状态位
        unsigned char status;
          status = TWSR & TWSR_STATUS_MASK;
        switch(status)
        {
        // 主方式
        case TW_START:                                            // 0x08: START 已发送
        case TW_REP_START:                                        // 0x10: 重复START 已发送
          // 发送器件地址
                i2cSendByte(I2cDeviceAddrRW);
                break;
         
        // 主发送,主接收状态码
        case TW_MT_SLA_ACK:                                        // 0x18: SLA+W 已发送;接收到ACK
        case TW_MT_DATA_ACK:                                // 0x28: 数据已发送;接收到ACK
                 
                if(I2cSendDataIndex < I2cSendDataLength)
                {
                        // 发送数据
                        i2cSendByte( I2cSendData[I2cSendDataIndex++] );
                }
                else
                {
                        // 发送停止条件,保持TWEA以便从接收
                        i2cSendStop();
                        // 设置状态
                        I2cState = I2C_IDLE;
                }
                break;
        case TW_MR_DATA_NACK:                                // 0x58: 接收到数据;NOT ACK 已返回
                 
                // 保存最终数据
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
                //继续发送条件
        case TW_MR_SLA_NACK:                                // 0x48: SLA+R 已发送,接收到NOT ACK
        case TW_MT_SLA_NACK:                                // 0x20: SLA+W 已发送,接收到NOT ACK
        case TW_MT_DATA_NACK:                                // 0x30: 数据已发送,接收到NOT ACK
         
                // 发送停止条件,保持TWEA以便从接收
                i2cSendStop();
                // 设置状态
                I2cState = I2C_IDLE;
                break;
        case TW_MT_ARB_LOST:                                // 0x38: SLA+W 或数据的仲裁失败
         
         
                // 释放总线
                  TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
                // 设置状态
                I2cState = I2C_IDLE;
                 
                break;
        case TW_MR_DATA_ACK:                                // 0x50: 接收到数据,ACK 已返回
         
                // 保存接收到的数据位
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
                // 检查是否接收完
        case TW_MR_SLA_ACK:                                        // 0x40: SLA+R 已发送,接收到ACK
         
                if(I2cReceiveDataIndex < (I2cReceiveDataLength-1))
                        // 数据位将接收 , 回复 ACK (传送更多字节)
                        i2cReceiveByte(TRUE);
                else
                        // 数据位将接收 , 回复 NACK (传送最后字节)
                        i2cReceiveByte(FALSE);
                break;

        // 从接收状态码
        case TW_SR_SLA_ACK:                                        // 0x60: 自己的SLA+W 已经被接收,ACK 已返回
        case TW_SR_ARB_LOST_SLA_ACK:// 0x68: SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收,ACK 已返回
        case TW_SR_GCALL_ACK:                                // 0x70: 接收到广播地址,ACK 已返回
        case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: SLA+R/W 作为主机的仲裁失败;接收到广播地址,ACK 已返回
         
                // 被选中为从写入 (数据将从主机接收)
                // 设置状态
                I2cState = I2C_SLAVE_RX;
                // 缓冲准备
                I2cReceiveDataIndex = 0;
                // 接收数据,回应 ACK
                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
                break;
        case TW_SR_DATA_ACK:                                // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回
        case TW_SR_GCALL_DATA_ACK:        // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回
                 
                 
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR;
                //检查接收缓冲区状态
               
                if(I2cReceiveDataIndex < I2C_RECEIVE_DATA_BUFFER_SIZE)
                {
                        // 接收数据,回应 ACK
                        i2cReceiveByte(TRUE);
                }
                else
                {
                        // 接收数据,回应 NACK
                        i2cReceiveByte(FALSE);
                }
               
                break;
        case TW_SR_DATA_NACK:                                // 0x88: 以前以自己的 SLA+W 被寻址;数据已经被接收,NOT ACK 已返回
        case TW_SR_GCALL_DATA_NACK:        // 0x98: 以前以广播方式被寻址;数据已经被接收,NOT ACK 已返回
         
                // 接收数据,回应 NACK
                i2cReceiveByte(FALSE);
                break;
        case TW_SR_STOP:                                        // 0xA0: 在以从机工作时接收到STOP或重复START
    TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
                // i2c 接收完成
                if(i2cSlaveReceive)  
                         i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData);
                // 设置状态
                I2cState = I2C_IDLE;
                break;

        // 从发送
        case TW_ST_SLA_ACK:                                        // 0xA8: 自己的SLA+R 已经被接收,ACK 已返回
        case TW_ST_ARB_LOST_SLA_ACK:// 0xB0: SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收,ACK 已返回
         
                // 被选中为从读出 (数据将从传回主机)
                // 设置状态
                I2cState = I2C_SLAVE_TX;
                // 数据请求
                if(i2cSlaveTransmit) I2cSendDataLength = i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE, I2cSendData);
                I2cSendDataIndex = 0;
                //  
        case TW_ST_DATA_ACK:                                // 0xB8: TWDR 里数据已经发送,接收到ACK
         
                // 发送数据位
                  TWDR=I2cSendData[I2cSendDataIndex++];
                if(I2cSendDataIndex < I2cSendDataLength)
                        // 回应 ACK
                          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
                else
                        // 回应 NACK
                          TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT);
                break;
        case TW_ST_DATA_NACK:                                // 0xC0: TWDR 里数据已经发送接收到NOT ACK
        case TW_ST_LAST_DATA:                                // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
                 
                // 全部完成
                // 从方式开放
                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWEA);
                // 设置状态
                I2cState = I2C_IDLE;
                break;


        case TW_NO_INFO:                                          // 0xF8: 没有相关的状态信息;TWINT = “0”
                // 无操作
                 
                break;
        case TW_BUS_ERROR:                                        // 0x00: 由于非法的START 或STOP 引起的总线错误
         
                // 内部硬件复位,释放总线
                TWCR=TWCR&TWCR_CMD_MASK|(1<<TWINT)|(1<<TWSTO)|(1<<TWEA);
                // 设置状态
                I2cState = I2C_IDLE;
                break;
        }
}


// 从操作
void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData)
{
        unsigned char i;
  //此函数在本机被选中为从写入时运行
        // 接收到的数据存入本地缓冲区
        for(i=0; i<receiveDataLength; i++)
        {
                localBuffer = *receiveData++;
        }
        localBufferLength = receiveDataLength;

}

unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)
{
        unsigned char i;

        //此函数在本机被选中为从读出时运行
        //要发送的数据存入发送缓冲区
        for(i=0; i<localBufferLength; i++)
        {
                *transmitData++ = localBuffer;
        }

        localBuffer[0]++;

        return localBufferLength;
}





#define TARGET_ADDR        0xA0
//测试 (24xxyy 器件)
void testI2cMemory(void)
{
        unsigned char i;
        unsigned char txdata[66];
        unsigned char rxdata[66];
         
        txdata[0] = 0;
        txdata[1] = 0;
         
        for(i=0; i<16; i++)
           txdata[2+i] = localBuffer;
        // 发送地址和数据
        i2cMasterSendNI(TARGET_ADDR, 18, txdata);
         

        txdata[18] = 0;

        // 发送地址
        i2cMasterSendNI(TARGET_ADDR, 2, txdata);
        // 接收数据
        i2cMasterReceiveNI(TARGET_ADDR, 16, rxdata);
        //  
        rxdata[16] = 0;



}
       
void testI2c_SendNum(void)
{
        unsigned char i;
        unsigned char Num[10];
        unsigned char TAGET_ADDR=0x02;
         
        for(i=0;i<10;i++)
                        Num=i;
        i2cMasterSend(TAGET_ADDR,10,Num);
                               
}

void add(void)
{
unsigned char i;
unsigned char receiveAdd[10];
unsigned char TAGET_ADDR=0x02;
for(i=0;i<10;i++)
        {
                localBuffer=localBuffer+1;       
        }

i2cMasterSend(TAGET_ADDR,10,localBuffer);                                       
}


void main(void)       
{       
i2cInit();
i2cSetLocalDeviceAddr(0x04,0);       
//设置从接收函数句柄(此函数在被选中为从接收时执行)       
i2cSetSlaveReceiveHandler(i2cSlaveReceiveService );       
//设置从发送函数句柄(此函数在被选中为从发送时执行)       
i2cSetSlaveTransmitHandler(i2cSlaveTransmitService );       


while(1)
{
  testI2c_SendNum();//发送数据,I2cState = I2C_MASTER_TX
  while(I2cState);        //正在发送数据,等待发送完毕
  while(!I2cState);        //数据发送完毕,I2cState =I2C_IDLE,等待接收数据
  while(I2cState);        //等待数据接收完毕,接收完毕以后I2cState =I2C_IDLE
  add();
  while(I2cState);        //正在发送数据,等待发送完毕
  while(!I2cState);        //数据发送完毕,I2cState =I2C_IDLE,等待接收数据
  while(I2cState);        //等待数据接收完毕,接收完毕以后I2cState =I2C_IDLE
}

}

出0入0汤圆

发表于 2008-1-25 16:02:03 | 显示全部楼层
看得脑都晕了,能分开点写清楚每部分功能吗,那样好看明白

出0入0汤圆

发表于 2008-1-26 12:29:12 | 显示全部楼层
做个标记

出0入0汤圆

发表于 2008-1-29 08:59:43 | 显示全部楼层
楼主你的程序貌似别人的开源代码呀......怎么都不见版权声明?

呵呵,有点较真的哈!

出0入0汤圆

发表于 2008-4-3 09:49:54 | 显示全部楼层
下面函数里的transmitDataLengthMax怎么没用到呢?奇怪了?
unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)
{  
        unsigned char i;  
        //此函数在本机被选中为从读出时运行  
        //要发送的数据存入发送缓冲区  
        for(i=0; i<localBufferLength; i++)  
        {  
                *transmitData++ = localBuffer;  
        }  
        localBuffer[0]++;  
        return localBufferLength;  
}
我觉得应该写成下面的代码
unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData)
{  
        unsigned char i;  
        //此函数在本机被选中为从读出时运行  
        //要发送的数据存入发送缓冲区  
        if(localBufferLength>transmitDataLengthMax)return 0;//如果发送的数据量大于发送缓冲区返回0
        for(i=0; i<localBufferLength; i++)  
        {  
                *transmitData++ = localBuffer;  
        }  
        return localBufferLength;
}
各位高手指点指点!

出0入0汤圆

发表于 2009-3-24 19:03:10 | 显示全部楼层
多谢,多谢!

出0入0汤圆

发表于 2009-9-16 13:09:10 | 显示全部楼层
先看一下, 谢谢。

出0入0汤圆

发表于 2009-9-20 14:20:19 | 显示全部楼层
m

出0入0汤圆

发表于 2009-10-7 15:09:48 | 显示全部楼层
先看看,学到串口和I2C这里来了,就是没有进展

出0入0汤圆

发表于 2010-10-21 19:51:21 | 显示全部楼层
参考

出0入0汤圆

发表于 2011-8-3 21:32:44 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-11 17:49:31 | 显示全部楼层
mark,收下

出0入0汤圆

发表于 2011-12-12 09:25:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-20 09:27:15 | 显示全部楼层
MARK
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-28 01:49

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表