/**************************************************
** 文件名称:NUC120_HOT_I2C_Interrupt.c
** 文件说明:NUC120助学板练习程序
** 创建日期:2011-04-26
** 修改日期:
** 备 注:I2C中断方式读写数据
**************************************************/
#include <stdio.h>
#include "NUC1xx.h"
#include "Driver\DrvGPIO.h"
#include "Driver\DrvSYS.h"
#include "Driver\DrvUART.h"
#include "Driver\DrvI2C.h"
uint8_t Run_Led = 4; //2----LED1 3----LED2 4----LED3 5----LED4
volatile uint8_t Receive_Data = 0;
volatile uint8_t IsStart = FALSE; //为1表示上位机发送指令正在执行 为0表示上位机发送指令处理完毕
typedef enum
{
I2C_START = 0x08,
I2C_REP_START = 0x10,
I2C_MT_SLA_ACK = 0x18,
I2C_MT_SLA_NACK = 0x20,
I2C_MT_DATA_ACK = 0x28,
I2C_MT_DATA_NACK = 0x30,
I2C_MT_ARB_LOST = 0x38,
I2C_MR_ARB_LOST = 0x38,
I2C_MR_SLA_ACK = 0x40,
I2C_MR_SLA_NACK = 0x48,
I2C_MR_DATA_ACK = 0x50,
I2C_MR_DATA_NACK = 0x58,
I2C_ST_SLA_ACK = 0xA8,
I2C_ST_ARB_LOST_SLA_ACK = 0xB0,
I2C_ST_DATA_ACK = 0xB8,
I2C_ST_DATA_NACK = 0xC0,
I2C_ST_LAST_DATA = 0xC8,
I2C_SR_SLA_ACK = 0x60,
I2C_SR_ARB_LOST_SLA_ACK = 0x68,
I2C_SR_GCALL_ACK = 0x70,
I2C_SR_ARB_LOST_GCALL_ACK = 0x78,
I2C_SR_DATA_ACK = 0x80,
I2C_SR_DATA_NACK = 0x88,
I2C_SR_GCALL_DATA_ACK = 0x90,
I2C_SR_GCALL_DATA_NACK = 0x98,
I2C_SR_STOP = 0xA0,
I2C_NO_INFO = 0xF8,
I2C_BUS_ERROR = 0x00,
I2C_BUS_OK = 0xFF
}NU_I2C_STATUS_ENUM;
typedef struct
{
unsigned char Busy;
unsigned int State;
unsigned int SystickCount;
unsigned int Count;
unsigned int MainCount, SubCount;
unsigned int SubAddr;
unsigned char MainComm, SubComm;
unsigned char TxBuffer[16], RxBuffer[16];
}I2C_HOT_T;
volatile I2C_HOT_T I2c;
/***************
** 函数声明 **
***************/
void Init_System (void);
void Init_Uart (void);
void Init_I2C(void);
void I2C_Start(void);
void I2C_REStart(void);
void I2C_Stop(void);
void I2C_Exit(void);
void UART_INT_HANDLE(uint32_t u32IntStatus);
void I2C1_INT_HANDLE (uint32_t status);
/*****************************
** Name: UART_INT_HANDLE
** Function: UART Callback function
** Input: u32IntStatus
** OutPut: None
** Data: 2011-03-17
** Note:
****************************/
void UART_INT_HANDLE(uint32_t u32IntStatus)
{
uint8_t bInChar[1]={0xFF};
if(u32IntStatus & DRVUART_RDAINT)
{
/* Get all the input characters */
while(UART0->ISR.RDA_IF==1)
{
/* Get the character from UART Buffer */
DrvUART_Read(UART_PORT0,bInChar,1);
if (IsStart!=TRUE)
{
IsStart = TRUE;
Receive_Data = bInChar[0];
}
}
}
}
/*****************************
** Name: I2C1_INT_HANDLE
** Function: I2C1 Callback function
** Input: status
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void I2C1_INT_HANDLE (uint32_t status)
{
switch(status & 0xf8)
{
case I2C_START://主机收到自己发送的开始信号
if (I2c.State == I2C_START) {//本次中断应该接收TW_START信号
I2C1->DATA = I2c.SubAddr & 0xfe;//发送子机地址(写)
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0); //STA位必须清除,否则死机 清除中断标志
I2c.State = I2C_MT_SLA_ACK;//Status下次I2C_MT_SLA_ACK
}
else I2C_Exit();//通讯失败
break;
case I2C_REP_START://主机收到自己发送的重新开始信号
if (I2c.State == I2C_REP_START) {//本次中断应该接收TW_RESTART信号
I2C1->DATA = I2c.SubAddr | 0x01;//发送子机地址(读)
I2c.State = I2C_MR_SLA_ACK;//Status下次I2C_MR_SLA_ACK
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1); //STA位必须清除,否则死机 清除中断标志
}
else I2C_Exit();//通讯失败
break;
case I2C_MT_SLA_ACK://主发机接收到从机的地址应答信号后发送命令
if (I2c.State == I2C_MT_SLA_ACK) {//本次中断应该接收TW_MT_SLA_ACK信号
I2c.State = I2C_MT_DATA_ACK;//Status下次应该收TW_MT_DATA_ACK
I2C1->DATA = I2c.SubComm;//发送子机命令
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);
}
else I2C_Exit();//通讯失败
break;
case I2C_MR_SLA_ACK://主收机接收到从机的地址应答信号
if ((I2c.State == I2C_MR_SLA_ACK) && I2c.SubCount) {//本次中断应该接收TW_MR_SLA_ACK信号
I2c.State = I2C_MR_DATA_ACK;//Status下次应该收TW_MR_DATA_ACK
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);
}
else I2C_Exit();//通讯失败
break;
case I2C_MT_DATA_ACK://主收机接收到从机的数据应答信号
if ((I2c.State == I2C_MT_DATA_ACK) && (I2c.Count < I2c.MainCount)) {//本次中断应该接收TW_MT_DATA_ACK信号
I2C1->DATA = I2c.TxBuffer[I2c.Count ++];//发送子机数据
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);
}
else {
if ((I2c.State == I2C_MT_DATA_ACK) && (I2c.Count == I2c.MainCount) && (I2c.SubAddr & 1)) {//本次中断应该接收TW_MT_DATA_ACK信号
I2C_REStart();//
}
else I2C_Stop();//通讯成功
}
break;
case I2C_MR_DATA_ACK:
if ((I2c.State == I2C_MR_DATA_ACK) && (I2c.Count < I2c.SubCount)) {
I2c.RxBuffer[I2c.Count ++] = I2C1->DATA;//接收子机数据
if (I2c.Count < I2c.SubCount) {
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);
}
else {
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
I2c.State = I2C_MR_DATA_NACK;//下次进入I2C_MR_DATA_NACK,接收数据准备完成
}
}
else I2C_Exit();//通讯失败
break;
case I2C_MR_DATA_NACK://数据接收结束
if ((I2c.State == I2C_MR_DATA_NACK) && (I2c.Count == I2c.SubCount)) {
I2C_Stop();//通讯成功
}
else I2C_Exit();//通讯失败
break;
// case I2C_MT_DATA_NACK:
// Exit();//通讯失败
// break;
default:
I2C_Exit();//通讯失败
}
}
/*****************************
** Name: Init_System
** Function: 系统初始化函数
** Input: None
** OutPut: None
** Data: 2011-03-17
** Note:
****************************/
void Init_System(void)
{
/* Unlock the locked registers before access */
UNLOCKREG();
/* Enable the 12MHz oscillator oscillation */
DrvSYS_SetOscCtrl(E_SYS_XTL12M, 1); //SYSCLK->PWRCON.XTL12M_EN = 1;
/* Waiting for 12M Xtal stable */
DrvSYS_Delay(5000);
LOCKREG();
}
/*****************************
** Name: Init_Uart
** Function: UART初始化函数
** Input: None
** OutPut: None
** Data: 2011-03-17
** Note:
****************************/
void Init_Uart(void)
{
STR_UART_T param;
DrvSYS_SelectIPClockSource(E_SYS_UART_CLKSRC,0); //使能UART时钟
//SYSCLK->CLKSEL1.UART_S = 0; //UART时钟源选择. 00 =外部12MHz 晶振 01 = PLL 1x =内部 22MHz 振荡器
DrvGPIO_InitFunction(E_FUNC_UART0); //GPB_MFP0-1-2-3置位 GPIO使能UART功能
param.u32BaudRate = 115200; // 波特率
param.u8cDataBits = DRVUART_DATABITS_8; // 数据位
param.u8cStopBits = DRVUART_STOPBITS_1; // 停止位
param.u8cParity = DRVUART_PARITY_NONE; // 校验位
param.u8cRxTriggerLevel = DRVUART_FIFO_1BYTES; // FIFO存储深度 1 字节
param.u8TimeOut = 0; // FIFO超时设定
/* Set UART Configuration */
if(DrvUART_Open(UART_PORT0,¶m) != E_SUCCESS) // 串口开启、结构体整体赋值
printf("UART0 open failed\n");
DrvUART_EnableInt(UART_PORT0, DRVUART_RDAINT,UART_INT_HANDLE);
}
/*****************************
** Name: Init_I2C
** Function: I2C初始化函数
** Input: None
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void Init_I2C(void)
{
/* Set I2C I/O */
DrvGPIO_InitFunction(E_FUNC_I2C1);
I2c.SubAddr = 0xA0;
}
/*****************************
** Name: I2C_Start
** Function: I2C启动函数
** Input: None
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void I2C_Start(void)
{
I2c.Busy = TRUE;
I2c.State = I2C_START;//主机准备发送启始位
I2c.Count = 0;//发送数据个数
/* Open I2C1, and set clock = 50Kbps */
DrvI2C_Open(I2C_PORT1,50000);
/* Enable I2C1 interrupt and set corresponding NVIC bit */
DrvI2C_EnableInt(I2C_PORT1);
/* Install I2C1 call back function for slave */
DrvI2C_InstallCallback(I2C_PORT1, I2CFUNC, I2C1_INT_HANDLE);
DrvI2C_Ctrl(I2C_PORT1, 1, 0, 0, 0);
DrvSYS_Delay(8000);
}
/*****************************
** Name: I2C_REStart
** Function: I2C重新启动函数
** Input: None
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void I2C_REStart(void)
{
I2c.Busy = TRUE;
I2c.State = I2C_REP_START;//主机准备发送启始位
I2c.Count = 0;//发送数据个数
DrvI2C_Ctrl(I2C_PORT1, 1, 0, 1, 0);
}
/*****************************
** Name: I2C_Stop
** Function: I2C停止函数
** Input: None
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void I2C_Stop(void)
{
I2c.Busy= FALSE;
I2c.State = I2C_BUS_OK;//通讯成功
DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0);
}
/*****************************
** Name: I2C_Exit
** Function: I2C退出函数
** Input: None
** OutPut: None
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
void I2C_Exit(void)
{
I2c.Busy = FALSE;
I2c.State = I2C_BUS_ERROR;//通讯失败
DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0);
}
/*****************************
** Name: I2C_ReadByte
** Function: I2C写单字节函数
** Input: unsigned int Address, unsigned char &Data
** OutPut: I2c.State
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
unsigned char I2C_ReadByte(unsigned int Address, unsigned char *Data)
{
I2c.SubAddr |= 0x01;
I2c.MainCount = 0;//发送0个数据(只读)
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
I2c.SubComm = Address;//读出地址
I2c.SubCount = 1;//接收1个数据
I2C_Start();//启动I2C模块
if (I2c.State == I2C_BUS_OK) {//通讯成功
Data[0] = I2c.RxBuffer[0];//从接收缓冲区取出一个字节
}
return I2c.State;//(读出数据在RxBuffer[0]~RxBuffer[15])
}
/*****************************
** Name: I2C_ReadBuffer
** Function: I2C写多字节函数
** Input: unsigned int Address, unsigned char &Data,unsigned int Cnt
** OutPut: I2c.State
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
unsigned char I2C_ReadBuffer(unsigned int Address, unsigned char *Data, unsigned int Cnt)
{
int i;
I2c.SubAddr |= 0x01;
I2c.MainCount = 0;//发送0个数据(只读)
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
I2c.SubComm = Address;//读出地址
I2c.SubCount = (Cnt <= sizeof(I2c.RxBuffer)) ? Cnt : sizeof(I2c.RxBuffer);//接收Cnt个数据
I2C_Start();//启动I2C模块
if (I2c.State == I2C_BUS_OK) {//通讯成功
for (i = 0; i < I2c.SubCount; i ++) Data[i] = I2c.RxBuffer[i];//从接收缓冲区取出Cnt个字节
}
return I2c.State;//(读出数据在RxBuffer[0]~RxBuffer[15])
}
/*****************************
** Name: I2C_WriteByte
** Function: I2C读单字节函数
** Input: unsigned int Address, unsigned char &Data
** OutPut: I2c.State
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
unsigned char I2C_WriteByte(unsigned int Address, unsigned char Data)
{
I2c.SubAddr &= 0xfe;
I2c.MainCount = 1;//发送1个数据
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
I2c.SubComm = Address;//写入地址
I2c.TxBuffer[0] = Data;//写入1个数据到发送缓冲区
I2c.SubCount = 0;//接收0个数据
I2C_Start();//启动I2C模块
DrvSYS_Delay(100);
return I2c.State;
}
/*****************************
** Name: I2C_WriteBuffer
** Function: I2C写多字节函数
** Input: unsigned int Address, unsigned char &Data,unsigned int Cnt
** OutPut: I2c.State
** Data: 2011-04-26
** Note: 拷贝HOT大叔C++例程中IIC的操作
****************************/
unsigned char I2C_WriteBuffer(unsigned int Address, unsigned char *Data, unsigned int Cnt)
{
int i;
I2c.SubAddr &= 0xfe;
I2c.MainCount = (Cnt <= sizeof(I2c.TxBuffer)) ? Cnt : sizeof(I2c.TxBuffer);//发送Cnt个数据
//本程序为通用I2C,故发送器件后一般为命令,对EEPROM来说,命令实际是EEPROM地址
I2c.SubComm = Address;//写入地址
for (i = 0; i < I2c.MainCount; i ++) I2c.TxBuffer[i] = Data[i];//写入Cnt个数据到发送缓冲区
I2c.SubCount = 0;//接收0个数据
I2C_Start();//启动I2C模块
DrvSYS_Delay(100);
return I2c.State;
}
int main (void)
{
uint8_t test = 250;
uint8_t EEPROM_Data = 0; //IIC地址0x00读写数据
uint8_t I2C_Page_Test[16]; //IIC地址0x10页读写数据
uint8_t i = 0;
Init_System();
Init_Uart();
Init_I2C();
DrvGPIO_Open(E_GPA,Run_Led, E_IO_OUTPUT); //程序运行指示
DrvGPIO_ClrBit(E_GPA,Run_Led);
printf("\n");
printf("/*==========================\n");
printf("======菜农 %d 助学计划======\n",test);
printf("========NUC120助学板========\n");
printf("====程序参考新唐BSP库及HOT大叔例程====\n");
printf("=======2011年04月26日=======\n");
printf("========I2C(中断)实验=======\n");
printf("I2C中断方式完成对AT24C16的读写操作\n");
printf("'r'为读地址0x00单字节指令、'u'为地址0x00单字节加1并存储指令\n");
printf("'d'为地址0x00单字节减1并存储指令\n");
printf("'R'为读地址0x10开始单页指令、'u'为地址0x10开始单页加1并存储指令\n");
printf("'d'为地址0x10开始单页减1并存储指令\n");
printf("===========================/\n");
if(I2C_BUS_OK==(I2C_ReadByte(0x00,&EEPROM_Data)))
printf("AT24C16地址0的内容为:0x%x!\n",EEPROM_Data);
else
printf("AT24C16地址0的内容读取失败!\n");
if (I2C_BUS_OK==I2C_ReadBuffer(0x10,I2C_Page_Test,16))
{
printf("AT24C16地址0x10开始16字节的内容为:\n");
for (i=0;i<16;i++)
printf("0x%x ",I2C_Page_Test[i]);
}
else
printf("AT24C16地址0x10开始16字节的内容读取失败!\n");
printf("\n====请输入字符开始测试!===\n");
printf("==========================*/\n");
while(1)
{
if (IsStart)
{
switch (Receive_Data)
{
case 'R':
if (I2C_BUS_OK==I2C_ReadBuffer(0x10,I2C_Page_Test,16))
{
printf("\nAT24C16地址0x10开始16字节的内容为:\n");
for (i=0;i<16;i++)
printf("0x%x ",I2C_Page_Test[i]);
}
else
printf("\nAT24C16地址0x10开始16字节的内容读取失败!");
break;
case 'r':
if (I2C_BUS_OK==I2C_ReadByte(0x00,&EEPROM_Data))
printf("\nAT24C16地址0的内容为:0x%x!",EEPROM_Data);
else
printf("\nAT24C16地址0的内容读取失败!");
break;
case 'U':
for (i=0;i<16;i++)
I2C_Page_Test[i]++;
if (I2C_BUS_OK==I2C_WriteBuffer(0x10,I2C_Page_Test,16))
printf("\nAT24C16地址0x10开始16字节的内容加1成功!");
else
{
printf("\nAT24C16地址0x10开始16字节的内容加1失败!");
for (i=0;i<16;i++)
I2C_Page_Test[i]--;
}
break;
case 'u':
if (I2C_BUS_OK==I2C_WriteByte(0x00,++EEPROM_Data))
printf("\nAT24C16地址0的内容加1成功!");
else
printf("\nAT24C16地址0的内容加1失败!");
break;
case 'D':
for (i=0;i<16;i++)
I2C_Page_Test[i]--;
if (I2C_BUS_OK==I2C_WriteBuffer(0x10,I2C_Page_Test,16))
printf("\nAT24C16地址0x10开始16字节的内容减1成功!");
else
{
printf("\nAT24C16地址0x10开始16字节的内容减1失败!");
for (i=0;i<16;i++)
I2C_Page_Test[i]++;
}
break;
case 'd':
if (I2C_BUS_OK==I2C_WriteByte(0x00,--EEPROM_Data))
printf("\nAT24C16地址0的内容减1成功!");
else
printf("\nAT24C16地址0的内容减1失败!");
break;
default:
printf("\n请确认您输入的指令是否合法!");
}
IsStart = FALSE;
}
}
}