[牛人杂谈]

函数指针在I2C收发上的应用

[复制链接]
776|4
手机看帖
扫描二维码
随时随地手机跟帖
小明的同学|  楼主 | 2024-6-16 16:04 | 显示全部楼层 |阅读模式
看到了NANO130的一个示例,操作I2C读写一个传感器芯片的。在中断中执行读或者写作业,通过函数指针传递进来,实现中断函数执行读或者写。
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     CJMCU116.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
* $Revision: 1 $
* $Date: 14/05/13 7:20p $
* [url=home.php?mod=space&uid=247401]@brief[/url]    CJMCU116 Library
*
* @note
* Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "CJMCU116.h"

__INLINE void I2C_PIN_Init(void)
{
                /* Set GPA8,9 multi-function pins for I2C0 SDA and SCL */
                SYS->PA_H_MFP |= (SYS_PA_H_MFP_PA8_MFP_I2C0_SDA | SYS_PA_H_MFP_PA9_MFP_I2C0_SCL);
       
          /* Enable I2C0 clock */        
   // CLK->APBCLK |= CLK_APBCLK_I2C0_EN;
                CLK->APBCLK |= CLK_APBCLK_I2C0_EN_Msk;//CLK_APBCLK_I2C0_EN_Pos
    /* Reset I2C0 */
    SYS->IPRST_CTL2 |=  SYS_IPRST_CTL2_I2C0_RST_Msk;
    SYS->IPRST_CTL2 &= ~SYS_IPRST_CTL2_I2C0_RST_Msk;       
}

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
uint8_t g_au8TxData[3];
uint8_t g_u8RxData;
uint8_t g_u8DataLen;
volatile uint8_t g_u8EndFlag = 0;
typedef void (*I2C_FUNC)(uint32_t u32Status);
static I2C_FUNC s_I2CHandlerFn = NULL;

/*---------------------------------------------------------------------------------------------------------*/
/*  I2C IRQ Handler                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
void I2C0_IRQHandler(void)
{
    uint32_t u32Status;

    // clear interrupt flag
    I2C0->INTSTS = I2C_INTSTS_INTSTS_Msk;       
       
    u32Status = I2C0->STATUS;

    if (I2C0->INTSTS & I2C_INTSTS_TIF_Msk)
    {
        /* Clear I2C Timeout Flag */
        I2C0->INTSTS = I2C_INTSTS_TIF_Msk;                  
    }   
    else
    {
        if (s_I2CHandlerFn != NULL)
            s_I2CHandlerFn(u32Status);
    }
}

/*---------------------------------------------------------------------------------------------------------*/
/*  I2C Initial Function                                                                                       */
/*---------------------------------------------------------------------------------------------------------*/
void I2C0_Init(uint8_t u8Freg)
{
                uint8_t u8Divider;
                I2C_PIN_Init();
    /* Enable I2C Controller */
    I2C0->CON |= I2C_CON_IPEN_Msk;
   
    /* I2C clock divider, I2C Bus Clock = PCLK / (4*120) = 100kHz */
    u8Divider = SystemCoreClock/(u8Freg*4000)-1;
                I2C0->DIV = u8Divider;

    /* Enable I2C interrupt and set corresponding NVIC bit */
    I2C0->CON |= I2C_CON_INTEN_Msk;
    NVIC_EnableIRQ(I2C0_IRQn);
}

/*---------------------------------------------------------------------------------------------------------*/
/*  I2C Rx Callback Function                                                                               */
/*---------------------------------------------------------------------------------------------------------*/
void I2C_MasterRx(uint32_t u32Status)
{
    if (u32Status == 0x08)                      /* START has been transmitted and prepare SLA+W */
    {
        I2C0->DATA = g_au8TxData[g_u8DataLen++] << 1;     /* Write SLA+W to Register I2CDAT */
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }   
    else if (u32Status == 0x18)                 /* SLA+W has been transmitted and ACK has been received */
    {
        I2C0->DATA = g_au8TxData[g_u8DataLen++];
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }
    else if (u32Status == 0x20)                 /* SLA+W has been transmitted and NACK has been received */
    {
        I2C_SET_CONTROL_REG(I2C0, I2C_STA | I2C_STO | I2C_SI);
    }
    else if (u32Status == 0x28)                 /* DATA has been transmitted and ACK has been received */
    {
        I2C_SET_CONTROL_REG(I2C0, I2C_STA | I2C_SI);
    }
               
    else if (u32Status == 0x10)                 /* Repeat START has been transmitted and prepare SLA+R */
    {
        I2C0->DATA = ((g_au8TxData[0] << 1) | 0x01);   /* Write SLA+R to Register I2CDAT */
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }
    else if (u32Status == 0x40)                 /* SLA+R has been transmitted and ACK has been received */
    {
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }      
    else if (u32Status == 0x58)                 /* DATA has been received and NACK has been returned */
    {
        g_u8RxData = I2C0->DATA;
        I2C_SET_CONTROL_REG(I2C0, I2C_STO | I2C_SI);
        g_u8EndFlag = 1;
    }
    else if (u32Status == 0xF8)    /*I2C wave keeps going*/
    {

    }                
    else
    {
        /* TO DO */
        //printf("Status 0x%x is NOT processed\n", u32Status);
                                while(1);
    }           
}

/*---------------------------------------------------------------------------------------------------------*/
/*  I2C Tx Callback Function                                                                               */
/*---------------------------------------------------------------------------------------------------------*/
void I2C_MasterTx(uint32_t u32Status)
{
    if (u32Status == 0x08)                      /* START has been transmitted */
    {
        I2C0->DATA = g_au8TxData[g_u8DataLen++] << 1;     /* Write SLA+W to Register I2CDAT */
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }   
    else if (u32Status == 0x18)                 /* SLA+W has been transmitted and ACK has been received */
    {
        I2C0->DATA = g_au8TxData[g_u8DataLen++];
        I2C_SET_CONTROL_REG(I2C0, I2C_SI);
    }
    else if (u32Status == 0x20)                 /* SLA+W has been transmitted and NACK has been received */
    {
        I2C_SET_CONTROL_REG(I2C0, I2C_STA | I2C_STO | I2C_SI);
    }   
    else if (u32Status == 0x28)                 /* DATA has been transmitted and ACK has been received */
    {
        if (g_u8DataLen != 3)
        {
            I2C0->DATA = g_au8TxData[g_u8DataLen++];
            I2C_SET_CONTROL_REG(I2C0, I2C_SI);
        }
        else
        {
            I2C_SET_CONTROL_REG(I2C0, I2C_STO | I2C_SI);
            g_u8EndFlag = 1;
        }      
    }
    else if (u32Status == 0xF8)    /*I2C wave keeps going*/
    {

    }                
    else
    {
        /* TO DO */
        //printf("Status 0x%x is NOT processed\n", u32Status);
                                while(1);
    }      
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Write I2C                                                                                     */
/*---------------------------------------------------------------------------------------------------------*/
void I2C0_Write(uint8_t u8Address,uint8_t u8Reg, uint8_t u8Data)
{
                g_au8TxData[0] = u8Address;
                g_au8TxData[1] = u8Reg;
                g_au8TxData[2] = u8Data;       
       
                g_u8DataLen = 0;
                g_u8EndFlag = 0;
               
                /* I2C function to write data to slave */
                s_I2CHandlerFn = (I2C_FUNC)I2C_MasterTx;
               
                /* I2C as master sends START signal */
                I2C_SET_CONTROL_REG(I2C0, I2C_STA);

                /* Wait I2C Tx Finish */
                while (g_u8EndFlag == 0);       
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Read I2C                                                                                */
/*---------------------------------------------------------------------------------------------------------*/
uint8_t I2C0_Read(uint8_t u8Address, uint8_t u8Reg)
{
                g_au8TxData[0] = u8Address;
                g_au8TxData[1] = u8Reg;       
       
                g_u8DataLen = 0;
                g_u8EndFlag = 0;
               
                /* I2C function to write data to slave */
                s_I2CHandlerFn = (I2C_FUNC)I2C_MasterRx;
               
                /* I2C as master sends START signal */
                I2C_SET_CONTROL_REG(I2C0, I2C_STA);

                /* Wait I2C Tx Finish */
                while (g_u8EndFlag == 0);       
       
                return g_u8RxData;
}






使用特权

评论回复
小明的同学|  楼主 | 2024-6-16 16:09 | 显示全部楼层
不过这种没有直接写成函数式的好理解,或者说更方便使用。

使用特权

评论回复
小明的同学|  楼主 | 2024-6-16 16:09 | 显示全部楼层
这是需要多个函数配合才实现的收发。

使用特权

评论回复
小明的同学|  楼主 | 2024-6-16 16:09 | 显示全部楼层
这是以前的系列都是这样的,看了最近几年出的型号的BSP已经提供了相关单个函数实现收发了。

使用特权

评论回复
小明的同学|  楼主 | 2024-6-16 16:33 | 显示全部楼层
uint8_t I2C_WriteByte(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t data);
uint32_t I2C_WriteMultiBytes(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t data[], uint32_t u32wLen);
uint8_t I2C_WriteByteOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, uint8_t data);
uint32_t I2C_WriteMultiBytesOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, uint8_t data[], uint32_t u32wLen);
uint8_t I2C_WriteByteTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, uint8_t data);
uint32_t I2C_WriteMultiBytesTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, uint8_t data[], uint32_t u32wLen);
uint8_t I2C_ReadByte(I2C_T *i2c, uint8_t u8SlaveAddr);
uint32_t I2C_ReadMultiBytes(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t rdata[], uint32_t u32rLen);
uint8_t I2C_ReadByteOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr);
uint32_t I2C_ReadMultiBytesOneReg(I2C_T *i2c, uint8_t u8SlaveAddr, uint8_t u8DataAddr, uint8_t rdata[], uint32_t u32rLen);
uint8_t I2C_ReadByteTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr);
uint32_t I2C_ReadMultiBytesTwoRegs(I2C_T *i2c, uint8_t u8SlaveAddr, uint16_t u16DataAddr, uint8_t rdata[], uint32_t u32rLen);

M487系列提供的新函数,更加好用了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

1383

帖子

2

粉丝