EMW3031下模拟I2C实现

来源:互联网 发布:北京编程培训 编辑:程序博客网 时间:2024/05/29 12:47
#define CT_SDA_PIN   MICO_GPIO_5 //254                         //定义SDA所对应的GPIO接口编号 
#define CT_SCL_PIN   MICO_GPIO_6 //255                         //定义SCL所对应的GPIO接口编号 
#define CT_RST_PIN         GPIO_Pin_13
#define CT_INT_PIN          GPIO_Pin_12
 
//#define RCC_CT_I2C_PORT         RCC_APB2Periph_GPIOF
//#define RCC_CT_CONTROL_PORT     RCC_APB2Periph_GPIOF
#define CT_CONTROL_PORT         GPIOF
#define CT_I2C_PORT             GPIOF
 
//#define TOUCH_GPIO_PortSource   GPIO_PortSourceGPIOF
#define TOUCH_GPIO_PinSource    GPIO_PinSource12
#define TOUCH_EXTI_Line         EXTI_Line12
#define TOUCH_EXTI_IRQn         EXTI15_10_IRQn


#define CT_ADDR                 (0x70)                  //器件地址
#define CT_WRITE_MASK           (0x00)
#define CT_READ_MASK            (0x01)
 
#define CT_CACK_TIMEOUT         (3000)                  //等待ACK超时时间


#define CT_COM_OK               (0)
#define CT_ACK_FAIL             (1)




#define     SDA_High                    MicoGpioOutputHigh(CT_SDA_PIN)
#define     SDA_Low                     MicoGpioOutputLow(CT_SDA_PIN)
#define     SDA_INPUT                   0//{CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 8ul<<28;}//第15脚,(15-8)*4 = 28
#define     SDA_OUTPUT                 1// {CT_I2C_PORT->CRH&=0X0FFFFFFF;CT_I2C_PORT->CRH|= 3ul<<28;}//第15脚,(15-8)*4 = 28
#define     SCL_High                    MicoGpioOutputHigh(CT_SCL_PIN)
#define     SCL_Low                     MicoGpioOutputLow(CT_SCL_PIN)
#define     GetSDABit                   MicoGpioInputGet(CT_SDA_PIN)
 
#define     CT_DELAY_US(val)            Delay_us(val)
/* 
**函数名:CTI2C_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化CTI2C引脚
*/ 
void CTI2C_GPIO_Config(void)
{
    /*定义一个GPIO_InitTypeDef类型的结构体*/  
    GPIO_InitTypeDef GPIO_InitStructure; 
    EXTI_InitTypeDef    EXTI_InitStructure; 
     
    /*开启GPIO的外设时钟*/  
    RCC_APB2PeriphClockCmd(RCC_CT_I2C_PORT | RCC_CT_CONTROL_PORT, ENABLE); 
           
    /*选择要控制的引脚*/                                                                 
    GPIO_InitStructure.GPIO_Pin = CT_SDA_PIN | CT_SCL_PIN;        
    /*设置引脚模式为通用推挽输出*/  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_I2C_PORT,&GPIO_InitStructure); 
 
    /*选择要控制的引脚*/                                                                 
    GPIO_InitStructure.GPIO_Pin = CT_RST_PIN;        
    /*设置引脚模式为通用推挽输出*/  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            
    /*设置引脚速率为10MHz */      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 
     
    /*选择要控制的引脚*/                                                                 
    GPIO_InitStructure.GPIO_Pin = CT_INT_PIN;        
    /*设置引脚模式为通用推挽输出*/  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;            
    /*设置引脚速率为10MHz */      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;        
    /*调用库函数,初始化GPIO*/
    GPIO_Init(CT_CONTROL_PORT,&GPIO_InitStructure); 
 
    /*********************初始化外部中断**********************/   
    /*开启引脚复用AFIO的外设时钟,因为用到了AFIO外部中断配置寄存器*/  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE); 
    /* Selects as EXTI Line */
    GPIO_EXTILineConfig(TOUCH_GPIO_PortSource, TOUCH_GPIO_PinSource);
    /*选择外部中断线*/
    EXTI_InitStructure.EXTI_Line = TOUCH_EXTI_Line; 
    /*设置EXTI线路为中断请求*/
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /*下降沿触发*/      
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    /*使能选中线路*/     
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
    /*外部中断初始化*/
    EXTI_Init(&EXTI_InitStructure);
/******************************************************/
}
/**************************/
static void CTI2C_start(void)//CTI2C启动函数
{
    SDA_OUTPUT;
    SCL_High;
    SDA_High;
    CT_DELAY_US(300);
    SDA_Low;
    CT_DELAY_US(300);
    SCL_Low;
}
 
/**************************/
static void CTI2C_stop(void)// CTI2C停止函数
{
    SDA_OUTPUT;
    SDA_Low;
    SCL_High;
    CT_DELAY_US(300);
    SDA_High;
    CT_DELAY_US(300);
    SDA_Low;
    SCL_Low;
}
 
/**************************/
static void CTI2C_write_byte(const uint8_t s)//CTI2C写1byte函数,S为需要写的内容
{
      uint8_t temps;
      uint8_t dat,i;
      temps=s;
      dat=0x80;
      SDA_OUTPUT;
      for(i=0;i<8;i++)
      {
        if(dat&temps)//对应位为一就发一 
         {
            SDA_High;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            //SCL的频率,高速为400KHz,标准为100KHz
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         else
         {
            SDA_Low;
            CT_DELAY_US(100);//延时一下,保证数据建立时间大于50ns
            SCL_High;
            CT_DELAY_US(300);
            SCL_Low;
            CT_DELAY_US(300);
         }
         dat=dat>>1;//注意Keil中将有符号数的右移操作作算术右移处理,我需要的是逻辑右移,因此dat要先定义为无符号数,否则会出错
      }
    SDA_High;//主控制器写完后要预先释放对SDA总线的控制
    CT_DELAY_US(100);//留一点时间接收应答信号
}
 
/**************************/
static void CTI2C_read_byte(uint8_t *s)//CTI2C读1byte函数,数据放在形参中,成功返回1,失败返回0
{
     uint8_t temps=0,i;
     uint8_t text=0x80;
     uint8_t sdain;
     SDA_INPUT;
     SDA_High;//设SDA为输入方式
     for(i=0;i<8;i++)
     {
         SCL_High;//使SDA上的数据有效
         CT_DELAY_US(100);//延时一下,保证SDA已经稳定
         sdain = GetSDABit;//取得SDA上的数据
         if(1==sdain)
         {
            temps |=(text>>i);//先接收高位
         }
         SCL_Low;//读完后允许SDA上的数据刷新,并延时一下让被读器件有时间更新要输出的数据
         CT_DELAY_US(300);
     }
     *s=temps;
    CT_DELAY_US(300);//留一点时间发送应答信号
}
/**************************/
static uint8_t CTI2C_check_ack(void)//CTI2C应答位检查函数,正常应答返回0,否则返回1
{
    uint8_t sdain;
    SDA_INPUT;
    SDA_High;//置SDA为输入
    SCL_High;//使SDA上的数据有效
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    sdain = GetSDABit;//取得SDA上的数据
    SCL_Low;
    if(1==sdain)
        return 1;
    else
        return 0;   
}
 
/**************************/
static void CTI2C_send_ack(void)//CTI2C发送应答信号函数
{
    SDA_OUTPUT;
    SDA_Low;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_High;
 
}
/**************************/
static void CTI2C_send_nack(void)//CTI2C发送非应答信号函数
{
    SDA_OUTPUT;
    SDA_High;
    CT_DELAY_US(100);//延时一下,保证SDA已经稳定
    SCL_High;
    CT_DELAY_US(300);
    SCL_Low;
    SDA_Low;
}
/**************************/
 
/******************************************************************************
 * FUNCTION: CT_Write_Nbyte ( )
 * DESCRIPTION: 写触摸屏寄存器
 *    Input the description of function: 
 * Input Parameters: 器件地址,待写寄存器地址,待写数据数量,存储待写入数据的地址
 * Output Parameters: 无
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Write_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,const uint8_t *s)//CTI2C写nbyte函数,写数据由形参数组传入,成功返回1,失败返回0
{
    uint8_t temps,ack=1;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
        return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());
 
    CTI2C_write_byte(add);//发送要写入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
        return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());
 
    for(tempn=0;tempn<n;tempn++)
    {
        ack=1;//应答位
        cack_time=0;
        temps=*(s+tempn);
        while(ack)
        {
            CTI2C_write_byte(temps);
            ack=CTI2C_check_ack();//检查应答信号,非应答则重发该字节
            cack_time++;
            if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
                return CT_ACK_FAIL;
        }
    }
    CTI2C_stop();// CTI2C停止
    return CT_COM_OK;
}
 
/******************************************************************************
 * FUNCTION: CT_Read_Nbyte ( )
 * DESCRIPTION: 从触摸屏中读出数据
 *    Input the description of function: 
 * Input Parameters: 器件地址,待读寄存器地址,待读数据数量,存储待读出数据的地址
 * Output Parameters: 读取的数据
 * Returns Value: 
 * 
 * Author: FuDongQiang @ 2015/05/22
 * 
 * modification history
 *   ...
 ******************************************************************************/
uint8_t CT_Read_Nbyte(const uint8_t sla_add,const uint8_t add,uint16_t n,uint8_t *s)//CTI2C读nbyte函数,所读数据放在形参数组中(由程序员设置合适的数组大小),成功返回1,失败返回0
{
    uint8_t temps;
    uint16_t tempn;
    uint16_t cack_time=0;
    CTI2C_start();//启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_WRITE_MASK);//发送寻址字节,伪写
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
        return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());
 
    CTI2C_write_byte(add);//发送要读入的起始地址
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
        return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());
 
    CTI2C_start();//再次启动CTI2C总线
    CTI2C_write_byte(sla_add | CT_READ_MASK);//再次发送寻址字节,读
    cack_time=0;
    do
    {
       cack_time++;
       if(cack_time>CT_CACK_TIMEOUT)//在规定时间cack_timeout内收不到应答信号,返回出错信号
        return CT_ACK_FAIL;
    }
    while(CTI2C_check_ack());
 
    for(tempn=0;tempn<n;tempn++)
    {
        CTI2C_read_byte(&temps);
        *(s+tempn)=temps;
        if(tempn+1<n)//如果已经读完所有数据了,就不要发应答信号,直接发非应答位和停止位
            CTI2C_send_ack();//CTI2C发送应答信号.准备下一字节的接收
    }
    CTI2C_send_nack();//接收完毕,发送非应答位和停止位
    CTI2C_stop();
    return CT_COM_OK;
}
 




#define SDA MICO_GPIO_5 //254                         //定义SDA所对应的GPIO接口编号 
#define SCL  MICO_GPIO_6 //255                         //定义SCL所对应的GPIO接口编号  
#define OUTP 1//OUTPUT_OPEN_DRAIN_PULL_UP                          //表示GPIO接口方向为输出  
#define INP 0//INPUT_PULL_DOWN                           //表示GPIO接口方向为输入 


/* I2C起始条件 */  
int i2c_start()  
{  
//初始化GPIO口  


MicoGpioInitialize(SDA, OUTP);
MicoGpioInitialize(SCL, OUTP);
MicoGpioOutputHigh(SDA);
MicoGpioOutputHigh(SCL);
mico_thread_msleep(1);
MicoGpioOutputLow(SDA);
mico_thread_msleep(1);
MicoGpioOutputLow(SCL);



/* I2C终止条件 */  
void i2c_stop()  
{  
MicoGpioInitialize(SDA, OUTP);

MicoGpioOutputLow(SDA);
MicoGpioOutputHigh(SCL);

mico_thread_msleep(1);
MicoGpioOutputHigh(SDA);  
mico_thread_msleep(1);
MicoGpioOutputLow(SDA);
MicoGpioOutputLow(SCL);

}
  
/*   
I2C读取ACK信号(写数据时使用)  
返回值 :0表示ACK信号有效;非0表示ACK信号无效  
*/  
unsigned char i2c_read_ack()  
{  
unsigned char r;  
MicoGpioInitialize(SDA, INP);
MicoGpioOutputLow(SCL);
r = MicoGpioInputGet(SDA);
mico_thread_msleep(1);
MicoGpioOutputHigh(SCL);
mico_thread_msleep(1);

return r;  



/* I2C发出ACK信号(读数据时使用) */  
int i2c_send_ack()  
{  
MicoGpioInitialize(SDA, OUTP);
MicoGpioOutputLow(SCL);
MicoGpioOutputLow(SDA);
mico_thread_msleep(1);
MicoGpioOutputHigh(SCL);
mico_thread_msleep(1); 



/* I2C字节写 */  
void i2c_write_byte(unsigned char b)  
{  
int i;  
MicoGpioInitialize(SDA, OUTP);          //设置SDA方向为输出  
for (i=7; i>=0; i--) 
{  
MicoGpioOutputLow(SCL);             // SCL变低  
mico_thread_msleep(5);  
if(b & (1<<i))
{
MicoGpioOutputHigh(SDA);   
}
else
{
MicoGpioOutputLow(SDA);   
}
MicoGpioOutputHigh(SCL);             // SCL变高  
mico_thread_msleep(5);  
}  
i2c_read_ack();                 //检查目标设备的ACK信号  



/* I2C字节读 */  
unsigned char i2c_read_byte()  
{  
int i;  
unsigned char r = 0;  
MicoGpioInitialize(SDA, INP);           //设置SDA方向为输入  
for (i=7; i>=0; i--) 
{  
MicoGpioOutputLow(SCL);         // SCL变低  
mico_thread_msleep(5);   
r = (r <<1) | MicoGpioInputGet(SDA);      //从高位到低位依次准备数据进行读取  
MicoGpioOutputHigh(SCL);         // SCL变高  
mico_thread_msleep(5);    
}  
i2c_send_ack();                 //向目标设备发送ACK信号  
return r; 



/*  
I2C读操作  
addr:目标设备地址  
buf:读缓冲区  
len:读入字节的长度  
*/  
void i2c_read(unsigned char addr, unsigned char* buf, int len)  
{  
int i;  
unsigned char t;  
i2c_start();                        //起始条件,开始数据通信  
//发送地址和数据读写方向  
t = (addr << 1) | 1;                    //低位为1,表示读数据  
i2c_write_byte(t);  
//读入数据  
for (i=0; i<len; i++)  
buf[i] = i2c_read_byte();  
i2c_stop();                     //终止条件,结束数据通信  
}
  
/*  
I2C写操作  
addr:目标设备地址  
buf:写缓冲区  
len:写入字节的长度  
*/  
void i2c_write (unsigned char addr, unsigned char* buf, int len)  
{  
int i;  
unsigned char t;  
i2c_start();                        //起始条件,开始数据通信  
//发送地址和数据读写方向  
t = (addr << 1) | 0;                    //低位为0,表示写数据  
i2c_write_byte(t);  
//写入数据  
for (i=0; i<len; i++)  
i2c_write_byte(buf[i]);  
i2c_stop();                     //终止条件,结束数据通信  
0 0