大家好,
许多天来,我一直在努力让I2C在STM32F401CE上工作(在PROTEUS中模拟)。
USART工作得很好,但I2C还没有!我使用默认值,HSI 16MHz作为源时钟,没有预分频器。
我需要你的帮助
我初始化I2C1并发送启动条件的代码是:
void i2c1_init(){
// Enable clocks to the peripherals
RCC -> APB1ENR |= 1<<21; // Enable I2C1 clock
RCC -> AHB1ENR |= 1<<1; // Enable GPIOB clock
// set pins B6=SCL and B7=SDA to Alternate Function, Pull-up enabled, Open-Drain and high speed
GPIOB -> MODER = 2<<2*7 | 2<<2*6; //MODER7/6[1:0] = 10 => Alternate function mode
GPIOB -> OTYPER = 1<<1*7| 1<<1*6; // B6/7 = 1 => Output open-drain
GPIOB -> OSPEEDR = 3<<2*7 | 3<<2*6; // OSPEEDR7/6[1:0] = 11 => High speed
GPIOB -> PUPDR = 1<<2*7 | 1<<2*6; // PUPDR7/6[1:0] = 01 => Pull-up
GPIOB -> AFRL = (4 << 4*7) | (4 << 4*6); //AFRL7/6[3:0] = 0100 => AF4 (I2C1)
// initialization steps:
I2C1 -> CR1 |= 1<<15; // SWRST (bit15) = 1 => Enable the software reset
I2C1 -> CR1 &= ~(1<<15); // then immediately resetting the SWRST bit.
I2C1 -> CR2 = 16; // FREQ[5:0] (Bits 5:0) = 16 => Peripheral clock frequency = 16 MHz// other bits = 0 => Interrupts and DMA disabled
//I2C1 -> OAR1 = 0x30; // Own address in slave mode only
// set SCL clock: Thigh = Tlow = CCR * TPCLK1 (here TPCLK1 = 1/16 MHz)
// For 100kHz, Thigh = Tlow = 5uS => CCR = (5/0.0625) = 80
I2C1 -> CCR = 80; // F/S (Bit 15) = 0 => standard master mode// CCR[11:0] (Bits 11:0) = 80 => SCL clock = 100kHz
I2C1 -> TRISE |= 11; // TRISE[5:0] (Bits 5:0) = 9 => Maximum rise time in standard mode
I2C1 -> CR1 |= 1; // PE (bit0) = 1 => Enable the peripheral
}// send a start condition and slave address
void I2C1_Start(char address)
{
uint16_t reg; //I2C1->CR1 |= (1<<10>
I2C1 -> CR1 |= 1<<8; // START (Bit 8) = 1 => start generation (and enter master mode)
while(!(I2C1 -> SR1 & 1<<0)); // wait until SB (Bit 0) = 1 => Start condition generated
reg = I2C1 -> SR1; // MUST read SR1 reg first
// then send the address to clear SB bit
I2C1 -> DR = (address << 1) | 0x00; // write address in DR reg
while(!(I2C1 -> SR1 & 1<<1)); // wait until ADDR (Bit 1) = 1 => End of address transmission
// ADDR bit is cleared by software reading SR1 followed by reading SR2
reg = I2C1 -> SR1;
reg = I2C1 -> SR2; //In datasheet p499: TxE is not set during address phase ?!
//while(!(I2C1 -> SR1 & 1<<7 xss=removed> Data register empty }void main(){
i2c1_init();
I2C1_Start(0x60); for (;;) ;
}
附完整项目
请帮忙
编辑:
要构建代码,请在“periph.h”中去掉第33行的注释。
EDIT2(编辑2):
解决了的
PROTEUS中STM32F401CE的I2C模块存在缺陷!!
我为ATMEGA328测试了它,它工作得很好。
无论如何,PROTEUS确实是一个很棒的工具。
GPIOB -> MODER = 2<<2>
GPIOB -> OTYPER = 1<<1>
GPIOB -> OSPEEDR = 3<<2>
GPIOB -> PUPDR = 1<<2>
GPIOB -> AFRL = (4 << 4>
有没有什么好的理由不使用C宏 ?
有什么好的理由不使用STM头文件吗?
我的天哪,至少要使用cmsis头文件和宏定义的!
怎么说呢?是人就会犯错。
举个例子:
你确定 1<<15 是 SWRST? 也许可能是 1<<14. Or 1<<13?
或者再过2个月,然后再次打开此项目。如果你长时间不再做这个项目,你会很难去查看出所有的东西。
现在它有问题了,你可以来小平头电子技术社区寻求帮助(没关系!)。
但是。。也许你的代码错了。。。还是其中一个错误了?
现在到处都有40个BIT位。
这不是寻求帮助,这几乎是一次大排查,要求任何人打开RM并检查每个BIT位以确保一切正常。。。
完全浪费时间
但使用CMSIS标头会更好:
I2C1 -> CR1 |= I2C1_CR1_SWRST;
I2C1_CR1_SWRST解释了一切:
-用于I2C1
-用于CR1
-这是SWRST位
因此,任何错误都很容易检测到:
I2C1 -> CR1 |= I2C2_CR1_SWRST;
I2C1 -> CR1 |= I2C1_CR1_POTATO;
I2C1 -> CR2 |= I2C1_CR1_SWRST;
CMSIS标头是由ARM自己制作的,它不是任何类型的库,您仍将在裸机级别进行编码。
无需重复造轮子
只需搜索“stm32 F4 baremetal i2c”:
https://github.com/fcayci/stm32f4-bare-metal/blob/master/projects/i2c/i2c.c
MCU模拟器通常不能完美地模拟所有外围设备。该代码可能在真正的STM32上运行良好
一周热门 更多>