目录
[1. ADC](#1. ADC)
[1.1 简单理论部分](#1.1 简单理论部分)
[1.1.1 两种通道](#1.1.1 两种通道)
[1.1.2 转换顺序](#1.1.2 转换顺序)
[1.1.3 触发方式](#1.1.3 触发方式)
[1.1.4 转换时间](#1.1.4 转换时间)
[1.1.5 数据寄存器](#1.1.5 数据寄存器)
[1.2 ADC配置部分](#1.2 ADC配置部分)
[2.1 定时器理论部分](#2.1 定时器理论部分)
[2.1.1 PWM输出](#2.1.1 PWM输出)
[2.2 PWM模式配置](#2.2 PWM模式配置)
[3. I2C](#3. I2C)
[3.1 理论部分](#3.1 理论部分)
[3.1.1 简单介绍](#3.1.1 简单介绍)
[3.1.2 时序介绍](#3.1.2 时序介绍)
[3.2 I2C配置](#3.2 I2C配置)
[3.3 I2C代码部分](#3.3 I2C代码部分)
[3.3.1 I2C通信例程](#3.3.1 I2C通信例程)
一、基础外设
1. ADC
1.1 简单理论部分
1.1.1 两种通道
规则通道就是一般常用的,没啥好讲的。注入通道的话,可以和中断很像,是在规则通道中插入的;
1.1.2 转换顺序
分别有规则序列寄存器、注入序列寄存器;
规则序列寄存器有4个,SQR1、SQR2、SQR3、SQR4,如下图,
这里SQx填入a,表示通道a为第x个转换;
注入序列寄存器JSQR只有一个
1.1.3 触发方式
ADC控制寄存器触发:ADC_CR的ADSTART位触发,写1开始转换,写0停止转换;
ADC外部事件触发:比如定时器触发、IO触发等;
1.1.4 转换时间
ADC_SMPR1/2 的 SMP[2:0] 用于设置采样周期,ADC_SMPR1控制0~9通道,ADC_SMPR2控制10~19通道;
假设ADC的时钟频率 ADCCLK=24Mhz,采样时间设置为1.5个周期,那么ADC转换时间为:
Tconv = 采样时间 + 7.5 = 1.5 + 7.5 = 9个周期,也就是0.375us;
1.1.5 数据寄存器
ADCx_DR 用于存放规则通道数据;
ADC_JDRx 用于存放注入通道数据;
ADC_CDR 多模情况下使用;
1.2 ADC配置部分
首先把需要的通道打开;
Data Alignment 这里我用的是右对齐,这样也方便直接读数据,不用去缩放;
Sampling Time 我用28.5,主要用来采集电流、温度
2.TIM
2.1 定时器理论部分
2.1.1 PWM输出
关于时钟可以在cubemx clock configuration的APB1 Timer clocks和APB2 Timer clocks那里看到,比如TIM1的时钟,这里称为 f_TIMCLK;
计数时钟:
计数周期 (向上计数):
PWM 占空比 (PWM 模式 1):
2.2 PWM模式配置
比如这里把 TIM1的Channel1通道打开,设置为PWM生成模式;
比如这里,我要生成的PWM频率为20Khz,我的APB1时钟为72Mhz;
那么
f_cnt = 72Mhz / (0+1) = 72Mhz
T = (3599+1) / 72 Mhz,所以频率为 72Mhz / 3600 = 20Khz
3. I2C
3.1 理论部分
3.1.1 简单介绍
I2C通信用两根线,SCL(时钟) 与 SDA(数据)(其实工程上还得加个GND,用来共地);
I2C上拉电阻取决于总线等效电容,一般在2k~10kR,最常用的是4.7K,假如用示波器抓取信号时发现原来应该是方波的地方,上升沿有点"弯弯的",这种就是上拉电阻太大了;
假如不知道总线电容的话,其实可以这样。I2C总线比较短,总线上挂载设备不多时可以用4.7KR的上拉电阻。I2C总线比较长,挂载设备多的时候可以用10KR的电阻;
总线电容的话,I2C规范是<400pF,高速模式时要<100pF。
I2C有三种速度模式,100Khz为标准、400Khz为快速、3.4Mhz为高速
3.1.2 时序介绍
空闲:SCL=H,SDA=H
START:SCL=H,SDA=(H -> L)
STOP:SCL=H,SDA=(L -> H)
地址帧:7bit设备地址 + 1bit读写位(0写,1读)
3.2 I2C配置
3.3 I2C代码部分
3.3.1 I2C通信例程
cpp/* 这部分用STM32 CUBEMX 一般来说生成了*/ /* I2C1 init function */ void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; // 100 kHz hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { /* 初始化错误,进入错误处理 */ Error_Handler(); } } //--------------------------------------------------------------------------------------- #include "main.h" #include "stm32f1xx_hal.h" I2C_HandleTypeDef hi2c1; UART_HandleTypeDef huart2; // 用于调试输出 /* 发送/接收缓冲区 */ uint8_t tx_buf[] = {0xA5, 0x5A, 0x01}; // 待发送的数据 uint8_t rx_buf[2]; // 接收缓冲区 /* 从设备 7 位地址(左移 1 位形成 HAL 需要的 8 位地址) */ #define SLAVE_ADDR (0x50 << 1) // 示例 EEPROM 地址 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); // 调试串口 MX_I2C1_Init(); // 初始化 I2C /* ----------- 主机发送数据 ----------- */ if (HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDR, tx_buf, sizeof(tx_buf), HAL_MAX_DELAY) != HAL_OK) { const char *msg = "I2C Tx Error\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); Error_Handler(); } /* ----------- 主机接收数据 ----------- */ if (HAL_I2C_Master_Receive(&hi2c1, SLAVE_ADDR, rx_buf, sizeof(rx_buf), HAL_MAX_DELAY) != HAL_OK) { const char *msg = "I2C Rx Error\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); Error_Handler(); } /* 打印接收到的数据(十六进制) */ char dbg[64]; snprintf(dbg, sizeof(dbg), "Rx: %02X %02X\r\n", rx_buf[0], rx_buf[1]); HAL_UART_Transmit(&huart2, (uint8_t*)dbg, strlen(dbg), HAL_MAX_DELAY); while (1) { /* 主循环可以放置其他业务代码 */ } }






