基于中断的I2C库
本帖最后由 js200300953 于 2012-6-24 15:50 编辑这个库是NUC140的,应该很容易就可以移植到其他芯片上(其实这个库是从AVRi移植过来的),特别是同为M3的STM32。
希望对大家有帮助。
废话少说,上代码。
这是头文件:/* lib/bus/i2c/i2c.h
* 2012-5-11 16:05:24 */
#ifndef __FILE_LIB_BUS_I2C_I2C_H__
#define __FILE_LIB_BUS_I2C_I2C_H__
#include "NUC1xx.h"
#include "../../common/common.h"
/* 数据传输回调函数。
* 每(准备)传输一个字节都调用一次。
* 参数:
* seq=> 序号,第一次调用时为0,以后每次调用递增。
* data => seq==0时写(从机地址+W/R)到data。
* seq!=0时data是数据。发送就写data,接收就读data。
* 返回值表示下一步的行为:
* I2C_RT_START => 发送开始信号。
* I2C_RT_STOP=> 发送停止信号。
* I2C_RT_REPEAT_START_OR_STOP => 如果有下一次传输,就发送RepeatStart,否则发送Stop。
* I2C_RT_ACK => 继续传送,回应ACK。
* I2C_RT_NACK=> 继续传送,回应NACK。*/
typedef uint8_t (* I2C_transmitCallback)(uint8_t seq,uint8_t * data);
/* 异常回调函数。
* 总线出现异常就会被调用。
* 参数:
* exception => 异常类型,{I2C_EXCEPTION_NACK,I2C_EXCEPTION_ARBITRATION_LOST}。
* 返回值表示下一步的行为:
* I2C_RT_START => 发送开始信号。
* I2C_RT_STOP=> 发送停止信号,终止传输(推荐)。
* I2C_RT_ACK => 继续传送,回应ACK。
* I2C_RT_NACK=> 继续传送,回应NACK。*/
typedef uint8_t (* I2C_exceptionCallback)(uint8_t exception);
enum {I2C_EXCEPTION_NACK,I2C_EXCEPTION_ARBITRATION_LOST};
#define I2C_NO_CALLBACK 0
#define I2C_isCallback(cb) ((cb) != I2C_NO_CALLBACK)
/* 包装变量的结构体。*/
typedef struct
{
I2C_transmitCallback transmitCallback;
I2C_transmitCallback nextCallback;
I2C_exceptionCallback exceptionCallback;
uint32_t curSeq : 7;
uint32_t isIdle : 1;
}I2C_t;
/*
* 函数声明。 */
void I2C_init (uint8_t which,uint32_t rate);
uint8_t I2C_transmit (uint8_t which,I2C_transmitCallback cb);
uint8_t I2C_isIdle (uint8_t which);
void I2C_setNextCallback (uint8_t which,I2C_transmitCallback cb);
void I2C_setExceptionCallback(uint8_t which,I2C_exceptionCallback cb);
//
void I2C_IRQHandler (uint8_t which);
void I2C_actionStart (uint8_t which);
void I2C_actionStop (uint8_t which);
void I2C_actionAck (uint8_t which);
void I2C_actionNack (uint8_t which);
void I2C_actionStart_notInIRQ(uint8_t which);
/* 用7位的地址构造(地址+W/R)字节。*/
#define I2C_addressToByte_write(addr7) ((addr7)<<1)
#define I2C_addressToByte_read(addr7)(((addr7)<<1) | 1)
/*
* 函数返回值。
* RT : return */
enum
{
I2C_RT_IS_IDLE_NO= 0,
I2C_RT_IS_IDLE_YES = 1
};
enum
{
I2C_RT_TRANSMIT_NORMAL = 0,
I2C_RT_TRANSMIT_BUSY,
I2C_RT_TRANSMIT_ERROR,
};
enum
{
I2C_RT_START,
I2C_RT_REPEAT_START_OR_STOP,
I2C_RT_STOP,
I2C_RT_ACK,
I2C_RT_NACK,
};
/*
* 总线状态。
* ST : status
* MA : master
* MT : master transmit
* MR : master receive */
enum
{
I2C_ST_MA_STARTED = 0x08,
I2C_ST_MA_REPEAT_STARTED = 0x10,
I2C_ST_MT_ADDR_ACK = 0x18,
I2C_ST_MT_ADDR_NACK = 0x20,
I2C_ST_MT_DATA_ACK = 0x28,
I2C_ST_MT_DATA_NACK = 0x30,
I2C_ST_MA_ARBITRATION_LOST = 0x38,
I2C_ST_MR_ADDR_ACK = 0x40,
I2C_ST_MR_ADDR_NACK = 0x48,
I2C_ST_MR_DATA_ACK = 0x50,
I2C_ST_MR_DATA_NACK = 0x58,
I2C_ST_ERROR = 0x00,
};
#endif // __FILE_LIB_BUS_I2C_I2C_H__
然后是代码:/* lib/bus/i2c/i2c.c
* 2012-5-11 16:04:52 */
#include "NUC1xx.h"
#include "../../common/common.h"
#include "i2c.h"
/*
* 定义变量*/
I2C_T * const I2C_Base = {I2C0,I2C1};
volatile static I2C_t I2C_var;
/*
* 初始化I2C。
* 参数
* which => 指定总线,{0,1}。
* rate=> 时钟,kHz,。基于48Mhz的系统时钟。*/
void I2C_init(uint8_t which,uint32_t rate)
{
if(which == 0)
{
/*
* 设置针脚功能。 */
SYS->GPAMFP.I2C0_SCL = 1;
SYS->GPAMFP.I2C0_SDA = 1;
/*
* 允许中断。 */
NVIC_ISER->I2C0_INT = 1;
/*
* 通入时钟。 */
SYSCLK->APBCLK.I2C0_EN = 1;
}
else if(which == 1)
{
/*
* 设置针脚功能。 */
SYS->GPAMFP.I2C1_SCL_nRD = 1;
SYS->GPAMFP.I2C1_SDA_nWR = 1;
SYS->ALTMFP.EBI_EN = 0;
/*
* 允许中断。 */
NVIC_ISER->I2C1_INT = 1;
/*
* 通入时钟。 */
SYSCLK->APBCLK.I2C1_EN = 1;
}
I2C_var.isIdle = 1;
I2C_var.transmitCallback = I2C_NO_CALLBACK;
I2C_var.nextCallback = I2C_NO_CALLBACK;
I2C_var.exceptionCallback = I2C_NO_CALLBACK;
/*
* 设置时钟。 */
I2C_Base->u32I2CLK = 12000 / rate - 1;
}
/* 判断I2C是否空闲。
* 参数
* which => 指定总线,{0,1}。*/
uint8_t I2C_isIdle(uint8_t which)
{
return I2C_var.isIdle;
}
/*
* 传送数据,异步。
* 参数
* which => 指定总线,{0,1}。
* cb => 回调函数,传送是发送还是接收,取决于回调函数的具体实现。
* 返回值
* I2C_RT_TRANSMIT_NORMAL => 正常。但不保证发送成功。
* I2C_RT_TRANSMIT_BUSY => 总线忙。
* I2C_RT_TRANSMIT_ERROR=> 指定的总线不存在。*/
uint8_t I2C_transmit(uint8_t which,I2C_transmitCallback cb)
{
if(!I2C_isIdle(which))
return I2C_RT_TRANSMIT_BUSY;
I2C_var.isIdle = 0;
//
if(which > 1)
return I2C_RT_TRANSMIT_ERROR;
//
I2C_var.transmitCallback = cb;
I2C_var.nextCallback = I2C_NO_CALLBACK;
I2C_var.exceptionCallback = I2C_NO_CALLBACK;
//
I2C_actionStart(which);
return I2C_RT_TRANSMIT_NORMAL;
}
/*
* 设置下一个任务。
* 用于连续传输,中间是Repeat Start,而不是Stop。
* 本次传输有效,下次调用I2C_transmit()时会重置。 */
void I2C_setNextCallback(uint8_t which,I2C_transmitCallback cb)
{
I2C_var.nextCallback = cb;
}
/*
* 设置错误回调函数。
* 详细见I2C_transmitCallback的定义。
* 本次传输有效,下次调用I2C_transmit()时会重置。 */
void I2C_setExceptionCallback(uint8_t which,I2C_exceptionCallback cb)
{
I2C_var.exceptionCallback = cb;
}
/*
* I2C通用中断处理函数。
* 参数
* which => 指定总线。 */
void I2C_IRQHandler(uint8_t which)
{
/*
* 根据总线状态决定下一步动作。 */
uint8_t action = I2C_RT_REPEAT_START_OR_STOP;
switch(I2C_Base->I2CSTATUS)
{
case I2C_ST_MA_STARTED :
case I2C_ST_MA_REPEAT_STARTED :
/* Start信号已发出,初始化计数,发送(地址+W/R)。 */
I2C_var.curSeq = 0;
action = I2C_var.transmitCallback(I2C_var.curSeq,
(uint8_t *)&(I2C_Base->u32I2CDAT));
break;
case I2C_ST_MT_ADDR_ACK :
case I2C_ST_MT_DATA_ACK :
case I2C_ST_MR_DATA_ACK :
/* 处理数据和获取下一步动作。 */
I2C_var.curSeq ++;
action = I2C_var.transmitCallback(I2C_var.curSeq,
(uint8_t *)&(I2C_Base->u32I2CDAT));
break;
case I2C_ST_MR_ADDR_ACK :
/* 接收模式,发送完地址,直接ACK就可以。 */
action = I2C_RT_ACK;
break;
case I2C_ST_MT_ADDR_NACK :
case I2C_ST_MT_DATA_NACK :
case I2C_ST_MR_ADDR_NACK :
/* 发送数据后收到NACK,默认动作是Stop。 */
if(I2C_isCallback(I2C_var.exceptionCallback))
action = I2C_var.exceptionCallback(I2C_EXCEPTION_NACK);
else
action = I2C_RT_REPEAT_START_OR_STOP;
break;
case I2C_ST_MR_DATA_NACK :
/* 如果接收数据时响应了NACK,自动Stop。 */
action = I2C_RT_REPEAT_START_OR_STOP;
break;
case I2C_ST_MA_ARBITRATION_LOST :
/* 总线失控,默认等待重新开始。*/
if(I2C_isCallback(I2C_var.exceptionCallback))
action = I2C_var.exceptionCallback(I2C_EXCEPTION_ARBITRATION_LOST);
else
action = I2C_RT_START;
break;
case I2C_ST_ERROR :
default :
action = I2C_RT_STOP;
break;
}
/*
* 执行动作。 */
switch(action)
{
case I2C_RT_START :
I2C_actionStart(which);
break;
case I2C_RT_REPEAT_START_OR_STOP :
/* 检查有没有连续的任务,有就Repeat Start,否则Stop。 */
if(I2C_isCallback(I2C_var.nextCallback))
{
I2C_var.transmitCallback = I2C_var.nextCallback;
I2C_var.nextCallback = I2C_NO_CALLBACK;
I2C_actionStart(which);
}
else
{
I2C_actionStop(which);
}
break;
case I2C_RT_STOP :
I2C_actionStop(which);
break;
case I2C_RT_ACK :
I2C_actionAck(which);
break;
case I2C_RT_NACK :
I2C_actionNack(which);
break;
}
}
/*
* I2C0中断处理函数。 */
void I2C0_IRQHandler(void)
{
I2C_IRQHandler(0);
}
/*
* I2C1中断处理函数。 */
void I2C1_IRQHandler(void)
{
I2C_IRQHandler(1);
}
void I2C_actionStart(uint8_t which)
{
I2C_Base->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(5));
}
void I2C_actionStop(uint8_t which)
{
I2C_Base->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(4));
I2C_var.isIdle = 1;
}
void I2C_actionAck(uint8_t which)
{
I2C_Base->u32I2CON = (_BV(3)|_BV(6)|_BV(7)|_BV(2));
}
void I2C_actionNack(uint8_t which)
{
I2C_Base->u32I2CON = (_BV(3)|_BV(6)|_BV(7));
}
void I2C_actionStart_notInIRQ(uint8_t which)
{
I2C_Base->u32I2CON = (_BV(6)|_BV(7)|_BV(5));
}
接口只有5个函数:void I2C_init (uint8_t which,uint32_t rate);
uint8_t I2C_transmit (uint8_t which,I2C_transmitCallback cb);
uint8_t I2C_isIdle (uint8_t which);
void I2C_setNextCallback (uint8_t which,I2C_transmitCallback cb);
void I2C_setExceptionCallback(uint8_t which,I2C_exceptionCallback cb); 收藏下过些天研究下STM32的硬件IIC Name_006 发表于 2012-6-24 18:54 static/image/common/back.gif
收藏下过些天研究下STM32的硬件IIC ...
me,too.不过我是研究stm32基础 留待备用
页:
[1]