单片机 - STM32CubeMX HAL库开发部分

目录

一、基础外设

[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.TIM

[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)
    {
        /* 主循环可以放置其他业务代码 */
    }
}
相关推荐
日更嵌入式的打工仔2 小时前
两种核心消息队列:环形队列与RTOS消息队列解析
笔记·单片机
TheNextByte12 小时前
如何轻松地将音乐从Mac传输到Android ?
android·stm32·macos
石马马户2 小时前
keil使用Jlink下载时出现No Cortex-M SW Device Found 解决方法
单片机·嵌入式硬件
快乐的划水a2 小时前
嵌入式时间测量方法总结
c++·stm32·单片机
文弱书生6562 小时前
3-electronbot舵机板电路分析
linux·单片机·嵌入式硬件
风哥在风中2 小时前
一“芯”二用,氧化铝陶瓷发热芯的温度控制原理与技术特性分析
嵌入式硬件·硬件工程·焊接工具
Zeku2 小时前
20251224 - 嵌入式 Linux 开发中的MQTT指南
stm32·freertos·linux驱动开发·linux应用开发
TEC_INO2 小时前
STM32_4:TIM
stm32·单片机·嵌入式硬件
会编程是什么感觉...2 小时前
单片机 - STM32HAL库常用API
stm32·单片机