STM32F407使用PB9和PB10的I2C初始化并使用DMA进行数据收发并且适合实时系统的完整代码,不使用HAL库,使用标准库
时间: 2024-05-04 10:21:16 浏览: 206
STM32F407串口1使用DMA收发数据
以下是使用PB9和PB10的I2C初始化并使用DMA进行数据收发的完整代码,适用于STM32F407,并且不使用HAL库,使用标准库。
首先,需要在stm32f4xx.h文件中定义I2C的寄存器地址:
```c
#define I2C1_BASE (PERIPH_BASE + 0x5400)
#define I2C1 ((I2C_TypeDef *) I2C1_BASE)
#define I2C2_BASE (PERIPH_BASE + 0x5800)
#define I2C2 ((I2C_TypeDef *) I2C2_BASE)
#define I2C3_BASE (PERIPH_BASE + 0x5C00)
#define I2C3 ((I2C_TypeDef *) I2C3_BASE)
```
然后,需要定义I2C的初始化函数:
```c
void I2C_Init(I2C_TypeDef* I2Cx, uint32_t ClockSpeed, uint16_t OwnAddress, uint16_t OwnAddressMask)
{
uint16_t prescaler = 0;
uint16_t duty_cycle = I2C_DutyCycle_2;
// Enable I2Cx clock
if (I2Cx == I2C1)
{
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
}
else if (I2Cx == I2C2)
{
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
}
else if (I2Cx == I2C3)
{
RCC->APB1ENR |= RCC_APB1ENR_I2C3EN;
}
// Reset I2Cx
I2Cx->CR1 |= I2C_CR1_SWRST;
I2Cx->CR1 &= ~I2C_CR1_SWRST;
// Disable I2Cx
I2Cx->CR1 &= ~I2C_CR1_PE;
// Calculate prescaler value
prescaler = (uint16_t)(SystemCoreClock / (ClockSpeed * 2));
I2Cx->CR2 = prescaler & I2C_CR2_FREQ;
// Set duty cycle
I2Cx->CCR = (uint16_t)(prescaler / (ClockSpeed * 3)) & I2C_CCR_CCR;
I2Cx->CCR |= duty_cycle;
// Set own address and mask
I2Cx->OAR1 = OwnAddress << 1;
I2Cx->OAR2 = OwnAddressMask << 1;
// Enable DMA
I2Cx->CR2 |= I2C_CR2_DMAEN;
// Enable I2Cx
I2Cx->CR1 |= I2C_CR1_PE;
}
```
接下来,需要定义I2C的发送和接收函数:
```c
void I2C_Write(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t reg, uint8_t data)
{
// Wait until I2Cx is ready for transmission
while (!(I2Cx->SR1 & I2C_SR1_TXE));
// Send start bit
I2Cx->CR1 |= I2C_CR1_START;
// Wait until start bit is sent
while (!(I2Cx->SR1 & I2C_SR1_SB));
// Send address
I2Cx->DR = addr << 1;
// Wait until address is sent
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
// Clear ADDR flag
(void)I2Cx->SR2;
// Send register address
I2Cx->DR = reg;
// Wait until register address is sent
while (!(I2Cx->SR1 & I2C_SR1_TXE));
// Send data
I2Cx->DR = data;
// Wait until data is sent
while (!(I2Cx->SR1 & I2C_SR1_TXE));
// Send stop bit
I2Cx->CR1 |= I2C_CR1_STOP;
// Wait until stop bit is sent
while (I2Cx->CR1 & I2C_CR1_STOPF);
}
uint8_t I2C_Read(I2C_TypeDef* I2Cx, uint8_t addr, uint8_t reg)
{
uint8_t data = 0;
// Wait until I2Cx is ready for transmission
while (!(I2Cx->SR1 & I2C_SR1_TXE));
// Send start bit
I2Cx->CR1 |= I2C_CR1_START;
// Wait until start bit is sent
while (!(I2Cx->SR1 & I2C_SR1_SB));
// Send address
I2Cx->DR = addr << 1;
// Wait until address is sent
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
// Clear ADDR flag
(void)I2Cx->SR2;
// Send register address
I2Cx->DR = reg;
// Wait until register address is sent
while (!(I2Cx->SR1 & I2C_SR1_TXE));
// Send repeated start bit
I2Cx->CR1 |= I2C_CR1_START;
// Wait until start bit is sent
while (!(I2Cx->SR1 & I2C_SR1_SB));
// Send address with read bit
I2Cx->DR = (addr << 1) | 0x01;
// Wait until address is sent
while (!(I2Cx->SR1 & I2C_SR1_ADDR));
// Clear ACK flag
I2Cx->CR1 &= ~I2C_CR1_ACK;
// Clear ADDR flag
(void)I2Cx->SR2;
// Enable DMA
I2Cx->CR2 |= I2C_CR2_DMAEN;
// Enable DMA receive
I2Cx->CR2 |= I2C_CR2_RD_WRN;
// Set DMA transfer direction
DMA1_Stream0->CR &= ~DMA_SxCR_DIR;
DMA1_Stream0->CR |= DMA_SxCR_DIR_0;
// Set DMA memory address
DMA1_Stream0->M0AR = (uint32_t)&data;
// Set DMA number of data to transfer
DMA1_Stream0->NDTR = 1;
// Enable DMA stream
DMA1_Stream0->CR |= DMA_SxCR_EN;
// Wait until DMA transfer is complete
while (!(DMA1->LISR & DMA_LISR_TCIF0));
// Clear DMA transfer complete flag
DMA1->LIFCR |= DMA_LIFCR_CTCIF0;
// Send stop bit
I2Cx->CR1 |= I2C_CR1_STOP;
// Wait until stop bit is sent
while (I2Cx->CR1 & I2C_CR1_STOPF);
return data;
}
```
最后,需要定义DMA的初始化函数:
```c
void DMA_Init(void)
{
// Enable DMA1 clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
// Reset DMA1 stream0
DMA1->LIFCR |= DMA_LIFCR_CTCIF0 | DMA_LIFCR_CHTIF0 | DMA_LIFCR_CTEIF0 | DMA_LIFCR_CDMEIF0;
// Configure DMA1 stream0
DMA1_Stream0->CR &= ~DMA_SxCR_CHSEL;
DMA1_Stream0->CR |= DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0; // Channel 7
DMA1_Stream0->CR |= DMA_SxCR_PL_1; // Priority high
DMA1_Stream0->CR |= DMA_SxCR_MSIZE_0; // Memory size 8-bit
DMA1_Stream0->CR |= DMA_SxCR_PSIZE_0; // Peripheral size 8-bit
DMA1_Stream0->CR |= DMA_SxCR_MINC; // Memory increment
DMA1_Stream0->CR &= ~DMA_SxCR_PINC; // Peripheral no increment
DMA1_Stream0->CR &= ~DMA_SxCR_CIRC; // Circular mode disabled
DMA1_Stream0->CR &= ~DMA_SxCR_DIR; // Peripheral to memory
DMA1_Stream0->CR |= DMA_SxCR_TCIE; // Transfer complete interrupt enabled
}
```
现在,可以在主函数中调用这些函数来初始化I2C和DMA,并进行数据收发:
```c
int main(void)
{
uint8_t data = 0;
// Initialize I2C
I2C_Init(I2C1, 100000, 0x00, 0x00);
// Initialize DMA
DMA_Init();
// Write data to I2C device
I2C_Write(I2C1, 0xA0, 0x00, 0x01);
// Read data from I2C device
data = I2C_Read(I2C1, 0xA0, 0x00);
while (1)
{
}
}
```
注意:这只是一个简单的示例代码,并且需要根据实际情况进行适当修改。
阅读全文