求个STM32F0 模拟I2C的程序例程
各位大牛,求一个STM32F0 模拟I2C的程序例程,求分享,谢谢! 这个应该不难吧,关键是要调整好SCL的时序。 直接拷贝stm32f103的例程,改成自己的GPIO端口(注意使用相应库函数)。就行了。 HAL库的I2C硬件驱动可以直接使用,建议使用硬件驱动。 安 发表于 2019-12-6 11:29HAL库的I2C硬件驱动可以直接使用,建议使用硬件驱动。
硬件上没有接I2C复用引脚,只能使用模拟的 ldptest 发表于 2019-12-6 11:19
直接拷贝stm32f103的例程,改成自己的GPIO端口(注意使用相应库函数)。就行了。 ...
能分享一下例程吗,感谢!! 下面是我基于G431的软件模拟I2C对AT24C32进行读写操作的代码,应该可以直接使用,最多就是调整一下延时函数,希望能帮到您。
//#include "main.h"
#include "i2c.h"
//#include <stdio.h>
/***************************************************
函数功能:毫秒延时
入口参数:延时毫秒
***************************************************/
void delay_us(uint8_t us)
{
uint8_t x,y;
for(x=us;x>0;x--)
for(y=20;y>0;y--);
}
/***************************************************
函数功能:软件I2C配置
入口参数:无
***************************************************/
void SI2C_Config(void) //引脚配置
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SI2C_SCL | SI2C_SDA; //SCL,SDA,RST输出模式、弱上拉
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
}
/***************************************************
函数功能:DAT引脚配置
入口参数:x
***************************************************/
void SI2C_PortConfig(uint8_t dir) //DAT端口配置(根据需要配置成输出或输入模式)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(dir == 0){
GPIO_InitStruct.Pin = SI2C_SDA; //SDA输出模式、弱上拉
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
}
else{
GPIO_InitStruct.Pin = SI2C_SDA; //SDA输入模式
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(SI2C_PORT, &GPIO_InitStruct);
}
HAL_GPIO_WritePin(SI2C_PORT,SI2C_SDA,GPIO_PIN_SET);
}
/******************************************************************************************************************************************
* 函数名称: I2C_Start()
* 功能说明: 产生I2C传输的Start信号
* 输 入: 无
* 输 出: 无
******************************************************************************************************************************************/
void SI2C_Start(void)
{
SDA_OUT; //SDA输出
SDA_1;
SCL_1; //scl = 1;
delay_us(7);
SDA_0; //sda = 0; scl为高时sda的下降沿表示“起始”
delay_us(5);
SCL_0; //scl = 0;钳住I2C总线,准备发送或接收数据 START:when CLK is high,DATA change form high to low
}
/******************************************************************************************************************************************
* 函数名称: I2C_Stop()
* 功能说明: 产生I2C传输的Stop信号
* 输 入: 无
* 输 出: 无
******************************************************************************************************************************************/
void SI2C_Stop(void)
{
SDA_OUT;
SCL_0; // scl = 0;
SDA_0; // STOP:when CLK is high DATA change form low to high
delay_us(5);
SCL_1; // scl = 1;
delay_us(5);
SDA_1; // sda = 1; sclk为高时sdat的上升沿表示“停止”
}
/******************************************************************************************************************************************
* 函数名称: I2C_Send()
* 功能说明: 向IIC总线发送一个字节的数据
* 输 入: byte dat 要发送的数据
* 输 出: 无
******************************************************************************************************************************************/
void SI2C_Send(uint8_t dat)
{
uint8_t i;
SDA_OUT;
SCL_0; //拉低时钟开始数据传输
for(i=0;i<8;i++)
{
// if(((dat&0x80)>>7) == 1) SDA_1;//准备好SDA数据
if((dat>>(7-i))&0x01) SDA_1;
else SDA_0;
// dat>>=1;
delay_us(5);
SCL_1; //拉高时钟等待从设备读取数据
delay_us(9);
SCL_0; //拉低时钟准备下一位数据
delay_us(5);
}
}
/******************************************************************************************************************************************
* 函数名称: I2C_Receive()
* 功能说明: 从IIC总线接收一个字节的数据
* 输 入: 无
* 输 出: byte 从IIC总线上接收到得数据
* 注意事项: 无
******************************************************************************************************************************************/
uint8_t SI2C_Receive(void)
{
uint8_t i,dat;
SDA_IN; //设置为输入
for(i=0;i<8;i++)
{
SCL_0;
delay_us(7);
SCL_1;
dat<<=1;
if(1 == SDA_X)
dat|=0x01;
delay_us(5);
}
return dat;
/*
ui08 i = 0;
byte d = 0;
byte dat = 0;
for(i=0;i<8;i++)
{
scl = 0;
DELAY();
sda = 1; //本语句必须有:于IIC,是释放SDA线;于51单片机,则是由于51的IO不是真双向口,在读之前必须写0
DELAY();
scl = 1;
DELAY();
d = sda;
DELAY();
dat |= (d<<(7-i));
}
return dat;
*/
}
/******************************************************************************************************************************************
* 函数名称: I2CDoAck()
* 功能说明: 在应答位位置产生应答,从而继续连续传输
* 输 入: 无
* 输 出: 无
******************************************************************************************************************************************/
void SI2CDoAck(void)
{
SCL_0;
SDA_OUT;
SDA_0; //sda = 0; /拉低数据线,即给于应答
delay_us(7);
SCL_1; //scl = 1;
delay_us(7);
SCL_0; //scl = 0;
}
/******************************************************************************************************************************************
* 函数名称: I2CNoAck()
* 功能说明: 在应答位位置不产生应答,从而终止连续传输
* 输 入: 无
* 输 出: 无
******************************************************************************************************************************************/
void SI2CNoAck(void)
{
SCL_0;
SDA_OUT;
SDA_1; // sda = 1; 不拉低数据线,即不给于应答
delay_us(7);
SCL_1; // scl = 1;
delay_us(7);
SCL_0; // scl = 0;
}
/******************************************************************************************************************************************
* 函数名称: I2CIsAck()
* 功能说明: 检测从机应答位
* 输 入: 无
* 输 出: uint8_t 0=ACK_OK 从机产生了应答;1=ACK_NO 从机没有产生应答
******************************************************************************************************************************************/
uint8_t SI2CIsAck(void)
{
uint8_t i;
SDA_OUT;
SDA_1; // sda = 1; 释放数据线
delay_us(4);
SDA_IN;
SCL_1; // scl = 1;
delay_us(4);
while(SDA_X){
i++;
if(i>250){
SI2C_Stop();//数据线未被拉低,即未收到应答
return 1;
}
}
SCL_0;
return 0;
}
#include "i2c.h"
#include "at24c32.h"
/*************************************************************
* 函数名:at24cxx_Wite_Data(uint8_t addr,uint8_t data)
* 输入参数:addr = 要写入的地址
* data = 要写入的数据
* 输出参数:无
*************************************************************/
void at24cxx_Write_Data(uint16_t addr,uint8_t data) // 将数据data写入指定地址Addr
{
SI2C_Start(); //开始I2C通讯
SI2C_Send(0xA0); //发送EEPROM器件写入地址
SI2CIsAck(); //等待应答
SI2C_Send(addr>>8); //发送高8位地址
SI2CIsAck(); //等待应答
SI2C_Send(addr%256); //发送低8位地址
SI2CIsAck(); //等待应答
SI2C_Send(data); //发送数据
SI2CIsAck(); //等待应答
SI2C_Stop(); //结束I2C通讯
delay_us(4);
}
/*************************************************************
* 函数名:at24cxx_Read_Data(uint8_t addr)
* 输入参数:addr = 要读取的地址
* 输出参数:data = 读出的数据
*************************************************************/
uint8_t at24cxx_Read_Data(uint16_t addr) // 读指定地址Addr里的数据Data
{
uint8_t data=0x00;
SI2C_Start(); //开始I2C通讯
SI2C_Send(0xA0); //发送EEPROM器件地址
SI2CIsAck(); //等待应答
SI2C_Send(addr>>8); //发送高8位地址
SI2CIsAck(); //等待应答
SI2C_Send(addr%256); //发送低8位地址
SI2CIsAck(); //等待应答
SI2C_Start();
SI2C_Send(0xA1); //发送EEPROM器件读取地址
SI2CIsAck();
data = SI2C_Receive(); //读一字节数据
SI2CDoAck();
SI2C_Stop();
delay_us(4);
return data;
}
/*************************************************************
* 函数名:at24cxx_Page_Write(uint8_t addr,uint8_t *buff,uint8_t size)
* 输入参数:addr = 要写入的起始地址
* *buff= 要写入的数组指针
* size = 数组的长度
* 输出参数:无
*************************************************************/
void at24cxx_Page_Write(uint16_t addr,uint8_t *buff,uint8_t size) // 将数据buff数组写入指定起的始地址Addr
{
uint8_t i;
SI2C_Start(); //开始I2C通讯
SI2C_Send(0xA0); //发送EEPROM器件写入地址
SI2CIsAck(); //等待应答
SI2C_Send(addr>>8); //发送高8位地址
SI2CIsAck(); //等待应答
SI2C_Send(addr%256); //发送低8位地址
SI2CIsAck(); //等待应答
for(i=0; i<size; i++){
SI2C_Send(buff); //发送数据
SI2CIsAck(); //等待应答
}
SI2C_Stop(); //结束I2C通讯
delay_us(4);
}
/*************************************************************
* 函数名:at24cxx_Page_Read(uint8_t addr)
* 输入参数:addr = 要读取的地址
* 输出参数:data = 读出的数据
*************************************************************/
uint8_t at24cxx_Page_Rea(uint16_t addr,uint8_t size)// 读指定起始地址Addr里的数据到buff
{
uint8_t i,buff;
SI2C_Start(); //开始I2C通讯
SI2C_Send(0xA0); //发送EEPROM器件地址
SI2CIsAck(); //等待应答
SI2C_Send(addr>>8); //发送高8位地址
SI2CIsAck(); //等待应答
SI2C_Send(addr%256); //发送低8位地址
SI2CIsAck(); //等待应答
SI2C_Start();
SI2C_Send(0xA1); //发送EEPROM器件读取地址
SI2CIsAck();
for(i=0; i<size; i++){
buff = SI2C_Receive();//读一字节数据
SI2CDoAck();
}
SI2C_Stop();
delay_us(4);
return *buff;
}
还希望您支持一下:
https://www.stmcu.org.cn/module/forum/thread-622444-1-1.html
hujjj 发表于 2019-12-8 09:30
还希望您支持一下:
https://www.stmcu.org.cn/module/forum/thread-622444-1-1.html
这两天准备调试I2C,谢谢分享 若调试不成功,则我再抽空在STM32F030开发板上测试,关键就是延时要符合要求,不同主频的单片机,延时会有差异,超出范围则会影响到I2C读写。
页:
[1]
2