×
单片机 > 单片机程序设计 > 详情

一个stm32的I2C比较通俗易懂的入门例程

发布时间:2020-07-08 发布时间:
|

买了个核心板,算是有自己的STM32板子了,所以顺便也整一整I2C(因为上面的是24C02,嘻嘻,比较亲切),刚开始的时候,按照参考书上面的例程写了一个读写程序,但是直接把程序下载到板子里串口无数据输出(我是用的串口把读出的数据发送出来),然后我就在FLASH里调试,一步步的走下去,发现程序停在了while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)){;},然后就是找各种可能的原因,最后实在不行了就百度了一下,发现了一条重要信息:有些IIC设备读写的时候需要加延时!感觉可能是这个原因,毕竟24C02是I2C的入门级芯片,于是就在程序加了延时函数,下载到板子里,通了!感谢网络上的各位前辈!


下面贴出源代码:




I2C.c文件

#include

#include "I2C.h"

#include

#include

void I2C_GPIO_Config()

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;

GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void I2C1_Init()

{

I2C_InitTypeDef I2C_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;

I2C_InitStructure.I2C_OwnAddress1 = 0xA0;

I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;

I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

I2C_InitStructure.I2C_ClockSpeed = 400000;

I2C_Cmd(I2C1, ENABLE);

I2C_Init(I2C1, &I2C_InitStructure);

}

void I2C_Write(u8 addr, u8 data)

{

I2C_AcknowledgeConfig(I2C1,ENABLE); //使能应答

I2C_GenerateSTART(I2C1,ENABLE); //发送一个开始位

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){;}//等待EV5

I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter); //发送从地址

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){;} //等待EV6

I2C_SendData(I2C1,addr); //发送要写入数据的地址

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;} //等待EV8

I2C_SendData(I2C1,data); //发送要写入的数据

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;} //等待EV8

I2C_GenerateSTOP(I2C1,ENABLE); //发送停止位

}

u8 I2C_Read(u8 nAddr)

{

I2C_AcknowledgeConfig(I2C1,ENABLE); //使能应答

I2C_GenerateSTART(I2C1,ENABLE); //发送一个开始位

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){;} //等待EV5

I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Transmitter); //发送一个伪写指令

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){;}//等待EV6

I2C_SendData(I2C1,nAddr);//发送读地址

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){;} //等待EV8

I2C_GenerateSTART(I2C1,ENABLE); //发送一个开始位

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){;} //等待EV5

I2C_Send7bitAddress(I2C1,0xA0,I2C_Direction_Receiver); //发送一个读指令

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){;} //等待EV6

I2C_AcknowledgeConfig(I2C1,DISABLE); //应答使能关闭

I2C_GenerateSTOP(I2C1,ENABLE); //发送一个停止位

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)){;} //等待EV7

return I2C_ReceiveData(I2C1); //返回读到的数据

}

Usart.c文件

#include

#include"usart.h"

void usart_gpio_config()

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&GPIO_InitStructure);

}

void usart_init()

{

USART_InitTypeDef USART_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

USART_InitStructure.USART_BaudRate = 9600;

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

USART_InitStructure.USART_StopBits = USART_StopBits_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 usart_putchar(u8 ch)

{

USART_SendData(USART1,ch);

while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);

}

delay.c文件

#include

#include "delay.h"

static u8 fac_us=0;//us延时倍乘数

static u16 fac_ms=0;//ms延时倍乘数

//初始化延迟函数

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(u8 SYSCLK)

{

SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8

fac_us=SYSCLK/8;

fac_ms=(u16)fac_us*1000;

}

//延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864

void delay_ms(u16 nms)

{

u32 temp;

SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)

SysTick->VAL =0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while(temp&0x01&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

//延时nus

//nus为要延时的us数.

void delay_us(u32 nus)

{

u32 temp;

SysTick->LOAD=nus*fac_us; //时间加载

SysTick->VAL=0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while(temp&0x01&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

main.c文件

#include

#include "I2C.h"

#include "Usart.h"

#include "delay.h"

int main()

{

SystemInit();

delay_init(72);

I2C_GPIO_Config();

I2C1_Init();

usart_gpio_config();

usart_init();

I2C_Write(0x10,0x30);

delay_ms(10);

while(1)

{

usart_putchar(I2C_Read(0x10));

delay_ms(1000);

}

}

因为只是想试验一下,所以就只是写入一个数据,然后通过串口读出写入的数据,仅此而已。





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
8051单片机的函数发生器的设计