You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F103C8与PCA9685通信时I2C_DR寄存器无法自动清除问题

STM32F103C8 操作I2C_DR寄存器发送数据时数据残留问题

我用STM32F103C8搭配PCA9685,通过直接操作I2C_DR寄存器的方式在I2C总线上发送数据。现在遇到的问题是:写入数据后,I2C_DR寄存器里的数据会残留——按协议本该在数据发送完成后自动清除,但我的代码里没实现这个自动清除的逻辑,不知道问题出在哪。

逻辑分析仪捕获的I2C信号如下:
I2C总线信号捕获结果

我的代码如下:

#include "stm32f10x.h"

void I2C_Write_Single(int device_address, int mem_address, int data);
void I2C_Restart(int device_address, int data);

uint32_t temp = 0;

int main(){
/*********STEPS FOLLOWED*********
1. Enable the I2C Clock and GPIO Clock
2. Configure I2C Pins for alternate function
3. Reset I2C
4. Program the peripheral input clock in I2C_CR2 Register in order to generate correct timing
5. configure the clock control register
6. Configure the rise time register
7. Program the I2C_CR1 register to enable the peripheral
*/  
    
    I2C1->CR1 |= (1<<15);
    I2C1->CR1 &=~ (1<<15);  
    
    //GPIO Port B enabled
    RCC->APB2ENR |= (1<<3);
    //I2C enabled
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    //timer enable TIM2 (general timer)
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
    
    //TIM2 config
    TIM4->PSC |= 0;
    TIM4->ARR |= 71;
    TIM4->CR1 |= TIM_CR1_URS;
    TIM4->DIER |= TIM_DIER_UIE;
    TIM4->EGR |= TIM_EGR_UG;
    
    NVIC_EnableIRQ(TIM4_IRQn);  
    
    //Mode register set for 50MHz (B7 and B6)
    GPIOB->CRL |= (1<<25) | (1<<24);
    GPIOB->CRL |= (1<<29) | (1<<28);
    //GPIO B7 and B6 pin registers (alternate function open drain) 
    GPIOB->CRL |= (1<<27) | (1<<26);
    GPIOB->CRL |= GPIO_CRL_CNF7_1 | (1<<30);    
    
    //Peripheral frequency (APB1) 36MHz (its written in datasheet)
    I2C1->CR2 |= 36 ;
    //I2C clock control register
    /* to calculate CCR (Clock Control Register) CCR= [((I2C_Period)/2)/(APB1_Period)] 
    I2C period is 400KHz(from user manual page 781) Ti2c= 1/100K = 10us
    APB1 Period = 1/36 = 27.7 ns
    CCR = [(5000ns)/(27.7ns)]= 180
    */
    I2C1->CCR |= 180;
    I2C1->TRISE |= 37 ; // TRise = CR2+1 (from datasheet page 783)
    I2C1->CR1 |= I2C_CR1_ACK;
    I2C1->CR1 |= I2C_CR1_PE;    
    
    I2C_Restart(0x00, 0x06);    

    I2C_Write_Single( 0x80, 0x00, 0x08); //SLEEP bit gets cleared so we can get PWM signal
    
    I2C_Write_Single( 0x40, 0x00, 1<<6); //EXTERNAL CLOCK bit gets cleared so we can get PWM signal
     
    I2C_Write_Single( 0x40, 0xFE, 0XB0); // PRE_SCALE registers set to 0xB0 that way PWM Frequency will be 50 MHz (PCA9685 Datasheet page 9)
    
    // PWM delay %0 so LED0_ON_L and LED0_ON_H registers set to 0
    I2C_Write_Single( 0x40, 0x06, 0X01);
    I2C_Write_Single( 0x40, 0x07, 0X99); 
    
    // 1.5ms PWM will be given (1,5/20)*4096=307 LED0_OFF_H= 3 (decimal) LED0_OFF_H= 07 (decimal)
    I2C_Write_Single( 0x41, 0x09, 0X08);
    I2C_Write_Single( 0x41, 0x08, 0X00);    
    
    return 0;
}

void I2C_Write_Single(int device_address, int mem_address, int data)
{
    I2C1->CR1 |= I2C_CR1_START; //generate start condition
    while (!(I2C1->SR1 & I2C_SR1_SB)); // we check the SB flag if start bit didn't sent master device will stay in this loop

    I2C1->DR |= device_address  ; // device address is 0x00 
    while (!(I2C1->SR1 & I2C_SR1_ADDR)); // we check ADDR flag. Once there is address mach device will exit the loop
    temp = I2C1->SR1 | I2C_SR2; // we need to clear ADDR bit after we checked the flags. To reset SR1 and SR2 registers we just read them

    while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
    I2C1->DR |= mem_address  ; // MODE1 register (PCA9685 datasheet page 9)
    while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
    
    while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
    I2C1->DR |= data << 1  ; // to set PWM frequency we set SLEEP bit 1 (PCA9685 datasheet page 24)
    while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
    
    I2C1->CR1 |= I2C_CR1_STOP; //generate stop condition
}

void I2C_Restart(int device_address, int data)
{
    I2C1->CR1 |= I2C_CR1_START; //generate start condition
    while (!(I2C1->SR1 & I2C_SR1_SB)); // we check the SB flag if start bit didn't sent master device will stay in this loop

    I2C1->DR |= device_address; // device address is 0x00 
    while (!(I2C1->SR1 & I2C_SR1_ADDR)); // we check ADDR flag. Once there is address mach device will exit the loop
    temp = I2C1->SR1 | I2C_SR2; // we need to clear ADDR bit after we checked the flags. To reset SR1 and SR2 registers we just read them

    while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer
    I2C1->DR |= data; // MODE1 register (PCA9685 datasheet page 9)
    while (!(I2C1->SR1 & I2C_SR1_BTF));//wait for transmit
    while (!(I2C1->SR1 & I2C_SR1_TXE)); // wait for the byte transfer   
    
    I2C1->CR1 |= I2C_CR1_STOP; //generate stop condition    
}

我尝试过手动清除寄存器,但执行I2C1->DR &=~ 0xFF时,主设备会立即向从设备发送0x00数据。


内容的提问来源于stack exchange,提问作者Clyde Xander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:25:55