使用寄存器的STM32F401xx I2C驱动程序

问题描述 投票:0回答:1

我想在

STM32F401xx MCU
中使用两个
proteus
。其中一个是成为
master
,另一个是成为
slave

这是我给大师的代码:

使用 (

MicroC Pro For Arm
) 程序。

 #include <stdint.h>
 #include <stdio.h>
 uint8_t temp=0;
 void begin(uint8_t addr);
 void end(void);
 void Write (uint8_t dat);
void main() {
       // Enable the I2C CLOCK and GPIO CLOCK
          RCC_APB1ENR |= (1<<21);  // enable I2C CLOCK
          RCC_AHB1ENR |= (1<<1);  // Enable GPIOB CLOCK

          // Configure the I2C PINs for ALternate Functions
          //PB8 and PB9 are connected to I2C1_SCL and I2C1_SDA
          GPIOB_MODER |= (2<<16) | (2<<18);

          GPIOB_OTYPER |= (1<<8) | (1<<9);
          GPIOB_OSPEEDR |= (3<<16) | (3<<18);
          GPIOB_PUPDR |= (1<<16) | (1<<18);
          GPIOB_AFRH |= (4<<0) | (4<<4);
          begin(0x08);
          Write(0x01);
          end();
}

void begin(uint8_t addr){
          //join I2C as a master mode
         //Generate a start condition
            I2C1_CR1 |= (1<<10);  // Enable the ACK
            I2C1_CR1 |= (1<<8);  // Generate START
            while (!(I2C1_SR1 & (1<<0)));  // Wait for SB bit to set to 1

           //Send the Slave Address to the DR Register
            I2C1_DR = addr;  //  send the address
            while (!(I2C1_SR1 & (1<<1)));  //
            temp = I2C1_SR1 | I2C1_SR2;  // read SR1 and SR2 to clear the ADDR bit

            // Reset the I2C
            I2C1_CR1 |= (1<<15); //I2C Peripheral under reset state -->page.493 manual
            I2C1_CR1 &= ~(1<<15); //I2C Peripheral not under reset  -->page.493 manual
            // Program the peripheral input clock in I2C_CR2 Register in order to generate correct timings
            I2C1_CR2 |= (42 <<0);  // PCLK1 FREQUENCY in MHz
            I2C1_CCR = 210<<0;  // Configure the clock control registers
            I2C1_TRISE = 43;  // Configure the rise time register
            I2C1_CR1 |= (1<<0);  // Enable I2C
}
 void end(void)  {

           I2C1_CR1 |= (1<<9);//stop generation
            // Wait until the STOP condition is complete
           while (I2C1_SR2 & (1<<0)); //Cleared by hardware after detecting a Stop condition on the bus
           // Clear the STOP bit
           I2C1_CR1 &= ~(1<<9);
  }

    void Write (uint8_t dat)
  {
          while (!(I2C1_SR1 & (1<<7)));  // wait for TXE bit to set
              I2C1_DR = dat   ;  // wait for BTF bit to set
          while (!(I2C1_SR1 & (1<<2))); //waiting while BTF=0 but when BTF=1; Data byte transfer succeeded

  }

从机代码:

 #include <stdint.h>
 #include <stdio.h>
 uint8_t temp=0;
 uint8_t state =0x00;
 void begin(uint8_t addr);
 void end(void);
 uint8_t Read ();
void main() {
          RCC_APB1ENR |= (1<<21);  // enable I2C CLOCK -
          RCC_AHB1ENR |= (1<<1);  // Enable GPIOB CLOCK
          RCC_AHB1ENR |= (1<<0);  // Enable GPIOA CLOCK
          GPIOA_MODER |=(1<<0); //set pin 0 as output
          // Configure the I2C PINs for ALternate Functions
          //PB8 and PB9 are connected to I2C1_SCL and I2C1_SDA
          GPIOB_MODER |= (2<<16) | (2<<18);

          GPIOB_OTYPER |= (1<<8) | (1<<9);
          GPIOB_OSPEEDR |= (3<<16) | (3<<18);
          GPIOB_PUPDR |= (1<<16) | (1<<18);
          GPIOB_AFRH |= (4<<0) | (4<<4);
          begin(0x08);
          state =  Read();
          end();
        if (state == 0x01){
            GPIOA_ODR |=(1<<0);//set 1 for pin 0
         }
}
void begin(uint8_t addr){
            //join I2C bus as a slave mode
            I2C1_CR2 |= (42<<0);  // PCLK1 FREQUENCY in MHz
            I2C1_OAR1 = addr;//own address interface
            I2C1_CR1 |= (1<<0);  // Enable I2C
            I2C1_CR1 |= (1<<10);  // Enable the ACK ,indicate that a byte is received
}
 void end(void)  {
           I2C1_CR1 |= (1<<9);//stop generation
            // Wait until the STOP condition is complete
           while (I2C1_SR2 & (1<<0)); //Cleared by hardware after detecting a Stop condition on the bus

           // Clear the STOP bit
           I2C1_CR1 &= ~(1<<9);
  }
   uint8_t Read (){
            uint8_t receivedData = 0;
            I2C1_CR1 &= ~(1<<10);  // clear the ACK bit
            temp = I2C1_SR1 | I2C1_SR2;  // read SR1 and SR2 to clear the ADDR bit.... EV6 condition
            I2C1_CR1 |= (1<<9);  // Stop I2C
            while (!(I2C1_SR1 & (1<<6)));  // wait for RxNE to set
            receivedData = I2C1_DR; // Read the data from the DATA REGISTER
        return receivedData;
     }

我尝试在Proteus上进行模拟,但是没有什么可以改变的,

led still off
。所以,我想知道如何在Proteus上制作
simulation
,如果我提供的代码有任何问题,我按照STM32F401xx的
datasheet
manual
来编写这个简单的驱动程序。
proteus
两个 STM32F401xx MCU 的连接:

stm32 i2c stm32f4discovery stm32f4 proteus
1个回答
0
投票

你的主人的“开始”功能做了一些奇怪的事情。

I2C1_TRISE = 43;
after 设置起始位怎么样?您在配置之前尝试使用 I2C。在使用任何应答或起始位之前,TRISE 必须是对 I2C 执行的首要操作之一。整个函数以奇怪的顺序执行操作。

寄存器中的“起始位”不启用起始位功能。当您写入时,它实际上会尝试立即发送一个起始位,并且在您的代码中,它会在您设置 TRISE 之前甚至在启用 I2C 外设之前发生。因此,行为是不可预测的。

我检查了F401的外设,它与F103的外设一模一样,只是F401多了一个用于模拟和数字噪声滤波器控制的寄存器。除此之外,它们是相同的并且完美地映射到另一个。 (根据勘误表,F401 不存在与 F103 相同的带有滤波器故障的硅缺陷)。

以下是我使用该外设的操作顺序,跳过了明显的 GPIO 备用功能设置,因此此处仅注册 I2C。这是 I2C 主设备配置,但一般设置是相同的,从设备配置和主设备配置之间的区别在于以下必要步骤:

  1. 配置GPIO,使能I2C时钟。
  2. 将CR2中的FREQ配置为APBx时钟频率(例如STM32运行在64MHz时为32,因为I2C的APBx运行在32000000Hz)
  3. 在CCR中配置时钟周期倍频器
  4. 配置 TRISE 的上升/下降时间

现在,如果您写入起始位,您可以将数据加载到 DR 并将其作为主设备发送。到目前为止,您不需要向 Start 位写入任何内容,也不需要向 ACK 位写入任何内容,这些位用于正在进行的通信,而不是用于配置。

对于从机,您可以进行类似的设置,但显然还需要配置其从机地址。

我觉得你太着急了。从主 MCU 开始,确保您首先可以在 I2C 线路上看到一些内容。

© www.soinside.com 2019 - 2024. All rights reserved.