此为本人写的MC9S12XEP100的IIC集成电路总线的硬件驱动程序。


文章目录

  • 前言
    • 相关理论
    • 驱动模块简介
  • 代码
    • 驱动模块
    • 基于UCOS-II的驱动
    • 示例代码
    • 代码下载

前言

相关理论

相关理论请自行参考数据手册。
此为我对数据手册IIC模块部分的翻译:https://blog.csdn.net/lin_strong/article/details/80259571

驱动模块简介

整个模块是中断驱动的,ISR的运行逻辑基本就是照着数据手册中给出的框图。

这里稍微有一点要注意的,就是在主机接收器的寻址周期(即图左边中间那个Master Rx)结束时不是要切换Rx mode并虚读么,这个时候应该要判断下下一个读的字节是不是最后一个,并据此来设置TXAK,而不应该像图上那样直接就触发下一个接收了,当然,驱动程序中已经写了这个逻辑了。

另外当前模块并不支持10bit 地址,主要就是暂时用不到,懒得写。

模块提供了模块初始化,主机发送/主机接收,函数注册的接口。
中断与主机接口之间采用信号量的方式进行通讯,主机接口先进行会导致中断的操作,然后阻塞地pend信号量;IIC的中断会驱动着完成后续的工作,然后post信号量并通知结果;然后主机接口就会成功pend到信号量,并得知操作结果。

模块内部提供了默认的信号量实现,当在RTOS中运行时,可以通过函数注册接口把操作系统提供的信号量函数给模块使用,这样就可以最大化内核的使用,减少无意义的任务切换开销。后面提供了对uCOS-II进行适配的函数。

从机功能则是完全由中断驱动的,当使用从机功能时,要求用户按照声明的函数提供具体实现,当发生从机接收/从机发送时,对应的函数会被调用,以传递给用户刚刚收到的数据,或从用户处获取下一个要发送的数据。

头文件的配置中提供了一些宏以实现按照需求对代码进行精简,以及对模块进行配置。主要要记得根据自己的CPU频率修改IIC_INIT_IBFD的值

由于模块是中断驱动的,一定要记得把中断向量指向中断服务例程IIC_ISR,并启用中断,使用uCOS-II的时候则要把中断向量指向.s文件中的IIC_uC_ISR。

代码

驱动模块

头文件:

/*
*******************************************************************************************
*
*                                    IIC INTERFACE
*                                       IIC接口
*
* File : IIC.h
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2019/03/26
* version: V1.4
* History: 2018/05/07  V1.0   the prototype
*          2018/05/15  V1.1   add the slave part of IIC.
*                             add the functions register, so user can change the behaviour
*                             of the module.
*                      V1.2   a tip on the ISR
*          2018/05/20  V1.3   figure out the method to make ISR in this module and in IIC_uCos
*                             compatible.
*          2019/03/26  V1.4   some modification to the malloc configuration.
* NOTE(s):  1. don't support 10-bit address for now.
*           2. this module is ISR-drived, so you must point the IIC_ISR to the corresponding
*              address and enable interrupt.
*           3. note that the funcitons in this module is not thread-safe.
*********************************************************************************************
*/#ifndef   IIC_H
#define   IIC_H/*
********************************************************************************************
*                                   INCLUDES
********************************************************************************************
*/#include "common.h"/*
******************************************************************************************
*                                    CONSTANT
******************************************************************************************
*/// IIC address length
#define IIC_ADDRLEN_7BIT        0
#define IIC_ADDRLEN_10BIT       1/*
*******************************************************************************************
*                               CONFIGURE 主配置
*******************************************************************************************
*/// to exclude code for IIC slave mode.
// #define IIC_SLAVEMODE_DISABLE// to exclude code for IIC master Rx mode.
// #define IIC_MASTER_RX_DISABLE// to exclude code for IIC master Tx mode.
// #define IIC_MASTER_TX_DISABLE// to enable debug message through standard printf
// #define _DEBUG//************ 初始化配置 ***************//
// 根据手册设置分频寄存器
#ifndef IIC_INIT_IBFD
#define IIC_INIT_IBFD        0x94              // 总线时钟32MHz,设置SCL主频为100KHz
#endif
// IIC模块使用的地址长度
#ifndef IIC_INIT_ADDRLEN
#define IIC_INIT_ADDRLEN     IIC_ADDRLEN_7BIT  // 当前只支持7位地址,不支持10位的
#endif
// IIC模块使用的从机地址(定义在低7bits),如果启用了从机代码
#ifndef IIC_INIT_SLAVEADDR
#define IIC_INIT_SLAVEADDR   0x37
#endif
// 在等待模式下内部时钟是否停止
#ifndef IIC_INIT_STOPINWAIT
#define IIC_INIT_STOPINWAIT  TRUE
#endif/*
****************************************************************************************
*                                  ERROR CODES
****************************************************************************************
*/#define IIC_ERR_NULL    0
#define IIC_ERR_AUG     1      // 参数错误
#define IIC_ERR_NOACK   2      // 未收到答复
#define IIC_ERR_IBAL    3      // 仲裁丢失
#define IIC_ERR_IBB     4      // 总线忙
#define IIC_ERR_TIMEOUT 5      // 等待超时
#define IIC_ERR_UNKNOWN 6      // 未知错误
/*
******************************************************************************************
*                                  TYPE DEFINE
******************************************************************************************
*/// Description: IIC内部阻塞等待时使用的函数,比如可以在其中添加线程Dly函数来实现阻塞等待时放弃CPU时间
// Arguments  : wCnt     当前等待次数计数
// return     : TRUE     继续等待
//              FALSE    停止等待,返回错误
typedef unsigned char (* IIC_FUNC_WAITFUNC)(unsigned long wCnt);// IIC内部信号量相关函数,当使用操作系统时可以替换为操作系统的信号量// Description: 等待信号量
// Arguments  :
// return     : TRUE     成功pend到信号量
//              FALSE    等待超时或其他错误
typedef unsigned char (* IIC_FUNC_SEM_PEND)(void);
// Description: 发送信号量
// Arguments  :
// return     :
typedef void (* IIC_FUNC_SEM_POST)(void);
// Description: 重置信号量
// Arguments  :
// return     :
typedef void (* IIC_FUNC_SEM_RESET)(void);/*
************************************************************************************
*                          FUNCTION PROTOTYPES  函数原型
************************************************************************************
*/unsigned char IIC_Init(void);
#define IIC_ReceiveChar(calAddr,pChar)   IIC_Recv(calAddr,pChar,1)
unsigned char IIC_Recv(unsigned char calAddr,unsigned char *rBuf,unsigned short len);
#define IIC_SendChar(calAddr,pChar)      IIC_Send(calAddr,pChar,1)
unsigned char IIC_Send(unsigned char calAddr,unsigned char *sBuf,unsigned short len);void IIC_FuncReg_Wait(IIC_FUNC_WAITFUNC f);
void IIC_FuncReg_Sem(IIC_FUNC_SEM_RESET r,IIC_FUNC_SEM_POST pt,IIC_FUNC_SEM_PEND pd);// 启用从机时要求用户实现的函数
// 注意,这些函数是在ISR中被调用的
// Description: when is in slave Tx mode, to get the next byte to send from user.
// Argument : No    the number of current byte of this conversation. begin from 0;
// return   : the byte to send.
extern unsigned char IIC_Send_AsSlave(unsigned short No);
// Description: when is in slave Rx mode, to pass the next byte received to user.
// Argument : No    the number of current byte of this conversation. begin from 0;
//            c     the data recevied.
// return   :
extern void IIC_Recv_AsSlave(unsigned short No,unsigned char c);// ISR 中断服务例程
#pragma push
#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt void near IIC_ISR(void);
#pragma pop/*
************************************************************************************
*                          ERROR CHECK 错误检查
************************************************************************************
*/
#ifdef IIC_SLAVEMODE_DISABLE#ifdef IIC_MASTER_RX_DISABLE#ifdef IIC_MASTER_TX_DISABLE#error "can't exclude all slave and master code."#endif#endif
#endif#endif  // of IIC_H

源文件:

/*
*******************************************************************************************
*
*                      MC9S12XEP100 IMPLEMENTATION OF IIC INTERFACES
*                               IIC接口的MC9S12XEP100实现
*
* File : IIC.c
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2019/03/26
* version: V1.4
* History: 2018/05/07  V1.0   the prototype
*          2018/05/15  V1.1   add the slave part of IIC.
*                             add the functions register, so user can change the behaviour
*                             of the module.
*                      V1.2   a tip on the ISR
*          2018/05/20  V1.3   figure out the method to make ISR in this module and in IIC_uCos
*                             compatible.
*          2019/03/26  V1.4   some modification to the malloc configuration.
*                             some modification to the code to eliminate compiler warning.
* NOTE(s):  1. don't support 10-bit address for now.
*           2. this module is ISR-drived, so you must point the IIC_ISR to the corresponding
*              address and enable interrupt.
*           3. note that the funcitons in this module is not thread-safe.
*********************************************************************************************
*//*
*********************************************************************************************
*                                       INCLUDES
*********************************************************************************************
*/#include <stddef.h>
#include "IIC.h"
#include <MC9S12XEP100.h>/*
*********************************************************************************************
*                                         CONSTANT
*********************************************************************************************
*/
#define ISR_ERR_NULL    0     // 正常处理完毕
#define ISR_SENDOK      1
#define ISR_ERR_NOACK   2
#define ISR_RECVOK      3
#define ISR_ERR_IBAL    4#undef  IIC_MASTER_EN
#ifndef IIC_MASTER_RX_DISABLE
#define IIC_MASTER_EN
#endif
#ifndef IIC_MASTER_TX_DISABLE
#define IIC_MASTER_EN
#endif#ifdef _DEBUG
#include <stdio.h>
#define dbgprintf(msg)             (void)printf(msg)
#else
#define dbgprintf(msg)
#endif
/*
*********************************************************************************************
*                                  LOCAL FUNCTION DECLARATION
*********************************************************************************************
*/
// 发起启动条件,默认当前为从机模式,如总线忙则会返回错误,后面需要软件查看IBIF来看是否成功
// CalAddr:主叫地址(D0:R/W)
static unsigned char _IIC_StartCondtion(unsigned char CalAddr);// 默认的等待函数,无限等待
static unsigned char _IIC_Wait(unsigned long wCnt){ (void)wCnt; return TRUE;}static unsigned char _sem;
// 默认使用的信号量函数
static unsigned char _IIC_SemPend(void){ while(_sem == 0); // 等待中断发来结果_sem--;return TRUE;
}
static void _IIC_SemPost(void){ _sem++;}
static void _IIC_SemReset(void){ _sem = 0;}
/*
*********************************************************************************************
*                                  LOCAL VARIABLE
*********************************************************************************************
*/static unsigned char* pTxRxBuf; // 指向主机使用的缓冲区
static unsigned short TxCnt;    // 等待发送的字节个数
#define _LastByteTransmitted() (TxCnt == 0)
#define _SendNextByte()        {TxCnt--; IIC0_IBDR = *pTxRxBuf++;}     // 发送下一个字节
static unsigned short RxCnt;    // 等待接收的字节个数
#define _isLastByteToRead()    (RxCnt == 1)
#define _isLast2ndToRead()     (RxCnt == 2)
#define _RecvNextByte()        {RxCnt--; *pTxRxBuf++ = IIC0_IBDR;}     // 接收下一个字节
static unsigned char isAddrCyc_MR; // whether in address cycle(for Master Rx)
static unsigned char iicRst;       // 存放上次的结果
static unsigned short No_Slave;    // 计数作为从机发送/接收到第几个字符了 static IIC_FUNC_WAITFUNC _Wait;
static IIC_FUNC_SEM_PEND _SemPend;
static IIC_FUNC_SEM_POST _SemPost;
static IIC_FUNC_SEM_RESET _SemRst;/*
*********************************************************************************************
*                                        IIC_Init()
*
* Description : Initialize IIC support hardware(marco style).  初始化IIC硬件
*
* Arguments   :
*
* Return      : IIC_ERR_NULL       if success.
*
* Note(s)     :
*********************************************************************************************
*/
unsigned char IIC_Init(){IIC0_IBFD = IIC_INIT_IBFD;IIC0_IBCR_IBEN = 1; // 使能IIC模块,然后才能设置IBCR的其他位IIC0_IBSR_IBAL = 1; // 清除IBAL标志位  IIC0_IBCR_IBIE = 1; // 使能中断
#if(IIC_INIT_STOPINWAIT == TRUE)IIC0_IBCR_IBSWAI = 1;
#endif
#ifndef IIC_SLAVEMODE_DISABLEIIC0_IBAD = IIC_INIT_SLAVEADDR << 1;  // 写入自己的从机地址
#endif_Wait = _IIC_Wait;_SemPend = _IIC_SemPend;_SemPost = _IIC_SemPost;_SemRst = _IIC_SemReset;return IIC_ERR_NULL;
}/*
*********************************************************************************************
*                                        IIC_Recv()
*
* Description : Receive several bytes from slave.
*
* Arguments   : calAddr       the calling address of the slave.
*               rBuf          point to the buffer which will hold the result.
*               len           the number of bytes needed to be received.
*
* Return      : IIC_ERR_NULL       if success.
*               IIC_ERR_NOACK      if no ack from slave.
*               IIC_ERR_IBAL       if arbitration lost
*               IIC_ERR_TIMEOUT    if timeout for pending semaphore
*               IIC_ERR_UNKNOWN    if unknown err;
* Note:
*********************************************************************************************
*/unsigned char IIC_Recv(unsigned char calAddr,unsigned char *rBuf,unsigned short len){unsigned char err;if(len == 0)                // 收0个数据没有意义,直接退出return IIC_ERR_AUG;// 初始化参数isAddrCyc_MR = 1;pTxRxBuf = rBuf;RxCnt = len;TxCnt = (unsigned short)-1;_SemRst();// 产生启动信号并发送主叫地址+读指令(bit 0 == 1)err = _IIC_StartCondtion((calAddr << 1) | 0x01);if(err)            // 如果发生错误,返回错误return err;if(!_SemPend())    // 等待结果,如果超时,返回超时错误return IIC_ERR_TIMEOUT;switch(iicRst){case ISR_ERR_NOACK:return IIC_ERR_NOACK;case ISR_ERR_IBAL:return IIC_ERR_IBAL;case ISR_RECVOK:return IIC_ERR_NULL;default:return IIC_ERR_UNKNOWN;}
}
/*
*********************************************************************************************
*                                       IIC_Send()
*
* Description : Send several bytes to slave.
*
* Arguments   : calAddr       the calling address of the slave.
*               rBuf          point to the buffer which contains the data to be send.
*               len           the number of bytes needed to be send.
*
* Return      : IIC_ERR_NULL       if success.
*               IIC_ERR_NOACK      if no ack from slave.
*               IIC_ERR_IBAL       if arbitration lost
*               IIC_ERR_TIMEOUT    if timeout for pending semaphore
*               IIC_ERR_UNKNOWN    if unknown err;
* Note:
*********************************************************************************************
*/
unsigned char IIC_Send(unsigned char calAddr,unsigned char *sBuf,unsigned short len){volatile unsigned char err;unsigned long wcnt = 0;if(len == 0)                // 发0个数据没有意义,直接退出return IIC_ERR_AUG;// 初始化参数isAddrCyc_MR = 0;pTxRxBuf = sBuf;RxCnt = 0;TxCnt = len;_SemRst();// 产生启动信号并发送主叫地址+写指令(bit 0 == 0)err = _IIC_StartCondtion(calAddr << 1);if(err)            // 如果发生错误,返回错误return err;if(!_SemPend())    // 等待结果return IIC_ERR_TIMEOUT;switch(iicRst){case ISR_ERR_NOACK:return IIC_ERR_NOACK;case ISR_ERR_IBAL:return IIC_ERR_IBAL;case ISR_SENDOK:return IIC_ERR_NULL;default:return IIC_ERR_UNKNOWN;}
}
/*
*********************************************************************************************
*                                  IIC_FuncReg_Wait()
*
* Description : function register of wait func.
*
* Arguments   : f       the function used for block wating.
*
* Return      :
*
* Note:
*********************************************************************************************
*/
void IIC_FuncReg_Wait(IIC_FUNC_WAITFUNC f){_Wait = f;
}
/*
*********************************************************************************************
*                                   IIC_FuncReg_Sem()
*
* Description : function register of semaphore funcs.
*
* Arguments   : r       the function used to reset semaphore.
*               pt      the function used to post semaphore.
*               pd      the function used to pend semaphore.
* Return      :
*
* Note:
*********************************************************************************************
*/
void IIC_FuncReg_Sem(IIC_FUNC_SEM_RESET r,IIC_FUNC_SEM_POST pt,IIC_FUNC_SEM_PEND pd){_SemRst = r;_SemPost = pt;_SemPend = pd;
}/*
*********************************************************************************************
*                                  LOCAL FUNCTION
*********************************************************************************************
*/
// 发起启动条件
static unsigned char _IIC_StartCondtion(unsigned char CalAddr){unsigned long wcnt = 0;IIC0_IBSR_IBIF = 1;      // 清零中断标志位IIC0_IBCR_TX_RX = 1;     // 设置单片机为发送模式while(IIC0_IBSR_IBB){    // 检查总线状态直到结束if(!_Wait(wcnt++)) return IIC_ERR_IBB;};IIC0_IBCR_MS_SL = 1;     // 设置主机传输模式;即生成启动信号while(!IIC0_IBSR_IBB){   // 等待IBB标志位置位if(!_Wait(wcnt++))return IIC_ERR_IBB;};    IIC0_IBDR = CalAddr;     // 传输主叫地址,D0=R/Wwhile(!IIC0_IBSR_IBB){   // 等待IBB标志位置位if(!_Wait(wcnt++))return IIC_ERR_IBB;};return IIC_ERR_NULL;
}
// 中断中通知主机函数的执行结果
static void _notifyRst(unsigned char rst){iicRst = rst;_SemPost();return;
}
// 主机发送中断
static void _IIC_ISR_MasterTx(void){unsigned char data;if(_LastByteTransmitted()){       // 如果发送完最后一个字节IIC0_IBCR_MS_SL = 0; // 那么生成停止信号_notifyRst(ISR_SENDOK);return;}if(IIC0_IBSR_RXAK != 0){ //如果发送后没有应答IIC0_IBCR_MS_SL = 0; // 那么生成停止信号_notifyRst(ISR_ERR_NOACK);return;}if(isAddrCyc_MR) {               // 如果是主接收的地址周期isAddrCyc_MR = 0;IIC0_IBCR_TX_RX = 0;           // 切换单片机为接收模式IIC0_IBCR_TXAK = (RxCnt <= 1); // 如果是最后一个要接收的数据,接收完后不应答,否则应答data = IIC0_IBDR;              // 虚读数据寄存器,启动接收第一个字节return;}else{_SendNextByte();            // 发送下一个字节return;}
}
// 主机接收中断
static void _IIC_ISR_MasterRx(void){#ifdef _DEBUGif(RxCnt == 0){dbgprintf("IIC Err,RxCnt == 0.\r\n");  // 这里不应该出现0,出现了说明程序有bug}
#endifif(_isLastByteToRead()){  // 如果是要读的最后一个字节IIC0_IBCR_MS_SL = 0;    // 那么生成停止信号_notifyRst(ISR_RECVOK);}else if(_isLast2ndToRead()){         // 是倒数第二个要读取的数据时设置不应答IIC0_IBCR_TXAK = 1;}_RecvNextByte();          // 读取数据进行存储,如果不是最后一个字节的话会发起下一个接收return;
}
// 地址匹配中断
static void _IIC_ISR_Addressed(void){unsigned char data;No_Slave = 0;if(IIC0_IBSR_SRW){          // 如果主机想读数据IIC0_IBCR_TX_RX = 1;      // 则作为从机应该发送数据IIC0_IBDR = IIC_Send_AsSlave(0);  // 获取第一个要发送的字符并发送}else{                      // 如果主机想发数据IIC0_IBCR_TX_RX = 0;      // 则作为从机应该接收数据IIC0_IBCR_TXAK = 0;       // 对所有数据进行应答data = IIC0_IBDR;         // 虚读以开始接收}
}
// 从机接收中断
static void _IIC_ISR_SlaveRx(void){unsigned char data;data = IIC0_IBDR;IIC_Recv_AsSlave(No_Slave++,data);
}
// 从机发送中断
static void _IIC_ISR_SlaveTx(void){unsigned char data;if(IIC0_IBSR_RXAK != 0){    //如果发送后没有应答IIC0_IBCR_TX_RX = 0;      // 则切换到接收模式data = IIC0_IBDR;         // 并虚读一次}else{                      // 如果收到应答的话IIC0_IBDR = IIC_Send_AsSlave(++No_Slave);  // 向用户要下一个字节来发送}
}
/*
*********************************************************************************************
*                                          ISR
*********************************************************************************************
*/#pragma push
#pragma CODE_SEG __NEAR_SEG NON_BANKEDvoid near _IIC_ISR(void){IIC0_IBSR_IBIF = 1;if(IIC0_IBCR_MS_SL){       // 如果当前为主机if(IIC0_IBCR_TX_RX){      // 且TX/RX置位
#ifndef IIC_MASTER_TX_DISABLE_IIC_ISR_MasterTx();   // 则为主机发送中断
#elsedbgprintf("IIC Err,发生主机发送中断.\r\n");
#endif}else{     // 否则
#ifndef IIC_MASTER_RX_DISABLE_IIC_ISR_MasterRx();   // 为主机接收中断
#elsedbgprintf("IIC Err,发生主机接收中断.\r\n");
#endif}}else{                     // 如果当前为从机if(IIC0_IBSR_IBAL){      // 如果发生仲裁丢失IIC0_IBSR_IBAL = 1;    // 清零标志位
#ifdef IIC_MASTER_EN_notifyRst(ISR_ERR_IBAL); // 通知仲裁丢失if(IIC0_IBSR_IAAS == 0) // 如果没有被作为从机寻址return;               // 则直接退出
#elsedbgprintf("IIC Err,发生主机仲裁丢失中断.\r\n");
#endif}
#ifndef IIC_SLAVEMODE_DISABLEif(IIC0_IBSR_IAAS){  // 如果被作为从机寻址_IIC_ISR_Addressed();   // 为地址匹配发生的中断,(当前不支持10位地址)return;}if(IIC0_IBCR_TX_RX)_IIC_ISR_SlaveTx();else_IIC_ISR_SlaveRx();
#elsedbgprintf("IIC错误,发生从机中断.\r\n");
#endif}
}interrupt void near IIC_ISR(void){_IIC_ISR();
}
#pragma pop

基于UCOS-II的驱动

头文件:

/*
*******************************************************************************************
*
*
*                                IIC SUPPORT PACKAGE
*                                  for uC/OS - II
*
* File : IIC_uCos.h
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2018/05/20
* version: V1.1
* History: 2018/05/15  V1.0   the prototype
*          2018/05/20  V1.1   a little modification for ISR
* NOTE(s):  1. This module is based on the my IIC driver module for MC9S12XEP100.
*           2. it give the example of adapting the IIC driver to uC/OS-II RTOS.
*           3. to use iic in uCos-II, you should point IIC_uC_ISR in IIC.s to the corresponding
*              address and enable interrupt, not the IIC_ISR.
*           4. the module is only useful when you use IIC as master.
*********************************************************************************************
*/#ifndef   IIC_UCOS_H
#define   IIC_UCOS_H/*
********************************************************************************************
*                                   INCLUDE
********************************************************************************************
*/#include "IIC.h"
#include "ucos_ii.h"/*
*******************************************************************************************
*                               CONFIGURE 主配置
*******************************************************************************************
*/#define IIC_UCOS_WAIT_MAX     200   // 最长等待多少次TICK
#define IIC_UCOS_SEMPEND_MAX  200   // 最久等待信号量多久个TICK/*
************************************************************************************
*                          FUNCTION PROTOTYPES  函数原型
************************************************************************************
*/void IIC_uCos_Init(void);/*
************************************************************************************
*                          ERROR CHECK 错误检查
************************************************************************************
*/#endif  // of IIC_UCOS_H

源文件:

/*
*******************************************************************************************
*
*
*                                IIC SUPPORT PACKAGE
*                                  for uC/OS - II
*
* File : IIC_uCos.c
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2018/05/20
* version: V1.1
* History: 2018/05/15  V1.0   the prototype
*          2018/05/20  V1.1   a little modification for ISR
* NOTE(s):  1. This module is based on the my IIC driver module for MC9S12XEP100.
*           2. it give the example of adapting the IIC driver to uC/OS-II RTOS.
*           3. to use iic in uCos-II, you should point IIC_uC_ISR in IIC.s to the corresponding
*              address and enable interrupt, not the IIC_ISR.
*           4. the module is only useful when you use IIC as master.
*********************************************************************************************
*//*
*********************************************************************************************************
*                                       INCLUDES
*********************************************************************************************************
*/
#include <stddef.h>
#include "IIC_uCos.h"/*
*********************************************************************************************************
*                                  LOCAL FUNCTION DECLARATION
*********************************************************************************************************
*/
// functions for register
static unsigned char iic_wait(unsigned long wCnt);
static unsigned char iic_sem_pend(void);
static void iic_sem_post(void);
static void iic_sem_reset(void);/*
*********************************************************************************************************
*                                  LOCAL VARIABLE
*********************************************************************************************************
*/static OS_EVENT* iic_sem;/*
*********************************************************************************************************
*                                        IIC_uCos_Init()
*
* Description : Initialize IIC for uCos-II.  初始化
*
* Arguments   :
*
* Return      : IIC_ERR_NULL       if success.
*
* Note(s)     :
*********************************************************************************************************
*/
void IIC_uCos_Init(){#if(IIC_MASTER_RX_EN || IIC_MASTER_TX_EN)iic_sem = OSSemCreate(0);m_assert(iic_sem != NULL,"给iic分配信号量时出现错误,信号量不够用。\r\n");IIC_FuncReg_Wait(iic_wait);IIC_FuncReg_Sem(iic_sem_reset,iic_sem_post,iic_sem_pend);
#endif
}/*
*********************************************************************************************************
*                                  LOCAL FUNCTION
*********************************************************************************************************
*/
// Description: IIC内部阻塞等待时使用的函数,比如可以在其中添加线程Dly函数来实现阻塞等待时放弃CPU时间
// Arguments  : wCnt     当前等待次数计数
// return     : TRUE     继续等待
//              FALSE    停止等待,返回错误
unsigned char iic_wait(unsigned long wCnt){OSTimeDly(1);if(wCnt > IIC_UCOS_WAIT_MAX)   // 计时两百次都没等待成功就停止阻塞返回错误return FALSE;elsereturn TRUE;
}// IIC内部信号量相关函数,当使用操作系统时可以替换为操作系统的信号量// Description: 等待信号量
// Arguments  :
// return     : TRUE     成功pend到信号量
//              FALSE    等待超时或其他错误
unsigned char iic_sem_pend(void){INT8U err;OSSemPend(iic_sem,IIC_UCOS_SEMPEND_MAX,&err);return err == OS_ERR_NONE;
}
// Description: 发送信号量
// Arguments  :
// return     :
void iic_sem_post(void){OSSemPost(iic_sem);
}
// Description: 重置信号量
// Arguments  :
// return     :
void iic_sem_reset(void){INT8U err;OSSemSet(iic_sem,0,&err);
}

按UCOS要求写的中断函数:

;********************************************************************************************************
;                                               uC/OS-II
;                                         The Real-Time Kernel
;
;                         (c) Copyright 2002, Jean J. Labrosse, Weston, FL
;                                          All Rights Reserved
;
;
;                                       PAGED S12X Specific code
;                                            (CODEWARRIOR)
;
; File         : IIC_uCos.s
; By           : Lin Shijun(http://blog.csdn.net/lin_strong)
;
; Notes        : THIS FILE *MUST* BE LINKED INTO NON_BANKED MEMORY! 这个文件必须放在非分页内存中
;                    modified according to uC/OS-II's example.  依据uC/OS-II的模版修改。
;********************************************************************************************************NON_BANKED:       section;********************************************************************************************************
;                                           I/O PORT ADDRESSES   I/O口地址
;********************************************************************************************************PPAGE:            equ    $0015         ; Addres of PPAGE register (assuming MC9S12XEP100 part)
RPAGE:            equ    $0016         ; Addres of RPAGE register (assuming MC9S12XEP100 part)
EPAGE:            equ    $0017         ; Addres of EPAGE register (assuming MC9S12XEP100 part)
GPAGE:            equ    $0010         ; Addres of GPAGE register (assuming MC9S12XEP100 part);********************************************************************************************************
;                                          PUBLIC DECLARATIONS   公开声明
;********************************************************************************************************xdef   IIC_uC_ISR;********************************************************************************************************
;                                         EXTERNAL DECLARATIONS  外部声明
;********************************************************************************************************xref   OSIntExitxref   OSIntNestingxref   OSTCBCurxref   _IIC_ISR;********************************************************************************************************
;                                           SCI RxTx ISR
;
; Description : This routine is the uC/Probe RxTx interrupt service routine
;
; Arguments   : none
;
; Notes       : 1) All USER interrupts should be modeled EXACTLY like this where the only
;                  line to be modified is the call to your ISR_Handler and perhaps the call to
;                  the label name SCI0_ISR_Handler.
;********************************************************************************************************IIC_uC_ISR:ldaa   GPAGE                       ; Get current value of GPAGE registerpsha                               ; Push GPAGE register onto current task's stackldaa   EPAGE                       ; Get current value of EPAGE registerpsha                               ; Push EPAGE register onto current task's stackldaa   RPAGE                       ; Get current value of RPAGE registerpsha                               ; Push RPAGE register onto current task's stackldaa   PPAGE                       ; Get current value of PPAGE registerpsha                               ; Push PPAGE register onto current task's stackinc    OSIntNesting                ; Notify uC/OS-II about ISRldab   OSIntNesting                ; if (OSIntNesting == 1) {cmpb   #$01bne    IIC_uC_ISR1ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointersts    0,y                         ; }IIC_uC_ISR1:JSR    _IIC_ISR                     ; near Call TxRx ISR handler. (See IIC.c);   cli                               ; Optionally enable interrupts to allow interrupt nestingcall   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().pula                               ; Get value of PPAGE registerstaa   PPAGE                       ; Store into CPU's PPAGE registerpula                               ; Get value of RPAGE registerstaa   RPAGE                       ; Store into CPU's RPAGE registerpula                               ; Get value of EPAGE registerstaa   EPAGE                       ; Store into CPU's EPAGE registerpula                               ; Get value of GPAGE registerstaa   GPAGE                       ; Store into CPU's GPAGE registerrti                               ; Return from interrupt to interrupted task.

可以看到,其实将这个模块改到uCOS-II上实际干的事情就只是把uCOS的信号量功能注册给了原先的驱动程序。

示例代码

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */
#include "IIC.h"
#include <stdio.h>
#include <string.h>typedef void (*near tIsrFunc)(void);
const tIsrFunc _vect @0xFFC0 = IIC_ISR;// IIC主从通讯程序
// 通过在编译器选项中定义宏 IIC_SLAVEMODE_DISABLE 来设置当前程序为主机,否则为从机// 主从机的通讯使用的协议:
// 主机写的时候第一个数据字节修改从机的寄存器指针的值,后面的数据字节则写入从机寄存器
// 主机读的时候则接收当前从机寄存器指针指向的字节
// 每次读/写后,从机的寄存器指针的值自增,增长到底后回到0#define LED_CPU_DDR  DDRK_DDRK4
#define LED_CPU      PORTK_PK4
#define BUS_CLOCK    32000000
void Delay(void) {unsigned int i,j;for(i = 0; i < 200; i++)for(j = 0; j < 50000; j++);
}
void INIT_PLL(void)
{CLKSEL &= 0x7f;       //set OSCCLK as sysclkPLLCTL &= 0x8F;       //DisaKble PLL circuitCRGINT &= 0xDF;#if(BUS_CLOCK == 40000000) SYNR = 0x44;#elif(BUS_CLOCK == 32000000)SYNR = 0x43;     #elif(BUS_CLOCK == 24000000)SYNR = 0x42;#endif REFDV = 0x81;         //PLLCLK=2×OSCCLK×(SYNR+1)/(REFDV+1)=64MHz ,fbus=32MPLLCTL =PLLCTL|0x70;  //Enable PLL circuitasm NOP;asm NOP;while(!(CRGFLG&0x08)); //PLLCLK is Locked alreadyCLKSEL |= 0x80;        //set PLLCLK as sysclk
}unsigned char TxCmd[] = {0x00,0x33,0x44,0x53,0x44};  // 从0x00开始写寄存器,分别为0x33,0x44,0x53
unsigned char Rxbuf[3];
char strbuf[100];
void main(void) {volatile unsigned char err;INIT_PLL();IIC_Init();LED_CPU_DDR = 1;LED_CPU = 0;EnableInterrupts;for(;;) {Delay();
#ifdef IIC_SLAVEMODE_DISABLE// 从0寄存器开始写入3个字节if((err = IIC_Send(IIC_INIT_SLAVEADDR,TxCmd,5)) != IIC_ERR_NULL)continue;// 指针重新归0if((err =IIC_SendChar(IIC_INIT_SLAVEADDR,&TxCmd[0])) != IIC_ERR_NULL)continue;// 读取三个字节if((err =IIC_Recv(IIC_INIT_SLAVEADDR,Rxbuf,3)) != IIC_ERR_NULL)continue;if(memcmp(&TxCmd[1],Rxbuf,3) != 0)continue;LED_CPU = !LED_CPU;// 每次改变写入的值TxCmd[1]++;TxCmd[2]++;TxCmd[3]++;
#endif}
}static unsigned char RegPointer;  // 从机的寄存器指针
static unsigned char Regs[0x13];  // 从机的寄存器
unsigned char IIC_Send_AsSlave(unsigned short No){unsigned char rst;rst = Regs[RegPointer++];    if(RegPointer >= 0x13)RegPointer = 0;LED_CPU = !LED_CPU;return rst;
}
void IIC_Recv_AsSlave(unsigned short No,unsigned char c){if(No == 0){if(c < 0x13)RegPointer = c;}else{Regs[RegPointer++] = c;}LED_CPU = !LED_CPU;
}

这里只给贴出了裸奔程序时使用的代码示例。基于uCOS-II的示例由于要改的地方较杂,就不细讲了。
基本就是先把中断向量指向IIC_uC_ISR,然后初始化时多调用次

  IIC_uCos_Init();

就好了。
其他都差不多。

代码下载

注:这里提供下载的代码是V1.3版本的。V1.4中略有修改。IIC_uCos则是1.0版本的,现为1.1版本的。
这里把代码及示例代码提供打包下载。稍微收点分。
https://download.csdn.net/download/lin_strong/10416624

注意,下载的代码中的裸奔程序直接运行时会跑飞,需要在void near IIC_ISR(void);前加一个interrupt才行。
新版本中已经解决了这个问题。


更新历史:
2019/03/26
IIC模块更新到V1.4,修改了头文件中进行配置的方法。对代码进行了一点修改以消除编译器警告。
IIC_uCos模块更新到V1.2,。

[嵌入式开发模块]MC9S12XEP100 IIC模块 驱动程序相关推荐

  1. [嵌入式开发模块]DS3231时钟芯片 驱动程序

    刚刚写完DS3231时钟芯片的驱动程序.这里开源出来供大家使用.需要的自取. 先简单介绍下这个芯片,然后直接给驱动代码以及示例代码. DS3231简介 简介 DS3231是一款低成本.高精度I2C实时 ...

  2. c语言数组实现环形缓冲区,[嵌入式开发模块]环形缓冲区/循环队列 C语言实现

    忙着毕设,很久没有写文章了,终于答辩完了,得了个校优秀毕业设计.毕设做的是个智能接口模块,用一周时间入门了,MC9S12XEP100的开发,又用一周时间入门了uC/OS-II嵌入式操作系统,在做毕设的 ...

  3. android驱动开发 老罗,在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)...

    在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法.简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的 ...

  4. MC9S12XEP100的IIC模块(IICV3)

    最近在写DS3231时钟芯片的驱动,这个芯片使用IIC进行通讯,以前没有用过IIC模块,照着教材和示例程序写程序后发现各种问题.没办法,还是官方数据手册靠谱,遂把相应部分又翻译了一遍.果然发现示例程序 ...

  5. 基于Arduino IDE开发的LD3320语音识别模块

    基于Arduino的LD3320语音识别模块设计详解 文章目录 基于Arduino的LD3320语音识别模块设计详解 前言 一.LD3320驱动编写 step 1.0 使用Arduino的SPI库,通 ...

  6. 《Windows CE嵌入式开发入门——基于Xscale架构》 第9章 Windows CE BSP及驱动程序结构分析

    9.1  Windows CE驱动程序结构概述 Windows CE的驱动程序可以从多种角度进行区分. 1.从加载以及接口方式来区分 可以分为本机设备驱动(Built-In Driver).可加载驱动 ...

  7. 硬件开发——语音模块开发 (包含语音识别模块代码等资料包 )

    一.语音模块以及硬件模块开发的行情 硬件模块的开发--常用:语音模块 语音模块STC11L08XE 比如 人脸识别打卡器--虹膜识别(购买方式) 语音识别(购买方式) 车牌识别(购买方式) 华为手机( ...

  8. DM368开发 -- 华为3G/4G模块移植

    一.模块介绍 用的是华为 ME909s-821 Mini PCIe. 模块介绍,参看: ME909s-821 Mini PCIe 规格参数 其他模块,参看:华为全系列模块 产品介绍 ME909s-82 ...

  9. taro 引入js_Taro跨端开发之多业务模块管理 React Native篇(终篇)

    React Native 热更新方案 rn的业务越来越庞大,同时协同的团队越来越多. rn的动态化就必须提上日程了. 对于rn热更新,首当其冲的问题就是分包. rn的基础库很大,再加上我们依赖了很多的 ...

最新文章

  1. 在NVIDIA A100 GPU中使用DALI和新的硬件JPEG解码器快速加载数据
  2. MATLAB实战系列(三十六)-MATLAB 离散Hopfield神经网络的分类——高校科研能力评价
  3. 例子 客户端_服务端也是可以主动向客户端推送数据的--WebSocket
  4. 论文学习12-Conditional Random Fields: Probabilistic Models for Segmenting and Labeling Sequence Data(CRF
  5. vc10的C2664和C2065错误
  6. 如何防范短信接口被恶意攻击
  7. Arduino 入门教程(十五) WS2811跑马灯
  8. easyui select 默认选中指定值
  9. 怎么安装mapinfo破解和符号库
  10. Android6.0源码下载
  11. Android开发之自定义DataTimePicker(日期时间选择器)
  12. zigbee芯片cc2430资料
  13. 炒鞋风潮下的“真鞋”鉴定生意
  14. Linux安装NVIDIA显卡驱动的正确姿势
  15. JavaScript - 通过居民身份证号码获取年龄和性别(函数封装)
  16. 创建XTP图表的方法
  17. java多项式加法与乘法_java多项式加减法
  18. 利用LSTM对脑电波信号进行分类
  19. java-大数据-精品课程目录(超级全)
  20. 投影html连接电脑,电脑如何链接投影仪_台式电脑主机怎么连接投影仪-win7之家...

热门文章

  1. Android常用设计模式之工厂模式理解
  2. EasyExcel怎么读取下载多个sheet页数据
  3. Selenium实战滑块验证码登陆网站
  4. Gradient Boosting
  5. Excel 把一个表格快速转化成想要的另一个格式
  6. 比亚乔劲霸80技术参数
  7. 逆水寒大型MMO项目UI管理的价值与责任
  8. OpenLayers 带内部箭头的线条绘制
  9. oracle case nvl,oracle中的nvl 、nvl2、decode、case when 函數的用法
  10. editplus配置java快捷键,editplus快捷键大全