据说stm32 iic 缺陷的iic很鸡肋这是真的吗

【菜鸟入门】stm32 之 iic - [ STM32开发 ] - 看云
纠结了两天,终于重新开始写了,这两天一直卡在硬件iic上,由于硬件iic是比较难啃的一块骨头,问题一大堆,明明感觉配置好,测试时,一会出这个问题,一会出那个问题,哎,说多了都是泪。。。。
最后木有办法了,总不能吊死在一棵树上吧,然后就写了个模拟的iic的,由于对iic研究和应用的比较多(我们实验室的设备都是iic通信的,所有设备的驱动都是我来写的),所以在搞这个的时候得心应手,一个小时就把所有的搞定了,有花了1个小时把eeprom(at24c02)调通;
我大致测了下,我的板子上的eeprom电路类似这个:
所以我要做的是就是把PB6配置称时钟线SCL,PB7配置成数据线SDA
这里我们再配置输出的时候,要把管脚配置成 General purpose output push-pull模式,具体原因看datasheet关于管脚配置的那章口头,说的很清楚;
先给大家看看我的头文件里面的定义
#ifndef __IIC_H__
#define __IIC_H__
#define INPUT
#define OUTPUT 0x3
/* Config GPIOx */
#define IIC
#define SCL_BIT
#define SDA_BIT
/*Set & Get GPIOx Value*/
#define SET_SDA(a)
IIC-&ODR |= 1&&SDA_BIT;\
IIC-&ODR &= ~(1&&SDA_BIT);\
#define SET_SCL(a)
if(a) IIC-&ODR |= 1&&SCL_BIT;\
IIC-&ODR &= ~(1&&SCL_BIT);\
#define SDA_OUT
IIC-&CRL &= ~((unsigned int)0xf&&(4*SDA_BIT));\
IIC-&CRL |= (unsigned int)OUTPUT&&(4*SDA_BIT);\
#define SDA_IN
IIC-&CRL &=
~((unsigned int)0xf&&(4*SDA_BIT));\
IIC-&CRL |= (unsigned int)INPUT&&(4*SDA_BIT);\
#define SDA_VAL
(IIC-&IDR&(1&&SDA_BIT))
#define SDA_H
SET_SDA(1)
#define SDA_L
SET_SDA(0)
#define SCL_H
SET_SCL(1)
#define SCL_L
SET_SCL(0)
#define DELAY
delay_us(10)
#define SLAVE_ADDR
#define IIC_READ
#define IIC_WRITE
extern int iic_init(void);
extern void iic_start(void);
extern void iic_stop(void);
extern void iic_send_ack(unsigned char ack);
extern unsigned char iic_recv_ack(void);
extern void iic_send(unsigned char bit);
extern unsigned char iic_send_byte(unsigned char dat);
extern unsigned char iic_recv(void);
extern unsigned char iic_recv_byte(void);
extern int iic_send_str(char str[],int len);
extern void iic_recv_str(char str[],int len);
下面是iic的应用函数
#include &stm32f10x.h&
#include "init.h"
#include "iic.h"
int iic_init()
RCC-&APB2ENR |= 1&&3;
//Set Clock for GPIOB
IIC-&CRL &= ~((unsigned int)0xf&&(4*SCL_BIT));
IIC-&CRL |= (unsigned int)OUTPUT&&(4*SCL_BIT);
//config scl
IIC-&CRL &= ~((unsigned int)0xf&&(4*SDA_BIT));
IIC-&CRL |= (unsigned int)OUTPUT&&(4*SDA_BIT);
//config sda
void delay5us()
/* iic start */
void iic_start()
SDA_H;DELAY;
SDA_L;DELAY;
/* iic stop */
void iic_stop()
SCL_L;SDA_L;
SCL_H;DELAY;
SDA_H;DELAY;
* iic send ack
* ack (0:ACK 1:NAK)
void iic_send_ack(unsigned char ack)
SDA_OUT;SCL_L;
if(ack == 0x00) SDA_L;
if(ack == 0x01) SDA_H;
SCL_H;DELAY;
SCL_L;DELAY;
/* receive ack */
unsigned char iic_recv_ack()
u32 val = 0;
SCL_H;DELAY;
val = SDA_VAL;
SCL_L;DELAY;
return (val!=0 ? 1:0);
/* send one bit*/
void iic_send(unsigned char bit)
if(bit == 0x01) SDA_H;
SCL_H;DELAY;
SCL_L;DELAY;
/* send one byte */
unsigned char iic_send_byte(unsigned char dat)
unsigned char i = 0;
for(i=0; i&8; i++)
if(dat & 0x80)
iic_send(0x01);
iic_send(0x00);
dat &&= 1;
/* iic receive bit */
unsigned char iic_recv()
u32 bit = 0;
SCL_H;DELAY;
bit = SDA_VAL;
SCL_L;DELAY;
return (bit!=0 ? 1:0);
/* iic receive byte */
unsigned char iic_recv_byte()
unsigned char dat = 0;
for (i=0; i&8; i++)
dat &&= 1;
dat |= iic_recv();
int iic_send_str(char str[],int len)
for(i=0; i& i++)
iic_send_byte(str[i]);
if(iic_recv_ack())
void iic_recv_str(char str[],int len)
for(i=0; i& i++)
str[i]=iic_recv_byte();
iic_send_ack(0);
str[i] = '\0';
就这多,关于iic协议的解析请看我的百度博客:ie_code
非常好的分析:
蓝桥杯-嵌入式交流群
页面正在加载中STM32两轮平衡小车——传感器IIC协议
上传时间为:
&上一篇主要讲述了如何对电机进行控制,接下来就该进行传感器相关的讲解了,而对于传感器部分,我是使用的MPU6050+HMC5883结合。而MPU6050呢又可以将HMC5883作为他的从机(我是这么理解的,也不知对不对)。传感器的数据通信是使用的IIC通信协议,IIC通信协议的最大好处呢就是只需要使用两个引脚就可以进行数据的交换和控制;还有就是它可以一对多,也就是说一个主机对应多个从机,每次主机需要通信时需要先发送从机地址。但是他也有他的缺点就是传输数度最大400K,而且仅适用于板上数据通信,因为其传输的距离比较有限。& IIC的连接方式和数据通信协议图如下所示(借用于百度):& 对于IIC的通信和串口一样STM32也有其通信的相关接口,但是由于前段时间STM32的IIC通信让人不是很满意(偶尔无故进入死循环),所以现在大部分人员都还是使用的模拟IIC,而且网上相关代码很多都是大同小异。接下来我就将相关主要代码贴上。
&&IIC引脚初始化:GPIO_InitTypeDef GPIO_InitS
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//配置PB6 PB7 为开漏输出
刷新频率为10Mhz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//应用配置到GPIOB
GPIO_Init(GPIOB, &GPIO_InitStructure);& IIC数据引脚输入输出改变:
#define IIC_SCL
PBout(6) //SCL
#define IIC_SDA
PBout(7) //SDA
#define READ_SDA
接下来就是各种函数:void IIC_Start(void)
SDA_OUT();
//sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
void IIC_Stop(void)
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
u8 IIC_Wait_Ack(void)
u8 ucErrTime=0;
//SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
ucErrTime++;
if(ucErrTime&50)
IIC_Stop();
delay_us(1);
IIC_SCL=0;//时钟输出0
void IIC_Ack(void)
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
void IIC_NAck(void)
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
void IIC_Send_Byte(u8 txd)
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t&8;t++)
IIC_SDA=(txd&0x80)&&7;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
u8 IIC_Read_Byte(unsigned char ack)
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i&8;i++ )
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive&&=1;
if(READ_SDA)receive++;
delay_us(2);
IIC_Ack(); //发送ACK
IIC_NAck();//发送nACK
unsigned char I2C_ReadOneByte(unsigned char I2C_Addr,unsigned char addr)
unsigned char res=0;
IIC_Start();
IIC_Send_Byte(I2C_Addr);
//发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(addr); res++;
//发送地址
IIC_Wait_Ack();
//IIC_Stop();//产生一个停止条件
IIC_Start();
IIC_Send_Byte(I2C_Addr+1); res++;
//进入接收模式
IIC_Wait_Ack();
res=IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
u8 IICreadBytes(u8 dev, u8 reg, u8 length, u8 *data){
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev);
//发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg);
//发送地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(dev+1);
//进入接收模式
IIC_Wait_Ack();
for(count=0;count&count++){
if(count!=length-1)data[count]=IIC_Read_Byte(1);
//带ACK的读数据
data[count]=IIC_Read_Byte(0);
//最后一个字节NACK
IIC_Stop();//产生一个停止条件
u8 IICwriteBytes(u8 dev, u8 reg, u8 length, u8* data){
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev);
//发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg);
//发送地址
IIC_Wait_Ack();
for(count=0;count&count++){
IIC_Send_Byte(data[count]);
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
return 1; //status == 0;
u8 IICreadByte(u8 dev, u8 reg, u8 *data){
*data=I2C_ReadOneByte(dev, reg);
unsigned char IICwriteByte(unsigned char dev, unsigned char reg, unsigned char data){
return IICwriteBytes(dev, reg, 1, &data);
u8 IICwriteBits(u8 dev,u8 reg,u8 bitStart,u8 length,u8 data)
if (IICreadByte(dev, reg, &b) != 0) {
u8 mask = (0xFF && (bitStart + 1)) | 0xFF && ((8 - bitStart) + length - 1);
data &&= (8 - length);
data &&= (7 - bitStart);
return IICwriteByte(dev, reg, b);
u8 IICwriteBit(u8 dev, u8 reg, u8 bitNum, u8 data){
IICreadByte(dev, reg, &b);
b = (data != 0) ? (b | (1 && bitNum)) : (b & ~(1 && bitNum));
return IICwriteByte(dev, reg, b);
这个家伙很懒,什么都没有留下。
作者其它经验
苏州灵动帧格网络科技有限公司 版权所有. 苏ICP备号-2勉强调通了stm32硬件i2c,发送接收一个字节|我爱单片机 - 数码之家
查看完整版本: [--
&Pages: ( 2 total )
赞助商链接
经过网上大神们的指导和自己两天的努力,i2c硬件基本调通了。。。stm32f103的i2c的确是有些bug的,主要是输入时钟频率这里,不能太高。还有芯片手册很难懂啊。但是为了不浪费这一功能,果断在各个论坛学习,勉强写了发送接收一个字节的程序。硬件本身的bug,需要编程避免,而且稳定性不是非常好。还好,对eeprom来说能凑合着用。二楼上程序
赞助商链接
使用函数库 #include&stm32f10x.h&u8void i2c_init(){ I2C_InitTypeDef I2C_S RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); I2C_Struct.I2C_ClockSpeed=100000; I2C_Struct.I2C_Mode=I2C_Mode_I2C ; I2C_Struct.I2C_DutyCycle=I2C_DutyCycle_2; I2C_Struct.I2C_Ack=I2C_Ack_E&&&&&&&&&&//使能应答位 I2C_Struct.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit&& ;&&I2C_Init&&( I2C1, &I2C_Struct); &&&&I2C_Cmd(I2C1,ENABLE);&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&& void gpio_init()&&&&{GPIO_InitTypeDef GPIO_S
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);&&&&GPIO_Struct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;&&&& GPIO_Struct.GPIO_Mode=GPIO_Mode_AF_OD;&&&& GPIO_Struct.GPIO_Speed= GPIO_Speed_50MHz;&&&& GPIO_Init(GPIOB,&GPIO_Struct);}void I2C_WaitEepromStandbyState(u8 id)&&&&&&&& //防守函数,非常重要{&&&&vu16 SR1_Tmp = 0;&&do&&{&&&&/* Send START condition */&&&&I2C_GenerateSTART(I2C1, ENABLE);&&&&/* Read I2C1 SR1 register */&&&&SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);&&&&/* Send EEPROM address for write */&&&&I2C_Send7bitAddress(I2C1, id, I2C_Direction_Transmitter);&&}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));&&&&&&//estimate the value of ADDR&&&&/* Clear AF flag */&&I2C_ClearFlag(I2C1, I2C_FLAG_AF);&&&&}void i2c_write(u8 id,u8 address,u8 byte){// I2C_WaitEepromStandbyState(id); I2C_GenerateSTART&&( I2C1, ENABLE); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));&&&& //ev5 I2C_Send7bitAddress&&( I2C1,id, I2C_Direction_Transmitter); &&while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ));&&//ev6&&I2C_SendData&&( I2C1, address); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING));&&&&&&//ev8&&I2C_SendData&&( I2C1, byte);&&while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));&&&& //ev8_2&&I2C_GenerateSTOP(I2C1, ENABLE);&&}u8 i2c_read(u8 id,u8 address){ u8 I2C_WaitEepromStandbyState(id); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); I2C_AcknowledgeConfig(I2C1, DISABLE); // I2C_Send7bitAddress&&( I2C1,id, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData&&( I2C1, address); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING)); I2C_GenerateSTART(I2C1, ENABLE);&&&&&&//restart&&while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //ev5 I2C_Send7bitAddress&&( I2C1,id, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //ev6 I2C_GenerateSTOP(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)); //ev7 temp=I2C_ReceiveData(I2C1);}int main(void){&&i2c_init();&&gpio_init();&&i2c_write(0xa0,3,0xab);&&data=i2c_read(0xa0,3);&&while(1); }&&&&
赞助商链接
这个也设个中奖有什么用呢?
这个表示不懂,在学51的
现在STM32的I2C BUG基本已经解决了应用不高的场合可以试下STM32F0系列的,跟51一个价了。
学了51,stm32我也马上要开始学了
慢慢的你就成高手了,
今年争取入门STM...现在玩STM8..
争取中奖,不玩stm32,玩lpc的
:现在STM32的I2C BUG基本已经解决了应用不高的场合可以试下STM32F0系列的,跟51一个价了。 ( 12:03) 有f0系列的资料吗,谢谢
:争取中奖,不玩stm32,玩lpc的 ( 18:54) lpc的怎么样?中文资料多吗,芯片内部资源咋样
对了,忘记发参考资料了,这里
这个也设个中奖
有什么用呢?同觉得也许楼主想学知识吧。
正准备学习STM32。
:lpc的怎么样?中文资料多吗,芯片内部资源咋样&( 22:10)&nxp资源丰富,要的话我可以发给你资料和模板给你研究研究,我最经只研究lpc213x和lpc23xx系列的mo的lpc1114也玩过一阵子
我也看了一下STM32的资料,不过感觉好难。现在正在学51
:nxp资源丰富,要的话我可以发给你资料和模板给你研究研究,我最经只研究lpc213x和lpc23xx系列的mo的lpc1114也玩过一阵子 谢了,我把邮箱留给你。还请多多指教哦
坛里钻研stm32的人真心不多啊。。。&&
坛里钻研stm32的真心不多啊。。。&&
有些时序图真费脑子,拿分 闪
我当年高硬件IIC也搞了很久。哎
我是来挣M的!!!!
我是来挣M的!!!!
我是来挣M的!!!!
我是来挣M的!!!!
不过感觉好难。现在正在学51
:不过感觉好难。现在正在学51 ( 09:58) 使用库函数能简单一些,不过最好对寄存器有比较清晰的了解。
正在学习STM32,不过I2C都是模拟的,没用硬件。
为了M币,继续。
为了M币,继续。第三次。
我有个红牛版,正想试试I2C,谢谢!
只会51的飘过
打算把51吃透了再学stm
回复本帖可获得3M币奖励!每人最多可获奖1次,奖池剩余24M币 (中奖几率50%)
:我有个红牛版,正想试试I2C,谢谢! ( 20:30) 我的就是红牛的,用jlink仿真试了,没有大问题的。
这个不懂,非常想学习。
看来楼主是高兴了 分享喜悦
好好学习,天天向上
哎,最近用的也是stm32f103系列,i2c接的时钟8563,有些批次时间能行有些却不行,看看楼主的经验,希望能解决问题
我也在学STM32,来看看
LZ的程序功能。。??
好牛逼,不会单片机哦
啊!!!stm32硬件IIC有BUG???用了那么久怎么没发现
再说中文资料也很多呀
:哎,最近用的也是stm32f103系列,i2c接的时钟8563,有些批次时间能行有些却不行,看看楼主的经验,希望能解决问题 ( 10:03) 希望对你有帮助。
:再说中文资料也很多呀 ( 21:27) 按照芯片手册上的,会很不稳定。
:[表情] LZ的程序功能。。?? ( 10:05) 就是往eeprom里面写数据,然后读数据。
回复本帖可获得3M币奖励!每人最多可获奖1次,奖池剩余12M币 (中奖几率50%)。1
回复本帖可获得3M币奖励!每人最多可获奖1次,奖池剩余12M币 (中奖几率50%) 2
查看完整版本: [--
Powered by
Gzip enabled请问模拟的iic时序读取数据的时候错误,有什么办法防止!
- 电子工程师超级俱乐部
请问模拟的iic时序读取数据的时候错误,有什么办法防止!
我现在有个iic电量计,里面有crc效验,但是读取出来的数据还是有ffff,我怀疑是时序的问题1,请问这个能有什么办法制止吗?
估计你有麻烦了;STM8S的IIC很烦;我是试过其它ARM的I2C,几乎不出错;但STM8S的IIC表现非常奇怪;有时正常,有时异常,异常时有可能出现总线忙的现象,即SDA或SCL被拉低了;IIC的输出完全不正常;IIC本身并不复杂,但STM32F10X,检测ACK信号时不稳定,据说这个ACK很短暂,一旦ACK出问题,和ACK绑在一起的其它标志都异常了;最莫名其妙的是I2C的端口分明是配置为I2C功能,但再读芯片时发现已经被改掉了;重新上电都不可恢复。(上面说是STM32F1XX,其实STM8S和STM32F1XX的情况是一样的);所以有些专家们不推荐使用ST的IIC模块,而是用IO端口模拟I2C的功能;我没有仔细检测,到底发生了什么,但试了试我害怕了,我也IO模拟了。据说ST新推出的STM32F0,已经重新设计了I2C模式;你可以换成STM32F0试试看;成本高不了3块钱,别出乱了,是吧。伤不起
略懂社热议
你测试一下1)是不是每次写完再读出来都是这些数字?2)试试换一个地址写入再读出,还是这些数字?
模拟 I2C, 有可能主机端的检测 ACK 信号会被忽略, 楼主检查一下, 或者用调试器跟踪一下出错情况
只能说STM8S IIC的状态位太搞了,实在搞不清楚它的标志位的作用时间,并且还有那么多的标志位,如果程序判断出点差错,就会被搞死,还不知道怎么死的。
略懂社热议
等待您来回答
该问题来自:
21ic论坛是中国注册用户最多、最活跃、最权威的电子技术论坛,众多圈内牛人常驻答疑,是电子工程师学习、发展的乐园。
QQ空间领域专家
&SOGOU - 京ICP证050897号>> STM32 模拟IIC
STM32 模拟IIC
所属分类:
下载地址:
i2c.zip文件大小:2.75 kB
分享有礼! 》
请点击右侧的分享按钮,把本代码分享到各社交媒体。
通过您的分享链接访问Codeforge,每来2个新的IP,您将获得0.1 积分的奖励。
通过您的分享链接,每成功注册一个用户,该用户在Codeforge上所获得的每1个积分,您都将获得0.2 积分的分成奖励。
避开STM32自带IIC硬件部分的操作,使用模拟IIC总线进行相关器件的操作,目前在PCF8563上已运行通过。
Sponsored links
源码文件列表
温馨提示: 点击源码文件名可预览文件内容哦 ^_^
12.32 kB 09:41
(提交有效评论获得积分)
评论内容不能少于15个字,不要超出160个字。
淡水鱼的水刚开始学习,希望有帮助!谢谢~~
评价成功,多谢!
下载i2c.zip
CodeForge积分(原CF币)全新升级,功能更强大,使用更便捷,不仅可以用来下载海量源代码马上还可兑换精美小礼品了
您的积分不足,优惠套餐快速获取 30 积分
10积分 / ¥100
30积分 / ¥200原价 ¥300 元
100积分 / ¥500原价 ¥1000 元
订单支付完成后,积分将自动加入到您的账号。以下是优惠期的人民币价格,优惠期过后将恢复美元价格。
支付宝支付宝付款
微信钱包微信付款
更多付款方式:、
您本次下载所消耗的积分将转交上传作者。
同一源码,30天内重复下载,只扣除一次积分。
鲁ICP备号-3 runtime:Elapsed:162.819ms - init:0.3;find:2.8;t:1.7;tags:0.3;related:57.6;comment:2.7;
登录 CodeForge
还没有CodeForge账号?
Switch to the English version?
^_^"呃 ...
Sorry!这位大神很神秘,未开通博客呢,请浏览一下其他的吧

我要回帖

更多关于 stm32 iic 缺陷 的文章

 

随机推荐