stm32f103 從機IIC的實現


根據網上的資料,大部分網友表示STM32自帶的硬件IIC存在bug,讀寫時很容易卡死。在移植過程中遇見的問題是移植過程中不細心把函數使用錯誤了。

1. 在移植過程中需要注意GPIO端口時鍾配置使用了RCC_APB2PeriphResetCmd作為配置GPIOB的時鍾是錯誤的

2.線子不要連接錯誤

3.IIC可以兩根線子通訊

 

————————————————
版權聲明:本文為CSDN博主「夜風~」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u014470361/article/details/82317285

IIC通訊協議  :https://blog.csdn.net/weizhangyjs/article/details/89338341

/*---------IIC1---------------*/
uint8_t Buffer_Rx_IIC1[40];//接收緩存
uint8_t Rx_Idx_IIC1=0;//接收計數
uint8_t Flag_RcvOK_IIC1 = 0;// 接收完成標志
uint8_t Tx_Idx_IIC1=0;//發送計數
u8 Response_Message[40];//發送緩存

void I2C1_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// SCL PB6
// SDA PB7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;//必須設置為開漏輸出,實現iic的線與邏輯
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);
}

 

//配置I2C管腳是stm32f103
void I2C1_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// SCL PB6
// SDA PB7
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//必須設置為開漏輸出,實現iic的線與邏輯
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//必須設置為開漏輸出,實現iic的線與邏輯
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
}

IIC工作參數配置
void I2C1_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_Slave_Address; //從機地址,一定要設置正確
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);


NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;//事件中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//錯誤中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);
I2C_Cmd(I2C1, ENABLE);
}

IIC初始化函數
void I2C1_Init(void)
{

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C1_GPIO_Configuration();
I2C1_Configuration();
}

 

從機中斷函數中接收的流程:EV1—>EV2—>EV4。
詳細的中斷處理程序如下:

void I2C1_EV_IRQHandler(void)
{

__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;

SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;

/* I2C1是從機(MSL = 0) */
if((SR2Register &0x0001) != 0x0001)
{
/* 主機已發送地址,地址為被置位·(ADDR = 1: EV1(包括發送和接收)) */
if((SR1Register & 0x0002) == 0x0002)
{
/* 清除標志位 */
SR1Register = 0;
SR2Register = 0;

Rx_Idx_IIC1=0;
Tx_Idx_IIC1=0;
}

 

/* 接收數據(RXNE = 1: EV2) */
if((SR1Register & 0x0040) == 0x0040)
{
Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
SR1Register = 0;
SR2Register = 0;
}
/* 檢測到停止條件(STOPF =1: EV4) */
if(( SR1Register & 0x0010) == 0x0010)
{
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
Flag_RcvOK_IIC1 = 1;
}

 


/* 發送數據(TxE = 1: EV3、EV3-1) */
if((SR1Register & 0x0080) == 0x0080)
{
I2C1->DR = Response_Message[Tx_Idx_IIC1++];
SR1Register = 0;
SR2Register = 0;
}
/* 檢測到非應答(AF =1: EV3-2) */
if(( SR1Register & 0x0400) == 0x0400)
{
I2C1->SR1 &= 0xFDFF;
SR1Register = 0;
SR2Register = 0;
}
}

}

 

上述中斷程序中,當主機讀取和寫入數據時,都會引起地址位被置位,即發生EV1事件(即本中斷處理程序中將發送和接收的EV1合並了);
  當主機寫入數據時,中斷的執行順序是EV1—>EV2—>EV4,其中有多個數據EV2會多次執行;
  當主機讀取數據時,中斷的執行順序是EV1—>EV3—>EV3-2,本中斷程序中將EV3和EV3-1合並了,若有多個數據,EV3將多次執行。
錯誤中斷處理函數如下:

void I2C1_ER_IRQHandler(void) {

__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;

if(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
}
else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {

}
else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {

I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
}
else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {

}
else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {

}
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
}
發送各種錯誤進行錯誤中斷不做對應的處理,最后只進行清除寄存器(SR1和SR2)操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM