[STM32]-ADC读取滑动电阻器代码实现_哔哩哔哩_bilibili
ADC图文件引入与初始化
Section titled “ADC图文件引入与初始化”- 图文件中引入ADC图文件
- 初始化部分新增ADC初始化
- 参数模式设置来源于TuberS配置
- 与前面配置一致
ADC相关函数
Section titled “ADC相关函数”- ADC图文件包含初始化相关和触发相关函数
- 可查看相关AP函数
- 第一个图文件为触发相关
ADC校准设置
Section titled “ADC校准设置”- 校准原因:ADC制造过程存在误差,建议采样前执行校准,提高数据精度
- 函数调用:
HAL_ADC_Calibration_Start(&hadc1) - 放置位置:从ADC扩展函数库copy该函数,放到MX_ADC1_Init()等初始化代码前面
- 忽略回调部分,直接放置
ADC校准函数实现
Section titled “ADC校准函数实现”- 新增函数MX_ADC1_Calibration(从ADC扩展库复制)
- 调用HAL_ADC_Calibration_Start(hadc1)
- 参数:hadc1(ADC实例句柄)
ADC转换启动与读取
Section titled “ADC转换启动与读取”- 启动转换:MX_ADC1_Start函数
- 调用HAL_ADC_Start(hadc1)
- 参数:hadc1
- 等待转换完成(主循环中):HAL_ADC_PollForConversion(hadc1, HAL_MAX_DELAY)
- 第一个参数:hadc1(句柄)
- 第二个参数:超时时间(如HAL_MAX_DELAY)
- 用于判断转换是否完成
void MX_ADC1_Calibration(void){ if (HAL_ADC_Calibration_Start(hadc1) != HAL_OK) { Error_Handler(); }}
void MX_ADC1_Start(void){ if (HAL_ADC_Start(hadc1) != HAL_OK) { Error_Handler(); }}ADC转换时间与超时设置
Section titled “ADC转换时间与超时设置”- 采样时间:1.5周期(之前设置)
- 总转换时间:采样时间1.5周期 + 12.5周期 = 14周期
- 参考芯片手册11.6节
- 实际时间估算:14周期 ≈ 1微秒(时钟12MHz)
- 实际稍大,但不会超太多
- 超时时间建议:10-50ms
- 只要大于转换时间即可(如HAL_MAX_DELAY或50ms)
// 示例:在主循环中使用HAL_ADC_PollForConversion(hadc1, 50); // 50ms超时ADC值读取与打印
Section titled “ADC值读取与打印”- 主循环中读取流程:先轮询等待转换完成,再获取ADC值
- 轮询函数:
HAL_ADC_PollForConversion(&hadc1, 50)(50ms超时,足够覆盖转换时间) - 超时设置:只需大于转换时间(如10ms),单位ms
- 获取值:
uint32_t adc_value = HAL_ADC_GetValue(&hadc1); - ADC为12位,用uint32_t或uint16_t存储
while (1){ if (HAL_ADC_PollForConversion(&hadc1, 50) == HAL_OK) { uint32_t adc_value = HAL_ADC_GetValue(&hadc1); // 通过串口打印观察ADC值变化 }}- 打印ADC值:重写printf函数,通过串口窗口输出,便于观察变化
ADC值串口打印与电压转换
Section titled “ADC值串口打印与电压转换”- 打印ADC值:在主循环中使用
printf("ADC value = %lu\r\n", adc_value)观察变化 - 通过重写printf函数,经串口输出
while (1){ HAL_ADC_PollForConversion(&hadc1, 100); uint32_t adc_value = HAL_ADC_GetValue(&hadc1); printf("ADC value = %lu\r\n", adc_value);}- 电压转换原理:12位ADC(0~4095),参考电压3.3V
- 分辨率:$$3.3 / 4096 \approx 0.00080566V$$
- 公式:电压 = adc_value × (3.3 / 4096)
模拟信号Vin ──► 采样保持 ──► 比较器 ──► SAR控制器 ──► 输出 │ └─► DAC参考电压 Vref = 3.3V
0x0000 = 0V0x0001 ≈ 0.0008V...0xFFF = 3.3V- 示例:
- 0x0100 ≈ 0.20252V
- 0x0101 ≈ 0.20505V
ADC电压转换与打印
Section titled “ADC电压转换与打印”- 实际电压计算:12位ADC,分辨率 3.3V / 4096
- 公式:
(float)adc_value * 3.3f / 4096.0f - 3.3f:浮点数后缀,确保浮点运算
while (1){ HAL_ADC_PollForConversion(&hadc1, 100); uint32_t adc_value = HAL_ADC_GetValue(&hadc1); printf("adc_value = %d\r\n", adc_value); printf("voltage = %f\r\n", (float)adc_value * 3.3f / 4096.0f); HAL_Delay(1000);}- 打印设置:小数点后4位,HAL_Delay(1000) 观察变化
- 超时调整为100ms(轮询)
ADC程序实际运行与调试
Section titled “ADC程序实际运行与调试”- 编译烧录与串口观察:配置debug为SWD模式,编译烧录后连接USB转串口线到电脑
- 打开串口助手,选择对应COM口
- 观察打印的ADC value和转换电压,每秒打印一次(延时控制)
- 信号变化测试:用十字螺丝刀调节电位器,观察串口窗口中ADC值和电压实时变化
- 验证ADC采样正常工作
// 主循环中添加延时,每秒打印一次HAL_Delay(1000);ADC实际测试验证
Section titled “ADC实际测试验证”- 电位器演示:旋转电位器改变PA0 (PA03) 输入电压
- 中间位置:接近3.3V,ADC值最大
- 往一侧旋转:电压接近3.3V,ADC值增大
- 往另一侧旋转:电压接近0V,ADC值减小
- 验证效果:通过串口观察ADC值和电压变化,确认0~3.3V范围采样正确
- 对应前面代码打印的adc_value和voltage
- 电路工作:电位器模拟信号 → PA0 → ADC采样 → 串口输出观察
UART与I2C通信协议对比
Section titled “UART与I2C通信协议对比”- UART:支持半双工或全双工,3根线(DS线、S线、D线),用于两个设备间通信
- I2C:半双工,2根线(SCL时钟线、SDA数据线)
UART: 设备A ── DS ── S ── D ── 设备BI2C: 主控 ── SCL ── SDA ── 从设备I2C与UART使用场景区别
Section titled “I2C与UART使用场景区别”- UART:处理器与处理器通信时常用
- I2C:处理器与外设通信时常用
- 闪存芯片
- 屏幕
- 传感器
- EEPROM(如24C02)
主控 │SCL (时钟线)SDA (数据线) ├─ 用户手册 ├─ 闪存 ├─ 24C02 └─ 传感器- 51单片机学习中用IO模拟I2C
I2C软件模拟实现
Section titled “I2C软件模拟实现”- STC51特点:无硬件I2C模块,必须用IO口模拟时序
- 逐个实现基础信号:起始信号、结束信号、发送数据、读取数据、应答信号
- 实现流程:编写各基础信号 → 组合成完整I2C通信
STM32硬件I2C与51模拟I2C对比
Section titled “STM32硬件I2C与51模拟I2C对比”- 51单片机I2C实现:用IO模拟,手动编写
- 起始信号、结束信号
- 数据通讯信号
- 应答信号(硬答/软答)
- 封装读写函数驱动外设(如温湿度传感器)
- 实现繁琐:效率低,所有信号手动控制
- STM32优势:提供硬件I2C功能
- 自动处理信号,封装更高效
- 便于驱动外设
STM32硬件I2C与51模拟I2C区别
Section titled “STM32硬件I2C与51模拟I2C区别”- STM32硬件I2C:底层芯片已封装起始信号、结束信号、数据发送/读取、应答信号
- 使用时只需调用读写函数,轻松操作外设实现驱动
- 51单片机:无硬件I2C,需IO模拟各时序信号后组合
- STM32也可模拟:用两个IO模拟信号并封装,但今天重点学硬件I2C
STM32硬件I2C: 封装信号 → 直接调用读写函数 → 驱动外设51模拟I2C: IO时序 → 组合信号 → 驱动外设I2C硬件实现与通信过程回顾
Section titled “I2C硬件实现与通信过程回顾”- STM32 I2C驱动:使用芯片提供的硬件I2C外设直接驱动外设
- 比51模拟更高效,无需手动编写时序
- 完整I2C通信过程(51中复习):
- 起始信号:SCL为高时,SDA从高到低跳变
- 通知从设备开始通信
SCL ───────┐────────────── │ │SDA ──────┘ └────── (起始后)- 后续步骤:数据传输、应答、结束信号(之前已详述)
I2C起始与结束信号时序
Section titled “I2C起始与结束信号时序”- 起始信号:SCL高电平期间,SDA由高变低
- 结束信号:SCL高电平期间,SDA由低变高
- 通信流程:起始信号后发送从设备地址
- 示例:操作温湿度传感器,发送其7位地址
- byte有8位,地址占7位(注意位宽)
I2C设备地址与读写位
Section titled “I2C设备地址与读写位”- 设备地址字节组成:操作设备地址 + 读写标志位 = 1 byte(8位)
- 写操作:读写位 = 0
- 读操作:读写位 = 1
- 通信流程:发送设备地址后,等待从设备应答
- 应答后:
- 写:发送数据 → 等待应答
- 读:接收数据
设备地址 ──(读写位 0/1)──► 等待应答 │ ├─ 写:发送数据 └─ 读:接收数据I2C完整通信过程 - 写操作与读操作细节
Section titled “I2C完整通信过程 - 写操作与读操作细节”- 写操作:发送完所有数据后,等待从设备应答,然后发送结束信号完成通信
- 结束信号:SCL高时 SDA由低变高
- 读操作:等待从设备发送数据
- 数据传输过来后,主机发送应答
- 继续接收下一个数据,直至所有数据传输完成
- 最后:主机返回应答 + 发送停止信号
- 从设备停止发送数据,总线释放
写: 地址(R/W=0) ── ACK ── DATA ── ACK ── ... ── STOP读: 地址(R/W=1) ── ACK ── DATA ── ACK ── DATA ── ACK ── STOP- 时序要点:每个数据后都有ACK(应答),传输完发STOP释放总线
STM32硬件I2C工程准备
Section titled “STM32硬件I2C工程准备”- 工程创建:复制demo001工程作为模板,重命名为demo013
- 删除MDK配置文件夹
- 打开CubeMX(cubemx)工具
- CubeMX初始界面:
- 顶部菜单:Pinout & Configuration、Clock Configuration、Project Manager、Tools
- 中心显示STM32F103RCTx LQFP64芯片图与引脚标签
- 左侧配置面板:System Core、Connectivity、Timers、ADC等类别
- 点击System Core开始配置
STM32硬件iPhone C接口与协议配置
Section titled “STM32硬件iPhone C接口与协议配置”- 芯片支持:两个硬件iPhone C接口(iPhone C1 和 iPhone C2)
- 先使能其中一个进行配置
- 协议选项:三种模式
- iPhone C:本节课主要学习
- SMBus总线:与iPhone C硬件接口类似
- 官方封装在一起
协议: iPhone C / SMBus- 配置步骤:设置成iPhone C模式
STM32硬件I2C CubeMX配置参数
Section titled “STM32硬件I2C CubeMX配置参数”- 配置位置:选择I2C后,下方显示参数配置
- Master特性:单片机作为I2C主机时配置
- 用于驱动外设(如温湿度传感器、屏幕)
- 单片机一般作为主机
- Lens特性:与master一起配置(具体含义待后续)
- 主机模式下只需配置这两个参数
STM32硬件I2C配置 - 模式与速率
Section titled “STM32硬件I2C配置 - 模式与速率”- 作为主机驱动程序:配置I2C1参数,主要驱动温湿度传感器和EEPROM
- 只需配置关键参数
- 第一个参数:模式
- 标准模式 (Standard Mode)
- 快速模式 (Fast Mode)
- 影响:I2C Clock Speed (Hz)(时钟速率)
- 当前设置:100000 Hz
I2C1 配置:模式 ──► 标准模式 / 快速模式 │ └─► I2C Clock Speed (Hz): 100000- 其他参数(屏幕显示,待讨论)
- Clock Stretch Mode: Disabled
- Primary Address Length: 7-bit
- Primary Address: 0x0000
- General Call: Disabled
STM32硬件I2C CubeMX配置参数 - 速率模式选择
Section titled “STM32硬件I2C CubeMX配置参数 - 速率模式选择”- I2C速率决定依据:根据外设传感器支持的最高速率
- 示例:传感器最高100k → 选择标准速率
- 支持快速速率 → 设置快速速率
- 模式选择后:下方参数一般默认(按默认即可)
- 驱动外设时,若外设不支持高速率 → 需调整速率
外设最高速率 ↓标准(100k) / 快速 ↓CubeMX配置 → 默认参数STM32硬件I2C配置 - 从机参数
Section titled “STM32硬件I2C配置 - 从机参数”- 下方参数:时钟拉伸模式(Clock Stretch Mode)、地址长度(Primary Address Length)、主地址(Primary Address)等
- 这些是从机(slave)的参数
- 本节不关注
- 主机驱动重点:了解主机如何驱动外设(如温湿度传感器)
- 先掌握主机参数配置
- 当前设置:保持默认值,先不修改速率(100000 Hz)
STM32硬件I2C实验目标与EEPROM电路
Section titled “STM32硬件I2C实验目标与EEPROM电路”- 实验内容:驱动EEPROM(本节重点)和温湿度传感器(51课程已讲)
- 先查看原理图第9页的EEPROM电路
EEPROM电路:[EEPROM芯片 + 电容 + 电阻]SCL ──┐SDA ──┤── VCC, GND └─- 电路连接:包含EEPROM芯片、电容、电阻,关键引脚SCL、SDA、VCC、GND
- SIZE | PAGE 9 of 17
STM32硬件I2C代码生成与API查看
Section titled “STM32硬件I2C代码生成与API查看”- 生成代码:配置I2C1为标准模式、速率100k后,直接生成代码
- 查看API:检查生成的I2C相关函数
STM32硬件I2C工程编译与初始化函数查看
Section titled “STM32硬件I2C工程编译与初始化函数查看”- 编译工程:配置完成后直接编译
- main函数变化:新增I2C1初始化调用
- 包含CubeMX中配置的参数
- 查看流程:
- 进入MX_I2C1_Init()
- 跳转**HAL_I2C_Init()**硬件初始化函数
- 查看其头文件
STM32硬件I2C主机通信API函数
Section titled “STM32硬件I2C主机通信API函数”- 主机传输函数:
HAL_StatusTypeDef HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)0x78, pData, Size, Timeout); - 用于主机发送数据
- 主机接收函数:
HAL_StatusTypeDef HAL_I2C_Master_Receive(&hi2c1, (uint16_t)0x78, pData, Size, Timeout); - 用于主机接收数据
- 内存写函数:
HAL_StatusTypeDef HAL_I2C_Mem_Write(&hi2c1, (uint16_t)0x78, MemAddress, I2C_MEMADD_SIZE_8BIT, pData, Size, Timeout); - 写EEPROM等内存设备
- 内存读函数:
HAL_StatusTypeDef HAL_I2C_Mem_Read(&hi2c1, (uint16_t)0x78, MemAddress, I2C_MEMADD_SIZE_8BIT, pData, Size, Timeout); - 读EEPROM等内存设备
- 其他函数:带IT后缀的用于中断模式
- 这些是I2C功能的核心接口
STM32硬件I2C主机通信API函数 - 参数详解
Section titled “STM32硬件I2C主机通信API函数 - 参数详解”- 四个核心函数:与中断/DMA函数类似,使用方式相似
- 基础轮询函数为主,其他类似
- HAL_I2C_Master_Transmit:主机发送函数
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);- 第1参数:I2C句柄(
I2C_HandleTypeDef *hi2c) - 第2参数:设备地址(
uint16_t DevAddress) - 其他函数参数类似:
HAL_I2C_Master_Receive:主机接收
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);HAL_I2C_Mem_Write:内存写(EEPROM)
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint8_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);HAL_I2C_Mem_Read:内存读(EEPROM)
HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint8_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);I2C主机API参数 - 设备地址与数据详解
Section titled “I2C主机API参数 - 设备地址与数据详解”- HAL_I2C_Master_Transmit 参数继续:
- 第2参数:设备地址 (
uint16_t DevAddress) - 总线上多个从机时,每个从机地址唯一
- 发送设备地址选择要操作的从机(如触摸屏)
- 第3参数:发送数据 (
uint8_t *pData) - 第4参数:发送数据长度 (
uint16_t Size) - 其他函数参数类似:每个设备在总线上有唯一地址
STM32硬件I2C主机通信API函数 - HAL_I2C_Master_Receive参数详解
Section titled “STM32硬件I2C主机通信API函数 - HAL_I2C_Master_Receive参数详解”- HAL_I2C_Master_Receive:主机接收函数,参数与发送类似
- 第1参数:I2C句柄
- 第2参数:设备地址(从哪个设备接收数据)
- 第3参数:数据存储指针(接收数据存储位置)
- 第4参数:数据长度(
uint16_t Size) - 第5参数:超时时间(
uint32_t Timeout)
STM32硬件I2C主机通信API函数 - 内存读写作用
Section titled “STM32硬件I2C主机通信API函数 - 内存读写作用”- 内存读写函数作用:用于操作EEPROM等存储芯片数据
- 理解方式:主控作为主机,通过I2C与EEPROM通信
+----------------+| 主控 |+----------------+
+----------------+| EEPROM |+----------------+- EEPROM特点:存储芯片,可存储数据(后续详解具体作用)
EEPROM存储结构与I2C通信
Section titled “EEPROM存储结构与I2C通信”- EEPROM内部结构:有很多存储区域,像一间间房子
- 可画表格表示
+--------+--------+--------+ | 区域1 | 区域2 | 区域3 | +--------+--------+--------+- 每个区域大小根据芯片型号决定
- I2C通信方式:两根线
- 时钟线 (SCL)
- 数据线 (SDA)
- 通信过程:首先指定要操作的存储区域
I2C总线多设备挂载与地址
Section titled “I2C总线多设备挂载与地址”- 设备地址示例:如0x51,总线上可挂多个I2C设备
- 只要地址不同即可(如第二个EEPROM地址0x52)
- 一个总线支持多个设备
- 每个I2C设备特点:都有内部存储地址
- 用于后续内存读写操作
+------------------+| 主控 |+------------------+ | v+------------------+ +------------------+| EEPROM | | EEPROM || 0x51 | | 0x52 |+------------------+ +------------------+- 内存读写函数应用:直接用于操作存储设备如EEPROM
- EEPROM示例:2kbit容量 = 256 byte(可存储256字节数据)
- 内部有存储地址,用于指定操作位置
+-----------------+ +------------+| System |----->| EEPROM OUT1|+-----------------+ +------------+ | v+-----------------+ +------------+| |----->| EEPROM OUT2|+-----------------+ +------------+- 存储区域示意:
+----+----+ +----+----+----+| FF | 11 |+----+----+ +----+----+----+
+----+----+----+| | | |+----+----+----+| | | |+----+----+----+HAL_I2C_Mem_Write 函数使用示例
Section titled “HAL_I2C_Mem_Write 函数使用示例”- 实际写操作示例:向EEPROM指定地址写入数据
- 例子0写入 0s ff
- 例子10写入数据
- 例子111写入数据
- 例子2写入数据
- 参数应用:
- 第1参数:I2C句柄
- 第2参数:设备地址(选择具体EEPROM)
- EEPROM1:0s01
- EEPROM2:0s02
- 通过设备地址区分总线上的不同EEPROM
I2C内存读写函数 - MemAddress参数详解
Section titled “I2C内存读写函数 - MemAddress参数详解”- 第3参数:内存地址 (
uint16_t MemAddress) - 对应EEPROM内部存储位置
- 示例:填0 表示第一个位置,写入FF
+------------------+| EEPROM || 内存地址 0 |+------------------+| FF | | | |+----+----+----+--+| | | | |+----+----+----+--+- EEPROM容量示例:2kbit = 256 byte
- 有256个位置可存储数据
- 通过地址指定操作位置(如地址1写入其他数据)
I2C内存读写函数 - MemAddSize参数详解
Section titled “I2C内存读写函数 - MemAddSize参数详解”- 第4参数:MemAddSize (
uint8_t MemAddSize) - 指定内存地址位宽(地址大小)
- 8bit = $$2^8 = 256$$,刚好覆盖256 byte位置
- 适用于2Kbit = 256 byte的EEPROM
- 16bit = $$2^{16}$$,用于更大容量
- 如1024 byte,8bit不够用需16bit覆盖所有地址
- 选择依据:根据EEPROM容量决定地址位宽
- 确保能遍历所有存储位置
8 bit ──► 2^8 = 256 (2Kbit EEPROM)16 bit ─► 2^16 (1024 byte EEPROM)- 示例:
- 16 byte容量:8bit足够(2^8=256 > 16)
- 1024 byte:需16bit
- 内存读写函数后序参数(第5~7参数,与Transmit/Receive类似)
- 第5参数:pData(uint8_t*),要写入/读出的数据指针
- 示例:存储数据10,直接写10(或放入数组)
- 第6参数:Size(uint16_t),数据长度
- 示例:单个数据10,长度为1
- 第7参数:Timeout(uint32_t),超时时间
- 读操作参数相同:先选设备地址 + 内存地址,然后指定读出数据位置、长度和超时
- 用于带内存地址的I2C存储设备(如EEPROM)的读写操作
- 内存读写函数剩余参数:用于从EEPROM指定内存地址读取数据
- 读操作示例:从内存地址0、1或2读取数据
- 参数顺序:内存地址(指定位置)、数据长度、读入数据存储位置、读数据大小
- 函数作用总结:完成I2C内存读写全过程
EEPROM 定义与Flash比较
Section titled “EEPROM 定义与Flash比较”- EEPROM:电可擦可编程只读存储器(Electrically Erasable Programmable Read-Only Memory)
- 特点:带电可擦写,断电后数据不丢失(非易失性)
- 与 Flash 比较:
- 共同点:均存储数据,断电不丢失
- 区别:
- EEPROM:字节单位擦写
- Flash:扇区单位擦写
EEPROM 与 Flash 比较 - 擦写次数与单位
Section titled “EEPROM 与 Flash 比较 - 擦写次数与单位”- 擦写次数:
- EEPROM:可达百万次
- Flash:十万次
- EEPROM耐久性更高
- 擦写单位:
- EEPROM:字节级擦除
- Flash:扇区级或整块擦除
- 应用场景:后续了解EEPROM与Flash的典型应用场合
EEPROM 与 Flash 应用场景区别
Section titled “EEPROM 与 Flash 应用场景区别”- EEPROM 应用:
- 写操作要求高(频繁擦写)
- 少量数据
- 示例:配置信息、日志信息
- Flash 应用:
- 写操作要求不高
- 数据量大
- 示例:大块数据存储
- 核心区别:
- EEPROM:频繁擦写 + 小数据量
- Flash:不频繁擦写 + 大数据量
EEPROM 开发板型号与容量
Section titled “EEPROM 开发板型号与容量”- 开发板EEPROM型号:BL24C02
- 容量:2Kbit = 2048 bit
- 换算:2048 ÷ 8 = 256 byte
- 最大存储:256 个字节
BL24C022Kbit = 2048 bit ↓ 256 byteEEPROM引脚功能与地址配置
Section titled “EEPROM引脚功能与地址配置”- BL24C32:EEPROM,32页,每页8 byte,数据在芯片手册中。
- A0, A1, A2:配置器件地址,用于I2C总线上区分设备。
EEPROM地址配置与多设备挂载
Section titled “EEPROM地址配置与多设备挂载”- A0, A1, A2:三个IO引脚,用于配置器件地址
- 通过不同高低电平组合,设置不同地址
- 允许多个EEPROM挂载在同一I2C总线上
- 只要器件地址不同,即可区分
- 原理图连接:
- SDA、SCL:I2C总线
- 写保护(WP):保护功能
- 电源:供电部分
I2C总线 (SDA, SCL) │ +───+───+ | A0,A1,A2 | ← 高低电平配置地址 | EEPROM1 | +───+───+ │ +───+───+ | A0,A1,A2 | ← 不同组合 | EEPROM2 | +───+───+EEPROM BL24C02 硬件连接与地址配置
Section titled “EEPROM BL24C02 硬件连接与地址配置”- 引脚连接:
- SCL → PB6
- SDA → PB7
- A0, A1, A2 → GND(标为D)
- 作用:A0/A1/A2配置器件地址,用于I2C总线区分设备
- 具体设备ID在芯片手册中查找
BL24C02 EEPROMSCL ── PB6SDA ── PB7A0 ── GNDA1 ── GNDA2 ── GND- 电源与滤波:
- 上拉电阻(两个)
- 电源接电容(使电源更干净)
EEPROM设备地址配置原理
Section titled “EEPROM设备地址配置原理”- A0、A1、A2接地(均为0):设备地址为1010 000(0x50)
- 前缀1010固定
- 后三位A2 A1 A0 = 000
- 改变地址示例:将A0接1(高电平),地址变为1010 001
- 通过不同高低电平组合,设置不同地址
- 实现同一I2C总线上多个EEPROM区分
地址格式:1010 A2 A1 A0
A0=A1=A2=0 (接地) → 1010 000 = 0x50A0=1, A1=A2=0 → 1010 001EEPROM BL24C02 器件地址计算
Section titled “EEPROM BL24C02 器件地址计算”- A0/A1/A2 均接低电平(D/GND):对应001(三个0)
- 地址格式:10101010 + 三个0 + 读写标志位
- 前7位:1010100(器件地址)
- 第8位:读写标志(0写、1读)
- 作用:主机通过此地址识别设备,进行读写数据操作
A0=A1=A2=0 (低电平)↓1010 1010 (完整字节)└── 前7位: 1010100 (设备地址) └── 第8位: R/W标志- 写操作:设备地址 + 读写位(0),如
0xA0。 - 读操作:设备地址 + 读写位(1),如
0xA1。 - 读写位的不同导致最终发送的byte不同。
EEPROM读写时序
Section titled “EEPROM读写时序”- 查看芯片手册获取读写时序图。
EEPROM写操作I2C通信起始过程
Section titled “EEPROM写操作I2C通信起始过程”- 写1字节步骤:
- 发送起始信号
- 发送设备地址(前7位 1010100)+ 写标志位0
- 完整字节:0x50(SA0,设备地址+写位)
- 等待设备应答
起始信号 ↓设备地址 (1010100) + 写位 (0) = 0x50 ↓设备应答- 地址格式回顾:I2C从机地址前7位 + 第8位读写标志(写为0)
EEPROM BL24C02 内存地址范围
Section titled “EEPROM BL24C02 内存地址范围”- 内存地址:8位(uint8_t 类型)
- 范围:00 到 FF
- 原因:芯片最大存储 256 byte 数据
- 256 = 2^8,故用8位地址表示
- 作用:指定芯片内部具体字节位置进行读写操作
内存地址:8 bit00 ──────┬─── FF │ 256 bytes └─ BL24C02 容量EEPROM读操作I2C通信起始过程
Section titled “EEPROM读操作I2C通信起始过程”- 读1字节步骤:分为两次I2C通信
- 第一次:发送设备地址 + 写标志位(0)
- 先将要读取的内存地址写进设备
- 设备地址后接内存地址
- 作用:告知设备具体内存位置,准备后续读取
读操作起始:起始信号 ↓设备地址 (1010100) + 写位 (0) ↓内存地址 (要读取的位置) ↓设备应答 ↓第二次I2C (读数据)EEPROM读操作I2C通信过程
Section titled “EEPROM读操作I2C通信过程”- 读操作步骤:
- 先发送设备地址(前7位 1010100)+ 写标志位0(0xA0),写入内存地址
- 设备知道要读哪个内存空间的数据
- 发送完内存地址后,开始真正读操作
- 发送设备地址 + 读标志位1(0xA1)
写阶段:起始 → 0xA0 (设备地址+写0) → 内存地址 → 设备应答↓读阶段:0xA1 (设备地址+读1) → 读取数据- 关键:先用写操作指定内存地址,再用读操作获取数据
EEPROM读操作I2C通信过程 - 读1字节与连续读
Section titled “EEPROM读操作I2C通信过程 - 读1字节与连续读”- 读1字节完成:
- 设备发送内存地址后,等待设备应答
- 芯片将该内存位置数据发送给主机
- 完成1字节读操作
- 连续读操作:
- 前半部分与单字节读相同(发送地址、写内存地址)
- 区别:读取多个数据时
- 不发送停止信号
- 主机持续发送应答(ACK)
- 读完所有数据后:发送NACK + 停止信号
单字节读:地址写完 → 设备应答 → 数据上传 → 停止
连续读:地址写完 → 设备应答 → 数据1 → ACK → 数据2 → ACK → ... → NACK + 停止- 关键:连续读通过连续ACK维持通信,最后NACK结束读取
EEPROM读写函数准备与硬件连接确认
Section titled “EEPROM读写函数准备与硬件连接确认”- 读写函数:了解时序后,使用HAL_I2C_Master_Transmit和HAL_I2C_Master_Receive操作EEPROM
- 这两个函数带内存地址,用于数据读写实现
- 硬件连接确认:芯片端连接PB6和PB7
- 手册对应:PB6(SCL)、PB7(SDA)
- PB6/PB7对应I2C接口:PB6是SCL,PB7是SDA。
- 硬件工程师设计:硬件工程师在设计时已确定芯片与PB6/PB7的连接。
- I2C1使能后,PB6和PB7引脚默认被选择。
- I2C1支持端口重映射。
- 可查阅芯片手册了解端口重映射信息。
STM32 I2C1 引脚重映射
Section titled “STM32 I2C1 引脚重映射”- P9点留意:支持引脚重映射
- 硬件设计时,若PB6/PB7已占用(备用于其他功能)
- 可将PB8和PB9重新设置为I2C1的SDA和SCL
- 当前配置:默认PB6(SCL)和PB7(SDA)
- 配置完成:
- 模式设为标准模式
- 从机参数不用管
- 点击生成代码
EEPROM读写函数代码实现 - main函数规划
Section titled “EEPROM读写函数代码实现 - main函数规划”- 实现步骤:
- 先写入8个byte数据到芯片
- 再读取8个byte数据从芯片
- 位置:在main函数中编写代码
- 打开工程,返回main函数查看如何编写
// 规划:先写8字节,再读8字节写入 → 芯片↓读取 ← 芯片- 目的:通过实际代码验证EEPROM读写功能
EEPROM写1字节函数实现
Section titled “EEPROM写1字节函数实现”- 写1字节代码:使用HAL_I2C_Mem_Write
HAL_I2C_Mem_Write(hi2c1, 0x50, 0x00, 1, &data, 1, 0xFFFF);- 参数详解:
hi2c1:I2C句柄0x50:设备地址(前7位 + 写标志位0)0x00:内存地址1:MemAddSize(8位地址)&data:数据指针1:数据长度(1字节)0xFFFF:超时时间- 验证写成功:写后读取数据,比较是否一致
- 目的:确认数据正确写入EEPROM内存
- 设备地址0x50:0xA0 >> 1(HAL库约定,地址左移1位,低位补写标志)
ADC缓冲区初始化
Section titled “ADC缓冲区初始化”- 数据准备:定义8字节数组用于ADC处理
int buffer_size = 8;// 初始化数组为 0,1,2,3,4,5,6,7- 函数调用:传入数组 + buffer_size作为长度
HAL_ADC_NewWriteTable(buffer, buffer_size);EEPROM写1字节函数实现 - 参数补充与调试
Section titled “EEPROM写1字节函数实现 - 参数补充与调试”- 超时时间:设为0xFFFF(毫秒)
- 足够让写入完成
- 内存地址:设为0x00
- 从芯片内存地址开始处写入
- 代码实现后:检查报错情况
- 确认函数调用正确
EEPROM写1字节函数 - MemAddSize参数详解
Section titled “EEPROM写1字节函数 - MemAddSize参数详解”- 内存地址长度(MemAddSize):设为1(8bit)
- 原因:EEPROM最大存储256字节(地址0~0xFF)
- 地址范围足够用8位表示
HAL_I2C_Mem_Write(hi2c1, 0x50, 0x00, 1, &data, 1, 0xFFFF);// 第4个参数:1 表示 8bit 内存地址长度- 关键:MemAddSize根据设备地址位宽选择(BL24C02用8bit)
EEPROM写1字节函数实现 - 成功判断与打印
Section titled “EEPROM写1字节函数实现 - 成功判断与打印”- 函数执行后判断:执行HAL_I2C_Mem_Write后,添加if判断
- 检查返回值等于0:表示写入成功
- 成功时继续打印相关信息
- 编译确认:调整地址参数后,编译无问题
- 数据已写入EEPROM芯片
if (HAL_I2C_Mem_Write(...) == 0) { // 打印成功信息}EEPROM写1字节函数 - 串口重定向与打印实现
Section titled “EEPROM写1字节函数 - 串口重定向与打印实现”- 写入成功判断后打印:返回值等于0表示写入成功
- 添加printf打印成功信息
- 串口重定向配置:
- 打开USART1(端口1)
- 重新生成代码
- 重写fputc函数支持printf
- 示例打印:
fputc('A', stdout); fputc('B', stdout); fputc('C', stdout); fputc('\r', stdout); fputc('\n', stdout);- 使用**HAL_Delay(1000)**控制打印间隔
EEPROM读1字节函数实现
Section titled “EEPROM读1字节函数实现”- 引入头文件与fputc重写:
- 加入头文件支持printf
- 重写fputc函数(从窗口复制,已讲过)
- 用于打印写入成功信息
- 读取准备:
- 初始化buff数组,长度8字节
- 使用HAL_I2C_Mem_Read函数读取
- 先确认写入成功,再执行读取
EEPROM读1字节函数实现 - 参数补充与打印
Section titled “EEPROM读1字节函数实现 - 参数补充与打印”- HAL_I2C_Mem_Read参数补充:
- 第5参数:读取长度(sizeof(buffer) 或 buffer_size)
- 第6参数:超时时间(0xFFFF)
- 读取完成后数据存入buffer
- 验证读取结果:使用for循环打印buffer内容
- 比较是否与写入数据(0,1,2,3,4,5,6,7)一致
for (i = 0; i < 10; i++) {}- 循环范围:
i = 0到i < 10(10次迭代) - 打印读取结果:使用
for循环遍历r_buf数组,打印每个字节 - 循环范围:
for (i = 0; i < sizeof(r_buf); i++) - 打印格式:
printf("%d ", r_buf[i]);,每个字节后加空格 - 循环结束后,添加
printf("\r\n");进行换行 - 验证:检查打印出的数据是否与写入的
0,1,2,3,4,5,6,7一致
EEPROM读写程序延时设置
Section titled “EEPROM读写程序延时设置”- 编译前优化:在主循环和写入操作后添加延时
- 原因:无延时读写过快,不便观察串口输出
- 效果:每秒执行一次写+读操作
HAL_Delay(1000); // 1秒延时- 位置:
- 主循环末尾:控制整体读写频率
- 写入后:确保写入完成再读取
EEPROM写操作延时必要性
Section titled “EEPROM写操作延时必要性”- 写入后延时原因:EEPROM设备需要时间完成数据写入
- 无延时虽打印“写入成功”,实际数据未写入
- 实验验证:不加延时读取数据不正确
- 延时位置:HAL_I2C_Mem_Write后立即添加
- 等待写入完全完成
- 确保后续读取数据准确
HAL_I2C_Mem_Write(...);HAL_Delay(时间); // 等待写入完成EEPROM读写程序烧录与串口验证
Section titled “EEPROM读写程序烧录与串口验证”- 烧录步骤:选择SWD模式,Flash下载路径选Load and Run
- 添加对应下载算法,编译烧录程序
- 验证观察:烧录完成后打开串口调试助手
- 找到设备串口,点击打开
- 输出显示**“write success”**确认写入成功
- 下方打印读取数据:0,1,2,3,4,5,6,7(与写入一致)
温湿度传感器驱动介绍
Section titled “温湿度传感器驱动介绍”- 设备连线:先查看温湿度传感器的连接方式
I2C引脚分配与连接
Section titled “I2C引脚分配与连接”- SDA和SCL引脚:SDA连接PB11,SCL连接PB10
- 用于连接温湿度传感器
- 引脚确认:通过芯片手册查找PB10和PB11的具体位置
温湿度传感器工程准备与特征介绍
Section titled “温湿度传感器工程准备与特征介绍”- PB10和PB11引脚对应:刚好对应I2C2接口
- 新建工程:借助上几课工程,改为demo14
- 先关闭demo13工程
- 配置前准备:打开CubeMX前,先了解温湿度传感器的一些特征
温湿度传感器I2C速率配置
Section titled “温湿度传感器I2C速率配置”- I2C接口速率:支持高达1MHz(快速模式)
- 前序配置使用标准速率(100kHz)
- 配置选择:
- 高采样率需求 → 快速模式
- 低采样率需求 → 标准模式(不影响使用)
- I2C2模式调整:
- 当前禁用I2C2,本节课启用
- 可改为快速模式,标准模式也行
I2C2配置自动调整与代码生成
Section titled “I2C2配置自动调整与代码生成”- 选择I2C2自动配置:选择I2C2后,PB10和PB11自动改为I2C2对应接口
- 代码生成:点击生成代码按钮
温湿度传感器设备地址配置
Section titled “温湿度传感器设备地址配置”- 芯片地址配置:通过ADDR引脚设置
- 低电平:设备地址 0x44
- 高电平:设备地址 0x45
- 全中文文档:对初学者更易上手
- 标注位置:银角处标出配置信息
温湿度传感器设备地址配置
Section titled “温湿度传感器设备地址配置”- 设备地址基础:0x44(前7位bit:0100 0100)
- 实际读写地址需后面加读写位
- 地址计算:将最高位去掉后得出完整地址
- 示例:抠出7bit 0x44,用于I2C通信
温湿度传感器设备地址格式
Section titled “温湿度传感器设备地址格式”- 7位地址 + 读写位:设备地址7位,最后一位为读写标识
- 写操作:7位地址后加0(写位),完整8位地址为0x88
- 读操作:7位地址后加1(读位),完整8位地址为0x89
// 写寄存器:0x88 + 写位(0)// 读寄存器:0x89 + 读位(1)- 手写笔记确认:7bit + 1bit(地址位 + 读写位)
温湿度传感器工作模式
Section titled “温湿度传感器工作模式”- 两种模式:
- 当次转换模式:单次测量
- 周期性模式(连续转换):持续测量
- 本节选择:使用周期性命令
- 已从文档抠出相关时序图
- 进入方式:首先发送特定命令进入周期性模式
- 温湿度传感器的重复率和转换周期会影响其精确度。可参考数据手册进行参数配置。可参考高重复率(每秒测量一次)。
- 首先配置起始信号。
温湿度传感器周期性模式 - 重复率与精度关系
Section titled “温湿度传感器周期性模式 - 重复率与精度关系”- 重复率影响:重复率越高(每秒转换次数越多)
- 转换时间越长
- 功耗越高
- 精度越高
- 参数来源:数据手册详细列出具体数值
- 示例表格:高/中/低重复率对应不同nps、MSB/LSB值和十六进制命令
| 操作 | nps | MSB | LSB | 十六进制值 ||------|-----|-----|-----|------------|| 高 | 0.5 | 0x0 | 24 | 0x24 || 低 | | 1/5 | 24 | 0x21 || 中 | 1 | 0x0 | 26 | 0x26 |周期性模式进入与转换启动
Section titled “周期性模式进入与转换启动”- 进入步骤:设置完模式后发送开始转换指令
- 数据读取格式(周期性模式)
- ADC地址:0x00(Command)
- 温度:MSB + LSB + CRC
- 湿度:MSB + LSB + CRC
Command | Fetch Data | Hex code---|---|---ADC address | 0x00 | 0x00Temperature MSB | Temperature LSB | CRCHumidity MSB | Humidity LSB | CRC温湿度传感器读写代码实现 - 发送周期性模式命令
Section titled “温湿度传感器读写代码实现 - 发送周期性模式命令”- 命令值:发送 0x2130 进入周期性模式
- 直接操作传感器本身,无内部内存地址
- 函数选择:使用 HAL_I2C_Master_Transmit(之前EEPROM写函数)
- 先 copy EEPROM写函数代码过来调整
- 代码位置:main函数中实现
温湿度传感器读操作函数选择
Section titled “温湿度传感器读操作函数选择”- 读数据函数:使用 HAL_I2C_Master_Receive
- 参数顺序:设备句柄、设备地址(0x88)、buff(数据缓冲区)、数据长度、超时时间(0xFFFF)
- 与写操作对应:第三个参数为数据接收缓冲区,后续参数同写函数
- 读数据函数:
HAL_I2C_Master_Receive,参数:设备句柄、设备地址(0x88)、buff(数据缓冲区)、数据长度、超时时间(0xFFFF) - 读操作地址:
0x89 - 6字节数组:用于存储读取的数据
温湿度传感器读数据函数调用
Section titled “温湿度传感器读数据函数调用”- HAL_I2C_Master_Receive 参数顺序:
- 设备句柄(hi2c2)
- 设备地址 0x88
- 数据缓冲区 buff
- 数据长度
- 超时时间 0xFFFF
- 数据转换:读取后调用转换函数
- 初始化两个变量:分别存储温度和湿度数据
uint16_t data_buf[32]; // 示例缓冲区HAL_I2C_Master_Receive(hi2c2, 0x88, data_buf, 数据长度, 0xFFFF);- HAL函数通用性:官方标准方式,直接使用即可
温湿度传感器驱动代码优化
Section titled “温湿度传感器驱动代码优化”- 当前实现:简单死代码,直接设置
- 支持芯片手册多种模式
- 不同重复率、采样率
- 优化建议:封装配置函数
- 参考手册参数
- 提高驱动灵活性
PWM实验准备与TIM4引脚配置
Section titled “PWM实验准备与TIM4引脚配置”- TIM4配置:可配置到6、7、8等背景IO引脚
- 通过通道输出进行引脚复用
- 输出PWM信号
- 后续使用:CubeMX (Q1S) 配置对应通道
- 复制模板工程 → DEMO15
PWM实验原理图与IO选择
Section titled “PWM实验原理图与IO选择”- 实验目标:在原理图中找到支持PWM输出的IO
- 用逻辑分析仪接到IO上验证信号
- 检查输出信号是否符合设置
PWM实验CubeMX配置 - PA7引脚与TIM3
Section titled “PWM实验CubeMX配置 - PA7引脚与TIM3”- 原理图选IO:PA7位于特定针脚,支持PWM输出
- 用逻辑分析仪接到该针脚验证信号波形
- 手册确认:PA7对应TIM3通道2
CubeMX TIM3 PWM配置步骤
Section titled “CubeMX TIM3 PWM配置步骤”- 打开CubeMX,右侧定时器选择TIM3
- 时钟源:设为内部时钟
- 通道选择:通道2设为PWM输出模式
- 配置截取:将TIM3配置块截取保存
// 示例:TIM3 CH2 -> PA7 PWM输出TIM3_Channel2_PWM_ModeCubeMX TIM3 PWM配置 - 通道输出特点
Section titled “CubeMX TIM3 PWM配置 - 通道输出特点”- PWM多通道特性:四路输出信号频率相同(与配置频率一致)
- 每路占空比可独立不同
- 与PWM模式区别:PWM只能输出相同频率信号
- 配置频率统一控制所有通道
PWM生成原理与CCR占空比控制
Section titled “PWM生成原理与CCR占空比控制”- 定时器计数过程:CNT从0开始递增至ARR
- CNT ≤ CCR:输出低电平
- CNT > CCR:输出高电平
- CNT > ARR:清零重置,重新开始
- 波形形成:高电平持续时间由CCR值决定
- CCR值越大,占空比越高
- ARR决定周期频率
CNT: 0 ──→ ARR (溢出清零) │ ├─≤ CCR: 低电平 ├─> CCR: 高电平 └─> ARR: 重置
示例波形:低──┬──────┴──────┐─── │ 高电平持续 (CCR决定) └─────────────────→ ARR重置PWM占空比与CCR设置示例
Section titled “PWM占空比与CCR设置示例”- 50%占空比设置:ARR预分频值为500时,CCR设为250
- CCR值决定高电平持续时间
- 值越大,占空比越高
- CCR初始值:先填0,后续用代码动态设置
输出比较预装载值作用
Section titled “输出比较预装载值作用”- 功能:使能或禁用输出比较预装载
- 使能后:重新设置预装载值时,不会立即生效
- 生效时机:等到下一次周期(当前周期输出完)
- 好处:避免设置过程中波形异常
- 确保新值在周期完整时切换
// 示例配置ARR = 500;CCR = 250; // 50%占空比Preload_Enable(); // 输出比较预装载使能PWM逻辑分析仪验证与实验
Section titled “PWM逻辑分析仪验证与实验”- 验证步骤:双击按钮连接无问题后显示knet状态,点击start启动
- 第二个通道显示0到1信号
- 明显观察标电平和高低电平各一半,即当前50%占空比
- 频率确认:位置显示两个字,即定时器频率
- 第一个实验:通过函数不停修改CCR值控制占空比
- 定义uint16_t变量记录当前值
uint16_t var; // 记录当前CCR值PWM占空比动态控制代码实现
Section titled “PWM占空比动态控制代码实现”- while循环控制:每次延时1毫秒,让CCR递增到最高500(ARR值)
- 达到最高时跳出循环(溢出)
- 递减操作:外层循环时进行减1操作
- 或直接设为0
- 判断条件:CCR > 1 为真
- CCR与占空比同步:减1操作同时设置CCR值
- 两个参数相同(CCR值控制占空比)
- 延时设置:每次设置完延时200毫秒
- 更清楚观察变化
// 示例代码框架while (var <= 500) { // 递增到ARR HAL_Delay(1); // 1ms延时 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, var++);}
while (var > 1) { // 递减 HAL_Delay(200); // 200ms观察变化 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, --var);}- 编译烧录验证:编译后烧录
- 点击调试,按住Ctrl观察现象
PWM占空比动态验证与函数控制
Section titled “PWM占空比动态验证与函数控制”- 逻辑分析仪观察:缩小视图后,黑线(高电平)变多,低电平变少
- CCR增大 → 高电平时间更长,占空比更高
- 接近50%时:高低电平时间均衡
- 动态修改:通过函数调用修改CCR参数
- 往右拉 → 接近500,高电平时间显著延长
- 两个关键函数控制占空比
- 后续实验:频率修改
PWM频率修改方法
Section titled “PWM频率修改方法”- 频率控制参数:定时器分频值(PSC)或预装载值(ARR)决定频率
- 修改任一值均可改变频率
- 示例:将PSC改为1000或ARR改为36
- 预分频值修改函数:
__HAL_TIM_SET_PRESCALER - 参数1:定时器句柄(如
&htim3) - 参数2:要设置的预分频值
// 修改PWM频率示例__HAL_TIM_SET_PRESCALER(&htim3, 1000); // 设置预分频为1000- 实验步骤:注释掉动态占空比代码
- 先复制函数查看位置
- 修改后观察频率变为2kHz
- 频率验证:逻辑分析仪显示新频率值
PWM频率动态修改代码实现
Section titled “PWM频率动态修改代码实现”- ARR值控制频率:CCR固定,修改ARR改变频率
- 原ARR = 72-1(1kHz频率)
- 改为36-1(0~35计数,频率变为2kHz)
// 示例代码__HAL_TIM_SET_AUTORELOAD(&htim3, 72-1); // 1kHzHAL_Delay(100); // 100ms延时观察
__HAL_TIM_SET_AUTORELOAD(&htim3, 36-1); // 2kHzHAL_Delay(100);- 编译警告处理:变量未使用警告可忽略
- 直接编译烧录验证
PWM频率变化验证
Section titled “PWM频率变化验证”- 逻辑分析仪观察:100ms内频率切换明显
- 1kHz:波形较疏
- 2kHz:波形更密(高频特征)
- 4kHz:密度进一步增加
- 现象确认:波形密度越高,频率越高
- 缩小视图观察变化过程
- 常用作声音提示或报警装置
- 电子玩具、报警器、电话机、打印机、复印机
- 医疗设备、仪器仪表、各电子设备工作提示音
- 示例:家用烧水壶水烧完发声提醒
- 通过压电陶瓷片或电磁线圈振动产生声音
- 有源蜂鸣器:内部集成振荡电路
- 驱动方式:只需接通电源(高低电平)即可发固定频率声音
- 特点:频率固定,只能发出一种声音
- 无源蜂鸣器:内部无振荡电路
- 驱动方式:需外部提供特定频率脉冲信号(如2KHz PWM)
- 特点:频率可调,能发出多种声音
有源只需高低电平,无源需PWM脉冲(如前面PWM实验)
无源蜂鸣器驱动电路 (原理图第12页)
Section titled “无源蜂鸣器驱动电路 (原理图第12页)”- 通过改变PA3端口的频率来控制发声。
- 本开发板用的是P管:
- 低电平时发声。
- 高电平时截止。
无源蜂鸣器PWM驱动实验
Section titled “无源蜂鸣器PWM驱动实验”- CCR设置示例:ARR预装载值为500时,设CCR=250实现50%占空比
- 编译无误后烧录
- 实验验证:烧录后蜂鸣器发出声音
- 麦克风可能屏蔽声音,实际实验可清晰听到
- 成功标志:蜂鸣器发声
- 频率修改效果:改变PWM频率产生不同声音
- 文档中提供合适频率范围
// 编译前检查:缺少通道参数需补充// 如 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 250);- 注意:P管驱动,低电平时发声,高电平时截止
ADC原理图分析
Section titled “ADC原理图分析”- 金属氧化物半导体:人体半导体结构,人呼气时半导体接触到氧化物导致电阻变化,影响电流。
- PT2324:一种气体传感器,提供模拟信号输出;原理图参考其应用电路设计。
- Q1:TOC为0时,CMOS关断;TOC为1时,CMOS导通;AHLB控制上下拉电阻。
- C17, C21:电源滤波电容,降低电源噪声,稳定电源。
按键输入配置
Section titled “按键输入配置”新工程准备与PC13引脚配置
Section titled “新工程准备与PC13引脚配置”- 工程复制:复制现有工程作为新工程基础
- 引脚选择:配置PC13为输入模式
- 外部已有上拉电阻,选择Pull-up(上拉)
- 不影响功能,也可选择无上拉/下拉(浮空)
- User Label修改:自定义标签,便于代码中使用
// GPIO配置参数GPIO mode: InputPull-up/Pull-down: Pull-upUser label: (自定义)- 目的:判断按键当前状态(按下与否)
按键状态读取与逻辑
Section titled “按键状态读取与逻辑”- 读取函数:
HAL_GPIO_ReadPin(KEY_OTD_GPIO_Port, KEY_OTD_Pin) - 按下:返回**
GPIO_PIN_RESET**(低电平) - 松开:返回**
GPIO_PIN_SET**(高电平,上拉电阻作用) - 按键检测逻辑(主循环中):
if (HAL_GPIO_ReadPin(KEY_OTD_GPIO_Port, KEY_OTD_Pin) == GPIO_PIN_RESET) { // 按键按下,等待松开 while (HAL_GPIO_ReadPin(KEY_OTD_GPIO_Port, KEY_OTD_Pin) == GPIO_PIN_RESET) { // 等待松开 } // 按键松开后执行动作 printf("Button pressed and released.\n");}- 外层if:检测按下
- 内层while:等待松开完成一次完整按键周期
- 消抖处理:按下/松开检测后添加**
HAL_Delay(20)**(20ms延时) - 确认状态稳定,避免抖动误判
- 打印验证:使用printf输出按键状态变化
- 配合串口重定向观察
- 完整示例(while循环内):
/* USER CODE BEGIN 3 */while (1) { if (HAL_GPIO_ReadPin(KEY_OTD_GPIO_Port, KEY_OTD_Pin) == GPIO_PIN_RESET) { while (HAL_GPIO_ReadPin(KEY_OTD_GPIO_Port, KEY_OTD_Pin) == GPIO_PIN_RESET) {} printf("Button pressed and released.\n"); } HAL_Delay(20);}/* USER CODE END 3 */- 编译烧录:编译,烧录程序。
- 接线:连接USB转串口线至电脑。
- 串口调试助手:打开,选择对应串口。
- 触发:点击触发按键进行测试。
- 触摸IC测试完成:点击后,触发一次。
- 用于电机控制类产品的位置闭环
- 计算编码器正反转及转动圈数
- 实现运动控制算法
- 速度闭环控制
- 位置闭环控制
- 开发板左侧DDR位置集成本轮选装编码器
- 本节实验使用此编码器
- 学习编码器驱动方法
- 通过读取值实现转动检测与控制
- 后续图示解释原理
- 贴图浅解工作机制
引脚功能与连接
Section titled “引脚功能与连接”- 四个引脚:A、B、C、S
- C:公共端,连接到B
- S:按键信号
- 三种控制:
- 顺时针旋转
- 逆时针旋转
- 按下(当物理按键使用)
- 按下信号:与之前按键操作相同
- 本节暂不演示(已掌握按键驱动)
编码器引脚: A ──┐ B ──┤ ENCODER C ──┤ (公共端 → B) S ──┘ (按键信号)编码器A、B信号时序与旋转方向判断
Section titled “编码器A、B信号时序与旋转方向判断”- 顺时针旋转(CW):A信号先于B变高
- A先高 → B再高
- A先低 → B再低
- A领先B
- 反时针旋转(CCW):B信号先于A变高
- B先高 → A再高
- B先低 → A再低
- B领先A
CW (顺时针):A: ____/‾‾‾\____B: __/‾‾‾\_____ ↑A先高 ↑A先低
CCW (反时针):B: ____/‾‾‾\____A: __/‾‾‾\_____ ↑B先高 ↑B先低- 判断原理:通过A、B相位差确定旋转方向
编码器原理图与STM32引脚连接
Section titled “编码器原理图与STM32引脚连接”- 信号连接:编码器A信号接PB0,B信号接PB1
- 通过读取PB0和PB1引脚电平状态判断旋转方向
- 编码器芯片引脚:A1、A2输入,OUT1、OUT2输出
- 连接电阻、电容等外部元件
- VCC、GND供电
编码器芯片连接: A1 ── PB0 (STM32) A2 ── PB1 (STM32) OUT1, OUT2 ── 输出波形 VCC, GND ── 电源- SW引脚:按键信号(忽略,本节不涉及)
STM32CubeMX新工程配置与PB0、PB1引脚设置
Section titled “STM32CubeMX新工程配置与PB0、PB1引脚设置”- 工程准备:复制现有工程,命名为encoder_demo(或018demo)
- PB0配置(连接A1信号):
- 模式:外部中断模式(Falling edge trigger detection,下降沿触发)
- User Label:修改为A1
- PB1配置(连接B信号):
- 模式:普通输入模式(Input mode)
- 目的:读取PB0、PB1电平状态判断编码器旋转方向
// GPIO配置示例PB0: External interrupt (Falling edge) + Label: A1PB1: Input mode- 后续:编译生成代码,准备读取A、B信号实现方向判断
编码器CubeMX配置与中断开启
Section titled “编码器CubeMX配置与中断开启”- 引脚调整:将PB0改为PB1,使A1和B1连接更清晰
- 配置完成后打开中断部分
- 开启串口(调试日志)观察效果
- 代码生成:配置完生成代码,编译无误
外部中断回调函数重写
Section titled “外部中断回调函数重写”- 位置:在外部中断文件中重写回调函数
- A通道中断触发时判断B电平状态
- 代码实现:直接复制之前外部中断代码
// 外部中断回调函数(示例) // 在中断服务函数中判断B引脚电平 // 实现旋转方向检测逻辑- 目的:通过中断方式捕获编码器信号变化
编码器程序实现与验证
Section titled “编码器程序实现与验证”- main函数修改:加入
<stdio.h>和<stdlib.h>。 - 全局变量定义:
is_cw和is_ccw,用于保存方向状态。
bool is_cw = false; bool is_ccw = false;- 中断服务程序:判断当前旋转方向,并打印信息。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if (GPIO_Pin == A1_Pin) { if (HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == GPIO_PIN_RESET) { is_ccw = true; is_cw = false; } else { is_cw = true; is_ccw = false; } }}- 主循环:根据
is_cw和is_ccw标志位打印旋转方向。
while (1){ if(is_ccw){ is_ccw = false; printf("is_ccw方向\r\n"); } if(is_cw){ is_cw = false; printf("is_cw方向\r\n"); }}- 添加头文件:添加
stdio.h和stdlib.h头文件。 - 编译与调试:编译代码,连接开发板,配置调试。
- 验证:旋转编码器,观察串口输出,确认方向判断正确。
STM32编码器专用模式配置
Section titled “STM32编码器专用模式配置”- 支持条件:AB两个引脚刚好是支持编码器模式的引脚
- 配置方式:直接配置该模式,根据文档进行设置
- 读取函数:
- 一个函数读取方向
- 一个函数读取数据
- 优势:无需手动编写底层代码,简化实现
课程总结与预告
Section titled “课程总结与预告”- 本节编码器驱动简解结束
- 下一节:电机相关知识,介绍电机种类
基本特点与控制
Section titled “基本特点与控制”- 有刷直流电机:两根线输出
- 一根接正极、一根接负极 → 正转
- 交换正负极 → 反转
- 转速控制:由供电电压决定
- 电压越高,转速越快
- 不超过额定电压
与步进电机对比
Section titled “与步进电机对比”- 常见电机类型:步进电机与直流电机
- 本课使用有刷直流电机说明
- 区别:步进电机(无刷/有刷),直流电机(有刷为主)
步进电机优点与缺点
Section titled “步进电机优点与缺点”- 优点:低速时扭矩大,控制精度高,可实现精确控制
- 缺点:成本较高,结构复杂,控制较复杂,转速偏低
- 主要用于精准位置控制
直流电机优点与缺点
Section titled “直流电机优点与缺点”- 优点:结构简单,成本低,运行平稳,噪音小
- 缺点:低速时扭矩较小,控制精度较低
- 位置控制困难,除非加额外编码器
STM32驱动电机思考
Section titled “STM32驱动电机思考”- 问题:STM32 IO口直接接电机引线是否可行?
- 需要思考原因(电流、功率等)
STM32 IO驱动电机不可行原因
Section titled “STM32 IO驱动电机不可行原因”- STM32 IO驱动能力有限:无法提供电机所需大电流
- 直接连接IO到电机引线不可行
三极管开关电路驱动方法
Section titled “三极管开关电路驱动方法”- 参考蜂鸣器驱动电路:使用三极管开关电路
- 电路组成:NPN三极管 + 蜂鸣器(或电机)
- 工作原理:高电平(1)时,VCC → 蜂鸣器 → 三极管 → GND 通路导通
- 实现大电流设备驱动
三极管开关电路: VCC ── 蜂鸣器 ── 三极管(C) │ (B) ← IO └── E ── GND直流电机驱动电路原理
Section titled “直流电机驱动电路原理”- 电路组成:替换蜂鸣器为电机,包含保护电机(续流二极管)和潜微电机(主电机)
- 不确定状态:网口低,MOS管不导通,电机停止
- 控制过程:
- 单片机输出高电平 → 三极管导通
- 电流路径:电源 → 电机 → 流出 → 接地
- 驱动能力增强:由电源提供,非IO直接驱动
- 开关电路作用:提高IO驱动能力
- 单片机仅控制信号,实际功率由外部电路承担
- 实现要点:加开关电路即可驱动电机旋转
H桥电路 (H-Bridge)用于电机正反转控制
Section titled “H桥电路 (H-Bridge)用于电机正反转控制”- 使用四个三极管组成,形似字母H。
- 通过控制三极管的开关状态改变电机电流方向,从而实现正反转。
- 正转:打开Q1和Q4,关闭Q3和Q2。
- 反转:打开Q3和Q2,关闭Q1和Q4。
H桥电路正反转控制细节
Section titled “H桥电路正反转控制细节”- 正转控制:打开Q1和Q4,关闭Q2和Q3
- 电流路径:VCC → Q1 → 电机 → Q4 → GND
- 电机顺时针旋转
- 反转控制:打开Q2和Q3,关闭Q1和Q4
- 电流路径:VCC → Q2 → 电机 → Q3 → GND
- 电机逆时针旋转
- 控制原理:通过控制四个三极管的开关状态改变电流方向
- 需要H桥电路实现正反转
- 注意事项:不能同时打开Q1和Q2
- 否则两个管导通导致短路情况
H桥电路注意事项与改进
Section titled “H桥电路注意事项与改进”- 短路风险:上管与下管同时导通时,VCC直接经管子短路至GND
- 后果:烧毁电路板或元器件
- 控制逻辑:确保不能让上下管同时导通
- 搭建困难:四路需要多个三极管及外围元器件(电阻、电容等)
- 手工焊接相对困难
- 控制逻辑复杂
- 改进方案:使用集成芯片驱动直流电机
- 开发板使用TC118S芯片
- 专用于驱动直流电机
- 简化电路与控制
TC118S 驱动芯片
Section titled “TC118S 驱动芯片”- MOSFET驱动能力:输出电流1.8A/2.5A
- 宽工作电压:3.3V到24V
- 两种封装:16DIP、SOP-8
引脚功能 (16DIP/SOP-8)
Section titled “引脚功能 (16DIP/SOP-8)”| 序号 | 符号 | I/O | 说明 |
|---|---|---|---|
| 1 | NC | NC | 空脚 |
| 2 | NA | - | 混合输入A |
| 3 | NB | - | 混合输入B |
| 4 | VDD | P | 电源 |
| 5 | GND | G | 地 |
| 6 | OUTA | O | 输出A |
| 7 | PGND | P | 电源地 |
| 8 | CUTA | O | 全桥输出A |
- NA/NB:接单片机IO控制信号
输入输出逻辑
Section titled “输入输出逻辑”| NA | NB | OUTA | OUTB | 方式 |
|---|---|---|---|---|
| L | L | H-Z | H-Z | 刹车 |
| H | L | L | H | 正转 |
| L | H | H | L | 反转 |
| H | H | L | L | 停止 |
TC118S 电机驱动实验
Section titled “TC118S 电机驱动实验”实验目标与控制
Section titled “实验目标与控制”- 目标:电机正转5秒 → 停止5秒 → 反转5秒 → 停止5秒
- 控制引脚:PMA(对应INA)、PMB(对应INB),接STM32 IO口
- 输出高/低电平控制电机状态
工程准备与原理图
Section titled “工程准备与原理图”- 打开demo19工程
- 查看原理图:确认PMA/PMB引脚连接
- 配置PMA/PMB为GPIO输出模式
- 通过代码设置高低电平驱动电机
// 示例控制逻辑// 正转:PMA=H, PMB=L// 反转:PMA=L, PMB=H// 停止:PMA=H, PMB=H 或其他状态HAL_Delay(5000); // 延时5秒TC118S电机驱动电路引脚连接
Section titled “TC118S电机驱动电路引脚连接”- 直流电机驱动电路:芯片NA连接PB14,NB连接PB15
- 控制PB14/PB15输出对应电平 → 驱动芯片 → 控制外围电机
- 外围元件:保护管 + 电容(滤波/稳定)
- 配置:PB14/PB15设为GPIO输出模式(控制高低电平)
TC118S电机驱动CubeMX引脚配置
Section titled “TC118S电机驱动CubeMX引脚配置”- PB14连接NA,标签改为DCMA
- PB15连接NB,标签改为DCMB
- 重新生成代码并编译验证无误
电机正转代码控制
Section titled “电机正转代码控制”- 正转:PB14高电平 + PB15低电平
- 使用HAL_GPIO_WritePin函数设置
HAL_GPIO_WritePin(DCMA_GPIO_Port, DCMA_Pin, GPIO_PIN_SET); // 高 HAL_GPIO_WritePin(DCMB_GPIO_Port, DCMB_Pin, GPIO_PIN_RESET); // 低程序烧录与电机正转验证
Section titled “程序烧录与电机正转验证”- 烧录程序后电机开始旋转
- 接电脑配置烧录模式 → 烧录完成 → 电机正转
- 贴标签观察效果
- 正转5秒 → 停止5秒 → 反转5秒
- 清晰验证方向控制完成
PWM控制电机速度
Section titled “PWM控制电机速度”- 速度控制需求:使用PWM
- 两个引脚支持PWM,选择PB15
- CubeMX配置
- PB15设为TIM4 CH3N(互补通道)
- 开启互补输出器
- 时钟源:内部时钟源
PWM电机速度控制CubeMX配置
Section titled “PWM电机速度控制CubeMX配置”- TIM4参数设置:预分频器 72-1,自动重装载 500-1
- 定时器时钟 72MHz,生成连续输出力
- PWM模式配置:通道按 PWM模式
- 后续通过HAL API修改占空比
PWM代码生成与启动
Section titled “PWM代码生成与启动”- 生成代码后新增定时器配置
- 使用前启动:调用
HAL_TIM_PWM_Start函数 - 然后使用
PWM函数
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3); // 示例启动PWM占空比动态控制代码实现(续)
Section titled “PWM占空比动态控制代码实现(续)”- 外循环条件:
pwm_value < 500 - 函数:
HAL_TIM_PWM_Start - 使用
HAL_TIM_SET_COMPARE设置占空比
while(1){ while (pwm_value < 500) { HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, pwm_value); pwm_value++; HAL_Delay(10); } HAL_Delay(1500); while (pwm_value > 0) { HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, pwm_value); pwm_value--; HAL_Delay(10); } HAL_Delay(1500);}- 参数:定时器句柄、通道、占空比值
工作原理介绍
Section titled “工作原理介绍”- 右手法则:线圈通电产生磁场
- 右手握拳,四指弯曲方向为电流方向
- 拇指方向为磁感线(磁场方向)
右手法则应用
Section titled “右手法则应用”- 通电线圈:画出磁感线
- 形成磁场
- 用于解释步进电机驱动原理
步进电机转子与定子磁场吸引原理
Section titled “步进电机转子与定子磁场吸引原理”- 转子:中间磁铁,具有N极和S极
- 定子线圈通电:产生磁场(如一侧S极、另一侧N极)
- 吸引转子向磁场方向旋转一步
- 下一步:同时通电两个线圈
- 中间产生次级磁场
- 继续吸引转子旋转
步进电机转子驱动过程
Section titled “步进电机转子驱动过程”- 通电线圈产生磁场(N极吸引转子S极)
- 转子旋转45度到正面位置
- 切换下一线圈通电
- 转子继续旋转到90度垂直位置
- 顺序通电周围线圈
- 转子逐步旋转,实现连续转动
初始:转子45° ← 线圈磁场下一步:转子90° ← 切换线圈步进电机类型
Section titled “步进电机类型”- 五相步进电机:5根线
- 四线双极性步进电机:4根线
- 接法:A+/A-/B+/B-
![电机模型示意]
- 外观区别:线数不同
步进电机类型 - 内部原理与电流流向
Section titled “步进电机类型 - 内部原理与电流流向”- 五相步进电机(5根线):有一根公共线
- 电流单向:从VCC流入(如线1、2、3、4),经过公共线流出
- 示例:通电线1或线2,电流从VCC → 对应线 → 公共线 → 地
- 四线双极性步进电机(4根线):A+/A-/B+/B-
- 电流双向流动:无公共线,内部结构允许正反电流
- 与单相性区别:电流方向可逆,支持双极驱动
五相(单相性):VCC ──► 线1 ──┐ 线2 ──┤ → 公共线 ──► GND 线3 ──┤ 线4 ──┘
四线(双极性):A+ ──► [内部] ──► A-B+ ──► [内部] ──► B-(电流双向)步进电机类型区别
Section titled “步进电机类型区别”- 五相步进电机(单极性):5根线,带公共线
- 电流方向单一:VCC从公共线流入线圈
- 四相双极性步进电机:4根线(A+/A-/B+/B-)或6线(带公共线)
- 电流方向双向:通过交换VCC/GND位置改变电流流向
- 示例:VCC→A+→A-→GND 或反向
五相四拍步进电机: V | 3 --- | 2 --- | 1 --- | 4 --- | 5 ---
四相双极性: V | 3 --- | 2 --- | 1 --- | 4 ---- 区别总结:
- 线数:5线 vs 4/6线
- 电流控制:单方向(公共线) vs 双方向(极性切换)
步进电机线圈控制原理
Section titled “步进电机线圈控制原理”- 单个线圈通电:产生磁场吸引转子
- 示例:通电A线圈 → 转子被吸至对应位置
- 同时通电两个线圈:中间产生次级磁场
- 吸引转子至45度中间角度
- 示例:A+B同时通电 → 转子旋转至45°
- 顺序切换通电:逐步控制转子旋转
- A通电 → 转子到位
- 断A通B → 转子移至下一位置
- C通电 → 继续吸引转子向下
线圈控制序列:A通电 → 转子到位 ↓A断+B通 → 45°位置 ↓B通+C通 → 继续旋转五相步进电机内部结构
Section titled “五相步进电机内部结构”- 公共线(公共桩):5根线中1根公共输出线
- A、B、C、D对应4个线圈输入
- 所有线圈通过公共线连接输出
- 电流路径:单向流动
- VCC → 输入线(A/B/C/D) → 公共线 → GND
- 控制简单:选择通电线圈即可产生磁场吸引转子
单相步进电机驱动原理
Section titled “单相步进电机驱动原理”- 四步控制方式:
- 第一步:A相线圈通电,产生励磁,转子旋转一个角度
- 第二步:B相线圈通电,产生励磁,转子再转一个角度
- 第三步:A相线圈反向通电,转子再转一个角度
- 第四步:B相线圈反向通电,转子完成整步行程
- 通过**A、B、A-、B-**端子适当电路控制,实现不同方向转动
双极性步进电机驱动原理
Section titled “双极性步进电机驱动原理”- 四根线:A+、A-、B+、B-
- **A+与A-**串联成一组线圈,**B+与B-**串联成另一组
- 两组线圈中间串联连接
- 第一步通电示例:特定组合通电产生磁场,驱动转子旋转
- 八步控制方式:相比四步,采用通电+两个线圈通电交替,实现更细致控制
双极性步进电机驱动原理
Section titled “双极性步进电机驱动原理”- 四根线:A+、A-、B+、B-
- **A+与A-**一组线圈,**B+与B-**另一组,中间串联连接
- 第一步:B相线圈供电
- B+接VCC,B-接GND
- 产生磁场(S极在上,N极在下),吸引转子到对应位置
- 第二步:B相反向供电
- B+接GND,B-接VCC
- 磁场反转(N极在上,S极在下),转子旋转到相反位置
- 第三步:A相供电
- A+接GND,A-接VCC
- 产生相反磁场,吸引转子到新位置
- 第四步:A相反向供电
- A+接VCC,A-接GND
- 磁场再次反转,转子完成四步循环
- 持续驱动:重复以上四步,实现连续旋转
满步驱动介绍
Section titled “满步驱动介绍”- 满步驱动:基本驱动方式(四步循环)
- 后续讲解半步驱动对比
满步驱动与半步驱动区别
Section titled “满步驱动与半步驱动区别”- 满步驱动:基本驱动方式(4步循环)
- 优点:扭矩更大,转速更高
- 图示(一相通电,满步):
.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'- 半步驱动:两相通电交替(8步)
- 优点:提高分辨率,转动角度更小、更精细
- 缺点:输出扭矩变小(约满步的70%)
- 图示(两相通电,半步):
.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'.--. .--. .--. .--.| | | | | | | |'--' '--' '--' '--'- 应用选择:
- 需要高精度角度控制 → 半步驱动
- 需要更大扭矩/更高转速 → 满步驱动
- 步进电机控制前置知识点到此完成
步进电机转动控制原理
Section titled “步进电机转动控制原理”- 步进数量:由脉冲个数决定
- 发多少脉冲,转多少步
- 转动速度:由脉冲频率决定
- 频率越高,转速越快
- 限制:不能超过额定最高频率
- 超出(如几百kHz、1MHz、2MHz)无效
- 实际调试:找到合适频率
- 保证运行效率最高
实验电机参数
Section titled “实验电机参数”- 后续查看电机参数
- 数据手册中提取相关规格
步进电机布局角
Section titled “步进电机布局角”- 布局角定义:单个线圈通电驱动转子旋转的角度
- 典型值:1.8度
- 减速箱作用:内部转子每步45度,经减速后输出1.8度
- 实现精细控制
- 无减速箱情况:每步90度
- 角度控制较粗糙,无法实现小角度精确旋转
双极性步进电机线圈数量
Section titled “双极性步进电机线圈数量”- 两线圈结构:使用前面提到的双极性驱动方式
- 每个线圈对应一组线(A+/A- 或 B+/B-)
- 额定电压:电路设计时考虑
- 与驱动电路相关,后续学习
步进电机驱动芯片 DRV8826
Section titled “步进电机驱动芯片 DRV8826”- 实验驱动芯片:DRV8826(手册显示),相当于两个H桥
- 拖出其中一个桥展示结构
- 引脚功能
- 电源相关:电源和地脚(略)
- 睡眠模式:控制芯片休眠
- 警报输出:电机出错时输出信号
- 四个数字口:控制电机驱动
- 连接单片机IO控制H桥输出
- 分辨率提升:电机带减速箱
- 输出呼吸角更小,分辨率更高
步进电机控制逻辑 (满步驱动与半步驱动)
Section titled “步进电机控制逻辑 (满步驱动与半步驱动)”- 满步驱动:逻辑简单
- 半步驱动:步骤更多(比满步多四步)
- 逻辑相似,只是步骤更多
步进电机驱动芯片 DRV8826 引脚连接
Section titled “步进电机驱动芯片 DRV8826 引脚连接”- DRV8826芯片:相当于两个H桥电路
- 四个数字控制引脚连接STM32 PC7、PC8、PC9、PA8
- 通过这些IO输入电平时序,控制芯片输出驱动电机旋转
- 睡眠模式设置:非睡眠模式,上拉高电平
- 警报引脚:目前悬空(未使用)
DRV8826外围电路
Section titled “DRV8826外围电路”- 保护元件:保护二极管 + 输入保护二极管
- 滤波电容:稳定供电
- 均为常规配置
后续控制方式
Section titled “后续控制方式”- 通过代码控制PC7/8/9 + PA8输出对应电平时序
- 实现电机步进驱动
步进电机实验工程准备
Section titled “步进电机实验工程准备”- 工程创建:复制demo00 → demo20
- CubeMX配置:
- A8、C9、C8、C7设为GPIO输出
- 起始电平:低
- 输出类型:推挽
- 上拉/下拉:无
- 标签修改:
- A8 → BN2A8(对应原理图)
- 其他引脚类似修改
- 参数确认:无需额外修改,直接生成代码
步进电机代码实现准备
Section titled “步进电机代码实现准备”- 引脚标签重命名:
- PC9 → bn2(对应B相N2)
- C9 → bn1(B相N1)
- C8 → an2(A相N2)
- C7 → an1(A相N1)
- 目的:与原理图定义一致,代码阅读更清晰
- 工程操作:
- 点击生成代码
- 打开工程,编译验证无误
- 电机控制函数定义:
- 函数名:ymotor_run(电机运行)
- 初始无参数
- 后续描述电平时序逻辑控制电机步进
// 示例函数声明void ymotor_run(void);步进电机满步驱动第一步代码实现
Section titled “步进电机满步驱动第一步代码实现”- 第一步时序:A、B输出高电平,A-、B-输出低电平
- 使用
HAL_GPIO_WritePin函数设置
// A引脚 (GPIOC, BN2A8_Pin)HAL_GPIO_WritePin(GPIOC, BN2A8_Pin, GPIO_PIN_SET); // 高电平
// B引脚 (对应BN2)HAL_GPIO_WritePin(GPIOC, BN2_Pin, GPIO_PIN_SET); // 高电平- 端口确认:A、B引脚均在GPIOC块
- 代码调试:检查引脚标签是否正确(如BN2A8、BN2),避免标签错误
步进电机满步驱动第二步代码实现
Section titled “步进电机满步驱动第二步代码实现”- 第二步时序:B和A-输出高电平,A和B-输出低电平
- 第一步与第二步之间添加**HAL_Delay(1)**延时
- 控制频率约1kHz
// 第二步HAL_GPIO_WritePin(GPIOC, BN2_Pin, GPIO_PIN_RESET); // A低HAL_GPIO_WritePin(GPIOC, BN2A8_Pin, GPIO_PIN_SET); // A-高HAL_GPIO_WritePin(GPIOC, bn1_Pin, GPIO_PIN_SET); // B高HAL_GPIO_WritePin(GPIOC, bn2_Pin, GPIO_PIN_RESET); // B-低HAL_Delay(1);步进电机满步驱动第三步代码实现
Section titled “步进电机满步驱动第三步代码实现”- 第三步时序:A-和B输出高电平,A和B-输出低电平
// 第三步HAL_GPIO_WritePin(GPIOC, BN2_Pin, GPIO_PIN_RESET); // A低HAL_GPIO_WritePin(GPIOC, BN2A8_Pin, GPIO_PIN_SET); // A-高HAL_GPIO_WritePin(GPIOC, bn1_Pin, GPIO_PIN_RESET); // B低HAL_GPIO_WritePin(GPIOC, bn2_Pin, GPIO_PIN_SET); // B-高HAL_Delay(1);步进电机满步驱动第四步代码实现
Section titled “步进电机满步驱动第四步代码实现”- 第四步时序:A和B-输出高电平,A-和B输出低电平
- 完成4步循环后回到第一步,重复实现连续转动
// 第四步HAL_GPIO_WritePin(GPIOC, BN2_Pin, GPIO_PIN_SET); // A高HAL_GPIO_WritePin(GPIOC, BN2A8_Pin, GPIO_PIN_RESET); // A-低HAL_GPIO_WritePin(GPIOC, bn1_Pin, GPIO_PIN_RESET); // B低HAL_GPIO_WritePin(GPIOC, bn2_Pin, GPIO_PIN_SET); // B-高HAL_Delay(1);步进电机满步驱动函数完整调用
Section titled “步进电机满步驱动函数完整调用”- 函数位置:
ymotor_run()函数内实现4步循环 - main函数调用:在无限循环中调用
ymotor_run()实现连续旋转
int main(void) { // 初始化代码...
while (1) { ymotor_run(); // 调用电机驱动函数 }}代码烧录与电机启动验证
Section titled “代码烧录与电机启动验证”- 代码烧录后,电机正常转动,说明代码正确。
- 修改
ymotor_run函数控制电机转动。
步进电机延时调整与速度控制
Section titled “步进电机延时调整与速度控制”- 调整HAL_Delay值控制转速
- 延时小 → 转速快
- 延时大 → 转速慢
步进电机反转控制
Section titled “步进电机反转控制”- 正转时序:1→2→3→4→1循环
- 反转时序:4→3→2→1→4循环
- 代码只需逆序执行相同4步逻辑
通用电机控制函数
Section titled “通用电机控制函数”- 函数:ymotor_run(方向, 延时)
- 方向:0=正转,1=反转
- 延时:每步延时ms,控制转速
// 示例调用ymotor_run(0, 1); // 正转,1ms延时ymotor_run(1, 2); // 反转,2ms延时- 通过参数灵活控制方向与速度
步进电机满步驱动函数优化
Section titled “步进电机满步驱动函数优化”- 函数参数:第一个参数为当前步数%4(0-3代表4步时序),第二个参数为方向(0为正转)
- 调用
ymotor_run(direction)实现对应电平输出 - main循环实现:设置
step=500,direction=0
int step = 500; int direction = 0; while(running) { for(i=1; i <= step; i++) { motor_run(direction); // 根据step%4选择时序 HAL_Delay(1); // 每步1ms,频率约1kHz } }- 速度控制:减小
HAL_Delay加快速度,增大延时减慢速度 - 循环结束:500步后将所有HAL_GPIO口设为低电平(GPIO_PIN_RESET)
步进电机实验总结
Section titled “步进电机实验总结”- 电机停止条件:输出低电平(L/L),电机停止运转
- 正反转与速度控制:通过时序顺序(1-2-3-4正转 / 4-3-2-1反转)和延时值实现
课程总结与SPI预告
Section titled “课程总结与SPI预告”- 直流电机与步进电机相关内容讲完
- 下一节:SPI(串行外围设备接口,简称创口)
- 特点:高速、全双工、同步通信总线
- 与I2C类似,为串行通信接口
SPI引脚功能
Section titled “SPI引脚功能”- MOSI:MASTER OUTPUT SLAVE INPUT(主机输出、从机输入)
- 主机发送数据到从机
- MISO:MASTER INPUT SLAVE OUTPUT(主机输入、从机输出)
- 从机发送数据到主机
- 时钟线(SCK):同步信号
- 提供时钟同步,确保数据传输时序一致
- CS片选线:设备选择信号
- 支持一对多通讯
- 通过CS选择总线上特定设备进行通讯
- 类似I2C的设备地址机制,但用硬件引脚实现
多设备通信原理
Section titled “多设备通信原理”- 片选控制:与设备A通信时,使能A(低电平),失能B;切换到B时失能A,使能B
- 接线图:多个从设备共享总线,通过独立片选线控制
与UART/I2C对比
Section titled “与UART/I2C对比”- UART:异步(常用),或USART同步;通讯线3根(TX、RX、GND)
- I2C:同步(有SCL时钟线)
- SPI:同步(有SCLK时钟线)
- 通讯线区别:UART 3根,其他更多(SPI典型4线:MOSI/MISO/SCLK/CS)
SPI与UART/I2C对比
Section titled “SPI与UART/I2C对比”- 引脚数量:UART两根(TX/RX),I2C两根(SDA/SCL),SPI四根(发送/接收 + SCL + 片选)
- 通讯方式:
- UART:一对一(如单片机间或电脑与单片机)
- I2C/SPI:总线方式(一对多)
- 数据速率:
- UART:几十K到几M
- I2C:标准100K,高速3.4M
- SPI:10M到上百M(远高于I2C)
- 选择依据:大数据高速通讯选SPI,串口通讯选UART
SPI协议与UART/I2C对比
Section titled “SPI协议与UART/I2C对比”- 通信参数对比表:
| 项目 | UART (异步) | I2C (同步) | SPI (同步) |
|---|---|---|---|
| 通信线路 | TXD发送 RXD接收 GND地 |
SDA数据 SCL时钟 |
MOSI主发送从接收 MISO主接收从发送 SCK时钟 CS片选 |
| 通信速率 | 几十Kbps | 慢模式100Kbps 标准模式400Kbps |
几十Mbps |
| 场景 | 串口、蓝牙、RS232/485、鼠标键盘 | 短距离、传感器、EEPROM、Flash | 短距离高速、传感器、EEPROM、Flash、屏幕 |
- SPI应用:短距离高速通信,适合传感器、SPI Flash(如W25Q系列)、屏幕(如OLED)与MCU通信
- 后续实验:点亮OLED屏幕
STM32 SPI工程配置准备
Section titled “STM32 SPI工程配置准备”- 新建工程查看CubeMX SPI参数
- 左侧Connectivity → SPI
- 后续课程实际应用演示
STM32 SPI硬件通道与IO绑定
Section titled “STM32 SPI硬件通道与IO绑定”- STM32芯片内置三路SPI(SPI1、SPI2、SPI3)
- 绑定到指定引脚组,可配置为全速Master模式
- 配置后自动绑定四个IO(MOSI/MISO/SCK/CS)
- SPI1示例:使用硬件绑定四个IO
- 参考芯片手册第31页引脚说明章节
- 引脚支持确认:查找PA4/5/6/7
- 手册显示支持SPI对应模式
STM32 SPI端口重映射与参数配置
Section titled “STM32 SPI端口重映射与参数配置”- 可用CubeMX直接使能某个SPI,自动绑定引脚。
- 也可在数据手册中查找端口重映射信息。
- SPI1:可用PA4/5/6/7,也可用PB3/4/5。
CubeMX配置SPI
Section titled “CubeMX配置SPI”- 打开CubeMX,查看SPI配置参数的含义。
- 首先是模式选择。
STM32 SPI NSS片选引脚配置
Section titled “STM32 SPI NSS片选引脚配置”- 硬件NSS:设为Output模式
- 主机自动控制片选信号
- 通过库SPI API直接操作使能/失能
- 软件NSS:选择其他GPIO作为片选
- 手动设为Output模式
- 通信时控制GPIO电平使能外设
- 示例:拉低使能,高电平失能
- 禁用NSS:自定义片选控制
- 手动编写代码开启并配置
- 灵活选择任意IO作为片选线
SPI配置后续参数
Section titled “SPI配置后续参数”- 配置完模式/参数后,继续查看下方SPI具体设置
CubeMX SPI配置 - 数据格式与长度
Section titled “CubeMX SPI配置 - 数据格式与长度”- 数据格式:固定摩托罗拉格式(Motorola模式)
- SPI标准协议,由摩托罗拉设计
- 数据长度:可选8位或16位
- 通常选8位:方便字节传输
- 若从机要求16位,则匹配设置
CubeMX SPI配置 - Bit Order与Byte Order
Section titled “CubeMX SPI配置 - Bit Order与Byte Order”- Bit Order (MSB/LSB):发送时先高位还是先低位
- 根据从机要求匹配
- 从机MSB First → 主机设MSB First
- Byte Order:多字节时先高字节还是先低字节
- 同样根据从机匹配
- 配置原则:主机参数严格匹配从机,确保数据传输正确
- 配置原则:主机参数严格匹配从机,确保数据传输正确。
CubeMX SPI配置 - 时钟参数
Section titled “CubeMX SPI配置 - 时钟参数”- SPI是同步通信,需要时钟线(SCK)来同步数据传输。
- 时钟参数位于
Clock Parameters区域。 - SPI时钟来源:由系统时钟分频而来。
- 预分频器(Prescaler):用于设置SPI时钟频率。
- 示例:系统时钟72MHz,预分频2 → SPI时钟36MHz。
- 预分频256 → SPI时钟281.25kHz。
- 时钟频率选择:根据从设备支持的最高速率来设置。
- 从设备支持10MHz → SPI时钟设为10MHz以下。
- 从设备支持2MHz → SPI时钟设为2MHz以下。
- 注意:SPI时钟不能超过从设备支持的最高速率,否则数据可能出错。
- CPOL (Clock Polarity):时钟极性
- 0:空闲时低电平
- 1:空闲时高电平
- CPHA (Clock Phase):时钟相位
- 0:第一个时钟沿采样数据
- 1:第二个时钟沿采样数据
- 时钟极性与相位:两者组合形成4种工作模式(模式0、1、2、3)。
- 主机和从机的CPOL/CPHA必须一致,才能正常通信。
- 配置原则:根据从设备手册要求进行设置。
CubeMX SPI配置 - NSS信号
Section titled “CubeMX SPI配置 - NSS信号”- NSS (Slave Select):从机选择信号。
- 模式选择:
- Hardware NSS Signal:硬件NSS信号。
- Output Enable:NSS引脚作为输出,由硬件自动控制。
- Output Disable:NSS引脚作为输入,用于多主模式或独立控制。
- Software NSS Signal:软件NSS信号。
- 由软件(代码)控制NSS引脚的高低电平。
- 适用于单主机、单从机的简单场景。
- 使用场景:通常选择软件NSS,通过GPIO操作来控制片选信号。
- 这样可以更灵活地控制多个从设备。
CubeMX SPI配置 - CRC校验
Section titled “CubeMX SPI配置 - CRC校验”- CRC Calculation:CRC校验。
- 功能:用于检查数据传输过程中的错误。
- 启用/禁用:通常选择禁用。
- 只有当从设备支持且需要高可靠性时才启用。
- 启用后会增加通信开销和复杂度。
SPI通信总结
Section titled “SPI通信总结”- 关键:SPI的所有参数(数据长度、位序、时钟极性、时钟相位、NSS模式)必须与从设备完全匹配。
- 配置流程:
- 使能对应的SPI外设。
- 配置工作模式(Master/Slave)。
- 配置数据参数(Data Size、Bit Order)。
- 配置时钟参数(Prescaler、CPOL、CPHA)。
- 配置NSS模式(硬件/软件)。
- 根据需要决定是否启用CRC校验。
- 目的:确保主机和从机能够正确解析和交换数据。
SPI屏幕驱动实验
Section titled “SPI屏幕驱动实验”- 实验目标:使用SPI协议驱动OLED屏幕。
- 屏幕型号:0.96寸OLED显示屏。
- 驱动芯片:SSD1306。
- 通信方式:SPI接口。
- 屏幕尺寸:128x64像素。
- 硬件连接:
- VCC/GND:电源。
- D0 (SCK):时钟线。
- D1 (MOSI):数据线。
- CS:片选线。
- DC (Data/Command):数据/命令选择线。
- RES:复位线。
0.96寸OLED屏幕引脚说明
Section titled “0.96寸OLED屏幕引脚说明”- D0 (SCK):对应STM32的SPI时钟引脚。
- D1 (MOSI):对应STM32的SPI主发从收引脚。
- CS:对应STM32的GPIO输出引脚(软件控制)。
- DC (Data/Command):对应STM32的GPIO输出引脚。
- 高电平:发送数据。
- 低电平:发送命令。
- RES (Reset):对应STM32的GPIO输出引脚。
- 用于复位OLED屏幕。
OLED屏幕驱动实验工程准备
Section titled “OLED屏幕驱动实验工程准备”- 工程复制:复制现有工程,重命名为oled_demo。
- CubeMX配置:
- SPI1:全双工主模式。
- GPIO输出:配置CS、DC、RES三个引脚。
OLED屏幕驱动实验 - SPI1引脚配置
Section titled “OLED屏幕驱动实验 - SPI1引脚配置”- SPI1引脚:
- PA5:SCK (SPI1时钟)。
- PA6:MISO (SPI1主入从出)。
- PA7:MOSI (SPI1主出从入)。
- PA4:NSS (SPI1片选)。
- CubeMX配置:
- PA5、PA7:配置为SPI1功能。
- PA6:由于OLED屏是单向通信(主机只发数据),MISO引脚可以不配置或配置为GPIO。
- PA4:配置为GPIO输出,用于软件控制CS。
OLED屏幕驱动实验 - 其他GPIO配置
Section titled “OLED屏幕驱动实验 - 其他GPIO配置”- DC引脚:PB1,配置为GPIO输出。
- RES引脚:PB0,配置为GPIO输出。
- User Label:为这些GPIO引脚添加有意义的标签,方便代码编写。
- 例如:
OLED_CS_Pin、OLED_DC_Pin、OLED_RES_Pin。
OLED屏幕驱动实验 - SPI参数配置
Section titled “OLED屏幕驱动实验 - SPI参数配置”- 模式:
Full-Duplex Master。 - 数据格式:
Motorola。 - 数据长度:
8 Bits。 - MSB First:
MSB First(高位在前)。 - 波特率预分频:根据屏幕支持的速率选择。
- 示例:
PCLK2/256。 - CPOL/CPHA:根据屏幕手册选择。
- 示例:
CPOL Low,CPHA 1 Edge。 - NSS模式:
Software NSS Signal(软件控制)。 - CRC:
Disabled。
OLED屏幕驱动实验 - 代码生成与文件结构
Section titled “OLED屏幕驱动实验 - 代码生成与文件结构”- 生成代码:配置完成后,点击生成代码。
- 文件结构:
oled.c:OLED屏幕驱动源文件,包含初始化、显示函数等。oled.h:OLED屏幕驱动头文件,包含函数声明、宏定义等。- 添加文件:将
oled.c和oled.h文件添加到工程中。 oled.c放到Core/Src目录下。oled.h放到Core/Inc目录下。- 编译验证:添加文件后,先编译一次工程,确保没有语法错误和文件路径问题。
STM32 SPI时钟配置与总线挂载
Section titled “STM32 SPI时钟配置与总线挂载”- SPI总线架构:SPI1挂载APB2总线,SPI2/3挂载APB1总线
- 时钟来源:对应APB1/APB2时钟
- 分频配置:通过时钟树调整APB时钟分频
- STM32建议:SPI时钟不超过18MHz
- 示例:选2分频超限时报错
- 需增大分频系数避免超过限制
CubeMX SPI配置 - 时钟相位与极性
Section titled “CubeMX SPI配置 - 时钟相位与极性”- 时钟相位 (CPHA) 与 时钟极性 (CPOL):决定SPI采样时刻与时钟同步
- 配置CubeMX时钟分频后设置(4或8改为18)
- 两个参数组合产生4种模式
- 模式对照表:
| SPI模式 | CPOL | CPHA | 数据采样时钟 | 数据发送时钟 |
|---|---|---|---|---|
| 模式0 | 0 | 0 | CPOL=0, CPHA=0 | CPOL=0, CPHA=0 |
| 模式1 | 1 | 0 | CPOL=1, CPHA=0 | CPOL=0, CPHA=0 |
| 模式2 | 0 | 1 | CPOL=0, CPHA=1 | CPOL=1, CPHA=1 |
| 模式3 | 1 | 1 | CPOL=1, CPHA=1 | CPOL=1, CPHA=1 |
- 时序图示(手册第461页)示例:
CPOL=1, CPHA=0: ______ ______ ______ ______SCK ______________________|
MOSI ____________________________________________________________
MISO ____________________________________________________________
CPOL=0, CPHA=0: ______ ______ ______ ______SCK ______________________|
MOSI ____________________________________________________________
MISO ____________________________________________________________- 作用:控制何时采样数据(上升/下降沿),确保主从机时序匹配
- 根据从机手册选择对应模式
SPI时钟极性与相位详解
Section titled “SPI时钟极性与相位详解”- CPOL (Clock Polarity,时钟极性):定义时钟线空闲时的电平
- CPOL=0:空闲时低电平
- CPOL=1:空闲时高电平
- CPHA (Clock Phase,时钟相位):定义数据采样时刻
- CPHA=0:在第一个时钟沿采样(即时钟变沿)
- CPHA=1:在第二个时钟沿采样
- 模式0示例 (CPOL=0, CPHA=0):低速边缘采样
- 低速边缘:时钟从空闲电平变沿时刻
- 时钟空闲低电平,上升沿时采样数据
模式0 (CPOL=0, CPHA=0): _____ _____ _____ _____SCK ________| |___| |___| |__ ← 上升沿采样
MOSI [数据位] [数据位] [数据位] ...
MISO [数据位] [数据位] [数据位] ...- 影响:CPOL/CPHA组合决定采样初始电平与时机,确保主从机同步
SPI时钟相位与极性 - 采样机制
Section titled “SPI时钟相位与极性 - 采样机制”- 采样时刻决定:CPOL/CPHA共同控制何时采样数据
- 第一个时钟沿:空闲电平后第一个上升/下降沿
- 第二个时钟沿:空闲电平后第二个沿
- 示例:
- CPOL=1, CPHA=0:空闲高电平,第一个下降沿采样
- CPOL=0, CPHA=1:空闲低电平,第二个上升沿采样
- 配置原则:
- 主机严格匹配从机参数
- 根据从机要求选择对应模式,确保采样时机一致
STM32硬件SPI代码生成与初始化函数
Section titled “STM32硬件SPI代码生成与初始化函数”- 生成代码后,main函数自动添加**MX_SPI1_Init()**调用
- 与其他外设初始化(如ADC、USART)顺序一致
int main(void) { // ... MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); MX_ADC1_Init(); MX_SPI1_Init(); // SPI初始化新增 // ...}HAL_SPI_MspInit函数实现
Section titled “HAL_SPI_MspInit函数实现”- SPI1 MSP初始化(HAL_SPI_MspInit调用)
- 使能SPI1时钟:
__HAL_RCC_SPI1_CLK_ENABLE() - 使能GPIOA时钟:
__HAL_RCC_GPIOA_CLK_ENABLE() - 配置PA4/5/6/7为SPI1功能
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);- HAL_SPI_MspDeInit反初始化
- 关闭SPI1时钟:
__HAL_RCC_SPI1_CLK_DISABLE() - 解除PA4/5/6/7 GPIO配置:
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
MX_SPI1_Init函数结构
Section titled “MX_SPI1_Init函数结构”- 基本配置
hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;(8位数据)- 初始化检查:
if (HAL_SPI_Init(&hspi1) != HAL_OK) Error_Handler();
STM32 SPI回调函数机制
Section titled “STM32 SPI回调函数机制”- 回调函数(Callback):用于输出设备硬件无关的函数
- 在调用HAL库发送/接收函数后自动触发
- HAL_SPI_TxCpltCallback:传输完成回调(弱函数)
- 函数末尾可见WEAK属性,可重写覆盖
- 示例:发送完毕后执行自定义逻辑
- 重写方法:在用户代码中重新定义该函数
- 调用HAL函数时,内部自动调用重写版本
- 用于自定义发送后处理(如数据校验)
SPI发送接收函数位置
Section titled “SPI发送接收函数位置”- 位于回调函数下方
- 包含SPI相关发送/接收API函数
SPI传输方式支持
Section titled “SPI传输方式支持”- 中断与DMA:SPI全双工通信支持中断(IT结尾函数)和DMA传输
- 与前面UART全双工通信类似
OLED屏幕驱动实验预告
Section titled “OLED屏幕驱动实验预告”- 实验内容:手把手操作开发板支持SPI的屏幕
- 屏幕接口:支持三线SPI、四线SPI、I2C
- 本实验使用四线SPI设计
- 资料准备:下载屏幕驱动手册,查看关键接口描述
1.3寸OLED SH1106屏幕
Section titled “1.3寸OLED SH1106屏幕”屏幕规格与接口
Section titled “屏幕规格与接口”- 分辨率:128x64
- 接口:4-wire SPI(MOSI/MISO/SCK/CS)或3-wire SPI(MOSI/SCK/CS)
- 驱动IC:SH1106
- 颜色:白色,尺寸28.0mm x 20.0mm,显示区23.5mm x 11.5mm
SPI接口配置
Section titled “SPI接口配置”| 配置 | 数据信号 | 控制信号 |
|---|---|---|
| 4-wire SPI | MOSI, MISO, SCK, CS | DC, RST, VSS, VDD |
| 3-wire SPI | MOSI, SCK, CS | DC, RST, VSS, VDD |
- 默认模式:SPI mode 0
- 选择依据:根据硬件连接和需求
控制引脚功能
Section titled “控制引脚功能”- DC (Data/Command):低电平发送命令,高电平发送数据
- 命令:配置屏幕模式/参数
- 数据:显示图像内容
- RST (Reset):复位显示屏
- CS (Chip Select):低电平选中设备,高电平取消选中
- 通过SPI驱动实现画点、画线、显示图像
OLED屏幕原理图引脚连接
Section titled “OLED屏幕原理图引脚连接”- RES:复位信号,连接PB8
- DC:指令/数据切换信号,连接PB4
- CLK:时钟信号(对应SCK),连接PB3
- SDIN:数据输入信号(对应MOSI),连接PB5
- 连接方式:通过网络标签连接到STM32相应引脚
OLED屏幕驱动实验 - SPI3引脚配置
Section titled “OLED屏幕驱动实验 - SPI3引脚配置”- SPI3模式选择:全双工Master或半双工Master
- 显示屏只需发送数据(无需接收),选半双工Master
- 自动引脚绑定:使能SPI3后,默认PB3(时钟SCK)、PB5(MOSI主出从入)
- NSS片选配置:Disable硬件NSS
- 原理图中CS引脚接地
- 手册说明:CS接地后芯片默认使能
- 上电即选中状态,无需额外控制
- 后续:配置完成后调整数据类型参数
控制引脚电平状态与配置
Section titled “控制引脚电平状态与配置”- RES (复位引脚):低电平复位芯片,高电平正常工作模式
- DC (A0, 数据/命令引脚):高电平发送显示数据,低电平发送命令数据
- 配置方式:将RES和DC引脚设置为输出模式
- 由STM32作为主机控制这两个引脚电平
- 用于驱动屏幕显示和参数配置
OLED屏幕驱动实验 - SPI数据参数配置
Section titled “OLED屏幕驱动实验 - SPI数据参数配置”- 数据格式:选择摩托罗拉格式(Motorola)
- SPI标准协议格式,与屏幕芯片匹配
- 数据长度:8位(8 Bits)
- 根据芯片手册:发送D7~D0 8位数据
- 位序 (Bit Order):MSB First
- 先发D7,再发D6…高位先行
- 初始波特率设置:预分频选较大值(如256)
- 降低SPI频率,避免硬件走线不良导致刷新失败或点亮不了
- 调试成功后再逐步提高频率
OLED屏幕初始化配置
Section titled “OLED屏幕初始化配置”- 配置CPOL/CPHA:根据芯片手册选择CPOL=1(高),CPHA=偶数边缘(第二个边缘)
- 与之前模式设置一致
- 生成代码验证:CubeMX生成后编译工程,无问题
OLED驱动代码编写
Section titled “OLED驱动代码编写”- 参考手册时序:芯片手册提供屏幕初始化时序图
- 厂家示例代码:包含屏幕特定参数
- 直接参考编写初始化和驱动函数
- 参数针对该屏幕设计,确保兼容
OLED复位序列实现
Section titled “OLED复位序列实现”- 复位流程:拉低OLED_RST_Pin(GPIO_PIN_RESET) → HAL_Delay(1000) → 拉高(GPIO_PIN_SET) → HAL_Delay(1000)
- 拉低:触发复位
- 拉高:进入正常工作模式
// Reset the OLED displayHAL_GPIO_WritePin(GPIOH, OLED_RST_PIN, GPIO_PIN_RESET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOH, OLED_RST_PIN, GPIO_PIN_SET);HAL_Delay(1000);- 位置:main函数
/* USER CODE BEGIN 2 */区域,紧跟外设初始化后执行
OLED复位序列实测简化
Section titled “OLED复位序列实测简化”- 实测简化:拉低OLED_RED_Pin复位 → HAL_Delay(1000) → 拉高 → HAL_Delay(1000),后续循环可省略,直接进入正常工作模式
HAL_GPIO_WritePin(GPIOB, OLED_RED_Pin, GPIO_PIN_SET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOB, OLED_RED_Pin, GPIO_PIN_RESET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOB, OLED_RED_Pin, GPIO_PIN_SET);HAL_Delay(1000);OLED命令发送函数调用
Section titled “OLED命令发送函数调用”- DC引脚控制:拉低OLED_DC_Pin进入命令发送模式
HAL_GPIO_WritePin(GPIOB, OLED_DC_Pin, GPIO_PIN_RESET)- SPI发送函数:
HAL_SPI_Transmit(&hspi3, (uint8_t*)&cmd, 1, HAL_MAX_DELAY) - 参数:SPI3句柄、8位命令数据指针(
uint8_t类型)、长度1