STM32F4XX中断方式通过IO模拟I2C总线Master模式
STM32的I2C硬核为了规避NXP的知识产权,使得I2C用起来经常出问题,因此ST公司推出了CPAL库,CPAL库在中断方式工作下仅支持无子地址
的器件,无法做到中断方式完成读写大部分I2C器件。同时CPAL库在多个I2C同时使用时,经测试也有问题,因此我们项目中放弃了使用ST公司的CPAL库以及标准外设库
访问I2c器件,用IO模拟I2c总线,同时也是支持中断方式完成I2C读写。
目前网上绝大部分IO模拟I2c总线的程序都是查询方式,浪费大量CPU周期用于循环等待,本文的程序使用定时器中断推动状态机来模拟I2C总线的操作,
中断方式使用,请定义回调函数,本程序将在读写完成或出错时自动调用回调函数
当然此程序也可以通过查询方式读写I2c总线,仅需查询IIC_BUSY.
本程序仅模拟主模式(Master)
i2c_sim.h
#ifndef __I2C_SIM_H__
#define __I2C_SIM_H__ #include <stm32f4xx.h> #define MAXFREQ 500000 extern uint8_t I2C_Read7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t *Buf, uint8_t Count); extern uint8_t I2C_Read16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count); extern uint8_t I2C_WriteByte7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t Data); extern uint8_t I2C_Write16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count); extern void IIC_Init(uint8_t IIC, uint16_t MicroSecond); extern void IIC_DeInit(uint8_t IIC); extern void IIC_SetCallback(uint8_t IIC, void(*OnTx)(void), void(*OnRx)(void) ,void(*OnErr)(void)); #endif
i2c_sim.c
#include "stm32f4xx_conf.h"
#include <string.h> #define IIC_COUNT 2 #if (IIC_COUNT>3)
Error! To many IIC
#endif /*----------- I2C1 Device -----------*/ #define I2C1_SCL_GPIO_PORT GPIOB
#define I2C1_SCL_GPIO_CLK RCC_AHB1Periph_GPIOB
#define I2C1_SCL_GPIO_PIN GPIO_Pin_6
#define I2C1_SCL_GPIO_PINSOURCE GPIO_PinSource6 #define I2C1_SDA_GPIO_PORT GPIOB
#define I2C1_SDA_GPIO_CLK RCC_AHB1Periph_GPIOB
#define I2C1_SDA_GPIO_PIN GPIO_Pin_7
#define I2C1_SDA_GPIO_PINSOURCE GPIO_PinSource7 /*-----------I2C2 Device -----------*/ #define I2C2_SCL_GPIO_PORT GPIOA
#define I2C2_SCL_GPIO_CLK RCC_AHB1Periph_GPIOA
#define I2C2_SCL_GPIO_PIN GPIO_Pin_8
#define I2C2_SCL_GPIO_PINSOURCE GPIO_PinSource8 #define I2C2_SDA_GPIO_PORT GPIOC
#define I2C2_SDA_GPIO_CLK RCC_AHB1Periph_GPIOC
#define I2C2_SDA_GPIO_PIN GPIO_Pin_9
#define I2C2_SDA_GPIO_PINSOURCE GPIO_PinSource9 /*-----------I2C3 Device -----------*/ #define I2C3_SCL_GPIO_PORT GPIOH
#define I2C3_SCL_GPIO_CLK RCC_AHB1Periph_GPIOH
#define I2C3_SCL_GPIO_PIN GPIO_Pin_7
#define I2C3_SCL_GPIO_PINSOURCE GPIO_PinSource7 #define I2C3_SDA_GPIO_PORT GPIOH
#define I2C3_SDA_GPIO_CLK RCC_AHB1Periph_GPIOH
#define I2C3_SDA_GPIO_PIN GPIO_Pin_8
#define I2C3_SDA_GPIO_PINSOURCE GPIO_PinSource8 GPIO_TypeDef* I2C_SCL_GPIO_PORT[3] = {I2C1_SCL_GPIO_PORT, I2C2_SCL_GPIO_PORT, I2C3_SCL_GPIO_PORT};
const uint16_t I2C_SCL_GPIO_PIN[3] = {I2C1_SCL_GPIO_PIN, I2C2_SCL_GPIO_PIN, I2C3_SCL_GPIO_PIN};
const uint32_t I2C_SCL_GPIO_CLK[3] = {I2C1_SCL_GPIO_CLK, I2C2_SCL_GPIO_CLK, I2C3_SCL_GPIO_CLK};
const uint16_t I2C_SCL_GPIO_PINSOURCE[3] = {I2C1_SCL_GPIO_PINSOURCE, I2C2_SCL_GPIO_PINSOURCE, I2C3_SCL_GPIO_PINSOURCE}; GPIO_TypeDef* I2C_SDA_GPIO_PORT[3] = {I2C1_SDA_GPIO_PORT,I2C2_SDA_GPIO_PORT,I2C3_SDA_GPIO_PORT};
const uint16_t I2C_SDA_GPIO_PIN[3] = {I2C1_SDA_GPIO_PIN,I2C2_SDA_GPIO_PIN,I2C3_SDA_GPIO_PIN};
const uint32_t I2C_SDA_GPIO_CLK[3] = {I2C1_SDA_GPIO_CLK,I2C2_SDA_GPIO_CLK,I2C3_SDA_GPIO_CLK};
const uint16_t I2C_SDA_GPIO_PINSOURCE[3] = {I2C1_SDA_GPIO_PINSOURCE,I2C2_SDA_GPIO_PINSOURCE,I2C3_SDA_GPIO_PINSOURCE}; TIM_TypeDef* Timer[3] = {TIM5, TIM6, TIM7};
const IRQn_Type TimerIRQ[3] = {TIM5_IRQn, TIM6_DAC_IRQn, TIM7_IRQn}; const uint32_t RCC_APB1Periph_TIM[3] ={RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7}; #define SDA_Clear(IIC) I2C_SDA_GPIO_PORT[IIC]->BSRRH=I2C_SDA_GPIO_PIN[IIC]
#define SDA_Set(IIC) I2C_SDA_GPIO_PORT[IIC]->BSRRL=I2C_SDA_GPIO_PIN[IIC] #define SCL_Clear(IIC) I2C_SCL_GPIO_PORT[IIC]->BSRRH=I2C_SCL_GPIO_PIN[IIC]
#define SCL_Set(IIC) I2C_SCL_GPIO_PORT[IIC]->BSRRL=I2C_SCL_GPIO_PIN[IIC] #define En_SDA_Input(IIC) I2C_SDA_GPIO_PORT[IIC]->MODER&=~(I2C_SDA_GPIO_PIN[IIC]<<I2C_SDA_GPIO_PINSOURCE[IIC])
#define En_SDA_Output(IIC) I2C_SDA_GPIO_PORT[IIC]->MODER|=(I2C_SDA_GPIO_PIN[IIC]<<I2C_SDA_GPIO_PINSOURCE[IIC]) #define SDA_Read(IIC) ((I2C_SDA_GPIO_PORT[IIC]->IDR&I2C_SDA_GPIO_PIN[IIC])!=0)?1:0 typedef struct {
__IO uint8_t StartState;
__IO uint8_t StopState;
__IO int8_t ReadByteState;
__IO uint8_t TransferByte;
__IO uint8_t ReadStop;
__IO uint8_t WriteByteState;
__IO uint8_t WriteACK;
__IO uint8_t Command; //1-Read, 0=Write;
__IO uint8_t Device;
__IO uint32_t SubAddr;
__IO uint8_t SubAddrLen;
__IO uint8_t *TransferBuf;
__IO uint16_t TransferCount;
__IO uint8_t ReadState;
__IO uint8_t WriteState; __IO uint8_t dat;
__IO uint8_t bit;
__IO uint8_t IIC_BUSY;
__IO uint8_t ERROR;
} IIC_State; static IIC_State iic_state[IIC_COUNT]; typedef struct {
void(*OnTx)(void);
void(*OnRx)(void);
void(*OnErr)(void);
} IIC_Callback; __IO IIC_Callback iic_callback[IIC_COUNT]; #define IN 1
#define OUT 0 void __INLINE SetIicSdaDir(uint8_t IIC, uint8_t x) {
if (x) En_SDA_Input(IIC);
else En_SDA_Output(IIC);
} void IIC_GPIOInit(uint8_t IIC)
{
GPIO_InitTypeDef GPIO_InitStructure; /* Enable I2Cx SCL and SDA Pin Clock */
RCC_AHB1PeriphClockCmd((I2C_SCL_GPIO_CLK[IIC] | I2C_SDA_GPIO_CLK[IIC]), ENABLE); /* Set GPIO frequency to 50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* Select Alternate function mode */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//????? /* Select output Open Drain type */
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /* Disable internal Pull-up */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /* Initialize I2Cx SCL Pin */
GPIO_InitStructure.GPIO_Pin = I2C_SCL_GPIO_PIN[IIC]; GPIO_Init((GPIO_TypeDef*)I2C_SCL_GPIO_PORT[IIC], &GPIO_InitStructure); /* Initialize I2Cx SDA Pin */
GPIO_InitStructure.GPIO_Pin = I2C_SDA_GPIO_PIN[IIC]; GPIO_Init((GPIO_TypeDef*)I2C_SDA_GPIO_PORT[IIC], &GPIO_InitStructure);
} static void IIC_DelayTimer_Init(uint8_t IIC)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TimerIRQ[IIC];
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ;
NVIC_Init(&NVIC_InitStructure);
memset((void *)&iic_state[IIC], 0, sizeof(IIC_State));
memset((void *)&iic_callback[IIC], 0, sizeof(IIC_Callback));
} static void IIC_DelayTimer_DeInit(uint8_t IIC)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TimerIRQ[IIC];
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(Timer[IIC], DISABLE);
memset(&iic_state[IIC], 0, sizeof(IIC_State));
} static void IIC_SetDelay(uint8_t IIC, uint16_t MicroSecond)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_ClocksTypeDef rccClocks;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM[IIC],ENABLE); RCC_GetClocksFreq(&rccClocks); TIM_DeInit(Timer[IIC]);
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
if (Timer[IIC]==TIM2||Timer[IIC]==TIM3||Timer[IIC]==TIM4||Timer[IIC]==TIM5||Timer[IIC]==TIM6||Timer[IIC]==TIM7||
Timer[IIC]==TIM12||Timer[IIC]==TIM13||Timer[IIC]==TIM14) TIM_TimeBaseStructure.TIM_Prescaler=rccClocks.PCLK1_Frequency*2/1000000;
else TIM_TimeBaseStructure.TIM_Prescaler=rccClocks.PCLK2_Frequency*2/1000000;
TIM_TimeBaseStructure.TIM_ClockDivision=0;
TIM_TimeBaseStructure.TIM_Period=MicroSecond;
TIM_TimeBaseInit(Timer[IIC], &TIM_TimeBaseStructure); TIM_ClearFlag(Timer[IIC], TIM_FLAG_Update); TIM_ITConfig(Timer[IIC],TIM_FLAG_Update, ENABLE);
} void IIC_Init(uint8_t IIC, uint16_t MicroSecond)
{
IIC_GPIOInit(IIC);
SDA_Set(IIC);
SCL_Set(IIC);
IIC_DelayTimer_Init(IIC);
IIC_SetDelay(IIC, MicroSecond);
}
#define p iic_state[IIC]
#define q iic_callback[IIC] void IIC_SetCallback(uint8_t IIC, void(*OnTx)(void), void(*OnRx)(void) ,void(*OnErr)(void))
{
q.OnErr=OnErr;
q.OnTx=OnTx;
q.OnRx=OnRx;
} void IIC_DeInit(uint8_t IIC)
{
IIC_DelayTimer_DeInit(IIC);
} static uint8_t IIC_StartStateMachine(uint8_t IIC)
{
switch(p.StartState) {
case 0:
SDA_Set(IIC);
SCL_Set(IIC);
p.StartState++;
break;
case 1:
SDA_Clear(IIC);
//SoftDelay(0);
p.StartState++;
break;
case 2:
SCL_Clear(IIC);
p.StartState=0;
break;
}
return p.StartState;
} static uint8_t IIC_StopStateMachine(uint8_t IIC)
{
switch(p.StopState) {
case 0:
SCL_Set(IIC);
SDA_Clear(IIC);
//SoftDelay(1);
p.StopState++;
break;
case 1:
SDA_Set(IIC);
p.StopState=0;
break;
}
return p.StopState;
} static uint8_t IIC_ReadByteStateMachine(uint8_t IIC)
{
switch(p.ReadByteState) {
case 0:
SetIicSdaDir(IIC, IN);
p.bit=0;
p.ReadByteState++;
break;
case 1:
p.dat <<= 1;
SCL_Set(IIC);
p.ReadByteState++;
break;
case 2:
if(SDA_Read(IIC))
{
p.dat |= 1;
}
SCL_Clear(IIC);
p.bit++;
if (p.bit==8) p.ReadByteState++;
else {
p.ReadByteState--;
break;
}
case 3:
p.TransferByte=p.dat;
SetIicSdaDir(IIC, OUT);
if (p.ReadStop) SDA_Set(IIC); else SDA_Clear(IIC); // ReadStop = 0; ask, ReadStop = 1,stop
p.ReadByteState++;
break;
case 4:
SCL_Set(IIC);
p.ReadByteState++;
break;
case 5:
SCL_Clear(IIC);
p.ReadByteState++;
case 6:
p.ReadByteState=0;
break;
}
return p.ReadByteState;
} static uint8_t IIC_WriteByteStateMachine(uint8_t IIC)
{
switch(p.WriteByteState) {
case 0:
p.dat=p.TransferByte;
p.bit=8;
p.WriteByteState++;
case 1:
if(p.dat & 0x80)
{
SDA_Set(IIC);
}
else
{
SDA_Clear(IIC);
}
p.WriteByteState++;
break;
case 2:
SCL_Set(IIC);
p.WriteByteState++;
break;
case 3:
p.dat <<= 1;
SCL_Clear(IIC);
p.bit--;
if (p.bit) {
p.WriteByteState=1;
break;
}
else p.WriteByteState++;
case 4:
SetIicSdaDir(IIC, IN);
p.WriteByteState++;
break;
case 5:
SCL_Set(IIC);
p.WriteByteState++;
break;
case 6:
p.WriteACK = SDA_Read(IIC);
SCL_Clear(IIC);
SetIicSdaDir(IIC, OUT);
p.WriteByteState++;
break;
case 7:
p.WriteByteState=0;
break;
}
return p.WriteByteState;
} static uint8_t IIC_ReadStateMachine(uint8_t IIC)
{
switch(p.ReadState) {
case 0:
p.ReadState++;
case 1:
if (IIC_StartStateMachine(IIC)==0) p.ReadState++;
break;
case 2:
p.TransferByte=p.Device;
p.ReadState++;
case 3:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.ReadState=14; //Stop
}
else {
if (p.SubAddrLen) p.ReadState++; //Send Access Address
else p.ReadState+=3; //No Address
}
}
break;
case 4: //Send Address
switch(p.SubAddrLen) {
case 4: p.TransferByte=(p.SubAddr >> 24)&0x000000FF; break;
case 3: p.TransferByte=(p.SubAddr >> 16)&0x000000FF; break;
case 2: p.TransferByte=(p.SubAddr >> 8)&0x000000FF; break;
case 1: p.TransferByte=p.SubAddr&0x000000FF; break;
}
p.SubAddrLen--;
p.ReadState++;
case 5:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.ReadState=14; //Stop
}
else {
if (p.SubAddrLen==0) p.ReadState++;
else p.ReadState--;
}
}
break;
case 6:
if (IIC_StartStateMachine(IIC)==0) p.ReadState++;
break;
case 7: //Send Device Read
p.TransferByte=p.Device|0x01;
p.ReadState++;
case 8:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.ReadState=14;
}
else {
if (p.TransferCount==1) p.ReadState+=3;
else p.ReadState++;
}
}
break;
case 9: //Read Bytes
p.ReadStop=0;
p.ReadState++;
case 10:
if (IIC_ReadByteStateMachine(IIC)==0) {
*p.TransferBuf=p.TransferByte;
p.TransferBuf++;
p.TransferCount--;
if (p.TransferCount==1) p.ReadState++;
}
break;
case 11: //Read Last Byte
p.ReadStop=1;
p.ReadState++;
case 12: //Read Last Byte
if (IIC_ReadByteStateMachine(IIC)==0) {
*p.TransferBuf=p.TransferByte;
p.TransferCount=0;
p.ReadState++;
}
break;
case 13:
if (IIC_StopStateMachine(IIC)==0) {
p.ReadState=0;
p.IIC_BUSY=0;
p.ERROR=0;
if (q.OnRx) q.OnRx();
}
break;
case 14:
if (IIC_StopStateMachine(IIC)==0) {
p.ReadState=0;
p.IIC_BUSY=0;
p.ERROR=1;
if (q.OnErr) q.OnErr();
}
break;
}
return p.ReadState;
} static uint8_t IIC_WriteStateMachine(uint8_t IIC)
{
switch(p.WriteState) {
case 0:
p.WriteState++;
case 1:
if (IIC_StartStateMachine(IIC)==0) p.WriteState++;
break;
case 2:
p.TransferByte=p.Device;
p.WriteState++;
case 3:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.WriteState=11; //Stop
}
else {
if (p.SubAddrLen) p.WriteState++; //Send Access Address
else {
if (p.TransferCount) p.WriteState+=5; //Multi-Bytes;
else p.WriteState+=3; //Single Byte
}
}
}
break;
case 4: //Send Address
switch(p.SubAddrLen) {
case 4: p.TransferByte=(p.SubAddr >> 24)&0x000000FF; break;
case 3: p.TransferByte=(p.SubAddr >> 16)&0x000000FF; break;
case 2: p.TransferByte=(p.SubAddr >> 8)&0x000000FF; break;
case 1: p.TransferByte=p.SubAddr&0x000000FF; break;
}
p.SubAddrLen--;
p.WriteState++;
case 5:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.WriteState=11; //Stop
}
else {
if (p.SubAddrLen==0) {
if (p.TransferCount) p.WriteState+=3; //Multi-Bytes;
else p.WriteState++; //Single Byte
}
else p.WriteState--;
}
}
break;
case 6: //Send Only One Byte
p.TransferByte=(uint32_t)p.TransferBuf;
p.WriteState++;
case 7:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.WriteState=11; //Stop
}
else {
p.WriteState+=3;
}
}
break;
case 8: //Send Multi-Bytes Data
p.TransferByte=*p.TransferBuf; p.TransferBuf++; p.TransferCount--;
p.WriteState++;
case 9:
if (IIC_WriteByteStateMachine(IIC)==0) {
if (p.WriteACK==1) {
p.WriteState=11; //Stop
}
else {
if (p.TransferCount==0) p.WriteState++;
else p.WriteState--;
}
}
break;
case 10:
if (IIC_StopStateMachine(IIC)==0) {
p.WriteState=0;
p.IIC_BUSY=0;
p.ERROR=0;
if (q.OnTx) q.OnTx();
}
break;
case 11:
if (IIC_StopStateMachine(IIC)==0) {
p.WriteState=0;
p.IIC_BUSY=0;
p.ERROR=1;
if (q.OnErr) q.OnErr();
}
break;
}
return p.WriteState;
} static uint8_t IIC_StateMachine(uint8_t IIC)
{
if (p.Command) return IIC_ReadStateMachine(IIC);
return IIC_WriteStateMachine(IIC);
} uint8_t I2C_Read7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t *Buf, uint8_t Count)
{
if (p.IIC_BUSY==0) {
memset(&p, 0, sizeof(IIC_State));
p.Command=1; //1-Read, 0=Write;
p.Device=device;
p.SubAddr=Addr;
p.SubAddrLen=1;
p.TransferBuf=Buf;
p.TransferCount=Count;
p.IIC_BUSY=1;
TIM_Cmd(Timer[IIC], ENABLE);
return 1;
}
else return 0;
} uint8_t I2C_Read16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count)
{
if (p.IIC_BUSY==0) {
memset(&p, 0, sizeof(IIC_State));
p.Command=1; //1-Read, 0=Write;
p.Device=device;
p.SubAddr=Addr;
p.SubAddrLen=2;
p.TransferBuf=Buf;
p.TransferCount=Count;
p.IIC_BUSY=1;
TIM_Cmd(Timer[IIC], ENABLE);
return 1;
}
else return 0;
} uint8_t I2C_WriteByte7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t Data)
{
if (p.IIC_BUSY==0) {
memset(&p, 0, sizeof(IIC_State));
p.Command=0; //1-Read, 0=Write;
p.Device=device;
p.SubAddr=Addr;
p.SubAddrLen=1;
p.TransferBuf=(uint8_t *)Data;
p.TransferCount=0;
p.IIC_BUSY=1;
TIM_Cmd(Timer[IIC], ENABLE);
return 1;
}
else return 0;
} uint8_t I2C_Write16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count)
{
if (p.IIC_BUSY==0) {
memset(&p, 0, sizeof(IIC_State));
p.Command=0; //1-Read, 0=Write;
p.Device=device;
p.SubAddr=Addr;
p.SubAddrLen=2;
p.TransferBuf=Buf;
p.TransferCount=Count;
p.IIC_BUSY=1;
TIM_Cmd(Timer[IIC], ENABLE);
return 1;
}
else return 0;
} #if (IIC_COUNT>=1)
void TIM5_IRQHandler(void)
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
if (IIC_StateMachine(0)==0) {
if (iic_state[0].IIC_BUSY==0) TIM_Cmd(TIM5, DISABLE);
}
}
}
#endif #if (IIC_COUNT>=2)
void TIM6_DAC_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
if (IIC_StateMachine(1)==0) {
if (iic_state[1].IIC_BUSY==0) TIM_Cmd(TIM6, DISABLE);
}
}
}
#endif #if (IIC_COUNT>=3)
void TIM7_IRQHandler(void)
{
if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
if (IIC_StateMachine(2)==0) {
if (iic_state[2].IIC_BUSY==0) TIM_Cmd(TIM7, DISABLE);
}
}
}
#endif
STM32F4XX中断方式通过IO模拟I2C总线Master模式的更多相关文章
- C51单片机模拟I2C总线驱动程序设计
/********************************** I2C总线驱动 ******************************** 模块名:I2C总线驱动 型号:I2C 功能描述 ...
- 51单片机模拟I2C总线的C语言实现
电路原理图 EEPROM为ATMEL公司的AT24C01A.单片机为ATMEL公司的AT89C51. 软件说明 C语言为Franklin C V3.2.将源程序另存为testi2c.c,用命令 C ...
- 51单片机 | 基于I2C总线的秒表模拟应用
———————————————————————————————————————————— 参考地址: http://blog.csdn.net/junyeer/article/details/4648 ...
- I2C总线完全版——I2C总线的结构、工作时序与模拟编程
I2C总线的结构.工作时序与模拟编程 I2C总线的结构.工作时序与模拟编程I2C总线(Inter Integrated Circuit)是飞利浦公司于上个世纪80年代开发的一种"电路板级&q ...
- MSP430的IO口模拟I2C总线对AT24C25进行读写程序
功能: 实现MSP430口线模拟I2C总线协议与24C04通信. ** 描述: 主系统工作时钟为12MHz,I2C工 ...
- I2C总线协议的软件模拟实现方法
I2C总线协议的软件模拟实现方法 在上一篇博客中已经讲过I2C总线通信协议,本文讲述I2C总线协议的软件模拟实现方法. 1. 简述 所谓的I2C总线协议的软件模拟实现方法,就是用软件控制GPIO的输入 ...
- 【转载】GPIO模拟i2c通信
I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主 ...
- I2C总线以及GPIO模拟I2C
·I2C总线的一些特征: 1. 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL) 2. 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址:主机可 ...
- Linux+I2C总线分析(主要是probe的方式)
Linux I2C 总线浅析 ㈠ Overview Linux的I2C体系结构分为3个组成部分: ·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法,I2C通信方法(即“algo ...
随机推荐
- MSSQL->serverlink[Oracle]
需求描述: SQL Server数据库连接Oracle数据库 条件准备: SQL Server数据库,SQL Server 2008R2 Oracle数据库,Oracle ...
- C# 平台问题
最近在C#项目中嵌入一个视频软件Ffplayer,出现报错现象,提示平台开发视频.dll文件的兼容性和加载格式不正确的问题.最终查看是由于项目平台选择的是Any CPU和X86的引起的.目标平台有什么 ...
- HTML后续
列表标签 <ul>.<ol>.<dl> 列表标签 无序列表 属性: type="属性值".属性值可以选: disc(实心原点,默认),squar ...
- [学习笔记] CDQ分治&整体二分
突然诈尸.png 这两个东西好像都是离线骗分大法... 不过其实这两个东西并不是一样的... 虽然代码长得比较像 CDQ分治 基本思想 其实CDQ分治的基本思想挺简单的... 大概思路就是长这样的: ...
- Linux命令--用户管理
useradd命令 Linux useradd命令用于建立用户帐号. useradd可用来建立用户帐号.帐号建好之后,再用passwd设定帐号的密码.而可用userdel删除帐号.使用useradd指 ...
- Oracle的四种连接方式【转载】
我们以Oracle自带的表来做例子 主要两张表:dept.emp 一个是部门,一个是员工表结构如下: emp name null? Type Empno not null number(4) enam ...
- JAVA对象与内存控制
1.1 实例变量和类变量 成员变量和局部变量: 局部变量分为三大类: 1)形参:在方法签名中定义的局部变量,由方法调用者为其赋值,随方法的结束而消亡. 2)方法内的局部变量:在方法内定义的局部变量,随 ...
- Tableau10.4中智能显示点击后消失的解决方案
如果你的电脑是Win10,并且是高分屏,可能会出现和我一样的问题,就点击智能显示后,发现找不到了. 那么解决方案就是: 这样就能找到智能显示了.
- 使用jenkins SonarQube gitlab 构建自动化发布系统
目前持续集成的生态越来越完善,工具也有很多,开源的或商业的.如: 最最流行的,也是使用最多的 Jenkins 有着持续集成DNA的ThoughtWorks GO.理念:"Deployment ...
- ES6标准入门 字符串的扩展
1:模板字符串与模板引擎 https://blog.csdn.net/crper/article/details/52940625 es6模板字符串中标签模板作为参数时产生空元素的问题 https:/ ...