当前位置: 首页 > news >正文

STM32基础

《STM32学习笔记》

author:lwpigking

学习STM32所写的笔记~!

GPIO

1. 功能概述

  • GPIO是STM32中最基本的外设,用于控制引脚的电平(输出)或读取引脚状态(输入)。

  • 每个GPIO引脚可独立配置为9种模式之一

    输入一般都是用来检测外部信号的,推挽模式和开漏模式也属于输出模式的其中一种,这两个又叫复用推挽和复用开漏,就是STM32芯片引脚上不仅写了PB10,还写了别的东西。

    模式 功能
    浮空输入 不接上拉电阻,也不接下拉电阻,完全处于浮空状态,无信号输入时引脚状态不确定。用来检测微弱信号的变化。
    上拉输入 内接上拉电阻,无外接信号时引脚为默认高电平。用来检测外部信号变为低电平(下降沿触发中断)。
    下拉输入 内接下拉电阻,无外接信号时引脚为默认低电平。用来检测外部信号变为高电平(上升沿触发中断)。
    模拟输入 用于接收模拟信号,要与ADC配合使用。用来测量模拟信号的变化。
    推挽输出 可以输出高电平和低电平。不能使用总线。
    模拟输出 输出模拟信号,与ADC配合使用。
    开漏输出 只能输出低电平和高阻态,输出高电平时要外接上拉电阻。
    推挽模式 具有推挽输出的特性,可用于将GPIO引脚用作特定外设的功能。如USART。
    开漏模式 具有开漏输出的特性,可用于将GPIO引脚用作特定外设的功能。如I2C总线通信。

2. GPIO寄存器

  • 2个配置寄存器(GPIOx_CRL、GPIOx_CRH):每一组GPIO都有16个引脚,0-7号引脚在CRL中,8-15号引脚在CRH中。
    image-20250907113838994

    image-20250907114013451

  • 2个数据寄存器(GPIOx_IDR、GPIOx_ODR)

    image-20250907114234916

    image-20250907114355922

  • 置位/复位寄存器(GPIOx_BSRR)、复位寄存器(GPIOx_BRR)、锁定寄存器(GPIOx_LCKR)

    image-20250907114626935

    image-20250907114652643

    image-20250907114715870

3. 寄存器开发流程

  1. 开启GPIO时钟(RCC_APB2ENR)
  2. 配置GPIO模式(CRL/CRH)
  3. 业务逻辑,比如点亮一个灯:输出数据(ODR)
// created by lwpigking
#include "stm32f10x.h"
int main(void) {// 1.时钟配置RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;// 2.GPIO工作模式的配置GPIOA->CRL &= ~GPIO_CRL_CNF0; // CNF: 00(推挽输出模式)GPIOA->CRL |= GPIO_CRL_MODE0; // MODE: 11(输出模式,最大速度50MHZ)// 3.输出低电平 GPIOA->ODR &= ~GPIO_ODR_ODR0; // PA0引脚输出低电平while(1) {}
}

详解:->是用于访问指向结构体的指针所指向的成员。stm32的源码中对于各个寄存器都有宏定义,比如GPIO_ODR_ODR0,通过|=可以将某一位置1(1|x=1, 0|x得看x),通过&=可以将某一位置0(1=0,0&x=0,1&x得看x)。

4. 实际应用

  • 输出模式:驱动LED、继电器、蜂鸣器、电机驱动等。
  • 输入模式:读取按键、开关状态、外部传感器信号。
  • 复用模式:用于USART、I2C、SPI等外设的引脚功能。

中断系统

1. 功能概述

  • NVIC:嵌套向量中断控制器,管理所有中断的优先级和使能。
  • EXTI:支持外部/事件控制器,用于响应GPIO引脚上的边沿信号(上升沿、下降沿)。
  • 支持中断嵌套,优先级分为抢占优先级和响应优先级。

2. EXTI寄存器

image-20250907133815938

image-20250907134611479

image-20250907134820153

image-20250907134856429

image-20250907134921449

image-20250907134940953

3.寄存器开发流程

  1. 开启GPIO和AFIO时钟
  2. 配置GPIO为输入模式
  3. 配置AFIO_EXTICR,选择中断引脚
  4. 配置EXTI触发方式(上升沿/下降沿)
  5. 使能EXTI中断线
  6. 配置NVIC优先级并使能中断
  7. 编写中断服务函数(ISR),并清除中断标志
#include "key.h"void Key_Init() {// 1. 配置时钟RCC->APB2ENR |= RCC_APB2ENR_IOPFEN;RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;// 2. GPIO工作模式配置 PF10:CNF - 10  MODE - 00GPIOF->CRH &= ~GPIO_CRH_MODE10;GPIOF->CRH |= GPIO_CRH_CNF10_1;GPIOF->CRH &= ~GPIO_CRH_CNF10_0;GPIOF->ODR &= ~GPIO_ODR_ODR10;// 3. AFIO配置引脚复用选择AFIO->EXTICR[2] |= AFIO_EXTICR3_EXTI10_PF;// 4. 配置EXTIEXTI->RTSR |= EXTI_RTSR_TR10; // 上升沿触发EXTI->IMR |= EXTI_IMR_MR10; // 开放中断请求// 5.配置NVICNVIC_SetPriorityGrouping(3); // 全部都是抢占优先级NVIC_SetPriority(EXTI15_10_IRQn, 3);NVIC_EnableIRQ(EXTI15_10_IRQn);}// 中断服务程序
void EXTI15_10_IRQHandler(void) {// 先清除中断挂起标志位EXTI->PR |= EXTI_PR_PR10;// 延时防抖Delay_ms(10);// 判断如果依然保持高电平,就反转LED1的状态if ((GPIOF->IDR & GPIO_IDR_IDR10) != 0) {LED_Toggle(LED1);}}

4.实际应用

  • 按键检测、紧急停止、外部传感器触发
  • 实时响应外部时间,避免轮询浪费CPU资源

USART

1. 功能概述

  • 用于异步串行通信,常用波特率:9600、115200
  • 支持全双工、半双工、单工模式
  • 可配置数据位、停止位、校验位

2. USART寄存器

image-20250907153816831

image-20250907154201556

image-20250907154726479

image-20250907154900039

image-20250907154955569

image-20250907155144243

image-20250907155302189

1. 状态寄存器 (USART_SR) - USART1->SR

这是一个只读寄存器(某些位可由特定操作清除),用于反映 USART 的当前状态。在发送或接收数据前,必须查询这个寄存器的相应位

名称 功能描述
TXE 发送数据寄存器空 (Transmit data register empty) - 0: 数据尚未从 TDR 转移到移位寄存器,未准备好发送新数据 - 1: TDR 寄存器为空,可以写入新的待发送数据 (发送时查询此位)
TC 发送完成 (Transmission Complete) - 0: 发送尚未完成 - 1: 发送已完成(包括停止位) (可通过软件序列或读 SR 写 DR 清除)
RXNE 接收数据寄存器非空 (Read data register not empty) - 0: 未收到数据或数据未读走 - 1: 接收到的数据已存在于 RDR 中,可以读取 (接收时查询此位,通过读 USART1->DR 清除)
IDLE 空闲总线检测 (IDLE line detected) - 0: 未检测到空闲总线 - 1: 检测到空闲总线(收到一帧完整数据后,总线持续高电平) (通过读 SR 再读 DR 清除)
PE 奇偶校验错误 (Parity error) - 0: 无奇偶校验错误 - 1: 检测到奇偶校验错误

最常用的位是 TXE (发送) 和 RXNE (接收)。

2. 数据寄存器 (USART_DR) - USART1->DR

这是一个可读可写的寄存器,但它对应两个不同的物理寄存器:

  • 当您向该寄存器写数据时,实际上是写入发送数据寄存器 (TDR)
  • 当您从该寄存器读数据时,实际上是从接收数据寄存器 (RDR) 读取。
功能
包含要发送或刚接收到的数据。数据的有效位数取决于 USART_CR1 中的 M 位(8位或9位)。

操作:

  • 发送USART1->DR = Data;
  • 接收Data = USART1->DR;

3. 波特率寄存器 (USART_BRR) - USART1->BRR

用于设置 USART 的通信波特率。

计算公式:
波特率 = fCK / (16 * USARTDIV)
其中 USARTDIV 是一个无符号定点数,存储在 USART_BRR 寄存器中。

名称 功能
DIV_Mantissa[11:0] USARTDIV 的整数部分
DIV_Fraction[3:0] USARTDIV 的小数部分

如何计算并设置?
例如,系统时钟 fCK = 72MHz,目标波特率 BaudRate = 115200

  1. 计算 USARTDIVUSARTDIV = 72MHz / (16 * 115200) = 39.0625
  2. 分离整数和小数部分:
    • DIV_Mantissa = integer(39.0625) = 39 = 0x27
    • DIV_Fraction = fractional(0.0625) * 16 = 1 = 0x1
  3. 组合: USART1->BRR = (39 << 4) | 1;0x0271

4. 控制寄存器 1 (USART_CR1) - USART1->CR1

这是最重要的控制寄存器,用于使能 USART 和其主要功能。

名称 功能描述
UE USART 使能 (USART enable) - 0: 禁用 USART - 1: 使能 USART必须置1
M 字长 (Word length) - 0: 1 起始位,8 数据位,n 停止位 - 1: 1 起始位,9 数据位,n 停止位
PCE 奇偶校验控制使能 (Parity control enable) - 0: 禁止奇偶校验 - 1: 使能奇偶校验
PS 奇偶校验选择 (Parity selection) - 0: 偶校验 - 1: 奇校验 (需 PCE=1
PEIE PE 中断使能 (PE interrupt enable)
TXEIE TXE 中断使能 (TXE interrupt enable)
TCIE TC 中断使能 (TC interrupt enable)
RXNEIE RXNE 中断使能 (RXNEIE interrupt enable)
TE 发送器使能 (Transmitter enable) - 1: 使能发送功能发送必须置1
RE 接收器使能 (Receiver enable) - 1: 使能接收功能接收必须置1

最基本配置: UE | TE | RE (使能USART、发送器、接收器)

3. 寄存器开发流程

  1. 开启USART和GPIO时钟
  2. 配置GPIO位复用推挽输出(TX)和浮空输入(RX)
  3. 配置波特率(BRR)
  4. 配置数据帧格式(数据位、停止位、校验位)
  5. 使能USART和发送/接收器
  6. 发送/接收数据(轮询方式或中断方式)
#include "usart.h"void USART_Init(void) {// 1. 配置时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;RCC->APB2ENR |= RCC_APB2ENR_USART1EN;// 2. GPIO工作模式 // PA9(复用推挽输出)CNF:10 MODE:11GPIOA->CRH |= GPIO_CRH_MODE9;GPIOA->CRH |= GPIO_CRH_CNF9_1;GPIOA->CRH &= ~GPIO_CRH_CNF9_0;// PA10(浮空输入) MODE:00 CNF:01GPIOA->CRH &= ~GPIO_CRH_MODE10;GPIOA->CRH &= ~ GPIO_CRH_CNF10_1;GPIOA->CRH |= GPIO_CRH_CNF10_0;// 3. 串口配置USART1->BRR = 0x271; // 波特率 115200USART1->CR1 |= USART_CR1_TE; // 接收使能USART1->CR1 |= USART_CR1_RE; // 发送使能USART1->CR1 |= USART_CR1_UE; // USART使能// 其他配置默认即可}void USART_SendChar(uint8_t ch) {// 判断SR里TXE是否为空while((USART1->SR & USART_SR_TXE) == 0) {}// 向DR写入新的数据USART1->DR = ch;
}uint8_t USART_ReceiveChar(void) {while((USART1->SR & USART_SR_RXNE) == 0) {// 判断空闲帧if (USART1->SR & USART_SR_IDLE) {return 0;}}// 读取已经接收到的数据,等待接收下一个数据return USART1->DR;
}void USART_SendString(uint8_t *str, uint8_t size) {for (uint8_t i = 0; i < size; i++) {USART_SendChar(str[i]);}
}void USART_ReceiveString(uint8_t buffer[], uint8_t *size) {// 定义一个变量,用来保存已经接收到的字符个数uint8_t i = 0;while((USART1->SR & USART_SR_IDLE) == 0) {buffer[i] = USART_ReceiveChar();i++;}// 清除IDLE// USART1->SR;USART1->DR;*size = i-1;
}uint8_t buffer[100] = {0};
uint8_t size = 0;int main(void) {USART_Init();while(1) {USART_ReceiveString(buffer, &size);USART_SendString(buffer, size);}
}
#include "usart.h"void USART_Init(void) {// 1. 配置时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;RCC->APB2ENR |= RCC_APB2ENR_USART1EN;// 2. GPIO工作模式 // PA9(复用推挽输出)CNF:10 MODE:11GPIOA->CRH |= GPIO_CRH_MODE9;GPIOA->CRH |= GPIO_CRH_CNF9_1;GPIOA->CRH &= ~GPIO_CRH_CNF9_0;// PA10(浮空输入) MODE:00 CNF:01GPIOA->CRH &= ~GPIO_CRH_MODE10;GPIOA->CRH &= ~ GPIO_CRH_CNF10_1;GPIOA->CRH |= GPIO_CRH_CNF10_0;// 3. 串口配置USART1->BRR = 0x271; // 波特率 115200USART1->CR1 |= USART_CR1_TE; // 接收使能USART1->CR1 |= USART_CR1_RE; // 发送使能USART1->CR1 |= USART_CR1_UE; // USART使能// 4. 开启中断使能USART1->CR1 |= USART_CR1_IDLEIE;USART1->CR1 |= USART_CR1_RXNEIE;// NVICNVIC_SetPriorityGrouping(3);NVIC_SetPriority(USART1_IRQn, 3);NVIC_EnableIRQ(USART1_IRQn);
}void USART_SendChar(uint8_t ch) {// 判断SR里TXE是否为空while((USART1->SR & USART_SR_TXE) == 0) {}// 向DR写入新的数据USART1->DR = ch;
}void USART_SendString(uint8_t *str, uint8_t size) {for (uint8_t i = 0; i < size; i++) {USART_SendChar(str[i]);}
}void USART1_IRQHandler(void) {// 判断中断类型if (USART1->SR & USART_SR_RXNE) { // 接收完成一个字符buffer[size] = USART1->DR;size++;} else if (USART1->SR & USART_SR_IDLE) { // 字符串整体接收完成// 清除IDLE标志位USART1->DR;// 直接发送字符串到电脑// USART_SendString(buffer, size);// 清除size// size = 0;isOver = 1;}
}uint8_t buffer[100] = {0};
uint8_t size = 0;
uint8_t isOver = 0;int main(void) {USART_Init();while(1) {if (isOver){USART_SendString(buffer, size);isOver = 0;size = 0;}	}
}

4. 实际应用

  1. 打印调试信息 (printf):最常用的功能,重定向 printf 到 USART,方便监控程序状态和变量值。
  2. 与上位机通信:与 PC 软件(如串口助手、自定义的上位机)进行数据交换,发送传感器数据,接收控制命令。
  3. 模块控制:与 GPS、蓝牙 (HC-05/06)、Wi-Fi (ESP8266/ESP32)、GSM 等模块进行 AT 指令通信。
  4. 嵌入式系统间通信:两个 MCU 之间进行简单的数据交换。
  5. 工业控制:支持 Modbus RTU 等工业串行协议,与 PLC、变频器等设备通信。

I2C

1. I2C协议回顾

I2C (Inter-Integrated Circuit) 是一种同步、半双工、串行的通信总线,I2C需要两根线,分别是SDA(Serial Data)数据线和SCL(Serial Clock)时钟线。SCL(只有主设备控制)用于控制时钟信号,设备在其每个上升沿读取SDA信号线上的电平。

关键特性:

  • 多主多从:总线上可以连接多个主设备和从设备。
  • 地址寻址:每个从设备都有一个唯一的 7 位或 10 位地址。
  • 低速通信:标准模式 (100 kbps),快速模式 (400 kbps),高速模式 (3.4 Mbps)。
  • 上拉电阻:设备空闲时,输出高阻态,当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

基本信号:

  • 起始条件 (S):SCL 为高电平时,SDA 从高到低的跳变。(先拉高SCL,准备好SDA从1到0即为START)
  • 停止条件 (P):SCL 为高电平时,SDA 从低到高的跳变。(先拉高SCL,准备好SDA从0到1即为STOP)
  • 从机地址与读写位:第一个字节的前7位组成了从机地址。第8位代表主机读(高电平)或主机写(低电平),它决定了后续数据的发送方和接收方。
  • 数据有效性:在 SCL 高电平期间,SDA 必须保持稳定。数据只能在 SCL 低电平时改变。
  • 应答 (ACK):发送方(可以是主或从)发送完 8 位数据后,接收方需要将 SDA 拉低,表示应答。(先拉低SDA,拉低的时候SCL要保持低电平,再拉高SCL)
  • 非应答 (NACK):SDA 保持高电平,表示非应答。(先拉高SDA,再拉高SCL)

2. 软件模拟I2C

#define ACK 0
#define NACK 1// STM32控制SCL和SDA的输出高低电平
#define SCL_HIGH (GPIOB->ODR |= GPIO_ODR_ODR10)
#define SCL_LOW (GPIOB->ODR &= ~GPIO_ODR_ODR10)
#define SDA_HIGH (GPIOB->ODR |= GPIO_ODR_ODR11)
#define SDA_LOW (GPIOB->ODR &= ~GPIO_ODR_ODR11)// STM32从EEPROM中读取,STM32作为从设备
#define READ_SDA (GPIOB->IDR & GPIO_IDR_IDR11)// 基本延迟
#define I2C_DELAY Delay_us(10)void I2C_Init(void) {// 1.配置时钟RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;// 2.工作模式:通用开漏输出GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_MODE11);GPIOB->CRH &= ~(GPIO_CRH_CNF10_1 | GPIO_CRH_CNF11_1);GPIOB->CRH |= (GPIO_CRH_CNF10_0 | GPIO_CRH_CNF11_0);
}void I2C_Start(void) {// SCL先拉高保持不变,SDA从高电平到低电平SCL_HIGH;SDA_HIGH;I2C_DELAY; // SDA拉高保持一段时间SDA_LOW;I2C_DELAY; // SDA拉低保持一段时间
}void I2C_Stop(void) {// SCL先拉高保持不变,SDA从低电平到高电平SCL_HIGH;SDA_LOW;I2C_DELAY; // SDA拉低保持一段时间SDA_HIGH;I2C_DELAY; // SDA拉高保持一段时间
}void I2C_Ack(void) {// SCL先拉低,SDA拉高,做好准备SCL_LOW;SDA_HIGH;I2C_DELAY;// SDA拉低,保持不变,SCL拉高开始采样SDASDA_LOW;I2C_DELAY;SCL_HIGH;I2C_DELAY;// 采样结束,SDA不变,SCL拉低SCL_LOW;I2C_DELAY;// SDA拉高,释放数据总线SDA_HIGH;I2C_DELAY;
}void I2C_Nack(void) {SCL_LOW;SDA_HIGH;I2C_DELAY;SCL_HIGH;I2C_DELAY;SCL_LOW;I2C_DELAY;
}uint8_t I2C_Wait4Ack(void) {// SCL拉低,SDA拉高,释放数据总线SCL_LOW;SDA_HIGH;I2C_DELAY;// 拉高SCL,开始数据采样SCL_HIGH;I2C_DELAY;// 读取SDA数据线上的电平uint16_t ack = READ_SDA;// 拉低SCL结束采样SCL_LOW;I2C_DELAY;return ack ? NACK : ACK;
}void I2C_SendByte(uint8_t byte) {for (uint8_t i = 0; i < 8; i++){// SCL为低时不进行采样,此时SDA可以根据byte的数据进行一位位的传输(SDA根据byte进行翻转)// SCL、SDA拉低,等待数据翻转SCL_LOW;SDA_LOW;       I2C_DELAY;// 字节最高位,向SDA写入数据// 该位为1就拉高SDA,为0就拉低SDAif (byte & 0x80) {SDA_HIGH;} else {SDA_LOW;}I2C_DELAY;// 翻转完毕,准备拉高SCL进行采样SCL_HIGH;I2C_DELAY;// SCL拉低,采样结束SCL_LOW;I2C_DELAY;byte <<= 1; // 继续采样byte的下一位}
}// 主机从从设备接受一个字节的数据,数据总线不归主设备管
uint8_t I2C_ReadByte(void) {uint8_t data = 0;for (uint8_t i = 0; i < 8; i++){// 拉低SCL,等待数据翻转SCL_LOW;I2C_DELAY;// 拉高SCL,采样SCL_HIGH;I2C_DELAY;data <<= 1; // 先左移,新存入的位永远在最低位// 开始读数据if (READ_SDA) {data |= 0x01; // 先存入最低位,然后每次都左移1位} // 拉低SCL,结束采样SCL_LOW;I2C_DELAY;}return data;}

3. I2C寄存器

1. 控制寄存器 1 (I2C_CR1) - I2C1->CR1

用于配置 I2C 的基本模式和使能。

名称 功能描述
SWRST 软件复位。1:I2C 处于复位状态。0:I2C 正常工作。(可用于调试,强制复位 I2C 外设)
SMBus SMBus 模式选择。0:I2C 模式。1:SMBus 模式。
SMBTYPE SMBus 类型。
ENARP SMBus ARP 使能
ENPEC PEC 计算使能
ENGC 广播呼叫使能
NOSTRETCH 时钟延展禁止主模式时,如果希望 Slave 的忙状态不会拉低 SCL(即不允许时钟延展),则置 1。从模式时必须为 0
ALERT SMBus 提醒。
ACK 应答使能至关重要! - 1:在接收模式下,发出 ACK 脉冲(收到一个字节后拉低 SDA)。 - 0:发出 NACK 脉冲(收到一个字节后不拉低 SDA)。(接收最后一个字节前,应置 0)
STOP 产生停止条件写 1 产生停止条件。该位由硬件自动清除。
START 产生起始条件写 1 产生起始条件。该位由硬件自动清除。
PE 外设使能。0:禁用 I2C。1:使能 I2C(必须在其他配置完成后最后开启)

2. 控制寄存器 2 (I2C_CR2) - I2C1->CR2

用于配置中断和时钟控制。

名称 功能描述
ITERREN 错误中断使能。
ITEVTEN 事件中断使能。
ITBUFEN 缓冲区中断使能
FREQ[5:0] 设置 I2C 外设的输入时钟频率 (MHz)必须正确设置! 例如,如果 I2C 挂载在 APB1 上 (PCLK1 = 36MHz),则 FREQ 应设置为 36 (0b100100)。

3. 自身地址寄存器 (I2C_OAR1/OAR2) - I2C1->OAR1

用于设置 STM32 作为从设备时的地址。主模式通常不需要配置。

4. 数据寄存器 (I2C_DR) - I2C1->DR

用于存放要发送或刚接收到的数据。

功能
包含要发送或刚接收到的数据

操作:

  • 发送I2C1->DR = Data;
  • 接收Data = I2C1->DR;

5. 状态寄存器 1 (I2C_SR1) - I2C1->SR1

这是最重要的状态寄存器! 它包含了许多标志位,用于指示 I2C 总线的当前状态。很多位通过读 SR1 寄存器,然后进行特定操作(读/写 DR)来清除。

名称 功能描述
TIMEOUT 超时错误。
OVR 溢出/不足错误。
AF 应答失败 (Acknowledge Failure)当发送方没有收到 ACK 时置 1通过写 0 清除
ARLO 仲裁丢失错误。
BERR 总线错误。
TxE 数据寄存器空 (Transmit empty)发送时查询此位。1:DR 为空,可以写入下一个数据。
RxNE 数据寄存器非空 (Receive not empty)接收时查询此位。1:DR 中有数据,可以读取。
BTF 字节传输完成 (Byte transfer finished)。1:一个字节已完全发送/接收。(常用于判断传输结束)
ADDR 地址已发送 (Address sent)(主模式)地址匹配 (Address matched)(从模式) 该位通过 读 SR1 -> 读 SR2 的序列清除。
SB 起始位已发送 (Start bit)(主模式) 该位通过 读 SR1 -> 写 DR 的序列清除。

6. 状态寄存器 2 (I2C_SR2) - I2C1->SR2

提供一些额外状态信息,通常与 SR1 配合使用。

名称 功能描述
MSL 主/从模式。1:处于主模式。
TRA 发送器/接收器。1:处于发送模式。0:处于接收模式。

7. 时钟控制寄存器 (I2C_CCR) - I2C1->CCR

用于设置 I2C 的通信速率(SCL 频率)。

名称 功能描述
F/S 模式选择。0:标准模式 (≤100 kHz)。1:快速模式 (≤400 kHz)
DUTY 快速模式下的占空比(仅当 F/S=1 时有效)。0:Tlow/Thigh = 2。1:Tlow/Thigh = 16/9。
CCR[11:0] 时钟控制分频值计算公式至关重要! 标准模式: CCR = PCLK1 / (2 * I2C_Speed) 快速模式 (DUTY=0): CCR = PCLK1 / (3 * I2C_Speed) 快速模式 (DUTY=1): CCR = PCLK1 / (25 * I2C_Speed) 结果必须大于 4,且为整数。

8. 上升时间寄存器 (I2C_TRISE) - I2C1->TRISE

用于设置 SCL 上升时间,必须根据时钟模式和 PCLK1 频率配置。

功能
TRISE[5:0] 设置最大上升时间 (ns)计算公式: TRISE = (PCLK1_MHz + 1) 例如,PCLK1 = 36MHz,则 TRISE = 36 + 1 = 37 (0x25)。

4. 寄存器开发流程

  1. 开启时钟和配置GPIO
  2. 配置I2C寄存器
  3. 编写底层驱动函数
#include "i2c.h"#define OK 0
#define FAIL 1void I2C_Init(void) {// 1.配置时钟RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;  // 72MHZRCC->APB1ENR |= RCC_APB1ENR_I2C2EN; // 36MHZ// 2.工作模式:复用开漏输出GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_MODE11 | GPIO_CRH_CNF10 | GPIO_CRH_CNF11);// 3.I2C2配置I2C2->CR1 &= ~I2C_CR1_SMBUS; // 开启I2C模式I2C2->CCR &= ~I2C_CCR_FS; // 标准模式:100KHZI2C2->CR2 |= 36; // 36MHZI2C2->CCR |= 180; // 数据传输速率100kb/s,SCL高电平时间为5usI2C2->TRISE |= 37; // SCL上升沿最大时钟周期数+1I2C2->CR1 |= I2C_CR1_PE; // 使能I2C2模块
}uint8_t I2C_Start(void) {I2C2->CR1 |= I2C_CR1_START;uint16_t timeout = 0xFFFF;// SB为1:Start信号已发送// SB置1则退出当前循环,timeout减为0也会退出while((I2C2->SR1 & I2C_SR1_SB)==0 && timeout) {timeout--;}return timeout ? OK : FAIL;
}// 设置发出停止信号
void I2C_Stop(void) {I2C2->CR1 |= I2C_CR1_STOP; // 不是立刻停止
}// 主机设置使能应答信号
void I2C_Ack(void) {I2C2->CR1 |= I2C_CR1_ACK; // 打开应答信号
}
// 主机设置使能非应答信号
void I2C_Nack(void) {I2C2->CR1 &= ~I2C_CR1_ACK; // 关闭应答信号
}// 主机发送设备地址并等待应答
uint8_t I2C_SendAddr(uint8_t addr) {// 直接将要发送的地址给DRI2C2->DR = addr;uint16_t timeout = 0xFFFF;while ((I2C2->SR1 & I2C_SR1_ADDR)==0 && timeout) {timeout--;}if (timeout > 0) { // timeout不为0说明addr发送I2C2->SR2; // 清除ADDR标志位}return timeout ? OK : FAIL;
}// 主机发送一个字节数据,并等待应答
uint8_t I2C_SendByte(uint8_t byte) {// 先等待DR为空,上一个字节数据已经发送完毕uint16_t timeout = 0xFFFF;while ((I2C2->SR1 & I2C_SR1_TXE)==0 && timeout) {timeout--;}// 将要发送的数据写入DRI2C2->DR = byte;timeout = 0xFFFF;while ((I2C2->SR1 & I2C_SR1_BTF)==0 && timeout) {timeout--;}return timeout ? OK : FAIL;   
}// 主机读取数据
uint8_t I2C_ReadByte(void) {uint16_t timeout = 0xFFFF;while ((I2C2->SR1 & I2C_SR1_RXNE)==0 && timeout) {timeout--;}return timeout ? I2C2->DR : FAIL;
}

5. 实际应用

  1. 传感器读取:与加速度计、陀螺仪、磁力计、温湿度传感器 、气压传感器等通信。
  2. EEPROM 存储:扩展非易失性存储空间,存储设备参数、校准数据等。
  3. RTC 时钟:与实时时钟芯片 通信,获取和设置时间。
  4. IO 扩展:使用 IO 扩展芯片来增加 GPIO 数量。
  5. 音频编解码器:配置音频芯片的参数。
  6. 触摸屏控制器:与电阻式或电容式触摸屏控制器通信。
http://www.sczhlp.com/news/79950/

相关文章:

  • 做钓鱼网站要什么工具凡科做网站不好
  • 网站建设和网站开发阜阳网站优化
  • 免费按模板制作微网站烟台网站建设设计公司
  • 精品成品网站源码百度推广后台登录
  • 企业网站标签页是什么合肥网站建设百家号
  • 邢台做网站的做网站的前景如何
  • 竞价托管公司企业seo排名费用报价
  • 软件实施工资一般多少网站怎么优化 优帮云
  • wordpress搜索全站计算机网络中小型企业网络设计方案
  • 昆明做网站建设的公司排名证券公司客户经理怎么拉客户
  • 南通哪里有做网站的网页设计报告需求分析
  • 如何做网站动态图标千库网怎么样
  • 宜昌做网站要什么条件福州网站建设策划
  • 企业网站备案怎么搞外贸建站平台
  • 做网站的三个软件购物网站排名第一的有哪些
  • 移动端网站排名自己可以学做网站吗
  • 网站域名备案注册证书查询用 可以做网站软件吗
  • 社交网站第一步怎么做重庆竣工验收备案网上查询
  • 马鞍山网站建设服务开发用织梦做网站调用乱码
  • 上海网站备案审核时间小语种网站怎么设计
  • 如何建设网站赚钱wordpress更新下固定链接
  • 湖南网站开发公司电话audio for wordpress
  • 搭建品牌电商网站怎么做wordpress 站点身份
  • 免费自助建站学佛网站开发项目需求分析
  • 营销类网站网站建设行业数据
  • 电商网站设计论文模板下载免费网站
  • 做设计常用网站网站备案有什么作用
  • 电子商务网站策划lamp 安装wordpress
  • 自助建站基础工作主要包括()怎么看网站是否被百度惩罚
  • 合肥中小企业网站制作安阳县高级中学