研究了很久STM32的硬件IIC,网上很多人都说硬件IIC可以能哪里不好,但是还是参考官方列程写了一个自发自收的。。新人写的不好勿喷,全部代码如下:
/*----------------------------------------------------------------------------------------------------
名称: I2C 测试 24C02 测试
编写: mingzhang.zhao
内容:测试 stm32f103vct6 的硬件 I2C 实现中断收发数据
注意事项:
1.USART1: PA9 为 TX, PA10 为 RX
I2C1: PB6 为 SCL, PB7 为 SDA
I2C2: PB10 为 SCL, PB11 为 SDA
—————————————————————————————————————*/
#include "stm32f10x.h"
#include "stdio.h"
#define PRINTF_ON 1
void RCC_Configuration(void);void GPIO_Configuration(void);
void USART_Configuration(void);
void I2C_Configuration(void);
void NVIC_Configuration(void);
void Delay(__IO uint32_t t);
u8 I2C1_ADDRESS = 0x30; //7 位 I2C 地址
u8 I2C2_ADDRESS = 0x31;
#define Size 4
vu8 I2C1_Buffer_Tx[Size] = {1,2,3,4};
vu8 I2C2_Buffer_Rx[Size] = {0};
u32 BufferSize = Size ;
extern u32 BufferSize ;
extern u8 I2C1_ADDRESS ;
extern u8 I2C2_ADDRESS ;
extern vu8 I2C1_Buffer_Tx[];
extern vu8 I2C2_Buffer_Rx[];
vu32 Tx_Counter = 0;
vu32 Rx_Counter = 0;
vu32 show_counter1 = 0;
vu32 show_counter2 = 0;
// I2C1 作为主机,用于中断接收从机数据
void I2C1_EV_IRQHandler(void)
{
show_counter1++;
if(show_counter1 > 1000000)
{
show_counter1 = 0;
printf("rn The I2C1 LastEvent is %x rn", I2C_GetLastEvent(I2C1)); //中断发送
}
switch(I2C_GetLastEvent(I2C1))
{
case I2C_EVENT_MASTER_MODE_SELECT: // EV9中断 已发送启始条件
{
// 七位地址发送
I2C_Send7bitAddress(I2C1, I2C2_ADDRESS, I2C_Direction_Receiver);//I2C1,I2C2设备地址,器件地址0x01
printf("rn The I2C1 is ready rn");
break;
}
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: // EV6中断 已发送从机地址
{
printf("rn The slave address is %x rn", I2C_ReceiveData(I2C1)); //返回I2C1最近接受的数据
break;
}
case (I2C_EVENT_MASTER_BYTE_RECEIVED | (I2C_FLAG_BTF & 0x0f)): // EV7中断 第一个数据已接收
{
// 要接收最后一个字节前先关总线,不然总线锁死
I2C_GenerateSTOP(I2C1,ENABLE); //I2C1传输STOP条件
printf("rn The I2C1 has received data2 %x rn", I2C_ReceiveData(I2C1));
printf("rn The I2C1 is finish rn");
break;
}
case 0x40:
{
// 接收了两个同样的数据,没有这个释放不了 RXNE
I2C_ReceiveData(I2C1);
}
default: {break;}
}
}
// I2C2 用于从机发送数据到主机
void I2C2_EV_IRQHandler(void) //输入事件中断
{
show_counter2++;
if(show_counter2 > 100000)
{
show_counter2 = 0;
printf("rn The I2C2 LastEvent is %x rn", I2C_GetLastEvent(I2C2)); //I2C2返回最近一次事件
}
switch(I2C_GetLastEvent(I2C2)) //检测到输入
{
// 收到匹配的地址数据
case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: //EV1中断
{
printf("rn The I2C2 is ready rn");
I2C_GenerateSTOP(I2C2, DISABLE); //I2C2使能STOP条件
break;
}
case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: // EV8中断
{
printf("rn The I2C2 transmits is transmitting rn");
I2C_SendData(I2C2, 0xb6 + Rx_Counter); //发送数据
break;
}
//发送数据,要发送,不然锁死,不过 master 没收到
case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //EV3中断
{
printf("rn The I2C2 transmits one byte rn");
I2C_SendData(I2C2, 0xb6 + (Rx_Counter++)); //发送数据
break;
}
case I2C_EVENT_SLAVE_STOP_DETECTED: // EV4中断 收到结束条件
{
printf("rn The I2C2 is finish rn");
I2C_ClearFlag(I2C2,I2C_FLAG_STOPF); //消除I2C2的标志位
I2C_GenerateSTOP(I2C2, ENABLE); //I2C2使能STOP条件
break;
}
default: {break;}
}
}
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
I2C_Configuration();
NVIC_Configuration();
I2C_GenerateSTART(I2C1,ENABLE);
while(1)
{
Delay(1000);
I2C_GenerateSTART(I2C1,ENABLE); //使能I2C1 循环读取数据
}
}
// 初始化和配置相关
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure; //I2C结构定义
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置为I2C模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //I2C快速模式2
I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDRESS; //设置I2C1设备自身地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //设置应答7位地址
I2C_InitStructure.I2C_ClockSpeed = 200000; //设置时钟频率
I2C_Init(I2C1,&I2C_InitStructure); //初始化I2C1
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //设置为I2C模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //I2C快速模式
I2C_InitStructure.I2C_OwnAddress1 = I2C2_ADDRESS; //设置I2C2的地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //使能应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //设置应答7位地址
I2C_InitStructure.I2C_ClockSpeed = 200000; //设置时钟频率
I2C_Init(I2C2,&I2C_InitStructure); //初始化I2C2
I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE); //使能I2C1缓存、事件中断屏蔽
I2C_ITConfig(I2C2,I2C_IT_EVT|I2C_IT_BUF,ENABLE); //使能I2C2缓存、事件中断屏蔽
I2C_Cmd(I2C1,ENABLE); //使能I2C1外设
I2C_Cmd(I2C2,ENABLE); //使能I2C2外设
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //中断优先级类型结构定义
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置先占优先级1位,从优先级3位
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; //设置I2C1事件中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置先占优先级1位,从占优先级3位
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从占优先级0位,占优先级4位
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); //中断初始化
NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn; //设置I2C2事件中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0位
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从占优先级0位
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); //中断初始化
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//初始化 I2C1
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速率为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //选中引脚Pin6,Pin7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //设置为复用开漏输出
GPIO_Init(GPIOB , &GPIO_InitStructure); //初始化GPIOB
//初始化 I2C2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; //选中引脚Pin10,Pin11
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最高输出速率为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //设置为复用开漏输出
GPIO_Init(GPIOB , &GPIO_InitStructure); //初始化GPIOB
//初始化 USART1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //选中RX端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA , &GPIO_InitStructure); //初始化GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //选中TX端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA , &GPIO_InitStructure); //初始化GPIOA
}
void RCC_Configuration(void)
{
/* 定义枚举类型变量 HSEStartUpStatus */
ErrorStatus HSEStartUpStatus;
/* 复位系统时钟设置*/
RCC_DeInit();
/* 开启 HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/* 等待 HSE 起振并稳定*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断 HSE 起是否振成功,是则进入 if()内部 */
if(HSEStartUpStatus == SUCCESS)
{
/* 选择 HCLK(AHB)时钟源为 SYSCLK 1 分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* 选择 PCLK2 时钟源为 HCLK(AHB) 1 分频 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* 选择 PCLK1 时钟源为 HCLK(AHB) 2 分频 */RCC_PCLK1Config(RCC_HCLK_Div2);
/* 设置 FLASH 延时周期数为 2 */
FLASH_SetLatency(FLASH_Latency_2);
/* 使能 FLASH 预取缓存 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 选择锁相环(PLL)时钟源为 HSE 1 分频, 倍频数为 9,则 PLL 输出频率为 8MHz
* 9 = 72MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 使能 PLL */
RCC_PLLCmd(ENABLE);
/* 等待 PLL 输出稳定 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* 选择 SYSCLK 时钟源为 PLL */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待 PLL 成为 SYSCLK 时钟源 */
while(RCC_GetSYSCLKSource() != 0x08);
}
/* 打开 APB2 总线上的 GPIOA 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1, ENABLE);
//RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1|RCC_APB1Periph_I2C2,ENABLE);
//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG|RCC_APB1Periph_SPI2, ENABLE);
}
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure; //定义结构体
USART_ClockInitTypeDef USART_ClockInitStructure; //定义串口时钟结构
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; //时钟低电平活动
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; //时钟低电平
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; //时钟第二个边沿进行数据捕获
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; //最后一位数据的时钟脉冲不从SCLK输出
USART_ClockInit(USART1 , &USART_ClockInitStructure); //初始串口时钟
USART_InitStructure.USART_BaudRate = 9600; //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1; //8位后传输1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶失能
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None; //硬件流控制失能
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //使能发送和接收
USART_Init(USART1,&USART_InitStructure); //初始化串口
USART_Cmd(USART1,ENABLE); //使能串口
}
void Delay(__IO uint32_t t) //延迟。。
{
while(t--);
}
#if PRINTF_ON
int fputc(int ch,FILE *f) //重定义fputc函数
{
USART_SendData(USART1,(u8) ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
return ch;
}
#endif
注释非常详细了,留个学习纪念-----^_^